Blender  V2.93
multires_unsubdivide.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2020 Blender Foundation.
17  * All rights reserved.
18  */
19 
27 #include "MEM_guardedalloc.h"
28 
29 #include "DNA_mesh_types.h"
30 #include "DNA_meshdata_types.h"
31 #include "DNA_modifier_types.h"
32 #include "DNA_scene_types.h"
33 
34 #include "BLI_gsqueue.h"
35 #include "BLI_math_vector.h"
36 
37 #include "BKE_customdata.h"
38 #include "BKE_lib_id.h"
39 #include "BKE_mesh.h"
40 #include "BKE_mesh_runtime.h"
41 #include "BKE_modifier.h"
42 #include "BKE_multires.h"
43 #include "BKE_subdiv.h"
44 #include "BKE_subsurf.h"
45 
46 #include "bmesh.h"
47 
48 #include "DEG_depsgraph_query.h"
49 
50 #include "multires_reshape.h"
51 #include "multires_unsubdivide.h"
52 
53 /* This is done in the following steps:
54  *
55  * - If there are already grids in the original mesh,
56  * convert them from tangent displacement to object space coordinates.
57  * - Assign data-layers to the original mesh to map vertices to a new base mesh.
58  * These data-layers store the indices of the elements in the original mesh.
59  * This way the original indices are
60  * preserved when doing mesh modifications (removing and dissolving vertices)
61  * when building the new base mesh.
62  * - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the
63  * center vertices of the lower level grid.
64  * If the algorithm can tag all vertices correctly,
65  * the lower level base mesh is generated by dissolving the tagged vertices.
66  * - Use the data-layers to map vertices from the base mesh to the original mesh and original to
67  * base mesh.
68  * - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh
69  * to original mesh
70  * - Extract the grid from the original mesh from that loop. If there are no grids in the original
71  * mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern
72  * over them. If there are grids in the original mesh, iterate in a grid pattern over the polys,
73  * reorder all the coordinates of the grid in that poly and copy those coordinates to the new
74  * base mesh grid.
75  * - Copy the new grid data over to a new allocated MDISP layer with the appropriate size to store
76  * the new levels.
77  * - Convert the grid data from object space to tangent displacement.
78  */
79 
83 static bool is_vertex_in_id(BMVert *v, const int *elem_id, int elem)
84 {
85  const int v_index = BM_elem_index_get(v);
86  return elem_id[v_index] == elem;
87 }
88 
90 {
91  return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3);
92 }
93 
94 static bool is_vertex_pole(BMVert *v)
95 {
96  return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3 || BM_vert_edge_count(v) >= 5);
97 }
98 
105 static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
106 {
107  BMIter iter;
108  BMVert *v;
109  BMVert *pole = NULL;
110  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
111  if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole_three(v)) {
112  return v;
113  }
114  if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole(v)) {
115  pole = v;
116  }
117  }
118  return pole;
119 }
120 
128 {
129  BMIter iter;
130  BMIter iter_a;
131  BMFace *f;
132  BMVert *v;
133  int count = 0;
134  if (bm->totface < 3) {
135  return false;
136  }
137 
138  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
139  count = 0;
140  BM_ITER_ELEM (v, &iter_a, f, BM_VERTS_OF_FACE) {
141  count++;
142  }
143 
144  if (count != 4) {
145  return false;
146  }
147  }
148 
149  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
150  if (BM_vert_is_wire(v)) {
151  return false;
152  }
153  if (BM_vert_edge_count(v) == 0) {
154  return false;
155  }
156  }
157 
158  return true;
159 }
160 
164 static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v)
165 {
166  return !BM_edge_exists(from_v, to_v);
167 }
168 
178 static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex)
179 {
180  bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
181  GSQueue *queue;
182  queue = BLI_gsqueue_new(sizeof(BMVert *));
183 
184  /* Add and tag the vertices connected by a diagonal to initial_vertex to the flood fill queue. If
185  * initial_vertex is a pole and there is a valid solution, those vertices should be the (0,0) of
186  * the grids for the loops of initial_vertex. */
187  BMIter iter;
188  BMIter iter_a;
189  BMFace *f;
190  BMVert *neighbor_v;
191  BM_ITER_ELEM (f, &iter, initial_vertex, BM_FACES_OF_VERT) {
192  BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
193  int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
194  if (neighbor_v != initial_vertex && is_vertex_diagonal(neighbor_v, initial_vertex)) {
195  BLI_gsqueue_push(queue, &neighbor_v);
196  visited_vertices[neighbor_vertex_index] = true;
197  BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
198  }
199  }
200  }
201 
202  /* Repeat a similar operation for all vertices in the queue. */
203  /* In this case, add to the queue the vertices connected by 2 steps using the diagonals in any
204  * direction. If a solution exists and `initial_vertex` was a pole, this is guaranteed that will
205  * tag all the (0,0) vertices of the grids, and nothing else. */
206  /* If it was not a pole, it may or may not find a solution, even if the solution exists. */
207  while (!BLI_gsqueue_is_empty(queue)) {
208  BMVert *from_v;
209  BLI_gsqueue_pop(queue, &from_v);
210 
211  /* Get the diagonals (first connected step) */
212  GSQueue *diagonals;
213  diagonals = BLI_gsqueue_new(sizeof(BMVert *));
214  BM_ITER_ELEM (f, &iter, from_v, BM_FACES_OF_VERT) {
215  BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
216  if (neighbor_v != from_v && is_vertex_diagonal(neighbor_v, from_v)) {
217  BLI_gsqueue_push(diagonals, &neighbor_v);
218  }
219  }
220  }
221 
222  /* Do the second connected step. This vertices are the ones that are added to the flood fill
223  * queue. */
224  while (!BLI_gsqueue_is_empty(diagonals)) {
225  BMVert *diagonal_v;
226  BLI_gsqueue_pop(diagonals, &diagonal_v);
227  BM_ITER_ELEM (f, &iter, diagonal_v, BM_FACES_OF_VERT) {
228  BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
229  int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
230  if (!visited_vertices[neighbor_vertex_index] && neighbor_v != diagonal_v &&
231  is_vertex_diagonal(neighbor_v, diagonal_v)) {
232  BLI_gsqueue_push(queue, &neighbor_v);
233  visited_vertices[neighbor_vertex_index] = true;
234  BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
235  }
236  }
237  }
238  }
239  BLI_gsqueue_free(diagonals);
240  }
241 
243  MEM_freeN(visited_vertices);
244 }
245 
257 static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int elem)
258 {
259  BMVert *v, *neighbor_v;
260  BMIter iter, iter_a, iter_b;
261  BMFace *f;
262 
263  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
264  if (is_vertex_in_id(v, elem_id, elem)) {
266  /* Tagged vertex in boundary */
267  if (BM_vert_is_boundary(v)) {
268  return false;
269  }
270  /* Tagged vertex with connected tagged vertex. */
271  BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
272  BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
273  if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
274  return false;
275  }
276  }
277  }
278  }
279  if (BM_vert_is_boundary(v)) {
280  /* Un-tagged vertex in boundary without connected tagged vertices. */
281  bool any_tagged = false;
282  BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
283  BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
284  if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
285  any_tagged = true;
286  }
287  }
288  }
289  if (!any_tagged) {
290  return false;
291  }
292  }
293  }
294  }
295 
296  return true;
297 }
298 
302 static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem)
303 {
304  /* First, get vertex candidates to try to generate possible un-subdivide solution. */
305  /* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be
306  * part of the base mesh. If it isn't, then there is no solution. */
307  GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *));
308  BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem);
309  if (initial_vertex_pole != NULL) {
310  BLI_gsqueue_push(initial_vertex, &initial_vertex_pole);
311  }
312 
313  /* Also try from the different 4 vertices of a quad in the current
314  * disconnected element ID. If a solution exists the search should return a valid solution from
315  * one of these vertices.*/
316  BMFace *f, *init_face = NULL;
317  BMVert *v;
318  BMIter iter_a, iter_b;
319  BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
320  BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
321  if (is_vertex_in_id(v, elem_id, elem)) {
322  init_face = f;
323  break;
324  }
325  }
326  if (init_face != NULL) {
327  break;
328  }
329  }
330 
331  BM_ITER_ELEM (v, &iter_a, init_face, BM_VERTS_OF_FACE) {
332  BLI_gsqueue_push(initial_vertex, &v);
333  }
334 
335  bool valid_tag_found = false;
336 
337  /* Check all vertex candidates to a solution. */
338  while (!BLI_gsqueue_is_empty(initial_vertex)) {
339 
340  BMVert *iv;
341  BLI_gsqueue_pop(initial_vertex, &iv);
342 
343  /* Generate a possible solution. */
345 
346  /* Check if the solution is valid. If it is, stop searching. */
347  if (unsubdivide_is_center_vertex_tag_valid(bm, elem_id, elem)) {
348  valid_tag_found = true;
349  break;
350  }
351 
352  /* If the solution is not valid, reset the state of all tags in this disconnected element ID
353  * and try again. */
354  BMVert *v_reset;
355  BMIter iter;
356  BM_ITER_MESH (v_reset, &iter, bm, BM_VERTS_OF_MESH) {
357  if (is_vertex_in_id(v_reset, elem_id, elem)) {
358  BM_elem_flag_set(v_reset, BM_ELEM_TAG, false);
359  }
360  }
361  }
362  BLI_gsqueue_free(initial_vertex);
363  return valid_tag_found;
364 }
365 
369 static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
370 {
371  bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
372  int current_id = 0;
373  for (int i = 0; i < bm->totvert; i++) {
374  if (!visited_vertices[i]) {
375  GSQueue *queue;
376  queue = BLI_gsqueue_new(sizeof(BMVert *));
377 
378  visited_vertices[i] = true;
379  elem_id[i] = current_id;
380  BMVert *iv = BM_vert_at_index(bm, i);
381  BLI_gsqueue_push(queue, &iv);
382 
383  while (!BLI_gsqueue_is_empty(queue)) {
384  BMIter iter;
385  BMVert *current_v, *neighbor_v;
386  BMEdge *ed;
387  BLI_gsqueue_pop(queue, &current_v);
388  BM_ITER_ELEM (ed, &iter, current_v, BM_EDGES_OF_VERT) {
389  neighbor_v = BM_edge_other_vert(ed, current_v);
390  const int neighbor_index = BM_elem_index_get(neighbor_v);
391  if (!visited_vertices[neighbor_index]) {
392  visited_vertices[neighbor_index] = true;
393  elem_id[neighbor_index] = current_id;
394  BLI_gsqueue_push(queue, &neighbor_v);
395  }
396  }
397  }
398  current_id++;
400  }
401  }
402  MEM_freeN(visited_vertices);
403  return current_id;
404 }
405 
411 {
412  BMVert *v;
413  BMIter iter;
414 
415  /* Stores the vertices which correspond to (1, 0) and (0, 1) of the grids in the select flag. */
417  BMVert *v_neighbor;
418  BMIter iter_a;
419  BMEdge *ed;
420  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
421  BM_ITER_ELEM (ed, &iter_a, v, BM_EDGES_OF_VERT) {
422  v_neighbor = BM_edge_other_vert(ed, v);
423  if (BM_elem_flag_test(v_neighbor, BM_ELEM_TAG)) {
425  }
426  }
427  }
428 
429  /* Dissolves the (0,0) vertices of the grids. */
432  "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
433  BM_ELEM_TAG,
434  false,
435  true);
436 
438 
439  /* Copy the select flag to the tag flag. */
440  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
443  }
444  }
445 
446  /* Dissolves the (1,0) and (0,1) vertices of the grids. */
449  "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
450  BM_ELEM_TAG,
451  false,
452  true);
453 }
454 
465 {
466 
467  /* Do a first check to make sure that it makes sense to search for un-subdivision in this mesh.
468  */
470  return false;
471  };
472 
473  /* Initialize the vertex table. */
476 
477  /* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */
478  int *elem_id = MEM_calloc_arrayN(sizeof(int), bm->totvert, " ELEM ID");
479  const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id);
480 
481  bool valid_tag_found = true;
482 
483  /* Reset the #BMesh flags as they are used to store data during the un-subdivide process. */
486 
487  /* For each disconnected mesh element ID, search if an un-subdivide solution is possible. The
488  * whole un-subdivide process fails if a single disconnected mesh element fails. */
489  for (int id = 0; id < tot_ids; id++) {
490  /* Try to the #BMesh vertex flag tags corresponding to an un-subdivide solution. */
491  if (!unsubdivide_tag_disconnected_mesh_element(bm, elem_id, id)) {
492  valid_tag_found = false;
493  break;
494  }
495  }
496 
497  /* If a solution was found for all elements IDs, build the new base mesh using the solution
498  * stored in the BMVert tags. */
499  if (valid_tag_found) {
501  }
502 
503  MEM_freeN(elem_id);
504  return valid_tag_found;
505 }
506 
510 static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
511 {
512  BMIter iter;
513  BMEdge *test_edge;
514  if (edge == NULL) {
515  (*r_next_vertex) = v;
516  return edge;
517  }
518  (*r_next_vertex) = BM_edge_other_vert(edge, v);
519  BM_ITER_ELEM (test_edge, &iter, (*r_next_vertex), BM_EDGES_OF_VERT) {
520  if (!BM_edge_share_quad_check(test_edge, edge)) {
521  return test_edge;
522  }
523  }
524  return NULL;
525 }
526 
527 static BMFace *face_step(BMEdge *edge, BMFace *f)
528 {
529  BMIter iter;
530  BMFace *face_iter;
531 
532  BM_ITER_ELEM (face_iter, &iter, edge, BM_FACES_OF_EDGE) {
533  if (BM_face_share_edge_check(face_iter, f)) {
534  return face_iter;
535  }
536  }
537  return f;
538 }
539 
544 static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
545 {
546  BMIter iter;
547  BMEdge *test_edge;
548  BM_ITER_ELEM (test_edge, &iter, f, BM_EDGES_OF_FACE) {
549  if (edge_x != test_edge) {
550  if (test_edge->v1 != initial_vertex && test_edge->v2 == initial_vertex) {
551  return test_edge;
552  }
553  if (test_edge->v2 != initial_vertex && test_edge->v1 == initial_vertex) {
554  return test_edge;
555  }
556  }
557  }
558  return NULL;
559 }
560 
565  float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop)
566 {
567  int origin[2];
568  int step_x[2];
569  int step_y[2];
570 
571  const int grid_offset = orig_grid_size - 1;
572  origin[0] = grid_offset;
573  origin[1] = grid_offset;
574 
575  switch (loop) {
576  case 0:
577  step_x[0] = -1;
578  step_x[1] = 0;
579 
580  step_y[0] = 0;
581  step_y[1] = -1;
582 
583  break;
584  case 1:
585  step_x[0] = 0;
586  step_x[1] = 1;
587 
588  step_y[0] = -1;
589  step_y[1] = -0;
590  break;
591  case 2:
592  step_x[0] = 1;
593  step_x[1] = 0;
594 
595  step_y[0] = 0;
596  step_y[1] = 1;
597  break;
598  case 3:
599  step_x[0] = 0;
600  step_x[1] = -1;
601 
602  step_y[0] = 1;
603  step_y[1] = 0;
604  break;
605  default:
606  BLI_assert(!"Should never happen");
607  break;
608  }
609 
610  for (int y = 0; y < orig_grid_size; y++) {
611  for (int x = 0; x < orig_grid_size; x++) {
612  const int remap_x = origin[1] + (step_x[1] * x) + (step_y[1] * y);
613  const int remap_y = origin[0] + (step_x[0] * x) + (step_y[0] * y);
614 
615  const int final_index = remap_x + remap_y * face_grid_size;
616  copy_v3_v3(face_grid[final_index], mdisp->disps[x + y * orig_grid_size]);
617  }
618  }
619 }
620 
626  float (*face_grid)[3],
627  int face_grid_size,
628  int gunsub_x,
629  int gunsub_y)
630 {
631  const int grid_it = face_grid_size - 1;
632  for (int y = 0; y < face_grid_size; y++) {
633  for (int x = 0; x < face_grid_size; x++) {
634  const int remap_x = (grid_it * gunsub_x) + x;
635  const int remap_y = (grid_it * gunsub_y) + y;
636 
637  const int remap_index_y = grid->grid_size - remap_x - 1;
638  const int remap_index_x = grid->grid_size - remap_y - 1;
639  const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
640  copy_v3_v3(grid->grid_co[grid_index], face_grid[x + y * face_grid_size]);
641  }
642  }
643 }
644 
653  BMVert *v,
654  BMFace *f,
655  int grid_x,
656  int grid_y)
657 {
658 
659  Mesh *original_mesh = context->original_mesh;
660  MPoly *poly = &original_mesh->mpoly[BM_elem_index_get(f)];
661 
662  const int corner_vertex_index = BM_elem_index_get(v);
663 
664  /* Calculates an offset to write the grids correctly oriented in the main
665  * #MultiresUnsubdivideGrid. */
666  int loop_offset = 0;
667  for (int i = 0; i < poly->totloop; i++) {
668  const int loop_index = poly->loopstart + i;
669  MLoop *l = &original_mesh->mloop[loop_index];
670  if (l->v == corner_vertex_index) {
671  loop_offset = i;
672  break;
673  }
674  }
675 
676  /* Write the 4 grids of the current quad with the right orientation into the face_grid buffer. */
677  const int grid_size = BKE_ccg_gridsize(context->num_original_levels);
678  const int face_grid_size = BKE_ccg_gridsize(context->num_original_levels + 1);
679  const int face_grid_area = face_grid_size * face_grid_size;
680  float(*face_grid)[3] = MEM_calloc_arrayN(face_grid_area, sizeof(float[3]), "face_grid");
681 
682  for (int i = 0; i < poly->totloop; i++) {
683  const int loop_index = poly->loopstart + i;
684  MDisps *mdisp = &context->original_mdisp[loop_index];
685  int quad_loop = i - loop_offset;
686  if (quad_loop < 0) {
687  quad_loop += 4;
688  }
689  if (quad_loop >= 4) {
690  quad_loop -= 4;
691  }
692  write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop);
693  }
694 
695  /* Write the face_grid buffer in the correct position in the #MultiresUnsubdivideGrids that is
696  * being extracted. */
697  write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y);
698 
699  MEM_freeN(face_grid);
700 }
701 
706 static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y)
707 {
708  const int remap_index_y = grid->grid_size - 1 - grid_x;
709  const int remap_index_x = grid->grid_size - 1 - grid_y;
710 
711  const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
712 
713  copy_v3_v3(grid->grid_co[grid_index], v->co);
714 }
715 
721  BMFace *f1,
722  BMEdge *e1,
723  bool flip_grid,
725 {
726  BMVert *initial_vertex;
727  BMEdge *initial_edge_x;
728  BMEdge *initial_edge_y;
729 
730  const int grid_size = BKE_ccg_gridsize(context->num_new_levels);
731  const int unsubdiv_grid_size = grid->grid_size = BKE_ccg_gridsize(context->num_total_levels);
732  grid->grid_size = unsubdiv_grid_size;
733  grid->grid_co = MEM_calloc_arrayN(
734  unsubdiv_grid_size * unsubdiv_grid_size, sizeof(float[3]), "grids coordinates");
735 
736  /* Get the vertex on the corner of the grid. This vertex was tagged previously as it also exist
737  * on the base mesh. */
738  initial_edge_x = e1;
739  if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
740  initial_vertex = initial_edge_x->v1;
741  }
742  else {
743  initial_vertex = initial_edge_x->v2;
744  }
745 
746  /* From that vertex, get the edge that defines the grid Y axis for extraction. */
747  initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
748 
749  if (flip_grid) {
750  BMEdge *edge_temp;
751  edge_temp = initial_edge_x;
752  initial_edge_x = initial_edge_y;
753  initial_edge_y = edge_temp;
754  }
755 
756  int grid_x = 0;
757  int grid_y = 0;
758 
759  BMVert *current_vertex_x = initial_vertex;
760  BMEdge *edge_x = initial_edge_x;
761 
762  BMVert *current_vertex_y = initial_vertex;
763  BMEdge *edge_y = initial_edge_y;
764  BMEdge *prev_edge_y = initial_edge_y;
765 
766  BMFace *current_face = f1;
767  BMFace *grid_face = f1;
768 
769  /* If the data is going to be extracted from the already existing grids, there is no need to go
770  * to the last vertex of the iteration as that coordinate is also included in the grids
771  * corresponding to the loop of the face of the previous iteration. */
772  int grid_iteration_max_steps = grid_size;
773  if (context->num_original_levels > 0) {
774  grid_iteration_max_steps = grid_size - 1;
775  }
776 
777  /* Iterate over the mesh vertices in a grid pattern using the axis defined by the two initial
778  * edges. */
779  while (grid_y < grid_iteration_max_steps) {
780 
781  grid_face = current_face;
782 
783  while (grid_x < grid_iteration_max_steps) {
784  if (context->num_original_levels == 0) {
785  /* If there were no grids on the original mesh, extract the data directly from the
786  * vertices. */
787  store_vertex_data(grid, current_vertex_x, grid_x, grid_y);
788  edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
789  }
790  else {
791  /* If there were grids in the original mesh, extract the data from the grids and iterate
792  * over the faces. */
793  store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y);
794  edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
795  grid_face = face_step(edge_x, grid_face);
796  }
797 
798  grid_x++;
799  }
800  grid_x = 0;
801 
802  edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
803  current_vertex_x = current_vertex_y;
804 
805  /* Get the next edge_x to extract the next row of the grid. This needs to be done because there
806  * may be two edges connected to current_vertex_x that belong to two different grids. */
807  BMIter iter;
808  BMEdge *ed;
809  BMFace *f;
810  BM_ITER_ELEM (ed, &iter, current_vertex_x, BM_EDGES_OF_VERT) {
811  if (ed != prev_edge_y && BM_edge_in_face(ed, current_face)) {
812  edge_x = ed;
813  break;
814  }
815  }
816  BM_ITER_ELEM (f, &iter, edge_x, BM_FACES_OF_EDGE) {
817  if (f != current_face) {
818  current_face = f;
819  break;
820  }
821  }
822 
823  prev_edge_y = edge_y;
824  grid_y++;
825  }
826 }
827 
835  BMEdge *e1,
836  BMVert **r_corner_x,
837  BMVert **r_corner_y)
838 {
839  BMVert *initial_vertex;
840  BMEdge *initial_edge_x;
841  BMEdge *initial_edge_y;
842 
843  initial_edge_x = e1;
844  if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
845  initial_vertex = initial_edge_x->v1;
846  }
847  else {
848  initial_vertex = initial_edge_x->v2;
849  }
850 
851  /* From that vertex, get the edge that defines the grid Y axis for extraction. */
852  initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
853 
854  BMVert *current_vertex_x = initial_vertex;
855  BMEdge *edge_x = initial_edge_x;
856 
857  BMVert *current_vertex_y = initial_vertex;
858  BMEdge *edge_y = initial_edge_y;
859 
860  /* Do an edge step until it finds a tagged vertex, which is part of the base mesh. */
861  /* x axis */
862  edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
863  while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) {
864  edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
865  }
866  (*r_corner_x) = current_vertex_x;
867 
868  /* Same for y axis */
869  edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
870  while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) {
871  edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
872  }
873  (*r_corner_y) = current_vertex_y;
874 }
875 
877 {
878  const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
879  BMesh *bm = BM_mesh_create(&allocsize,
880  &((struct BMeshCreateParams){
881  .use_toolflags = true,
882  }));
883 
885  mesh,
886  (&(struct BMeshFromMeshParams){
887  .calc_face_normal = true,
888  }));
889 
890  return bm;
891 }
892 
893 /* Data-layer names to store the original indices of the elements before modifying the mesh. */
894 static const char lname[] = "l_remap_index";
895 static const char vname[] = "v_remap_index";
896 
898 {
899  const int l_layer_index = CustomData_get_named_layer_index(&mesh->ldata, CD_PROP_INT32, lname);
900  if (l_layer_index != -1) {
902  }
903 
904  const int v_layer_index = CustomData_get_named_layer_index(&mesh->vdata, CD_PROP_INT32, vname);
905  if (v_layer_index != -1) {
906  CustomData_free_layer(&mesh->vdata, CD_PROP_INT32, mesh->totvert, v_layer_index);
907  }
908 }
909 
915 {
917 
918  int *l_index = CustomData_add_layer_named(
920 
921  int *v_index = CustomData_add_layer_named(
923 
924  /* Initialize these data-layer with the indices in the current mesh. */
925  for (int i = 0; i < mesh->totloop; i++) {
926  l_index[i] = i;
927  }
928  for (int i = 0; i < mesh->totvert; i++) {
929  v_index[i] = i;
930  }
931 }
932 
935 {
936 
937  Mesh *original_mesh = context->original_mesh;
938  Mesh *base_mesh = context->base_mesh;
939 
940  BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh);
941 
942  /* Initialize the elem tables. */
943  BM_mesh_elem_table_ensure(bm_original_mesh, BM_EDGE);
944  BM_mesh_elem_table_ensure(bm_original_mesh, BM_FACE);
945  BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT);
946 
947  /* Disable all flags. */
949  bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
951  bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
952 
953  /* Get the mapping data-layer. */
954  context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT32, vname);
955 
956  /* Tag the base mesh vertices in the original mesh. */
957  for (int i = 0; i < base_mesh->totvert; i++) {
958  int vert_basemesh_index = context->base_to_orig_vmap[i];
959  BMVert *v = BM_vert_at_index(bm_original_mesh, vert_basemesh_index);
961  }
962 
963  /* Create a map from loop index to poly index for the original mesh. */
964  context->loop_to_face_map = MEM_calloc_arrayN(sizeof(int), original_mesh->totloop, "loop map");
965 
966  for (int i = 0; i < original_mesh->totpoly; i++) {
967  MPoly *poly = &original_mesh->mpoly[i];
968  for (int l = 0; l < poly->totloop; l++) {
969  int original_loop_index = l + poly->loopstart;
970  context->loop_to_face_map[original_loop_index] = i;
971  }
972  }
973 }
974 
979 static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x)
980 {
981  MPoly *p = &mesh->mpoly[poly];
982 
983  MLoop *l_first = &mesh->mloop[p->loopstart];
984  if ((loop == (p->loopstart + (p->totloop - 1))) && l_first->v == v_x) {
985  return true;
986  }
987 
988  int next_l_index = loop + 1;
989  if (next_l_index < p->loopstart + p->totloop) {
990  MLoop *l_next = &mesh->mloop[next_l_index];
991  if (l_next->v == v_x) {
992  return true;
993  }
994  }
995 
996  return false;
997 }
998 
1000 {
1001  Mesh *original_mesh = context->original_mesh;
1002  Mesh *base_mesh = context->base_mesh;
1003 
1004  BMesh *bm_original_mesh = context->bm_original_mesh;
1005 
1006  context->num_grids = base_mesh->totloop;
1007  context->base_mesh_grids = MEM_calloc_arrayN(
1008  sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids");
1009 
1010  /* Based on the existing indices in the data-layers, generate two vertex indices maps. */
1011  /* From vertex index in original to vertex index in base and from vertex index in base to vertex
1012  * index in original. */
1013  int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap");
1014  int *base_to_orig_vmap = MEM_calloc_arrayN(sizeof(int), base_mesh->totvert, "base vmap");
1015 
1016  context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT32, vname);
1017  for (int i = 0; i < base_mesh->totvert; i++) {
1018  base_to_orig_vmap[i] = context->base_to_orig_vmap[i];
1019  }
1020 
1021  /* If an index in original does not exist in base (it was dissolved when creating the new base
1022  * mesh, return -1. */
1023  for (int i = 0; i < original_mesh->totvert; i++) {
1024  orig_to_base_vmap[i] = -1;
1025  }
1026 
1027  for (int i = 0; i < base_mesh->totvert; i++) {
1028  const int orig_vertex_index = context->base_to_orig_vmap[i];
1029  orig_to_base_vmap[orig_vertex_index] = i;
1030  }
1031 
1032  /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer,
1033  * so they can be used from #BMesh. */
1035 
1036  const int base_l_layer_index = CustomData_get_named_layer_index(
1037  &base_mesh->ldata, CD_PROP_INT32, lname);
1038  BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh);
1039  BMIter iter, iter_a, iter_b;
1040  BMVert *v;
1041  BMLoop *l, *lb;
1042 
1043  BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT);
1044  BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE);
1045 
1046  /* Get the data-layer that contains the loops indices. */
1047  const int base_l_offset = CustomData_get_n_offset(
1048  &bm_base_mesh->ldata, CD_PROP_INT32, base_l_layer_index);
1049 
1050  /* Main loop for extracting the grids. Iterates over the base mesh vertices. */
1051  BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) {
1052 
1053  /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the
1054  * vertex map. */
1055  const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)];
1056  BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index);
1057 
1058  /* Iterate over the loops of that vertex in the original mesh. */
1059  BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) {
1060  /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the
1061  * base mesh of the poly of grid that is going to be extracted. */
1062  BMVert *corner_x, *corner_y;
1063  multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y);
1064 
1065  /* Map the two obtained vertices to the base mesh. */
1066  const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)];
1067  const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)];
1068 
1069  /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained
1070  * vertices and the current vertex it is possible to get the index of the loop in the base
1071  * mesh the grid that is going to be extracted belongs to. */
1072  BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) {
1073  BMFace *base_face = lb->f;
1074  BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index);
1075  BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index);
1076  /* If this is the correct loop in the base mesh, the original vertex and the two corners
1077  * should be in the loop's face. */
1078  if (BM_vert_in_face(base_corner_x, base_face) &&
1079  BM_vert_in_face(base_corner_y, base_face)) {
1080  /* Get the index of the loop. */
1081  const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset);
1082  const int base_mesh_face_index = BM_elem_index_get(base_face);
1083 
1084  /* Check the orientation of the loops in case that is needed to flip the x and y axis
1085  * when extracting the grid. */
1086  const bool flip_grid = multires_unsubdivide_flip_grid_x_axis(
1087  base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index);
1088 
1089  /* Extract the grid for that loop. */
1090  context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index;
1092  context, l->f, l->e, !flip_grid, &context->base_mesh_grids[base_mesh_loop_index]);
1093 
1094  break;
1095  }
1096  }
1097  }
1098  }
1099 
1100  MEM_freeN(orig_to_base_vmap);
1101  MEM_freeN(base_to_orig_vmap);
1102 
1103  BM_mesh_free(bm_base_mesh);
1105 }
1106 
1108 {
1109  if (context->bm_original_mesh != NULL) {
1110  BM_mesh_free(context->bm_original_mesh);
1111  }
1112  MEM_SAFE_FREE(context->loop_to_face_map);
1113 }
1114 
1116  Mesh *original_mesh,
1117  struct MultiresModifierData *mmd)
1118 {
1119  context->original_mesh = original_mesh;
1120  context->num_new_levels = 0;
1121  context->num_total_levels = 0;
1122  context->num_original_levels = mmd->totlvl;
1123 }
1124 
1126 {
1127  Mesh *original_mesh = context->original_mesh;
1128 
1129  /* Prepare the data-layers to map base to original. */
1131  BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh);
1132 
1133  /* Un-subdivide as many iterations as possible. */
1134  context->num_new_levels = 0;
1135  int num_levels_left = context->max_new_levels;
1136  while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) {
1137  context->num_new_levels++;
1138  num_levels_left--;
1139  }
1140 
1141  /* If no un-subdivide steps were possible, free the bmesh, the map data-layers and stop. */
1142  if (context->num_new_levels == 0) {
1144  BM_mesh_free(bm_base_mesh);
1145  return false;
1146  }
1147 
1148  /* Calculate the final levels for the new grids over base mesh. */
1149  context->num_total_levels = context->num_new_levels + context->num_original_levels;
1150 
1151  /* Store the new base-mesh as a mesh in context, free bmesh. */
1152  context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
1154  bm_base_mesh,
1155  context->base_mesh,
1156  (&(struct BMeshToMeshParams){
1157  .calc_object_remap = true,
1158  }));
1159  BM_mesh_free(bm_base_mesh);
1160 
1161  /* Initialize bmesh and maps for the original mesh and extract the grids. */
1162 
1165 
1166  return true;
1167 }
1168 
1170 {
1172  for (int i = 0; i < context->num_grids; i++) {
1173  if (context->base_mesh_grids[i].grid_size > 0) {
1174  MEM_SAFE_FREE(context->base_mesh_grids[i].grid_co);
1175  }
1176  }
1177  MEM_SAFE_FREE(context->base_mesh_grids);
1178 }
1179 
1185  Mesh *base_mesh)
1186 {
1187  /* Free the current MDISPS and create a new ones. */
1188  if (CustomData_has_layer(&base_mesh->ldata, CD_MDISPS)) {
1189  CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop);
1190  }
1191  MDisps *mdisps = CustomData_add_layer(
1192  &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop);
1193 
1194  const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2);
1195  const int totloop = base_mesh->totloop;
1196 
1197  BLI_assert(base_mesh->totloop == context->num_grids);
1198 
1199  /* Allocate the MDISPS grids and copy the extracted data from context. */
1200  for (int i = 0; i < totloop; i++) {
1201  float(*disps)[3] = MEM_calloc_arrayN(totdisp, sizeof(float[3]), "multires disps");
1202 
1203  if (mdisps[i].disps) {
1204  MEM_freeN(mdisps[i].disps);
1205  }
1206 
1207  for (int j = 0; j < totdisp; j++) {
1208  if (context->base_mesh_grids[i].grid_co) {
1209  copy_v3_v3(disps[j], context->base_mesh_grids[i].grid_co[j]);
1210  }
1211  }
1212 
1213  mdisps[i].disps = disps;
1214  mdisps[i].totdisp = totdisp;
1215  mdisps[i].level = context->num_total_levels;
1216  }
1217 }
1218 
1220  struct Object *object,
1221  struct MultiresModifierData *mmd,
1222  int rebuild_limit,
1223  bool switch_view_to_lower_level)
1224 {
1225  Mesh *mesh = object->data;
1226 
1228 
1229  MultiresUnsubdivideContext unsubdiv_context = {0};
1230  MultiresReshapeContext reshape_context = {0};
1231 
1232  multires_unsubdivide_context_init(&unsubdiv_context, mesh, mmd);
1233 
1234  /* Convert and store the existing grids in object space if available. */
1235  if (mmd->totlvl != 0) {
1236  if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) {
1237  return 0;
1238  }
1239 
1240  multires_reshape_store_original_grids(&reshape_context);
1242  unsubdiv_context.original_mdisp = reshape_context.mdisps;
1243  }
1244 
1245  /* Set the limit for the levels that should be rebuild. */
1246  unsubdiv_context.max_new_levels = rebuild_limit;
1247 
1248  /* Un-subdivide and create the data for the new grids. */
1249  if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) {
1250  /* If there was no possible to rebuild any level, free the data and return. */
1251  if (mmd->totlvl != 0) {
1253  multires_unsubdivide_context_free(&unsubdiv_context);
1254  }
1255  multires_reshape_context_free(&reshape_context);
1256  return 0;
1257  }
1258 
1259  /* Free the reshape context used to convert the data from the original grids to object space. */
1260  if (mmd->totlvl != 0) {
1261  multires_reshape_context_free(&reshape_context);
1262  }
1263 
1264  /* Copy the new base mesh to the original mesh. */
1265  BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, object->data, object, &CD_MASK_MESH, true);
1266  Mesh *base_mesh = object->data;
1267  multires_create_grids_in_unsubdivided_base_mesh(&unsubdiv_context, base_mesh);
1268 
1269  /* Update the levels in the modifier. Force always to display at level 0 as it contains the new
1270  * created level. */
1271  mmd->totlvl = (char)unsubdiv_context.num_total_levels;
1272 
1273  if (switch_view_to_lower_level) {
1274  mmd->sculptlvl = 0;
1275  mmd->lvl = 0;
1276  }
1277  else {
1278  mmd->sculptlvl = (char)(mmd->sculptlvl + unsubdiv_context.num_new_levels);
1279  mmd->lvl = (char)(mmd->lvl + unsubdiv_context.num_new_levels);
1280  }
1281 
1282  mmd->renderlvl = (char)(mmd->renderlvl + unsubdiv_context.num_new_levels);
1283 
1284  /* Create a reshape context to convert the MDISPS data to tangent displacement. It can be the
1285  * same as the previous one as a new Subdivision needs to be created for the new base mesh. */
1286  if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) {
1287  return 0;
1288  }
1290  multires_reshape_context_free(&reshape_context);
1291 
1292  /* Free the un-subdivide context and return the total number of levels that were rebuild. */
1293  const int rebuild_subdvis = unsubdiv_context.num_new_levels;
1294  multires_unsubdivide_context_free(&unsubdiv_context);
1295 
1296  return rebuild_subdvis;
1297 }
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.c:2655
@ CD_CALLOC
void CustomData_free_layers(struct CustomData *data, int type, int totelem)
Definition: customdata.c:2716
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.c:2637
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
Definition: customdata.c:3217
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.c:2620
int CustomData_get_n_offset(const struct CustomData *data, int type, int n)
const CustomData_MeshMasks CD_MASK_MESH
Definition: customdata.c:1933
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.c:877
void multires_force_sculpt_rebuild(struct Object *object)
Definition: multires.c:456
int BKE_ccg_gridsize(int level)
Definition: CCGSubSurf.c:37
#define BLI_assert(a)
Definition: BLI_assert.h:58
void BLI_gsqueue_free(GSQueue *queue)
Definition: gsqueue.c:107
void BLI_gsqueue_push(GSQueue *queue, const void *item)
Definition: gsqueue.c:122
GSQueue * BLI_gsqueue_new(const size_t elem_size)
Definition: gsqueue.c:83
void BLI_gsqueue_pop(GSQueue *queue, void *r_item)
Definition: gsqueue.c:162
bool BLI_gsqueue_is_empty(const GSQueue *queue)
Definition: gsqueue.c:193
int pow_i(int base, int exp)
Definition: math_base.c:30
MINLINE void copy_v3_v3(float r[3], const float a[3])
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
@ 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:124
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#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.c:307
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
BMesh Make Mesh.
Definition: bmesh_mesh.c:157
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2352
#define BMALLOC_TEMPLATE_FROM_ME(...)
Definition: bmesh_mesh.h:163
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:98
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
Mesh -> BMesh.
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
#define BMO_FLAG_DEFAULTS
@ BMO_FLAG_RESPECT_HIDE
bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt,...)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1995
bool BM_vert_is_wire(const BMVert *v)
Definition: bmesh_query.c:919
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
Definition: bmesh_query.c:1335
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:555
bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
Definition: bmesh_query.c:1250
bool BM_vert_in_face(BMVert *v, BMFace *f)
Definition: bmesh_query.c:431
int BM_vert_edge_count(const BMVert *v)
Definition: bmesh_query.c:822
bool BM_vert_is_boundary(const BMVert *v)
Definition: bmesh_query.c:1168
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
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
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)
ThreadQueue * queue
all scheduled work for the cpu
struct SELECTID_Context context
Definition: select_engine.c:47
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMFace * f
Definition: bmesh_class.h:183
float co[3]
Definition: bmesh_class.h:99
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
struct CustomData pdata ldata
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
struct MDisps * mdisps
void * data