Blender  V3.3
multires_unsubdivide.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. All rights reserved. */
3 
11 #include "MEM_guardedalloc.h"
12 
13 #include "DNA_mesh_types.h"
14 #include "DNA_meshdata_types.h"
15 #include "DNA_modifier_types.h"
16 #include "DNA_scene_types.h"
17 
18 #include "BLI_gsqueue.h"
19 #include "BLI_math_vector.h"
20 
21 #include "BKE_customdata.h"
22 #include "BKE_lib_id.h"
23 #include "BKE_mesh.h"
24 #include "BKE_mesh_runtime.h"
25 #include "BKE_modifier.h"
26 #include "BKE_multires.h"
27 #include "BKE_subdiv.h"
28 #include "BKE_subsurf.h"
29 
30 #include "bmesh.h"
31 
32 #include "DEG_depsgraph_query.h"
33 
34 #include "multires_reshape.h"
35 #include "multires_unsubdivide.h"
36 
37 /* This is done in the following steps:
38  *
39  * - If there are already grids in the original mesh,
40  * convert them from tangent displacement to object space coordinates.
41  * - Assign data-layers to the original mesh to map vertices to a new base mesh.
42  * These data-layers store the indices of the elements in the original mesh.
43  * This way the original indices are
44  * preserved when doing mesh modifications (removing and dissolving vertices)
45  * when building the new base mesh.
46  * - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the
47  * center vertices of the lower level grid.
48  * If the algorithm can tag all vertices correctly,
49  * the lower level base mesh is generated by dissolving the tagged vertices.
50  * - Use the data-layers to map vertices from the base mesh to the original mesh and original to
51  * base mesh.
52  * - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh
53  * to original mesh
54  * - Extract the grid from the original mesh from that loop. If there are no grids in the original
55  * mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern
56  * over them. If there are grids in the original mesh, iterate in a grid pattern over the polys,
57  * reorder all the coordinates of the grid in that poly and copy those coordinates to the new
58  * base mesh grid.
59  * - Copy the new grid data over to a new allocated MDISP layer with the appropriate size to store
60  * the new levels.
61  * - Convert the grid data from object space to tangent displacement.
62  */
63 
67 static bool is_vertex_in_id(BMVert *v, const int *elem_id, int elem)
68 {
69  const int v_index = BM_elem_index_get(v);
70  return elem_id[v_index] == elem;
71 }
72 
74 {
75  return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3);
76 }
77 
78 static bool is_vertex_pole(BMVert *v)
79 {
80  return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3 || BM_vert_edge_count(v) >= 5);
81 }
82 
89 static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
90 {
91  BMIter iter;
92  BMVert *v;
93  BMVert *pole = NULL;
94  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
95  if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole_three(v)) {
96  return v;
97  }
98  if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole(v)) {
99  pole = v;
100  }
101  }
102  return pole;
103 }
104 
112 {
113  BMIter iter;
114  BMIter iter_a;
115  BMFace *f;
116  BMVert *v;
117  int count = 0;
118  if (bm->totface < 3) {
119  return false;
120  }
121 
122  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
123  count = 0;
124  BM_ITER_ELEM (v, &iter_a, f, BM_VERTS_OF_FACE) {
125  count++;
126  }
127 
128  if (count != 4) {
129  return false;
130  }
131  }
132 
133  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
134  if (BM_vert_is_wire(v)) {
135  return false;
136  }
137  if (BM_vert_edge_count(v) == 0) {
138  return false;
139  }
140  }
141 
142  return true;
143 }
144 
148 static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v)
149 {
150  return !BM_edge_exists(from_v, to_v);
151 }
152 
162 static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex)
163 {
164  bool *visited_vertices = MEM_calloc_arrayN(bm->totvert, sizeof(bool), "visited vertices");
165  GSQueue *queue;
166  queue = BLI_gsqueue_new(sizeof(BMVert *));
167 
168  /* Add and tag the vertices connected by a diagonal to initial_vertex to the flood fill queue. If
169  * initial_vertex is a pole and there is a valid solution, those vertices should be the (0,0) of
170  * the grids for the loops of initial_vertex. */
171  BMIter iter;
172  BMIter iter_a;
173  BMFace *f;
174  BMVert *neighbor_v;
175  BM_ITER_ELEM (f, &iter, initial_vertex, BM_FACES_OF_VERT) {
176  BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
177  int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
178  if (neighbor_v != initial_vertex && is_vertex_diagonal(neighbor_v, initial_vertex)) {
179  BLI_gsqueue_push(queue, &neighbor_v);
180  visited_vertices[neighbor_vertex_index] = true;
181  BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
182  }
183  }
184  }
185 
186  /* Repeat a similar operation for all vertices in the queue. */
187  /* In this case, add to the queue the vertices connected by 2 steps using the diagonals in any
188  * direction. If a solution exists and `initial_vertex` was a pole, this is guaranteed that will
189  * tag all the (0,0) vertices of the grids, and nothing else. */
190  /* If it was not a pole, it may or may not find a solution, even if the solution exists. */
191  while (!BLI_gsqueue_is_empty(queue)) {
192  BMVert *from_v;
193  BLI_gsqueue_pop(queue, &from_v);
194 
195  /* Get the diagonals (first connected step) */
196  GSQueue *diagonals;
197  diagonals = BLI_gsqueue_new(sizeof(BMVert *));
198  BM_ITER_ELEM (f, &iter, from_v, BM_FACES_OF_VERT) {
199  BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
200  if (neighbor_v != from_v && is_vertex_diagonal(neighbor_v, from_v)) {
201  BLI_gsqueue_push(diagonals, &neighbor_v);
202  }
203  }
204  }
205 
206  /* Do the second connected step. This vertices are the ones that are added to the flood fill
207  * queue. */
208  while (!BLI_gsqueue_is_empty(diagonals)) {
209  BMVert *diagonal_v;
210  BLI_gsqueue_pop(diagonals, &diagonal_v);
211  BM_ITER_ELEM (f, &iter, diagonal_v, BM_FACES_OF_VERT) {
212  BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
213  int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
214  if (!visited_vertices[neighbor_vertex_index] && neighbor_v != diagonal_v &&
215  is_vertex_diagonal(neighbor_v, diagonal_v)) {
216  BLI_gsqueue_push(queue, &neighbor_v);
217  visited_vertices[neighbor_vertex_index] = true;
218  BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
219  }
220  }
221  }
222  }
223  BLI_gsqueue_free(diagonals);
224  }
225 
227  MEM_freeN(visited_vertices);
228 }
229 
241 static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int elem)
242 {
243  BMVert *v, *neighbor_v;
244  BMIter iter, iter_a, iter_b;
245  BMFace *f;
246 
247  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
248  if (is_vertex_in_id(v, elem_id, elem)) {
250  /* Tagged vertex in boundary */
251  if (BM_vert_is_boundary(v)) {
252  return false;
253  }
254  /* Tagged vertex with connected tagged vertex. */
255  BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
256  BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
257  if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
258  return false;
259  }
260  }
261  }
262  }
263  if (BM_vert_is_boundary(v)) {
264  /* Un-tagged vertex in boundary without connected tagged vertices. */
265  bool any_tagged = false;
266  BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
267  BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
268  if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
269  any_tagged = true;
270  }
271  }
272  }
273  if (!any_tagged) {
274  return false;
275  }
276  }
277  }
278  }
279 
280  return true;
281 }
282 
286 static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem)
287 {
288  /* First, get vertex candidates to try to generate possible un-subdivide solution. */
289  /* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be
290  * part of the base mesh. If it isn't, then there is no solution. */
291  GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *));
292  BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem);
293  if (initial_vertex_pole != NULL) {
294  BLI_gsqueue_push(initial_vertex, &initial_vertex_pole);
295  }
296 
297  /* Also try from the different 4 vertices of a quad in the current
298  * disconnected element ID. If a solution exists the search should return a valid solution from
299  * one of these vertices. */
300  BMFace *f, *init_face = NULL;
301  BMVert *v;
302  BMIter iter_a, iter_b;
303  BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
304  BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
305  if (is_vertex_in_id(v, elem_id, elem)) {
306  init_face = f;
307  break;
308  }
309  }
310  if (init_face != NULL) {
311  break;
312  }
313  }
314 
315  BM_ITER_ELEM (v, &iter_a, init_face, BM_VERTS_OF_FACE) {
316  BLI_gsqueue_push(initial_vertex, &v);
317  }
318 
319  bool valid_tag_found = false;
320 
321  /* Check all vertex candidates to a solution. */
322  while (!BLI_gsqueue_is_empty(initial_vertex)) {
323 
324  BMVert *iv;
325  BLI_gsqueue_pop(initial_vertex, &iv);
326 
327  /* Generate a possible solution. */
329 
330  /* Check if the solution is valid. If it is, stop searching. */
331  if (unsubdivide_is_center_vertex_tag_valid(bm, elem_id, elem)) {
332  valid_tag_found = true;
333  break;
334  }
335 
336  /* If the solution is not valid, reset the state of all tags in this disconnected element ID
337  * and try again. */
338  BMVert *v_reset;
339  BMIter iter;
340  BM_ITER_MESH (v_reset, &iter, bm, BM_VERTS_OF_MESH) {
341  if (is_vertex_in_id(v_reset, elem_id, elem)) {
342  BM_elem_flag_set(v_reset, BM_ELEM_TAG, false);
343  }
344  }
345  }
346  BLI_gsqueue_free(initial_vertex);
347  return valid_tag_found;
348 }
349 
353 static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
354 {
355  bool *visited_vertices = MEM_calloc_arrayN(bm->totvert, sizeof(bool), "visited vertices");
356  int current_id = 0;
357  for (int i = 0; i < bm->totvert; i++) {
358  if (!visited_vertices[i]) {
359  GSQueue *queue;
360  queue = BLI_gsqueue_new(sizeof(BMVert *));
361 
362  visited_vertices[i] = true;
363  elem_id[i] = current_id;
364  BMVert *iv = BM_vert_at_index(bm, i);
365  BLI_gsqueue_push(queue, &iv);
366 
367  while (!BLI_gsqueue_is_empty(queue)) {
368  BMIter iter;
369  BMVert *current_v, *neighbor_v;
370  BMEdge *ed;
371  BLI_gsqueue_pop(queue, &current_v);
372  BM_ITER_ELEM (ed, &iter, current_v, BM_EDGES_OF_VERT) {
373  neighbor_v = BM_edge_other_vert(ed, current_v);
374  const int neighbor_index = BM_elem_index_get(neighbor_v);
375  if (!visited_vertices[neighbor_index]) {
376  visited_vertices[neighbor_index] = true;
377  elem_id[neighbor_index] = current_id;
378  BLI_gsqueue_push(queue, &neighbor_v);
379  }
380  }
381  }
382  current_id++;
384  }
385  }
386  MEM_freeN(visited_vertices);
387  return current_id;
388 }
389 
395 {
396  BMVert *v;
397  BMIter iter;
398 
399  /* Stores the vertices which correspond to (1, 0) and (0, 1) of the grids in the select flag. */
401  BMVert *v_neighbor;
402  BMIter iter_a;
403  BMEdge *ed;
404  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
405  BM_ITER_ELEM (ed, &iter_a, v, BM_EDGES_OF_VERT) {
406  v_neighbor = BM_edge_other_vert(ed, v);
407  if (BM_elem_flag_test(v_neighbor, BM_ELEM_TAG)) {
409  }
410  }
411  }
412 
413  /* Dissolves the (0,0) vertices of the grids. */
416  "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
417  BM_ELEM_TAG,
418  false,
419  true);
420 
422 
423  /* Copy the select flag to the tag flag. */
424  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
427  }
428  }
429 
430  /* Dissolves the (1,0) and (0,1) vertices of the grids. */
433  "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
434  BM_ELEM_TAG,
435  false,
436  true);
437 }
438 
449 {
450 
451  /* Do a first check to make sure that it makes sense to search for un-subdivision in this mesh.
452  */
454  return false;
455  };
456 
457  /* Initialize the vertex table. */
460 
461  /* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */
462  int *elem_id = MEM_calloc_arrayN(bm->totvert, sizeof(int), " ELEM ID");
463  const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id);
464 
465  bool valid_tag_found = true;
466 
467  /* Reset the #BMesh flags as they are used to store data during the un-subdivide process. */
470 
471  /* For each disconnected mesh element ID, search if an un-subdivide solution is possible. The
472  * whole un-subdivide process fails if a single disconnected mesh element fails. */
473  for (int id = 0; id < tot_ids; id++) {
474  /* Try to the #BMesh vertex flag tags corresponding to an un-subdivide solution. */
475  if (!unsubdivide_tag_disconnected_mesh_element(bm, elem_id, id)) {
476  valid_tag_found = false;
477  break;
478  }
479  }
480 
481  /* If a solution was found for all elements IDs, build the new base mesh using the solution
482  * stored in the BMVert tags. */
483  if (valid_tag_found) {
485  }
486 
487  MEM_freeN(elem_id);
488  return valid_tag_found;
489 }
490 
494 static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
495 {
496  BMIter iter;
497  BMEdge *test_edge;
498  if (edge == NULL) {
499  (*r_next_vertex) = v;
500  return edge;
501  }
502  (*r_next_vertex) = BM_edge_other_vert(edge, v);
503  BM_ITER_ELEM (test_edge, &iter, (*r_next_vertex), BM_EDGES_OF_VERT) {
504  if (!BM_edge_share_quad_check(test_edge, edge)) {
505  return test_edge;
506  }
507  }
508  return NULL;
509 }
510 
511 static BMFace *face_step(BMEdge *edge, BMFace *f)
512 {
513  BMIter iter;
514  BMFace *face_iter;
515 
516  BM_ITER_ELEM (face_iter, &iter, edge, BM_FACES_OF_EDGE) {
517  if (BM_face_share_edge_check(face_iter, f)) {
518  return face_iter;
519  }
520  }
521  return f;
522 }
523 
528 static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
529 {
530  BMIter iter;
531  BMEdge *test_edge;
532  BM_ITER_ELEM (test_edge, &iter, f, BM_EDGES_OF_FACE) {
533  if (edge_x != test_edge) {
534  if (test_edge->v1 != initial_vertex && test_edge->v2 == initial_vertex) {
535  return test_edge;
536  }
537  if (test_edge->v2 != initial_vertex && test_edge->v1 == initial_vertex) {
538  return test_edge;
539  }
540  }
541  }
542  return NULL;
543 }
544 
549  float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop)
550 {
551  int origin[2];
552  int step_x[2];
553  int step_y[2];
554 
555  const int grid_offset = orig_grid_size - 1;
556  origin[0] = grid_offset;
557  origin[1] = grid_offset;
558 
559  switch (loop) {
560  case 0:
561  step_x[0] = -1;
562  step_x[1] = 0;
563 
564  step_y[0] = 0;
565  step_y[1] = -1;
566 
567  break;
568  case 1:
569  step_x[0] = 0;
570  step_x[1] = 1;
571 
572  step_y[0] = -1;
573  step_y[1] = -0;
574  break;
575  case 2:
576  step_x[0] = 1;
577  step_x[1] = 0;
578 
579  step_y[0] = 0;
580  step_y[1] = 1;
581  break;
582  case 3:
583  step_x[0] = 0;
584  step_x[1] = -1;
585 
586  step_y[0] = 1;
587  step_y[1] = 0;
588  break;
589  default:
590  BLI_assert_msg(0, "Should never happen");
591  break;
592  }
593 
594  for (int y = 0; y < orig_grid_size; y++) {
595  for (int x = 0; x < orig_grid_size; x++) {
596  const int remap_x = origin[1] + (step_x[1] * x) + (step_y[1] * y);
597  const int remap_y = origin[0] + (step_x[0] * x) + (step_y[0] * y);
598 
599  const int final_index = remap_x + remap_y * face_grid_size;
600  copy_v3_v3(face_grid[final_index], mdisp->disps[x + y * orig_grid_size]);
601  }
602  }
603 }
604 
610  float (*face_grid)[3],
611  int face_grid_size,
612  int gunsub_x,
613  int gunsub_y)
614 {
615  const int grid_it = face_grid_size - 1;
616  for (int y = 0; y < face_grid_size; y++) {
617  for (int x = 0; x < face_grid_size; x++) {
618  const int remap_x = (grid_it * gunsub_x) + x;
619  const int remap_y = (grid_it * gunsub_y) + y;
620 
621  const int remap_index_y = grid->grid_size - remap_x - 1;
622  const int remap_index_x = grid->grid_size - remap_y - 1;
623  const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
624  copy_v3_v3(grid->grid_co[grid_index], face_grid[x + y * face_grid_size]);
625  }
626  }
627 }
628 
637  BMVert *v,
638  BMFace *f,
639  int grid_x,
640  int grid_y)
641 {
642 
643  Mesh *original_mesh = context->original_mesh;
644  MPoly *poly = &original_mesh->mpoly[BM_elem_index_get(f)];
645 
646  const int corner_vertex_index = BM_elem_index_get(v);
647 
648  /* Calculates an offset to write the grids correctly oriented in the main
649  * #MultiresUnsubdivideGrid. */
650  int loop_offset = 0;
651  for (int i = 0; i < poly->totloop; i++) {
652  const int loop_index = poly->loopstart + i;
653  MLoop *l = &original_mesh->mloop[loop_index];
654  if (l->v == corner_vertex_index) {
655  loop_offset = i;
656  break;
657  }
658  }
659 
660  /* Write the 4 grids of the current quad with the right orientation into the face_grid buffer. */
661  const int grid_size = BKE_ccg_gridsize(context->num_original_levels);
662  const int face_grid_size = BKE_ccg_gridsize(context->num_original_levels + 1);
663  const int face_grid_area = face_grid_size * face_grid_size;
664  float(*face_grid)[3] = MEM_calloc_arrayN(face_grid_area, sizeof(float[3]), "face_grid");
665 
666  for (int i = 0; i < poly->totloop; i++) {
667  const int loop_index = poly->loopstart + i;
668  MDisps *mdisp = &context->original_mdisp[loop_index];
669  int quad_loop = i - loop_offset;
670  if (quad_loop < 0) {
671  quad_loop += 4;
672  }
673  if (quad_loop >= 4) {
674  quad_loop -= 4;
675  }
676  write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop);
677  }
678 
679  /* Write the face_grid buffer in the correct position in the #MultiresUnsubdivideGrids that is
680  * being extracted. */
681  write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y);
682 
683  MEM_freeN(face_grid);
684 }
685 
690 static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y)
691 {
692  const int remap_index_y = grid->grid_size - 1 - grid_x;
693  const int remap_index_x = grid->grid_size - 1 - grid_y;
694 
695  const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
696 
697  copy_v3_v3(grid->grid_co[grid_index], v->co);
698 }
699 
705  BMFace *f1,
706  BMEdge *e1,
707  bool flip_grid,
709 {
710  BMVert *initial_vertex;
711  BMEdge *initial_edge_x;
712  BMEdge *initial_edge_y;
713 
714  const int grid_size = BKE_ccg_gridsize(context->num_new_levels);
715  const int unsubdiv_grid_size = grid->grid_size = BKE_ccg_gridsize(context->num_total_levels);
716  grid->grid_size = unsubdiv_grid_size;
717  grid->grid_co = MEM_calloc_arrayN(
718  unsubdiv_grid_size * unsubdiv_grid_size, sizeof(float[3]), "grids coordinates");
719 
720  /* Get the vertex on the corner of the grid. This vertex was tagged previously as it also exist
721  * on the base mesh. */
722  initial_edge_x = e1;
723  if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
724  initial_vertex = initial_edge_x->v1;
725  }
726  else {
727  initial_vertex = initial_edge_x->v2;
728  }
729 
730  /* From that vertex, get the edge that defines the grid Y axis for extraction. */
731  initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
732 
733  if (flip_grid) {
734  BMEdge *edge_temp;
735  edge_temp = initial_edge_x;
736  initial_edge_x = initial_edge_y;
737  initial_edge_y = edge_temp;
738  }
739 
740  int grid_x = 0;
741  int grid_y = 0;
742 
743  BMVert *current_vertex_x = initial_vertex;
744  BMEdge *edge_x = initial_edge_x;
745 
746  BMVert *current_vertex_y = initial_vertex;
747  BMEdge *edge_y = initial_edge_y;
748  BMEdge *prev_edge_y = initial_edge_y;
749 
750  BMFace *current_face = f1;
751  BMFace *grid_face = f1;
752 
753  /* If the data is going to be extracted from the already existing grids, there is no need to go
754  * to the last vertex of the iteration as that coordinate is also included in the grids
755  * corresponding to the loop of the face of the previous iteration. */
756  int grid_iteration_max_steps = grid_size;
757  if (context->num_original_levels > 0) {
758  grid_iteration_max_steps = grid_size - 1;
759  }
760 
761  /* Iterate over the mesh vertices in a grid pattern using the axis defined by the two initial
762  * edges. */
763  while (grid_y < grid_iteration_max_steps) {
764 
765  grid_face = current_face;
766 
767  while (grid_x < grid_iteration_max_steps) {
768  if (context->num_original_levels == 0) {
769  /* If there were no grids on the original mesh, extract the data directly from the
770  * vertices. */
771  store_vertex_data(grid, current_vertex_x, grid_x, grid_y);
772  edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
773  }
774  else {
775  /* If there were grids in the original mesh, extract the data from the grids and iterate
776  * over the faces. */
777  store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y);
778  edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
779  grid_face = face_step(edge_x, grid_face);
780  }
781 
782  grid_x++;
783  }
784  grid_x = 0;
785 
786  edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
787  current_vertex_x = current_vertex_y;
788 
789  /* Get the next edge_x to extract the next row of the grid. This needs to be done because there
790  * may be two edges connected to current_vertex_x that belong to two different grids. */
791  BMIter iter;
792  BMEdge *ed;
793  BMFace *f;
794  BM_ITER_ELEM (ed, &iter, current_vertex_x, BM_EDGES_OF_VERT) {
795  if (ed != prev_edge_y && BM_edge_in_face(ed, current_face)) {
796  edge_x = ed;
797  break;
798  }
799  }
800  BM_ITER_ELEM (f, &iter, edge_x, BM_FACES_OF_EDGE) {
801  if (f != current_face) {
802  current_face = f;
803  break;
804  }
805  }
806 
807  prev_edge_y = edge_y;
808  grid_y++;
809  }
810 }
811 
819  BMEdge *e1,
820  BMVert **r_corner_x,
821  BMVert **r_corner_y)
822 {
823  BMVert *initial_vertex;
824  BMEdge *initial_edge_x;
825  BMEdge *initial_edge_y;
826 
827  initial_edge_x = e1;
828  if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
829  initial_vertex = initial_edge_x->v1;
830  }
831  else {
832  initial_vertex = initial_edge_x->v2;
833  }
834 
835  /* From that vertex, get the edge that defines the grid Y axis for extraction. */
836  initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
837 
838  BMVert *current_vertex_x = initial_vertex;
839  BMEdge *edge_x = initial_edge_x;
840 
841  BMVert *current_vertex_y = initial_vertex;
842  BMEdge *edge_y = initial_edge_y;
843 
844  /* Do an edge step until it finds a tagged vertex, which is part of the base mesh. */
845  /* x axis */
846  edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
847  while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) {
848  edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
849  }
850  (*r_corner_x) = current_vertex_x;
851 
852  /* Same for y axis */
853  edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
854  while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) {
855  edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
856  }
857  (*r_corner_y) = current_vertex_y;
858 }
859 
861 {
862  const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
863  BMesh *bm = BM_mesh_create(&allocsize,
864  &((struct BMeshCreateParams){
865  .use_toolflags = true,
866  }));
867 
869  mesh,
870  (&(struct BMeshFromMeshParams){
871  .calc_face_normal = true,
872  .calc_vert_normal = true,
873  }));
874 
875  return bm;
876 }
877 
878 /* Data-layer names to store the original indices of the elements before modifying the mesh. */
879 static const char lname[] = "l_remap_index";
880 static const char vname[] = "v_remap_index";
881 
883 {
884  const int l_layer_index = CustomData_get_named_layer_index(&mesh->ldata, CD_PROP_INT32, lname);
885  if (l_layer_index != -1) {
887  }
888 
889  const int v_layer_index = CustomData_get_named_layer_index(&mesh->vdata, CD_PROP_INT32, vname);
890  if (v_layer_index != -1) {
892  }
893 }
894 
900 {
902 
903  int *l_index = CustomData_add_layer_named(
905 
906  int *v_index = CustomData_add_layer_named(
908 
909  /* Initialize these data-layer with the indices in the current mesh. */
910  for (int i = 0; i < mesh->totloop; i++) {
911  l_index[i] = i;
912  }
913  for (int i = 0; i < mesh->totvert; i++) {
914  v_index[i] = i;
915  }
916 }
917 
920 {
921 
922  Mesh *original_mesh = context->original_mesh;
923  Mesh *base_mesh = context->base_mesh;
924 
925  BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh);
926 
927  /* Initialize the elem tables. */
928  BM_mesh_elem_table_ensure(bm_original_mesh, BM_EDGE);
929  BM_mesh_elem_table_ensure(bm_original_mesh, BM_FACE);
930  BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT);
931 
932  /* Disable all flags. */
934  bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
936  bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
937 
938  /* Get the mapping data-layer. */
939  context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT32, vname);
940 
941  /* Tag the base mesh vertices in the original mesh. */
942  for (int i = 0; i < base_mesh->totvert; i++) {
943  int vert_basemesh_index = context->base_to_orig_vmap[i];
944  BMVert *v = BM_vert_at_index(bm_original_mesh, vert_basemesh_index);
946  }
947 
948  /* Create a map from loop index to poly index for the original mesh. */
949  context->loop_to_face_map = MEM_calloc_arrayN(original_mesh->totloop, sizeof(int), "loop map");
950 
951  for (int i = 0; i < original_mesh->totpoly; i++) {
952  MPoly *poly = &original_mesh->mpoly[i];
953  for (int l = 0; l < poly->totloop; l++) {
954  int original_loop_index = l + poly->loopstart;
955  context->loop_to_face_map[original_loop_index] = i;
956  }
957  }
958 }
959 
964 static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x)
965 {
966  MPoly *p = &mesh->mpoly[poly];
967 
968  MLoop *l_first = &mesh->mloop[p->loopstart];
969  if ((loop == (p->loopstart + (p->totloop - 1))) && l_first->v == v_x) {
970  return true;
971  }
972 
973  int next_l_index = loop + 1;
974  if (next_l_index < p->loopstart + p->totloop) {
975  MLoop *l_next = &mesh->mloop[next_l_index];
976  if (l_next->v == v_x) {
977  return true;
978  }
979  }
980 
981  return false;
982 }
983 
985 {
986  Mesh *original_mesh = context->original_mesh;
987  Mesh *base_mesh = context->base_mesh;
988 
989  BMesh *bm_original_mesh = context->bm_original_mesh;
990 
991  context->num_grids = base_mesh->totloop;
992  context->base_mesh_grids = MEM_calloc_arrayN(
993  base_mesh->totloop, sizeof(MultiresUnsubdivideGrid), "grids");
994 
995  /* Based on the existing indices in the data-layers, generate two vertex indices maps. */
996  /* From vertex index in original to vertex index in base and from vertex index in base to vertex
997  * index in original. */
998  int *orig_to_base_vmap = MEM_calloc_arrayN(bm_original_mesh->totvert, sizeof(int), "orig vmap");
999  int *base_to_orig_vmap = MEM_calloc_arrayN(base_mesh->totvert, sizeof(int), "base vmap");
1000 
1001  context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT32, vname);
1002  for (int i = 0; i < base_mesh->totvert; i++) {
1003  base_to_orig_vmap[i] = context->base_to_orig_vmap[i];
1004  }
1005 
1006  /* If an index in original does not exist in base (it was dissolved when creating the new base
1007  * mesh, return -1. */
1008  for (int i = 0; i < original_mesh->totvert; i++) {
1009  orig_to_base_vmap[i] = -1;
1010  }
1011 
1012  for (int i = 0; i < base_mesh->totvert; i++) {
1013  const int orig_vertex_index = context->base_to_orig_vmap[i];
1014  orig_to_base_vmap[orig_vertex_index] = i;
1015  }
1016 
1017  /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer,
1018  * so they can be used from #BMesh. */
1020 
1021  const int base_l_layer_index = CustomData_get_named_layer_index(
1022  &base_mesh->ldata, CD_PROP_INT32, lname);
1023  BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh);
1024  BMIter iter, iter_a, iter_b;
1025  BMVert *v;
1026  BMLoop *l, *lb;
1027 
1028  BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT);
1029  BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE);
1030 
1031  /* Get the data-layer that contains the loops indices. */
1032  const int base_l_offset = CustomData_get_n_offset(
1033  &bm_base_mesh->ldata, CD_PROP_INT32, base_l_layer_index);
1034 
1035  /* Main loop for extracting the grids. Iterates over the base mesh vertices. */
1036  BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) {
1037 
1038  /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the
1039  * vertex map. */
1040  const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)];
1041  BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index);
1042 
1043  /* Iterate over the loops of that vertex in the original mesh. */
1044  BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) {
1045  /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the
1046  * base mesh of the poly of grid that is going to be extracted. */
1047  BMVert *corner_x, *corner_y;
1048  multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y);
1049 
1050  /* Map the two obtained vertices to the base mesh. */
1051  const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)];
1052  const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)];
1053 
1054  /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained
1055  * vertices and the current vertex it is possible to get the index of the loop in the base
1056  * mesh the grid that is going to be extracted belongs to. */
1057  BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) {
1058  BMFace *base_face = lb->f;
1059  BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index);
1060  BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index);
1061  /* If this is the correct loop in the base mesh, the original vertex and the two corners
1062  * should be in the loop's face. */
1063  if (BM_vert_in_face(base_corner_x, base_face) &&
1064  BM_vert_in_face(base_corner_y, base_face)) {
1065  /* Get the index of the loop. */
1066  const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset);
1067  const int base_mesh_face_index = BM_elem_index_get(base_face);
1068 
1069  /* Check the orientation of the loops in case that is needed to flip the x and y axis
1070  * when extracting the grid. */
1071  const bool flip_grid = multires_unsubdivide_flip_grid_x_axis(
1072  base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index);
1073 
1074  /* Extract the grid for that loop. */
1075  context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index;
1077  context, l->f, l->e, !flip_grid, &context->base_mesh_grids[base_mesh_loop_index]);
1078 
1079  break;
1080  }
1081  }
1082  }
1083  }
1084 
1085  MEM_freeN(orig_to_base_vmap);
1086  MEM_freeN(base_to_orig_vmap);
1087 
1088  BM_mesh_free(bm_base_mesh);
1090 }
1091 
1093 {
1094  if (context->bm_original_mesh != NULL) {
1095  BM_mesh_free(context->bm_original_mesh);
1096  }
1097  MEM_SAFE_FREE(context->loop_to_face_map);
1098 }
1099 
1101  Mesh *original_mesh,
1102  struct MultiresModifierData *mmd)
1103 {
1104  context->original_mesh = original_mesh;
1105  context->num_new_levels = 0;
1106  context->num_total_levels = 0;
1107  context->num_original_levels = mmd->totlvl;
1108 }
1109 
1111 {
1112  Mesh *original_mesh = context->original_mesh;
1113 
1114  /* Prepare the data-layers to map base to original. */
1116  BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh);
1117 
1118  /* Un-subdivide as many iterations as possible. */
1119  context->num_new_levels = 0;
1120  int num_levels_left = context->max_new_levels;
1121  while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) {
1122  context->num_new_levels++;
1123  num_levels_left--;
1124  }
1125 
1126  /* If no un-subdivide steps were possible, free the bmesh, the map data-layers and stop. */
1127  if (context->num_new_levels == 0) {
1129  BM_mesh_free(bm_base_mesh);
1130  return false;
1131  }
1132 
1133  /* Calculate the final levels for the new grids over base mesh. */
1134  context->num_total_levels = context->num_new_levels + context->num_original_levels;
1135 
1136  /* Store the new base-mesh as a mesh in context, free bmesh. */
1137  context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
1139  bm_base_mesh,
1140  context->base_mesh,
1141  (&(struct BMeshToMeshParams){
1142  .calc_object_remap = true,
1143  }));
1144  BM_mesh_free(bm_base_mesh);
1145 
1146  /* Initialize bmesh and maps for the original mesh and extract the grids. */
1147 
1150 
1151  return true;
1152 }
1153 
1155 {
1157  for (int i = 0; i < context->num_grids; i++) {
1158  if (context->base_mesh_grids[i].grid_size > 0) {
1159  MEM_SAFE_FREE(context->base_mesh_grids[i].grid_co);
1160  }
1161  }
1162  MEM_SAFE_FREE(context->base_mesh_grids);
1163 }
1164 
1170  Mesh *base_mesh)
1171 {
1172  /* Free the current MDISPS and create a new ones. */
1173  if (CustomData_has_layer(&base_mesh->ldata, CD_MDISPS)) {
1174  CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop);
1175  }
1176  MDisps *mdisps = CustomData_add_layer(
1177  &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop);
1178 
1179  const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2);
1180  const int totloop = base_mesh->totloop;
1181 
1182  BLI_assert(base_mesh->totloop == context->num_grids);
1183 
1184  /* Allocate the MDISPS grids and copy the extracted data from context. */
1185  for (int i = 0; i < totloop; i++) {
1186  float(*disps)[3] = MEM_calloc_arrayN(totdisp, sizeof(float[3]), "multires disps");
1187 
1188  if (mdisps[i].disps) {
1189  MEM_freeN(mdisps[i].disps);
1190  }
1191 
1192  for (int j = 0; j < totdisp; j++) {
1193  if (context->base_mesh_grids[i].grid_co) {
1194  copy_v3_v3(disps[j], context->base_mesh_grids[i].grid_co[j]);
1195  }
1196  }
1197 
1198  mdisps[i].disps = disps;
1199  mdisps[i].totdisp = totdisp;
1200  mdisps[i].level = context->num_total_levels;
1201  }
1202 }
1203 
1205  struct Object *object,
1206  struct MultiresModifierData *mmd,
1207  int rebuild_limit,
1208  bool switch_view_to_lower_level)
1209 {
1210  Mesh *mesh = object->data;
1211 
1213 
1214  MultiresUnsubdivideContext unsubdiv_context = {0};
1215  MultiresReshapeContext reshape_context = {0};
1216 
1217  multires_unsubdivide_context_init(&unsubdiv_context, mesh, mmd);
1218 
1219  /* Convert and store the existing grids in object space if available. */
1220  if (mmd->totlvl != 0) {
1221  if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) {
1222  return 0;
1223  }
1224 
1225  multires_reshape_store_original_grids(&reshape_context);
1227  unsubdiv_context.original_mdisp = reshape_context.mdisps;
1228  }
1229 
1230  /* Set the limit for the levels that should be rebuild. */
1231  unsubdiv_context.max_new_levels = rebuild_limit;
1232 
1233  /* Un-subdivide and create the data for the new grids. */
1234  if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) {
1235  /* If there was no possible to rebuild any level, free the data and return. */
1236  if (mmd->totlvl != 0) {
1238  multires_unsubdivide_context_free(&unsubdiv_context);
1239  }
1240  multires_reshape_context_free(&reshape_context);
1241  return 0;
1242  }
1243 
1244  /* Free the reshape context used to convert the data from the original grids to object space. */
1245  if (mmd->totlvl != 0) {
1246  multires_reshape_context_free(&reshape_context);
1247  }
1248 
1249  /* Copy the new base mesh to the original mesh. */
1250  BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, object->data, object, &CD_MASK_MESH, true);
1251  Mesh *base_mesh = object->data;
1252  multires_create_grids_in_unsubdivided_base_mesh(&unsubdiv_context, base_mesh);
1253 
1254  /* Update the levels in the modifier. Force always to display at level 0 as it contains the new
1255  * created level. */
1256  mmd->totlvl = (char)unsubdiv_context.num_total_levels;
1257 
1258  if (switch_view_to_lower_level) {
1259  mmd->sculptlvl = 0;
1260  mmd->lvl = 0;
1261  }
1262  else {
1263  mmd->sculptlvl = (char)(mmd->sculptlvl + unsubdiv_context.num_new_levels);
1264  mmd->lvl = (char)(mmd->lvl + unsubdiv_context.num_new_levels);
1265  }
1266 
1267  mmd->renderlvl = (char)(mmd->renderlvl + unsubdiv_context.num_new_levels);
1268 
1269  /* Create a reshape context to convert the MDISPS data to tangent displacement. It can be the
1270  * same as the previous one as a new Subdivision needs to be created for the new base mesh. */
1271  if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) {
1272  return 0;
1273  }
1275  multires_reshape_context_free(&reshape_context);
1276 
1277  /* Free the un-subdivide context and return the total number of levels that were rebuild. */
1278  const int rebuild_subdvis = unsubdiv_context.num_new_levels;
1279  multires_unsubdivide_context_free(&unsubdiv_context);
1280 
1281  return rebuild_subdvis;
1282 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index)
Definition: customdata.cc:2831
@ CD_CALLOC
void CustomData_free_layers(struct CustomData *data, int type, int totelem)
Definition: customdata.cc:2904
bool CustomData_has_layer(const struct CustomData *data, int type)
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name)
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.cc:2792
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
int CustomData_get_n_offset(const struct CustomData *data, int type, int n)
const CustomData_MeshMasks CD_MASK_MESH
Definition: customdata.cc:2065
void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, const struct CustomData_MeshMasks *mask, bool take_ownership)
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
void multires_force_sculpt_rebuild(struct Object *object)
Definition: multires.c:437
int BKE_ccg_gridsize(int level)
Definition: CCGSubSurf.c:23
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
void BLI_gsqueue_free(GSQueue *queue)
Definition: gsqueue.c:90
GSQueue * BLI_gsqueue_new(size_t elem_size)
Definition: gsqueue.c:69
void BLI_gsqueue_push(GSQueue *queue, const void *item)
Definition: gsqueue.c:97
void BLI_gsqueue_pop(GSQueue *queue, void *r_item)
Definition: gsqueue.c:131
bool BLI_gsqueue_is_empty(const GSQueue *queue)
Definition: gsqueue.c:159
int pow_i(int base, int exp)
Definition: math_base.c:12
MINLINE void copy_v3_v3(float r[3], const float a[3])
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
@ CD_PROP_INT32
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define BM_ELEM_CD_GET_INT(ele, offset)
Definition: bmesh_class.h:518
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
Definition: bmesh_mesh.cc:258
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
Definition: bmesh_mesh.cc:125
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:558
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:624
#define BMALLOC_TEMPLATE_FROM_ME(...)
Definition: bmesh_mesh.h:197
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:103
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
@ BMO_FLAG_RESPECT_HIDE
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_FLAG_DEFAULTS
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
bool BM_vert_is_wire(const BMVert *v)
Definition: bmesh_query.c:688
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
Definition: bmesh_query.c:1054
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:420
bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
Definition: bmesh_query.c:984
bool BM_vert_in_face(BMVert *v, BMFace *f)
Definition: bmesh_query.c:306
int BM_vert_edge_count(const BMVert *v)
Definition: bmesh_query.c:607
bool BM_vert_is_boundary(const BMVert *v)
Definition: bmesh_query.c:916
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
const Depsgraph * depsgraph
SyclQueue * queue
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
void multires_reshape_assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context)
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context)
bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context, struct Depsgraph *depsgraph, struct Object *object, struct MultiresModifierData *mmd)
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context, struct Depsgraph *depsgraph, struct Object *object, struct MultiresModifierData *mmd)
void multires_reshape_object_grids_to_tangent_displacement(const MultiresReshapeContext *reshape_context)
static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem)
static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y)
static void write_loop_in_face_grid(float(*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop)
static BMFace * face_step(BMEdge *edge, BMFace *f)
static BMesh * get_bmesh_from_mesh(Mesh *mesh)
static bool is_vertex_in_id(BMVert *v, const int *elem_id, int elem)
static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideContext *context, Mesh *base_mesh)
static bool multires_unsubdivide_single_level(BMesh *bm)
static void multires_unsubdivide_prepare_original_bmesh_for_extract(MultiresUnsubdivideContext *context)
static void multires_unsubdivide_private_extract_data_free(MultiresUnsubdivideContext *context)
void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context, Mesh *original_mesh, struct MultiresModifierData *mmd)
static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x)
static bool is_vertex_pole_three(BMVert *v)
static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh)
bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex)
static bool is_vertex_pole(BMVert *v)
static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
static void store_grid_data(MultiresUnsubdivideContext *context, MultiresUnsubdivideGrid *grid, BMVert *v, BMFace *f, int grid_x, int grid_y)
static BMVert * unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
static const char lname[]
static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int elem)
static bool unsubdivide_is_all_quads(BMesh *bm)
static void multires_unsubdivide_get_grid_corners_on_base_mesh(BMFace *f1, BMEdge *e1, BMVert **r_corner_x, BMVert **r_corner_y)
static BMEdge * edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
static void unsubdivide_build_base_mesh_from_tags(BMesh *bm)
static void multires_unsubdivide_free_original_datalayers(Mesh *mesh)
static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v)
int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph, struct Object *object, struct MultiresModifierData *mmd, int rebuild_limit, bool switch_view_to_lower_level)
static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *context)
static void multires_unsubdivide_extract_single_grid_from_face_edge(MultiresUnsubdivideContext *context, BMFace *f1, BMEdge *e1, bool flip_grid, MultiresUnsubdivideGrid *grid)
static const char vname[]
static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid, float(*face_grid)[3], int face_grid_size, int gunsub_x, int gunsub_y)
void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context)
static BMEdge * get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMFace * f
Definition: bmesh_class.h:171
float co[3]
Definition: bmesh_class.h:87
int totvert
Definition: bmesh_class.h:297
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
float(* disps)[3]
unsigned int v
CustomData vdata
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
CustomData ldata
struct MDisps * mdisps
void * data