bmo_extrude.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  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.
  19. *
  20. * ***** END GPL LICENSE BLOCK *****
  21. */
  22. /** \file blender/bmesh/operators/bmo_extrude.c
  23. * \ingroup bmesh
  24. *
  25. * Extrude faces and solidify.
  26. */
  27. #include "MEM_guardedalloc.h"
  28. #include "DNA_meshdata_types.h"
  29. #include "BLI_math.h"
  30. #include "BLI_buffer.h"
  31. #include "BKE_customdata.h"
  32. #include "bmesh.h"
  33. #include "intern/bmesh_operators_private.h" /* own include */
  34. #define USE_EDGE_REGION_FLAGS
  35. enum {
  36. EXT_INPUT = 1,
  37. EXT_KEEP = 2,
  38. EXT_DEL = 4
  39. };
  40. #define VERT_MARK 1
  41. #define EDGE_MARK 1
  42. #define FACE_MARK 1
  43. #define VERT_NONMAN 2
  44. #define EDGE_NONMAN 2
  45. void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
  46. {
  47. const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
  48. GHash *select_history_map = NULL;
  49. BMOIter siter;
  50. BMFace *f_org;
  51. if (use_select_history) {
  52. select_history_map = BM_select_history_map_create(bm);
  53. }
  54. BMO_ITER (f_org, &siter, op->slots_in, "faces", BM_FACE) {
  55. BMFace *f_new;
  56. BMLoop *l_org, *l_org_first;
  57. BMLoop *l_new;
  58. BMO_face_flag_enable(bm, f_org, EXT_DEL);
  59. f_new = BM_face_copy(bm, bm, f_org, true, true);
  60. BMO_face_flag_enable(bm, f_new, EXT_KEEP);
  61. if (select_history_map) {
  62. BMEditSelection *ese;
  63. ese = BLI_ghash_lookup(select_history_map, f_org);
  64. if (ese) {
  65. ese->ele = (BMElem *)f_new;
  66. }
  67. }
  68. l_org = l_org_first = BM_FACE_FIRST_LOOP(f_org);
  69. l_new = BM_FACE_FIRST_LOOP(f_new);
  70. do {
  71. BMFace *f_side;
  72. BMLoop *l_side_iter;
  73. BM_elem_attrs_copy(bm, bm, l_org, l_new);
  74. f_side = BM_face_create_quad_tri(bm,
  75. l_org->next->v, l_new->next->v, l_new->v, l_org->v,
  76. f_org, BM_CREATE_NOP);
  77. l_side_iter = BM_FACE_FIRST_LOOP(f_side);
  78. BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next;
  79. BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next;
  80. BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); l_side_iter = l_side_iter->next;
  81. BM_elem_attrs_copy(bm, bm, l_org, l_side_iter);
  82. if (select_history_map) {
  83. BMEditSelection *ese;
  84. ese = BLI_ghash_lookup(select_history_map, l_org->v);
  85. if (ese) {
  86. ese->ele = (BMElem *)l_new->v;
  87. }
  88. ese = BLI_ghash_lookup(select_history_map, l_org->e);
  89. if (ese) {
  90. ese->ele = (BMElem *)l_new->e;
  91. }
  92. }
  93. } while (((void)
  94. (l_new = l_new->next),
  95. (l_org = l_org->next)) != l_org_first);
  96. }
  97. if (select_history_map) {
  98. BLI_ghash_free(select_history_map, NULL, NULL);
  99. }
  100. BMO_op_callf(bm, op->flag,
  101. "delete geom=%ff context=%i",
  102. EXT_DEL, DEL_ONLYFACES);
  103. BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, EXT_KEEP);
  104. }
  105. /**
  106. * \brief Copy the loop pair from an adjacent face to both sides of this quad.
  107. *
  108. * The face is assumed to be a quad, created by extruding.
  109. * This function won't crash if its not but won't work right either.
  110. * \a e_b is the new edge.
  111. *
  112. * \note The edge this face comes from needs to be from the first and second verts to the face.
  113. * The caller must ensure this else we will copy from the wrong source.
  114. */
  115. static void bm_extrude_copy_face_loop_attributes(BMesh *bm, BMFace *f)
  116. {
  117. /* edge we are extruded from */
  118. BMLoop *l_first_0 = BM_FACE_FIRST_LOOP(f);
  119. BMLoop *l_first_1 = l_first_0->next;
  120. BMLoop *l_first_2 = l_first_1->next;
  121. BMLoop *l_first_3 = l_first_2->next;
  122. BMLoop *l_other_0;
  123. BMLoop *l_other_1;
  124. if (UNLIKELY(l_first_0 == l_first_0->radial_next)) {
  125. return;
  126. }
  127. l_other_0 = BM_edge_other_loop(l_first_0->e, l_first_0);
  128. l_other_1 = BM_edge_other_loop(l_first_0->e, l_first_1);
  129. /* copy data */
  130. BM_elem_attrs_copy(bm, bm, l_other_0->f, f);
  131. BM_elem_flag_disable(f, BM_ELEM_HIDDEN); /* possibly we copy from a hidden face */
  132. BM_elem_attrs_copy(bm, bm, l_other_0, l_first_0);
  133. BM_elem_attrs_copy(bm, bm, l_other_0, l_first_3);
  134. BM_elem_attrs_copy(bm, bm, l_other_1, l_first_1);
  135. BM_elem_attrs_copy(bm, bm, l_other_1, l_first_2);
  136. }
  137. /* Disable the skin root flag on the input vert, assumes that the vert
  138. * data includes an CD_MVERT_SKIN layer */
  139. static void bm_extrude_disable_skin_root(BMesh *bm, BMVert *v)
  140. {
  141. MVertSkin *vs;
  142. vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN);
  143. vs->flag &= ~MVERT_SKIN_ROOT;
  144. }
  145. void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
  146. {
  147. BMOIter siter;
  148. BMOperator dupeop;
  149. BMFace *f;
  150. BMEdge *e, *e_new;
  151. BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
  152. BMO_edge_flag_enable(bm, e, EXT_INPUT);
  153. BMO_vert_flag_enable(bm, e->v1, EXT_INPUT);
  154. BMO_vert_flag_enable(bm, e->v2, EXT_INPUT);
  155. }
  156. BMO_op_initf(
  157. bm, &dupeop, op->flag,
  158. "duplicate geom=%fve use_select_history=%b",
  159. EXT_INPUT, BMO_slot_bool_get(op->slots_in, "use_select_history"));
  160. BMO_op_exec(bm, &dupeop);
  161. /* disable root flag on all new skin nodes */
  162. if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
  163. BMVert *v;
  164. BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) {
  165. bm_extrude_disable_skin_root(bm, v);
  166. }
  167. }
  168. for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) {
  169. BMVert *f_verts[4];
  170. e_new = BMO_iter_map_value_ptr(&siter);
  171. if (e->l && e->v1 != e->l->v) {
  172. f_verts[0] = e->v1;
  173. f_verts[1] = e->v2;
  174. f_verts[2] = e_new->v2;
  175. f_verts[3] = e_new->v1;
  176. }
  177. else {
  178. f_verts[0] = e->v2;
  179. f_verts[1] = e->v1;
  180. f_verts[2] = e_new->v1;
  181. f_verts[3] = e_new->v2;
  182. }
  183. /* not sure what to do about example face, pass NULL for now */
  184. f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
  185. bm_extrude_copy_face_loop_attributes(bm, f);
  186. if (BMO_edge_flag_test(bm, e, EXT_INPUT)) {
  187. e = e_new;
  188. }
  189. BMO_face_flag_enable(bm, f, EXT_KEEP);
  190. BMO_edge_flag_enable(bm, e, EXT_KEEP);
  191. BMO_vert_flag_enable(bm, e->v1, EXT_KEEP);
  192. BMO_vert_flag_enable(bm, e->v2, EXT_KEEP);
  193. }
  194. BMO_op_finish(bm, &dupeop);
  195. BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, EXT_KEEP);
  196. }
  197. void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
  198. {
  199. const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
  200. BMOIter siter;
  201. BMVert *v, *dupev;
  202. BMEdge *e;
  203. const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN);
  204. GHash *select_history_map = NULL;
  205. if (use_select_history) {
  206. select_history_map = BM_select_history_map_create(bm);
  207. }
  208. for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) {
  209. dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
  210. BMO_vert_flag_enable(bm, dupev, EXT_KEEP);
  211. if (has_vskin)
  212. bm_extrude_disable_skin_root(bm, v);
  213. if (select_history_map) {
  214. BMEditSelection *ese;
  215. ese = BLI_ghash_lookup(select_history_map, v);
  216. if (ese) {
  217. ese->ele = (BMElem *)dupev;
  218. }
  219. }
  220. /* not essential, but ensures face normals from extruded edges are contiguous */
  221. if (BM_vert_is_wire_endpoint(v)) {
  222. if (v->e->v1 == v) {
  223. SWAP(BMVert *, v, dupev);
  224. }
  225. }
  226. e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP);
  227. BMO_edge_flag_enable(bm, e, EXT_KEEP);
  228. }
  229. if (select_history_map) {
  230. BLI_ghash_free(select_history_map, NULL, NULL);
  231. }
  232. BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, EXT_KEEP);
  233. BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP);
  234. }
  235. #ifdef USE_EDGE_REGION_FLAGS
  236. /**
  237. * When create an edge for an extruded face region
  238. * check surrounding edge flags before creating a new edge.
  239. */
  240. static bool bm_extrude_region_edge_flag(const BMVert *v, char r_e_hflag[2])
  241. {
  242. BMEdge *e_iter;
  243. const char hflag_enable = BM_ELEM_SEAM;
  244. const char hflag_disable = BM_ELEM_SMOOTH;
  245. bool ok = false;
  246. r_e_hflag[0] = 0x0;
  247. r_e_hflag[1] = 0xff;
  248. /* clear flags on both disks */
  249. e_iter = v->e;
  250. do {
  251. if (e_iter->l && !BM_edge_is_boundary(e_iter)) {
  252. r_e_hflag[0] |= e_iter->head.hflag;
  253. r_e_hflag[1] &= e_iter->head.hflag;
  254. ok = true;
  255. }
  256. } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != v->e);
  257. if (ok) {
  258. r_e_hflag[0] &= hflag_enable;
  259. r_e_hflag[1] = hflag_disable & ~r_e_hflag[1];
  260. }
  261. return ok;
  262. }
  263. #endif /* USE_EDGE_REGION_FLAGS */
  264. void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
  265. {
  266. BMOperator dupeop, delop;
  267. BMOIter siter;
  268. BMIter iter, fiter, viter;
  269. BMEdge *e, *e_new;
  270. BMVert *v;
  271. BMFace *f;
  272. bool found, fwd, delorig = false;
  273. BMOpSlot *slot_facemap_out;
  274. BMOpSlot *slot_edges_exclude;
  275. /* initialize our sub-operators */
  276. BMO_op_initf(
  277. bm, &dupeop, op->flag,
  278. "duplicate use_select_history=%b",
  279. BMO_slot_bool_get(op->slots_in, "use_select_history"));
  280. BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, EXT_INPUT);
  281. /* if one flagged face is bordered by an un-flagged face, then we delete
  282. * original geometry unless caller explicitly asked to keep it. */
  283. if (!BMO_slot_bool_get(op->slots_in, "use_keep_orig")) {
  284. BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
  285. int edge_face_tot;
  286. if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) {
  287. continue;
  288. }
  289. found = false; /* found a face that isn't input? */
  290. edge_face_tot = 0; /* edge/face count */
  291. BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
  292. if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
  293. found = true;
  294. delorig = true;
  295. break;
  296. }
  297. edge_face_tot++;
  298. }
  299. if ((edge_face_tot > 1) && (found == false)) {
  300. /* edge has a face user, that face isn't extrude input */
  301. BMO_edge_flag_enable(bm, e, EXT_DEL);
  302. }
  303. }
  304. }
  305. /* calculate verts to delete */
  306. BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
  307. if (v->e) { /* only deal with verts attached to geometry [#33651] */
  308. found = false;
  309. BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) {
  310. if (!BMO_edge_flag_test(bm, e, EXT_INPUT) ||
  311. !BMO_edge_flag_test(bm, e, EXT_DEL))
  312. {
  313. found = true;
  314. break;
  315. }
  316. }
  317. /* avoid an extra loop */
  318. if (found == true) {
  319. BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) {
  320. if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
  321. found = true;
  322. break;
  323. }
  324. }
  325. }
  326. if (found == false) {
  327. BMO_vert_flag_enable(bm, v, EXT_DEL);
  328. }
  329. }
  330. }
  331. BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
  332. if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
  333. BMO_face_flag_enable(bm, f, EXT_DEL);
  334. }
  335. }
  336. if (delorig == true) {
  337. BMO_op_initf(bm, &delop, op->flag,
  338. "delete geom=%fvef context=%i",
  339. EXT_DEL, DEL_ONLYTAGGED);
  340. }
  341. BMO_slot_copy(op, slots_in, "geom",
  342. &dupeop, slots_in, "geom");
  343. BMO_op_exec(bm, &dupeop);
  344. /* disable root flag on all new skin nodes */
  345. if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
  346. BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) {
  347. bm_extrude_disable_skin_root(bm, v);
  348. }
  349. }
  350. slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out");
  351. if (bm->act_face && BMO_face_flag_test(bm, bm->act_face, EXT_INPUT)) {
  352. bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face);
  353. }
  354. if (delorig) {
  355. BMO_op_exec(bm, &delop);
  356. }
  357. /* if not delorig, reverse loops of original face */
  358. if (!delorig) {
  359. BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
  360. if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
  361. BM_face_normal_flip(bm, f);
  362. }
  363. }
  364. }
  365. BMO_slot_copy(&dupeop, slots_out, "geom.out",
  366. op, slots_out, "geom.out");
  367. slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude");
  368. for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) {
  369. BMVert *f_verts[4];
  370. #ifdef USE_EDGE_REGION_FLAGS
  371. BMEdge *f_edges[4];
  372. #endif
  373. /* this should always be wire, so this is mainly a speedup to avoid map lookup */
  374. if (BM_edge_is_wire(e) && BMO_slot_map_contains(slot_edges_exclude, e)) {
  375. BMVert *v1 = e->v1, *v2 = e->v2;
  376. /* The original edge was excluded,
  377. * this would result in a standalone wire edge - see [#30399] */
  378. BM_edge_kill(bm, e);
  379. /* kill standalone vertices from this edge - see [#32341] */
  380. if (!v1->e)
  381. BM_vert_kill(bm, v1);
  382. if (!v2->e)
  383. BM_vert_kill(bm, v2);
  384. continue;
  385. }
  386. /* skip creating face for excluded edges see [#35503] */
  387. if (BMO_slot_map_contains(slot_edges_exclude, e)) {
  388. /* simply skip creating the face */
  389. continue;
  390. }
  391. e_new = BMO_iter_map_value_ptr(&siter);
  392. if (!e_new) {
  393. continue;
  394. }
  395. /* orient loop to give same normal as a loop of newedge
  396. * if it exists (will be an extruded face),
  397. * else same normal as a loop of e, if it exists */
  398. if (!e_new->l)
  399. fwd = !e->l || !(e->l->v == e->v1);
  400. else
  401. fwd = (e_new->l->v == e_new->v1);
  402. if (fwd) {
  403. f_verts[0] = e->v1;
  404. f_verts[1] = e->v2;
  405. f_verts[2] = e_new->v2;
  406. f_verts[3] = e_new->v1;
  407. }
  408. else {
  409. f_verts[0] = e->v2;
  410. f_verts[1] = e->v1;
  411. f_verts[2] = e_new->v1;
  412. f_verts[3] = e_new->v2;
  413. }
  414. #ifdef USE_EDGE_REGION_FLAGS
  415. /* handle new edges */
  416. f_edges[0] = e;
  417. f_edges[2] = e_new;
  418. f_edges[1] = BM_edge_exists(f_verts[1], f_verts[2]);
  419. if (f_edges[1] == NULL) {
  420. char e_hflag[2];
  421. bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[2], e_hflag);
  422. f_edges[1] = BM_edge_create(bm, f_verts[1], f_verts[2], NULL, BM_CREATE_NOP);
  423. if (e_hflag_ok) {
  424. BM_elem_flag_enable(f_edges[1], e_hflag[0]);
  425. BM_elem_flag_disable(f_edges[1], e_hflag[1]);
  426. }
  427. }
  428. f_edges[3] = BM_edge_exists(f_verts[3], f_verts[0]);
  429. if (f_edges[3] == NULL) {
  430. char e_hflag[2];
  431. bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[3], e_hflag);
  432. f_edges[3] = BM_edge_create(bm, f_verts[3], f_verts[0], NULL, BM_CREATE_NOP);
  433. if (e_hflag_ok) {
  434. BM_elem_flag_enable(f_edges[3], e_hflag[0]);
  435. BM_elem_flag_disable(f_edges[3], e_hflag[1]);
  436. }
  437. }
  438. f = BM_face_create(bm, f_verts, f_edges, 4, NULL, BM_CREATE_NOP);
  439. #else
  440. f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
  441. #endif
  442. bm_extrude_copy_face_loop_attributes(bm, f);
  443. }
  444. /* link isolated vert */
  445. for (v = BMO_iter_new(&siter, dupeop.slots_out, "isovert_map.out", 0); v; v = BMO_iter_step(&siter)) {
  446. BMVert *v2 = BMO_iter_map_value_ptr(&siter);
  447. /* not essential, but ensures face normals from extruded edges are contiguous */
  448. if (BM_vert_is_wire_endpoint(v)) {
  449. if (v->e->v1 == v) {
  450. SWAP(BMVert *, v, v2);
  451. }
  452. }
  453. BM_edge_create(bm, v, v2, NULL, BM_CREATE_NO_DOUBLE);
  454. }
  455. /* cleanup */
  456. if (delorig) BMO_op_finish(bm, &delop);
  457. BMO_op_finish(bm, &dupeop);
  458. }
  459. /*
  460. * Compute higher-quality vertex normals used by solidify.
  461. * Only considers geometry in the marked solidify region.
  462. * Note that this does not work so well for non-manifold
  463. * regions.
  464. */
  465. static void calc_solidify_normals(BMesh *bm)
  466. {
  467. BMIter viter, eiter, fiter;
  468. BMVert *v;
  469. BMEdge *e;
  470. BMFace *f, *f1, *f2;
  471. float edge_normal[3];
  472. int i;
  473. /* can't use BM_edge_face_count because we need to count only marked faces */
  474. int *edge_face_count = MEM_callocN(sizeof(int) * bm->totedge, __func__);
  475. BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
  476. BM_elem_flag_enable(v, BM_ELEM_TAG);
  477. }
  478. BM_mesh_elem_index_ensure(bm, BM_EDGE);
  479. BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
  480. if (!BMO_face_flag_test(bm, f, FACE_MARK)) {
  481. continue;
  482. }
  483. BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
  484. /* And mark all edges and vertices on the
  485. * marked faces */
  486. BMO_edge_flag_enable(bm, e, EDGE_MARK);
  487. BMO_vert_flag_enable(bm, e->v1, VERT_MARK);
  488. BMO_vert_flag_enable(bm, e->v2, VERT_MARK);
  489. edge_face_count[BM_elem_index_get(e)]++;
  490. }
  491. }
  492. BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
  493. if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
  494. continue;
  495. }
  496. i = edge_face_count[BM_elem_index_get(e)]++;
  497. if (i == 0 || i > 2) {
  498. /* Edge & vertices are non-manifold even when considering
  499. * only marked faces */
  500. BMO_edge_flag_enable(bm, e, EDGE_NONMAN);
  501. BMO_vert_flag_enable(bm, e->v1, VERT_NONMAN);
  502. BMO_vert_flag_enable(bm, e->v2, VERT_NONMAN);
  503. }
  504. }
  505. MEM_freeN(edge_face_count);
  506. edge_face_count = NULL; /* don't re-use */
  507. BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
  508. if (!BM_vert_is_manifold(v)) {
  509. BMO_vert_flag_enable(bm, v, VERT_NONMAN);
  510. continue;
  511. }
  512. if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
  513. zero_v3(v->no);
  514. }
  515. }
  516. BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
  517. /* If the edge is not part of a the solidify region
  518. * its normal should not be considered */
  519. if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
  520. continue;
  521. }
  522. /* If the edge joins more than two marked faces high
  523. * quality normal computation won't work */
  524. if (BMO_edge_flag_test(bm, e, EDGE_NONMAN)) {
  525. continue;
  526. }
  527. f1 = f2 = NULL;
  528. BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
  529. if (BMO_face_flag_test(bm, f, FACE_MARK)) {
  530. if (f1 == NULL) {
  531. f1 = f;
  532. }
  533. else {
  534. BLI_assert(f2 == NULL);
  535. f2 = f;
  536. }
  537. }
  538. }
  539. BLI_assert(f1 != NULL);
  540. if (f2 != NULL) {
  541. const float angle = angle_normalized_v3v3(f1->no, f2->no);
  542. if (angle > 0.0f) {
  543. /* two faces using this edge, calculate the edge normal
  544. * using the angle between the faces as a weighting */
  545. add_v3_v3v3(edge_normal, f1->no, f2->no);
  546. normalize_v3_length(edge_normal, angle);
  547. }
  548. else {
  549. /* can't do anything useful here!
  550. * Set the face index for a vert in case it gets a zero normal */
  551. BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
  552. BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
  553. continue;
  554. }
  555. }
  556. else {
  557. /* only one face attached to that edge */
  558. /* an edge without another attached- the weight on this is undefined,
  559. * M_PI_2 is 90d in radians and that seems good enough */
  560. copy_v3_v3(edge_normal, f1->no);
  561. mul_v3_fl(edge_normal, M_PI_2);
  562. }
  563. add_v3_v3(e->v1->no, edge_normal);
  564. add_v3_v3(e->v2->no, edge_normal);
  565. }
  566. /* normalize accumulated vertex normal */
  567. BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
  568. if (!BMO_vert_flag_test(bm, v, VERT_MARK)) {
  569. continue;
  570. }
  571. if (BMO_vert_flag_test(bm, v, VERT_NONMAN)) {
  572. /* use standard normals for vertices connected to non-manifold edges */
  573. BM_vert_normal_update(v);
  574. }
  575. else if (normalize_v3(v->no) == 0.0f && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
  576. /* exceptional case, totally flat. use the normal
  577. * of any marked face around the vertex */
  578. BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
  579. if (BMO_face_flag_test(bm, f, FACE_MARK)) {
  580. break;
  581. }
  582. }
  583. copy_v3_v3(v->no, f->no);
  584. }
  585. }
  586. }
  587. static void solidify_add_thickness(BMesh *bm, const float dist)
  588. {
  589. BMFace *f;
  590. BMVert *v;
  591. BMLoop *l;
  592. BMIter iter, loopIter;
  593. float *vert_angles = MEM_callocN(sizeof(float) * bm->totvert * 2, "solidify"); /* 2 in 1 */
  594. float *vert_accum = vert_angles + bm->totvert;
  595. int i, index;
  596. BLI_buffer_declare_static(float, face_angles_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
  597. BLI_buffer_declare_static(float *, verts_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
  598. BM_mesh_elem_index_ensure(bm, BM_VERT);
  599. BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
  600. if (BMO_face_flag_test(bm, f, FACE_MARK)) {
  601. /* array for passing verts to angle_poly_v3 */
  602. float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len);
  603. /* array for receiving angles from angle_poly_v3 */
  604. float **verts = BLI_buffer_reinit_data(&verts_buf, float *, f->len);
  605. BM_ITER_ELEM_INDEX (l, &loopIter, f, BM_LOOPS_OF_FACE, i) {
  606. verts[i] = l->v->co;
  607. }
  608. angle_poly_v3(face_angles, (const float **)verts, f->len);
  609. i = 0;
  610. BM_ITER_ELEM (l, &loopIter, f, BM_LOOPS_OF_FACE) {
  611. v = l->v;
  612. index = BM_elem_index_get(v);
  613. vert_accum[index] += face_angles[i];
  614. vert_angles[index] += shell_v3v3_normalized_to_dist(v->no, f->no) * face_angles[i];
  615. i++;
  616. }
  617. }
  618. }
  619. BLI_buffer_free(&face_angles_buf);
  620. BLI_buffer_free(&verts_buf);
  621. BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
  622. index = BM_elem_index_get(v);
  623. if (vert_accum[index]) { /* zero if unselected */
  624. madd_v3_v3fl(v->co, v->no, dist * (vert_angles[index] / vert_accum[index]));
  625. }
  626. }
  627. MEM_freeN(vert_angles);
  628. }
  629. void bmo_solidify_face_region_exec(BMesh *bm, BMOperator *op)
  630. {
  631. BMOperator extrudeop;
  632. BMOperator reverseop;
  633. float thickness;
  634. thickness = BMO_slot_float_get(op->slots_in, "thickness");
  635. /* Flip original faces (so the shell is extruded inward) */
  636. BMO_op_init(bm, &reverseop, op->flag, "reverse_faces");
  637. BMO_slot_bool_set(reverseop.slots_in, "flip_multires", true);
  638. BMO_slot_copy(op, slots_in, "geom",
  639. &reverseop, slots_in, "faces");
  640. BMO_op_exec(bm, &reverseop);
  641. BMO_op_finish(bm, &reverseop);
  642. /* Extrude the region */
  643. BMO_op_initf(bm, &extrudeop, op->flag, "extrude_face_region use_keep_orig=%b", true);
  644. BMO_slot_copy(op, slots_in, "geom",
  645. &extrudeop, slots_in, "geom");
  646. BMO_op_exec(bm, &extrudeop);
  647. /* Push the verts of the extruded faces inward to create thickness */
  648. BMO_slot_buffer_flag_enable(bm, extrudeop.slots_out, "geom.out", BM_FACE, FACE_MARK);
  649. calc_solidify_normals(bm);
  650. solidify_add_thickness(bm, thickness);
  651. BMO_slot_copy(&extrudeop, slots_out, "geom.out",
  652. op, slots_out, "geom.out");
  653. BMO_op_finish(bm, &extrudeop);
  654. }