Blender V4.3
multires_unsubdivide.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12#include "MEM_guardedalloc.h"
13
14#include "DNA_mesh_types.h"
15#include "DNA_meshdata_types.h"
16#include "DNA_modifier_types.h"
17#include "DNA_scene_types.h"
18
19#include "BLI_gsqueue.h"
20#include "BLI_math_vector.h"
21
22#include "BKE_customdata.hh"
23#include "BKE_mesh.hh"
24#include "BKE_multires.hh"
25#include "BKE_subsurf.hh"
26
27#include "bmesh.hh"
28
29#include "multires_reshape.hh"
31
32/* This is done in the following steps:
33 *
34 * - If there are already grids in the original mesh,
35 * convert them from tangent displacement to object space coordinates.
36 * - Assign data-layers to the original mesh to map vertices to a new base mesh.
37 * These data-layers store the indices of the elements in the original mesh.
38 * This way the original indices are
39 * preserved when doing mesh modifications (removing and dissolving vertices)
40 * when building the new base mesh.
41 * - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the
42 * center vertices of the lower level grid.
43 * If the algorithm can tag all vertices correctly,
44 * the lower level base mesh is generated by dissolving the tagged vertices.
45 * - Use the data-layers to map vertices from the base mesh to the original mesh and original to
46 * base mesh.
47 * - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh
48 * to original mesh
49 * - Extract the grid from the original mesh from that loop. If there are no grids in the original
50 * mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern
51 * over them. If there are grids in the original mesh, iterate in a grid pattern over the faces,
52 * reorder all the coordinates of the grid in that face and copy those coordinates to the new
53 * base mesh grid.
54 * - Copy the new grid data over to a new allocated MDISP layer with the appropriate size to store
55 * the new levels.
56 * - Convert the grid data from object space to tangent displacement.
57 */
58
62static bool is_vertex_in_id(BMVert *v, const int *elem_id, int elem)
63{
64 const int v_index = BM_elem_index_get(v);
65 return elem_id[v_index] == elem;
66}
67
72
78
85static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
86{
87 BMIter iter;
88 BMVert *v;
89 BMVert *pole = nullptr;
91 if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole_three(v)) {
92 return v;
93 }
94 if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole(v)) {
95 pole = v;
96 }
97 }
98 return pole;
99}
100
108{
109 BMIter iter;
110 BMFace *f;
111 BMVert *v;
112 if (bm->totface < 3) {
113 return false;
114 }
115
116 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
117 if (f->len != 4) {
118 return false;
119 }
120 }
121
122 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
123 if (BM_vert_is_wire(v) || (v->e == nullptr)) {
124 return false;
125 }
126 }
127
128 return true;
129}
130
134static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v)
135{
136 return !BM_edge_exists(from_v, to_v);
137}
138
148static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex)
149{
150 blender::BitVector<> visited_verts(bm->totvert);
151 GSQueue *queue;
152 queue = BLI_gsqueue_new(sizeof(BMVert *));
153
154 /* Add and tag the vertices connected by a diagonal to initial_vertex to the flood fill queue. If
155 * initial_vertex is a pole and there is a valid solution, those vertices should be the (0,0) of
156 * the grids for the loops of initial_vertex. */
157 BMIter iter;
158 BMIter iter_a;
159 BMFace *f;
160 BMVert *neighbor_v;
161 BM_ITER_ELEM (f, &iter, initial_vertex, BM_FACES_OF_VERT) {
162 BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
163 int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
164 if (neighbor_v != initial_vertex && is_vertex_diagonal(neighbor_v, initial_vertex)) {
165 BLI_gsqueue_push(queue, &neighbor_v);
166 visited_verts[neighbor_vertex_index].set();
167 BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
168 }
169 }
170 }
171
172 /* Repeat a similar operation for all vertices in the queue. */
173 /* In this case, add to the queue the vertices connected by 2 steps using the diagonals in any
174 * direction. If a solution exists and `initial_vertex` was a pole, this is guaranteed that will
175 * tag all the (0,0) vertices of the grids, and nothing else. */
176 /* If it was not a pole, it may or may not find a solution, even if the solution exists. */
177 while (!BLI_gsqueue_is_empty(queue)) {
178 BMVert *from_v;
179 BLI_gsqueue_pop(queue, &from_v);
180
181 /* Get the diagonals (first connected step) */
182 GSQueue *diagonals;
183 diagonals = BLI_gsqueue_new(sizeof(BMVert *));
184 BM_ITER_ELEM (f, &iter, from_v, BM_FACES_OF_VERT) {
185 BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
186 if (neighbor_v != from_v && is_vertex_diagonal(neighbor_v, from_v)) {
187 BLI_gsqueue_push(diagonals, &neighbor_v);
188 }
189 }
190 }
191
192 /* Do the second connected step. This vertices are the ones that are added to the flood fill
193 * queue. */
194 while (!BLI_gsqueue_is_empty(diagonals)) {
195 BMVert *diagonal_v;
196 BLI_gsqueue_pop(diagonals, &diagonal_v);
197 BM_ITER_ELEM (f, &iter, diagonal_v, BM_FACES_OF_VERT) {
198 BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
199 int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
200 if (!visited_verts[neighbor_vertex_index] && neighbor_v != diagonal_v &&
201 is_vertex_diagonal(neighbor_v, diagonal_v))
202 {
203 BLI_gsqueue_push(queue, &neighbor_v);
204 visited_verts[neighbor_vertex_index].set(true);
205 BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
206 }
207 }
208 }
209 }
210 BLI_gsqueue_free(diagonals);
211 }
212
213 BLI_gsqueue_free(queue);
214}
215
227static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int elem)
228{
229 BMVert *v, *neighbor_v;
230 BMIter iter, iter_a, iter_b;
231 BMFace *f;
232
233 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
234 if (is_vertex_in_id(v, elem_id, elem)) {
236 /* Tagged vertex in boundary */
237 if (BM_vert_is_boundary(v)) {
238 return false;
239 }
240 /* Tagged vertex with connected tagged vertex. */
241 BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
242 BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
243 if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
244 return false;
245 }
246 }
247 }
248 }
249 if (BM_vert_is_boundary(v)) {
250 /* Un-tagged vertex in boundary without connected tagged vertices. */
251 bool any_tagged = false;
252 BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
253 BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
254 if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
255 any_tagged = true;
256 }
257 }
258 }
259 if (!any_tagged) {
260 return false;
261 }
262 }
263 }
264 }
265
266 return true;
267}
268
272static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem)
273{
274 /* First, get vertex candidates to try to generate possible un-subdivide solution. */
275 /* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be
276 * part of the base mesh. If it isn't, then there is no solution. */
277 GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *));
278 BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem);
279 if (initial_vertex_pole != nullptr) {
280 BLI_gsqueue_push(initial_vertex, &initial_vertex_pole);
281 }
282
283 /* Also try from the different 4 vertices of a quad in the current
284 * disconnected element ID. If a solution exists the search should return a valid solution from
285 * one of these vertices. */
286 BMFace *f, *init_face = nullptr;
287 BMVert *v;
288 BMIter iter_a, iter_b;
289 BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
290 BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
291 if (is_vertex_in_id(v, elem_id, elem)) {
292 init_face = f;
293 break;
294 }
295 }
296 if (init_face != nullptr) {
297 break;
298 }
299 }
300
301 BM_ITER_ELEM (v, &iter_a, init_face, BM_VERTS_OF_FACE) {
302 BLI_gsqueue_push(initial_vertex, &v);
303 }
304
305 bool valid_tag_found = false;
306
307 /* Check all vertex candidates to a solution. */
308 while (!BLI_gsqueue_is_empty(initial_vertex)) {
309
310 BMVert *iv;
311 BLI_gsqueue_pop(initial_vertex, &iv);
312
313 /* Generate a possible solution. */
315
316 /* Check if the solution is valid. If it is, stop searching. */
317 if (unsubdivide_is_center_vertex_tag_valid(bm, elem_id, elem)) {
318 valid_tag_found = true;
319 break;
320 }
321
322 /* If the solution is not valid, reset the state of all tags in this disconnected element ID
323 * and try again. */
324 BMVert *v_reset;
325 BMIter iter;
326 BM_ITER_MESH (v_reset, &iter, bm, BM_VERTS_OF_MESH) {
327 if (is_vertex_in_id(v_reset, elem_id, elem)) {
328 BM_elem_flag_set(v_reset, BM_ELEM_TAG, false);
329 }
330 }
331 }
332 BLI_gsqueue_free(initial_vertex);
333 return valid_tag_found;
334}
335
339static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
340{
341 bool *visited_verts = static_cast<bool *>(
342 MEM_calloc_arrayN(bm->totvert, sizeof(bool), "visited vertices"));
343 int current_id = 0;
344 for (int i = 0; i < bm->totvert; i++) {
345 if (!visited_verts[i]) {
346 GSQueue *queue;
347 queue = BLI_gsqueue_new(sizeof(BMVert *));
348
349 visited_verts[i] = true;
350 elem_id[i] = current_id;
351 BMVert *iv = BM_vert_at_index(bm, i);
352 BLI_gsqueue_push(queue, &iv);
353
354 while (!BLI_gsqueue_is_empty(queue)) {
355 BMIter iter;
356 BMVert *current_v, *neighbor_v;
357 BMEdge *ed;
358 BLI_gsqueue_pop(queue, &current_v);
359 BM_ITER_ELEM (ed, &iter, current_v, BM_EDGES_OF_VERT) {
360 neighbor_v = BM_edge_other_vert(ed, current_v);
361 const int neighbor_index = BM_elem_index_get(neighbor_v);
362 if (!visited_verts[neighbor_index]) {
363 visited_verts[neighbor_index] = true;
364 elem_id[neighbor_index] = current_id;
365 BLI_gsqueue_push(queue, &neighbor_v);
366 }
367 }
368 }
369 current_id++;
370 BLI_gsqueue_free(queue);
371 }
372 }
373 MEM_freeN(visited_verts);
374 return current_id;
375}
376
382{
383 BMVert *v;
384 BMIter iter;
385
386 /* Stores the vertices which correspond to (1, 0) and (0, 1) of the grids in the select flag. */
388 BMVert *v_neighbor;
389 BMIter iter_a;
390 BMEdge *ed;
391 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
392 BM_ITER_ELEM (ed, &iter_a, v, BM_EDGES_OF_VERT) {
393 v_neighbor = BM_edge_other_vert(ed, v);
394 if (BM_elem_flag_test(v_neighbor, BM_ELEM_TAG)) {
396 }
397 }
398 }
399
400 /* Dissolves the (0,0) vertices of the grids. */
403 "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
405 false,
406 true);
407
409
410 /* Copy the select flag to the tag flag. */
411 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
414 }
415 }
416
417 /* Dissolves the (1,0) and (0,1) vertices of the grids. */
420 "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
422 false,
423 true);
424}
425
436{
437
438 /* Do a first check to make sure that it makes sense to search for un-subdivision in this mesh.
439 */
441 return false;
442 };
443
444 /* Initialize the vertex table. */
447
448 /* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */
449 int *elem_id = static_cast<int *>(MEM_calloc_arrayN(bm->totvert, sizeof(int), " ELEM ID"));
450 const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id);
451
452 bool valid_tag_found = true;
453
454 /* Reset the #BMesh flags as they are used to store data during the un-subdivide process.
455 * Un-hiding all faces is important so the entire mesh is handled, see: #126633. */
458
459 /* For each disconnected mesh element ID, search if an un-subdivide solution is possible. The
460 * whole un-subdivide process fails if a single disconnected mesh element fails. */
461 for (int id = 0; id < tot_ids; id++) {
462 /* Try to the #BMesh vertex flag tags corresponding to an un-subdivide solution. */
464 valid_tag_found = false;
465 break;
466 }
467 }
468
469 /* If a solution was found for all elements IDs, build the new base mesh using the solution
470 * stored in the BMVert tags. */
471 if (valid_tag_found) {
473 }
474
475 MEM_freeN(elem_id);
476 return valid_tag_found;
477}
478
482static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
483{
484 BMIter iter;
485 BMEdge *test_edge;
486 if (edge == nullptr) {
487 (*r_next_vertex) = v;
488 return edge;
489 }
490 (*r_next_vertex) = BM_edge_other_vert(edge, v);
491 BM_ITER_ELEM (test_edge, &iter, (*r_next_vertex), BM_EDGES_OF_VERT) {
492 if (!BM_edge_share_quad_check(test_edge, edge)) {
493 return test_edge;
494 }
495 }
496 return nullptr;
497}
498
499static BMFace *face_step(BMEdge *edge, BMFace *f)
500{
501 BMIter iter;
502 BMFace *face_iter;
503
504 BM_ITER_ELEM (face_iter, &iter, edge, BM_FACES_OF_EDGE) {
505 if (BM_face_share_edge_check(face_iter, f)) {
506 return face_iter;
507 }
508 }
509 return f;
510}
511
516static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
517{
518 BMIter iter;
519 BMEdge *test_edge;
520 BM_ITER_ELEM (test_edge, &iter, f, BM_EDGES_OF_FACE) {
521 if (edge_x != test_edge) {
522 if (test_edge->v1 != initial_vertex && test_edge->v2 == initial_vertex) {
523 return test_edge;
524 }
525 if (test_edge->v2 != initial_vertex && test_edge->v1 == initial_vertex) {
526 return test_edge;
527 }
528 }
529 }
530 return nullptr;
531}
532
537 float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop)
538{
539 int origin[2];
540 int step_x[2];
541 int step_y[2];
542
543 const int grid_offset = orig_grid_size - 1;
544 origin[0] = grid_offset;
545 origin[1] = grid_offset;
546
547 switch (loop) {
548 case 0:
549 step_x[0] = -1;
550 step_x[1] = 0;
551
552 step_y[0] = 0;
553 step_y[1] = -1;
554
555 break;
556 case 1:
557 step_x[0] = 0;
558 step_x[1] = 1;
559
560 step_y[0] = -1;
561 step_y[1] = -0;
562 break;
563 case 2:
564 step_x[0] = 1;
565 step_x[1] = 0;
566
567 step_y[0] = 0;
568 step_y[1] = 1;
569 break;
570 case 3:
571 step_x[0] = 0;
572 step_x[1] = -1;
573
574 step_y[0] = 1;
575 step_y[1] = 0;
576 break;
577 default:
578 BLI_assert_msg(0, "Should never happen");
579 break;
580 }
581
582 for (int y = 0; y < orig_grid_size; y++) {
583 for (int x = 0; x < orig_grid_size; x++) {
584 const int remap_x = origin[1] + (step_x[1] * x) + (step_y[1] * y);
585 const int remap_y = origin[0] + (step_x[0] * x) + (step_y[0] * y);
586
587 const int final_index = remap_x + remap_y * face_grid_size;
588 copy_v3_v3(face_grid[final_index], mdisp->disps[x + y * orig_grid_size]);
589 }
590 }
591}
592
598 float (*face_grid)[3],
599 int face_grid_size,
600 int gunsub_x,
601 int gunsub_y)
602{
603 const int grid_it = face_grid_size - 1;
604 for (int y = 0; y < face_grid_size; y++) {
605 for (int x = 0; x < face_grid_size; x++) {
606 const int remap_x = (grid_it * gunsub_x) + x;
607 const int remap_y = (grid_it * gunsub_y) + y;
608
609 const int remap_index_y = grid->grid_size - remap_x - 1;
610 const int remap_index_x = grid->grid_size - remap_y - 1;
611 const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
612 copy_v3_v3(grid->grid_co[grid_index], face_grid[x + y * face_grid_size]);
613 }
614 }
615}
616
625 BMVert *v,
626 BMFace *f,
627 int grid_x,
628 int grid_y)
629{
630 Mesh *original_mesh = context->original_mesh;
631 const blender::OffsetIndices faces = original_mesh->faces();
632 const blender::Span<int> corner_verts = original_mesh->corner_verts();
633 const blender::IndexRange face = faces[BM_elem_index_get(f)];
634
635 const int corner_vertex_index = BM_elem_index_get(v);
636
637 /* Calculates an offset to write the grids correctly oriented in the main
638 * #MultiresUnsubdivideGrid. */
639 int loop_offset = 0;
640 for (int i = 0; i < face.size(); i++) {
641 const int loop_index = face[i];
642 if (corner_verts[loop_index] == corner_vertex_index) {
643 loop_offset = i;
644 break;
645 }
646 }
647
648 /* Write the 4 grids of the current quad with the right orientation into the face_grid buffer. */
649 const int grid_size = BKE_ccg_gridsize(context->num_original_levels);
650 const int face_grid_size = BKE_ccg_gridsize(context->num_original_levels + 1);
651 const int face_grid_area = face_grid_size * face_grid_size;
652 float(*face_grid)[3] = static_cast<float(*)[3]>(
653 MEM_calloc_arrayN(face_grid_area, sizeof(float[3]), "face_grid"));
654
655 for (int i = 0; i < face.size(); i++) {
656 const int loop_index = face[i];
657 MDisps *mdisp = &context->original_mdisp[loop_index];
658 int quad_loop = i - loop_offset;
659 if (quad_loop < 0) {
660 quad_loop += 4;
661 }
662 if (quad_loop >= 4) {
663 quad_loop -= 4;
664 }
665 write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop);
666 }
667
668 /* Write the face_grid buffer in the correct position in the #MultiresUnsubdivideGrids that is
669 * being extracted. */
670 write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y);
671
672 MEM_freeN(face_grid);
673}
674
679static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y)
680{
681 const int remap_index_y = grid->grid_size - 1 - grid_x;
682 const int remap_index_x = grid->grid_size - 1 - grid_y;
683
684 const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
685
686 copy_v3_v3(grid->grid_co[grid_index], v->co);
687}
688
694 BMFace *f1,
695 BMEdge *e1,
696 bool flip_grid,
698{
699 BMVert *initial_vertex;
700 BMEdge *initial_edge_x;
701 BMEdge *initial_edge_y;
702
703 const int grid_size = BKE_ccg_gridsize(context->num_new_levels);
704 const int unsubdiv_grid_size = grid->grid_size = BKE_ccg_gridsize(context->num_total_levels);
705 BLI_assert(grid->grid_co == nullptr);
706 grid->grid_size = unsubdiv_grid_size;
707 grid->grid_co = static_cast<float(*)[3]>(MEM_calloc_arrayN(
708 unsubdiv_grid_size * unsubdiv_grid_size, sizeof(float[3]), "grids coordinates"));
709
710 /* Get the vertex on the corner of the grid. This vertex was tagged previously as it also exist
711 * on the base mesh. */
712 initial_edge_x = e1;
713 if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
714 initial_vertex = initial_edge_x->v1;
715 }
716 else {
717 initial_vertex = initial_edge_x->v2;
718 }
719
720 /* From that vertex, get the edge that defines the grid Y axis for extraction. */
721 initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
722
723 if (flip_grid) {
724 BMEdge *edge_temp;
725 edge_temp = initial_edge_x;
726 initial_edge_x = initial_edge_y;
727 initial_edge_y = edge_temp;
728 }
729
730 int grid_x = 0;
731 int grid_y = 0;
732
733 BMVert *current_vertex_x = initial_vertex;
734 BMEdge *edge_x = initial_edge_x;
735
736 BMVert *current_vertex_y = initial_vertex;
737 BMEdge *edge_y = initial_edge_y;
738 BMEdge *prev_edge_y = initial_edge_y;
739
740 BMFace *current_face = f1;
741 BMFace *grid_face = f1;
742
743 /* If the data is going to be extracted from the already existing grids, there is no need to go
744 * to the last vertex of the iteration as that coordinate is also included in the grids
745 * corresponding to the loop of the face of the previous iteration. */
746 int grid_iteration_max_steps = grid_size;
747 if (context->num_original_levels > 0) {
748 grid_iteration_max_steps = grid_size - 1;
749 }
750
751 /* Iterate over the mesh vertices in a grid pattern using the axis defined by the two initial
752 * edges. */
753 while (grid_y < grid_iteration_max_steps) {
754
755 grid_face = current_face;
756
757 while (grid_x < grid_iteration_max_steps) {
758 if (context->num_original_levels == 0) {
759 /* If there were no grids on the original mesh, extract the data directly from the
760 * vertices. */
761 store_vertex_data(grid, current_vertex_x, grid_x, grid_y);
762 edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
763 }
764 else {
765 /* If there were grids in the original mesh, extract the data from the grids and iterate
766 * over the faces. */
767 store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y);
768 edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
769 grid_face = face_step(edge_x, grid_face);
770 }
771
772 grid_x++;
773 }
774 grid_x = 0;
775
776 edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
777 current_vertex_x = current_vertex_y;
778
779 /* Get the next edge_x to extract the next row of the grid. This needs to be done because there
780 * may be two edges connected to current_vertex_x that belong to two different grids. */
781 BMIter iter;
782 BMEdge *ed;
783 BMFace *f;
784 BM_ITER_ELEM (ed, &iter, current_vertex_x, BM_EDGES_OF_VERT) {
785 if (ed != prev_edge_y && BM_edge_in_face(ed, current_face)) {
786 edge_x = ed;
787 break;
788 }
789 }
790 BM_ITER_ELEM (f, &iter, edge_x, BM_FACES_OF_EDGE) {
791 if (f != current_face) {
792 current_face = f;
793 break;
794 }
795 }
796
797 prev_edge_y = edge_y;
798 grid_y++;
799 }
800}
801
809 BMEdge *e1,
810 BMVert **r_corner_x,
811 BMVert **r_corner_y)
812{
813 BMVert *initial_vertex;
814 BMEdge *initial_edge_x;
815 BMEdge *initial_edge_y;
816
817 initial_edge_x = e1;
818 if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
819 initial_vertex = initial_edge_x->v1;
820 }
821 else {
822 initial_vertex = initial_edge_x->v2;
823 }
824
825 /* From that vertex, get the edge that defines the grid Y axis for extraction. */
826 initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
827
828 BMVert *current_vertex_x = initial_vertex;
829 BMEdge *edge_x = initial_edge_x;
830
831 BMVert *current_vertex_y = initial_vertex;
832 BMEdge *edge_y = initial_edge_y;
833
834 /* Do an edge step until it finds a tagged vertex, which is part of the base mesh. */
835 /* x axis */
836 edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
837 while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) {
838 edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
839 }
840 *r_corner_x = current_vertex_x;
841
842 /* Same for y axis */
843 edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
844 while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) {
845 edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
846 }
847 *r_corner_y = current_vertex_y;
848}
849
851{
852 const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
853
854 BMeshCreateParams bm_create_params{};
855 bm_create_params.use_toolflags = true;
856 BMesh *bm = BM_mesh_create(&allocsize, &bm_create_params);
857
858 BMeshFromMeshParams bm_from_me_params{};
859 bm_from_me_params.calc_face_normal = true;
860 bm_from_me_params.calc_vert_normal = true;
861 BM_mesh_bm_from_me(bm, mesh, &bm_from_me_params);
862
863 return bm;
864}
865
866/* Data-layer names to store the original indices of the elements before modifying the mesh. */
867static const char lname[] = "l_remap_index";
868static const char vname[] = "v_remap_index";
869
871{
872 const int l_layer_index = CustomData_get_named_layer_index(
873 &mesh->corner_data, CD_PROP_INT32, lname);
874 if (l_layer_index != -1) {
875 CustomData_free_layer(&mesh->corner_data, CD_PROP_INT32, mesh->corners_num, l_layer_index);
876 }
877
878 const int v_layer_index = CustomData_get_named_layer_index(
879 &mesh->vert_data, CD_PROP_INT32, vname);
880 if (v_layer_index != -1) {
881 CustomData_free_layer(&mesh->vert_data, CD_PROP_INT32, mesh->verts_num, v_layer_index);
882 }
883}
884
890{
892
893 int *l_index = static_cast<int *>(CustomData_add_layer_named(
894 &mesh->corner_data, CD_PROP_INT32, CD_SET_DEFAULT, mesh->corners_num, lname));
895
896 int *v_index = static_cast<int *>(CustomData_add_layer_named(
897 &mesh->vert_data, CD_PROP_INT32, CD_SET_DEFAULT, mesh->verts_num, vname));
898
899 /* Initialize these data-layer with the indices in the current mesh. */
900 for (int i = 0; i < mesh->corners_num; i++) {
901 l_index[i] = i;
902 }
903 for (int i = 0; i < mesh->verts_num; i++) {
904 v_index[i] = i;
905 }
906}
907
910{
911 Mesh *original_mesh = context->original_mesh;
912
913 Mesh *base_mesh = context->base_mesh;
914
915 BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh);
916
917 /* Initialize the elem tables. */
918 BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE);
919
920 /* Disable all flags. */
921 BM_mesh_elem_hflag_disable_all(bm_original_mesh,
924 false);
925
926 /* Get the mapping data-layer. */
927 context->base_to_orig_vmap = static_cast<const int *>(
929
930 /* Tag the base mesh vertices in the original mesh. */
931 for (int i = 0; i < base_mesh->verts_num; i++) {
932 int vert_basemesh_index = context->base_to_orig_vmap[i];
933 BMVert *v = BM_vert_at_index(bm_original_mesh, vert_basemesh_index);
935 }
936
937 context->loop_to_face_map = original_mesh->corner_to_face_map();
938}
939
945 const blender::Span<int> corner_verts,
946 int face_index,
947 int loop,
948 int v_x)
949{
950 const blender::IndexRange face = faces[face_index];
951
952 const int v_first = corner_verts[face.start()];
953 if ((loop == (face.start() + (face.size() - 1))) && v_first == v_x) {
954 return true;
955 }
956
957 int next_l_index = loop + 1;
958 if (next_l_index < face.start() + face.size()) {
959 const int v_next = corner_verts[next_l_index];
960 if (v_next == v_x) {
961 return true;
962 }
963 }
964
965 return false;
966}
967
969{
970 Mesh *original_mesh = context->original_mesh;
971 Mesh *base_mesh = context->base_mesh;
972
973 BMesh *bm_original_mesh = context->bm_original_mesh;
974
975 context->num_grids = base_mesh->corners_num;
976 context->base_mesh_grids = static_cast<MultiresUnsubdivideGrid *>(
977 MEM_calloc_arrayN(base_mesh->corners_num, sizeof(MultiresUnsubdivideGrid), "grids"));
978
979 /* Based on the existing indices in the data-layers, generate two vertex indices maps. */
980 /* From vertex index in original to vertex index in base and from vertex index in base to vertex
981 * index in original. */
982 int *orig_to_base_vmap = static_cast<int *>(
983 MEM_calloc_arrayN(bm_original_mesh->totvert, sizeof(int), "orig vmap"));
984 int *base_to_orig_vmap = static_cast<int *>(
985 MEM_calloc_arrayN(base_mesh->verts_num, sizeof(int), "base vmap"));
986
987 context->base_to_orig_vmap = static_cast<const int *>(
989 for (int i = 0; i < base_mesh->verts_num; i++) {
990 base_to_orig_vmap[i] = context->base_to_orig_vmap[i];
991 }
992
993 /* If an index in original does not exist in base (it was dissolved when creating the new base
994 * mesh, return -1. */
995 for (int i = 0; i < original_mesh->verts_num; i++) {
996 orig_to_base_vmap[i] = -1;
997 }
998
999 for (int i = 0; i < base_mesh->verts_num; i++) {
1000 const int orig_vertex_index = context->base_to_orig_vmap[i];
1001 orig_to_base_vmap[orig_vertex_index] = i;
1002 }
1003
1004 /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer,
1005 * so they can be used from #BMesh. */
1007
1008 BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh);
1009 BMIter iter, iter_a, iter_b;
1010 BMVert *v;
1011 BMLoop *l, *lb;
1012
1013 BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT | BM_FACE);
1014
1015 /* Get the data-layer that contains the loops indices. */
1016 const int base_l_offset = CustomData_get_offset_named(
1017 &bm_base_mesh->ldata, CD_PROP_INT32, lname);
1018
1019 const blender::OffsetIndices faces = base_mesh->faces();
1020 const blender::Span<int> corner_verts = base_mesh->corner_verts();
1021
1022 /* Main loop for extracting the grids. Iterates over the base mesh vertices. */
1023 BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) {
1024
1025 /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the
1026 * vertex map. */
1027 const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)];
1028 BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index);
1029
1030 /* Iterate over the loops of that vertex in the original mesh. */
1031 BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) {
1032 /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the
1033 * base mesh of the face of grid that is going to be extracted. */
1034 BMVert *corner_x, *corner_y;
1035 multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y);
1036
1037 /* Map the two obtained vertices to the base mesh. */
1038 const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)];
1039 const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)];
1040 if (corner_x_index < 0 || corner_y_index < 0) {
1041 continue;
1042 }
1043
1044 /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained
1045 * vertices and the current vertex it is possible to get the index of the loop in the base
1046 * mesh the grid that is going to be extracted belongs to. */
1047 BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) {
1048 BMFace *base_face = lb->f;
1049 BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index);
1050 BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index);
1051 /* If this is the correct loop in the base mesh, the original vertex and the two corners
1052 * should be in the loop's face. */
1053 if (BM_vert_in_face(base_corner_x, base_face) && BM_vert_in_face(base_corner_y, base_face))
1054 {
1055 /* Get the index of the loop. */
1056 const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset);
1057 const int base_mesh_face_index = BM_elem_index_get(base_face);
1058
1059 /* Check the orientation of the loops in case that is needed to flip the x and y axis
1060 * when extracting the grid. */
1061 const bool flip_grid = multires_unsubdivide_flip_grid_x_axis(
1062 faces, corner_verts, base_mesh_face_index, base_mesh_loop_index, corner_x_index);
1063
1064 /* Extract the grid for that loop. */
1065 MultiresUnsubdivideGrid *grid = &context->base_mesh_grids[base_mesh_loop_index];
1066 if (UNLIKELY(grid->grid_co != nullptr)) {
1067 /* It's possible this grid has already been initialized which occurs when quads
1068 * share two edge, while not so common it happens with "Suzanne's" nose,
1069 * see: #126633 & run un-subdivide.
1070 *
1071 * Continue here instead of breaking as logically: quads sharing 2 edges
1072 * will share 3 vertices and those 3 vertices may be attached to any number of quads.
1073 * So in this case, continue scanning instead of breaking out of the loop
1074 * because the `lb` to extract a grid from has not yet been encountered. */
1075 continue;
1076 }
1077
1078 grid->grid_index = base_mesh_loop_index;
1080 context, l->f, l->e, !flip_grid, grid);
1081
1082 break;
1083 }
1084 }
1085 }
1086 }
1087
1088 MEM_freeN(orig_to_base_vmap);
1089 MEM_freeN(base_to_orig_vmap);
1090
1091 BM_mesh_free(bm_base_mesh);
1093}
1094
1096{
1097 if (context->bm_original_mesh != nullptr) {
1098 BM_mesh_free(context->bm_original_mesh);
1099 }
1100}
1101
1103 Mesh *original_mesh,
1105{
1106 context->original_mesh = original_mesh;
1107 context->num_new_levels = 0;
1108 context->num_total_levels = 0;
1109 context->num_original_levels = mmd->totlvl;
1110}
1111
1113{
1114 Mesh *original_mesh = context->original_mesh;
1115
1116 /* Prepare the data-layers to map base to original. */
1118 BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh);
1119
1120 /* Un-subdivide as many iterations as possible. */
1121 context->num_new_levels = 0;
1122 int num_levels_left = context->max_new_levels;
1123 while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) {
1124 context->num_new_levels++;
1125 num_levels_left--;
1126 }
1127
1128 /* If no un-subdivide steps were possible, free the bmesh, the map data-layers and stop. */
1129 if (context->num_new_levels == 0) {
1131 BM_mesh_free(bm_base_mesh);
1132 return false;
1133 }
1134
1135 /* Calculate the final levels for the new grids over base mesh. */
1136 context->num_total_levels = context->num_new_levels + context->num_original_levels;
1137
1138 /* Store the new base-mesh as a mesh in context, free bmesh.
1139 * NOTE(@ideasman42): passing the original mesh in the template is important so mesh settings &
1140 * vertex groups are kept, see: #93911. */
1141 context->base_mesh = BKE_mesh_new_nomain_from_template(original_mesh, 0, 0, 0, 0);
1142
1143 /* De-select all.
1144 * The user-selection has been overwritten and this selection has not been flushed. */
1146
1147 BMeshToMeshParams bm_to_me_params{};
1148 bm_to_me_params.calc_object_remap = true;
1149 BM_mesh_bm_to_me(nullptr, bm_base_mesh, context->base_mesh, &bm_to_me_params);
1150 BM_mesh_free(bm_base_mesh);
1151
1152 /* Initialize bmesh and maps for the original mesh and extract the grids. */
1153
1156
1157 return true;
1158}
1159
1161{
1163 for (int i = 0; i < context->num_grids; i++) {
1164 if (context->base_mesh_grids[i].grid_size > 0) {
1165 MEM_SAFE_FREE(context->base_mesh_grids[i].grid_co);
1166 }
1167 }
1168 MEM_SAFE_FREE(context->base_mesh_grids);
1169}
1170
1176 Mesh *base_mesh)
1177{
1178 /* Free the current MDISPS and create a new ones. */
1179 if (CustomData_has_layer(&base_mesh->corner_data, CD_MDISPS)) {
1180 CustomData_free_layers(&base_mesh->corner_data, CD_MDISPS, base_mesh->corners_num);
1181 }
1182 MDisps *mdisps = static_cast<MDisps *>(CustomData_add_layer(
1183 &base_mesh->corner_data, CD_MDISPS, CD_SET_DEFAULT, base_mesh->corners_num));
1184
1185 const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2);
1186 const int totloop = base_mesh->corners_num;
1187
1188 BLI_assert(base_mesh->corners_num == context->num_grids);
1189
1190 /* Allocate the MDISPS grids and copy the extracted data from context. */
1191 for (int i = 0; i < totloop; i++) {
1192 float(*disps)[3] = static_cast<float(*)[3]>(
1193 MEM_calloc_arrayN(totdisp, sizeof(float[3]), __func__));
1194
1195 if (mdisps[i].disps) {
1196 MEM_freeN(mdisps[i].disps);
1197 }
1198
1199 for (int j = 0; j < totdisp; j++) {
1200 if (context->base_mesh_grids[i].grid_co) {
1201 copy_v3_v3(disps[j], context->base_mesh_grids[i].grid_co[j]);
1202 }
1203 }
1204
1205 mdisps[i].disps = disps;
1206 mdisps[i].totdisp = totdisp;
1207 mdisps[i].level = context->num_total_levels;
1208 }
1209}
1210
1212 Object *object,
1214 int rebuild_limit,
1215 bool switch_view_to_lower_level)
1216{
1217 Mesh *mesh = static_cast<Mesh *>(object->data);
1218
1220
1221 MultiresUnsubdivideContext unsubdiv_context{};
1222 MultiresReshapeContext reshape_context{};
1223
1224 multires_unsubdivide_context_init(&unsubdiv_context, mesh, mmd);
1225
1226 /* Convert and store the existing grids in object space if available. */
1227 if (mmd->totlvl != 0) {
1228 if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) {
1229 return 0;
1230 }
1231
1232 multires_reshape_store_original_grids(&reshape_context);
1234 unsubdiv_context.original_mdisp = reshape_context.mdisps;
1235 }
1236
1237 /* Set the limit for the levels that should be rebuild. */
1238 unsubdiv_context.max_new_levels = rebuild_limit;
1239
1240 /* Un-subdivide and create the data for the new grids. */
1241 if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) {
1242 /* If there was no possible to rebuild any level, free the data and return. */
1243 if (mmd->totlvl != 0) {
1245 multires_unsubdivide_context_free(&unsubdiv_context);
1246 }
1247 multires_reshape_context_free(&reshape_context);
1248 return 0;
1249 }
1250
1251 /* Free the reshape context used to convert the data from the original grids to object space. */
1252 if (mmd->totlvl != 0) {
1253 multires_reshape_context_free(&reshape_context);
1254 }
1255
1256 /* Copy the new base mesh to the original mesh. */
1257 Mesh *base_mesh = static_cast<Mesh *>(object->data);
1258 BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, base_mesh, object);
1259 multires_create_grids_in_unsubdivided_base_mesh(&unsubdiv_context, base_mesh);
1260
1261 /* Update the levels in the modifier. Force always to display at level 0 as it contains the new
1262 * created level. */
1263 mmd->totlvl = char(unsubdiv_context.num_total_levels);
1264
1265 if (switch_view_to_lower_level) {
1266 mmd->sculptlvl = 0;
1267 mmd->lvl = 0;
1268 }
1269 else {
1270 mmd->sculptlvl = char(mmd->sculptlvl + unsubdiv_context.num_new_levels);
1271 mmd->lvl = char(mmd->lvl + unsubdiv_context.num_new_levels);
1272 }
1273
1274 mmd->renderlvl = char(mmd->renderlvl + unsubdiv_context.num_new_levels);
1275
1276 /* Create a reshape context to convert the MDISPS data to tangent displacement. It can be the
1277 * same as the previous one as a new Subdivision needs to be created for the new base mesh. */
1278 if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) {
1279 return 0;
1280 }
1282 multires_reshape_context_free(&reshape_context);
1283
1284 /* Free the un-subdivide context and return the total number of levels that were rebuild. */
1285 const int rebuild_subdvis = unsubdiv_context.num_new_levels;
1286 multires_unsubdivide_context_free(&unsubdiv_context);
1287
1288 return rebuild_subdvis;
1289}
CustomData interface, see also DNA_customdata_types.h.
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
int CustomData_get_named_layer_index(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool CustomData_free_layer(CustomData *data, eCustomDataType type, int totelem, int index)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_free_layers(CustomData *data, eCustomDataType type, int totelem)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
void multires_force_sculpt_rebuild(Object *object)
Definition multires.cc:451
int BKE_ccg_gridsize(int level)
Definition CCGSubSurf.cc:25
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
void BLI_gsqueue_free(GSQueue *queue)
Definition gsqueue.c:93
void BLI_gsqueue_push(GSQueue *queue, const void *item)
Definition gsqueue.c:100
void BLI_gsqueue_pop(GSQueue *queue, void *r_item)
Definition gsqueue.c:134
GSQueue * BLI_gsqueue_new(size_t elem_size)
Definition gsqueue.c:72
bool BLI_gsqueue_is_empty(const GSQueue *queue)
Definition gsqueue.c:162
int pow_i(int base, int exp)
Definition math_base.c:13
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNLIKELY(x)
@ CD_PROP_INT32
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define BM_ELEM_CD_GET_INT(ele, offset)
@ BM_ELEM_HIDDEN
@ BM_ELEM_SELECT
@ BM_ELEM_TAG
#define BM_elem_index_get(ele)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_flag_test(ele, hflag)
#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.
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
#define BMALLOC_TEMPLATE_FROM_ME(...)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_FLAG_DEFAULTS
@ BMO_FLAG_RESPECT_HIDE
bool BM_vert_is_wire(const BMVert *v)
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
bool BM_vert_in_face(BMVert *v, BMFace *f)
bool BM_vert_is_boundary(const BMVert *v)
#define BM_vert_edge_count_is_equal(v, n)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_vert_edge_count_is_over(v, n)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
const Depsgraph * depsgraph
draw_view in_light_buf[] float
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void multires_reshape_assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context)
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context, Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd)
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context)
void multires_reshape_object_grids_to_tangent_displacement(const MultiresReshapeContext *reshape_context)
bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context, Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd)
static BMFace * face_step(BMEdge *edge, BMFace *f)
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 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 BMEdge * edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
static void multires_unsubdivide_private_extract_data_free(MultiresUnsubdivideContext *context)
static BMVert * unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
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 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)
void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context, Mesh *original_mesh, MultiresModifierData *mmd)
static bool multires_unsubdivide_flip_grid_x_axis(const blender::OffsetIndices< int > faces, const blender::Span< int > corner_verts, int face_index, int loop, int v_x)
static void multires_unsubdivide_get_grid_corners_on_base_mesh(BMFace *f1, BMEdge *e1, BMVert **r_corner_x, BMVert **r_corner_y)
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)
static BMEdge * get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
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[]
int multiresModifier_rebuild_subdiv(Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd, int rebuild_limit, bool switch_view_to_lower_level)
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 BMesh * get_bmesh_from_mesh(Mesh *mesh)
BMVert * v1
BMVert * v2
struct BMEdge * e
struct BMFace * f
float co[3]
struct BMEdge * e
int totvert
CustomData ldata
int totface
float(* disps)[3]
int corners_num
CustomData corner_data
CustomData vert_data
int verts_num