Blender  V3.3
multires_reshape_smooth.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. All rights reserved. */
3 
8 #include "multires_reshape.h"
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "DNA_mesh_types.h"
13 #include "DNA_meshdata_types.h"
14 #include "DNA_modifier_types.h"
15 
16 #include "BLI_bitmap.h"
17 #include "BLI_math_vector.h"
18 #include "BLI_task.h"
19 #include "BLI_utildefines.h"
20 
21 #include "BKE_customdata.h"
22 #include "BKE_multires.h"
23 #include "BKE_subdiv.h"
24 #include "BKE_subdiv_eval.h"
25 #include "BKE_subdiv_foreach.h"
26 #include "BKE_subdiv_mesh.h"
27 
31 
32 #include "atomic_ops.h"
33 #include "subdiv_converter.h"
34 
35 /* -------------------------------------------------------------------- */
39 /* Surface refers to a simplified and lower-memory footprint representation of the limit surface.
40  *
41  * Used to store pre-calculated information which is expensive or impossible to evaluate when
42  * traversing the final limit surface. */
43 
44 typedef struct SurfacePoint {
45  float P[3];
46  float tangent_matrix[3][3];
48 
49 typedef struct SurfaceGrid {
52 
53 /* Geometry elements which are used to simplify creation of topology refiner at the sculpt level.
54  * Contains a limited subset of information needed to construct topology refiner. */
55 
56 typedef struct Vertex {
57  /* All grid coordinates which the vertex corresponding to.
58  * For a vertices which are created from inner points of grids there is always one coordinate. */
61 
62  float sharpness;
65 
66 typedef struct Corner {
67  const Vertex *vertex;
70 
71 typedef struct Face {
74 } Face;
75 
76 typedef struct Edge {
77  int v1;
78  int v2;
79 
80  float sharpness;
81 } Edge;
82 
83 /* Storage of data which is linearly interpolated from the reshape level to the top level. */
84 
85 typedef struct LinearGridElement {
86  float mask;
88 
89 typedef struct LinearGrid {
92 
93 typedef struct LinearGrids {
94  int num_grids;
95  int level;
96 
97  /* Cached size for the grid, for faster lookup. */
98  int grid_size;
99 
100  /* Indexed by grid index. */
102 
103  /* Elements for all grids are allocated in a single array, for the allocation performance. */
106 
107 /* Context which holds all information eeded during propagation and smoothing. */
108 
111 
112  /* Geometry at a reshape multires level. */
113  struct {
116 
117  /* Maximum number of edges which might be stored in the edges array.
118  * Is calculated based on the number of edges in the base mesh and the subdivision level. */
120 
121  /* Sparse storage of edges. Will only include edges which have non-zero sharpness.
122  *
123  * NOTE: Different type from others to be able to easier use atomic ops. */
124  size_t num_edges;
126 
129 
133 
134  /* Grids of data which is linearly interpolated between grid elements at the reshape level.
135  * The data is actually stored as a delta, which is then to be added to the higher levels. */
137 
138  /* Index i of this map indicates that base edge i is adjacent to at least one face. */
140 
141  /* Subdivision surface created for geometry at a reshape level. */
143 
144  /* Limit surface of the base mesh with original sculpt level details on it, subdivided up to the
145  * top level.
146  * Is used as a base point to calculate how much displacement has been made in the sculpt mode.
147  *
148  * NOTE: Referring to sculpt as it is the main user of this functionality and it is clear to
149  * understand what it actually means in a concrete example. This is a generic code which is also
150  * used by Subdivide operation, but the idea is exactly the same as propagation in the sculpt
151  * mode. */
153 
154  /* Defines how displacement is interpolated on the higher levels (for example, whether
155  * displacement is smoothed in Catmull-Clark mode or interpolated linearly preserving sharp edges
156  * of the current sculpt level).
157  *
158  * NOTE: Uses same enumerator type as Subdivide operator, since the values are the same and
159  * decoupling type just adds extra headache to convert one enumerator to another. */
162 
165 /* -------------------------------------------------------------------- */
169 static void linear_grids_init(LinearGrids *linear_grids)
170 {
171  linear_grids->num_grids = 0;
172  linear_grids->level = 0;
173 
174  linear_grids->grids = NULL;
175  linear_grids->elements_storage = NULL;
176 }
177 
178 static void linear_grids_allocate(LinearGrids *linear_grids, int num_grids, int level)
179 {
180  const size_t grid_size = BKE_subdiv_grid_size_from_level(level);
181  const size_t grid_area = grid_size * grid_size;
182  const size_t num_grid_elements = num_grids * grid_area;
183 
184  linear_grids->num_grids = num_grids;
185  linear_grids->level = level;
186  linear_grids->grid_size = grid_size;
187 
188  linear_grids->grids = MEM_malloc_arrayN(num_grids, sizeof(LinearGrid), "linear grids");
189  linear_grids->elements_storage = MEM_calloc_arrayN(
190  num_grid_elements, sizeof(LinearGridElement), "linear elements storage");
191 
192  for (int i = 0; i < num_grids; ++i) {
193  const size_t element_offset = grid_area * i;
194  linear_grids->grids[i].elements = &linear_grids->elements_storage[element_offset];
195  }
196 }
197 
199  const GridCoord *grid_coord)
200 {
201  BLI_assert(grid_coord->grid_index >= 0);
202  BLI_assert(grid_coord->grid_index < linear_grids->num_grids);
203 
204  const int grid_size = linear_grids->grid_size;
205 
206  const int grid_x = lround(grid_coord->u * (grid_size - 1));
207  const int grid_y = lround(grid_coord->v * (grid_size - 1));
208  const int grid_element_index = grid_y * grid_size + grid_x;
209 
210  LinearGrid *grid = &linear_grids->grids[grid_coord->grid_index];
211  return &grid->elements[grid_element_index];
212 }
213 
214 static void linear_grids_free(LinearGrids *linear_grids)
215 {
216  MEM_SAFE_FREE(linear_grids->grids);
217  MEM_SAFE_FREE(linear_grids->elements_storage);
218 }
219 
220 static void linear_grid_element_init(LinearGridElement *linear_grid_element)
221 {
222  linear_grid_element->mask = 0.0f;
223 }
224 
225 /* result = a - b. */
227  const LinearGridElement *a,
228  const LinearGridElement *b)
229 {
230  result->mask = a->mask - b->mask;
231 }
232 
234  const LinearGridElement elements[4],
235  const float weights[4])
236 {
237  result->mask = elements[0].mask * weights[0] + elements[1].mask * weights[1] +
238  elements[2].mask * weights[2] + elements[3].mask * weights[3];
239 }
240 
243 /* -------------------------------------------------------------------- */
247 static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context)
248 {
249  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
250 
251  const int num_grids = reshape_context->num_grids;
252  const int grid_size = reshape_context->top.grid_size;
253  const int grid_area = grid_size * grid_size;
254 
255  SurfaceGrid *surface_grid = MEM_malloc_arrayN(num_grids, sizeof(SurfaceGrid), "delta grids");
256 
257  for (int grid_index = 0; grid_index < num_grids; ++grid_index) {
258  surface_grid[grid_index].points = MEM_calloc_arrayN(
259  grid_area, sizeof(SurfacePoint), "delta grid displacement");
260  }
261 
262  reshape_smooth_context->base_surface_grids = surface_grid;
263 }
264 
265 static void base_surface_grids_free(MultiresReshapeSmoothContext *reshape_smooth_context)
266 {
267  if (reshape_smooth_context->base_surface_grids == NULL) {
268  return;
269  }
270 
271  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
272 
273  const int num_grids = reshape_context->num_grids;
274  for (int grid_index = 0; grid_index < num_grids; ++grid_index) {
275  MEM_freeN(reshape_smooth_context->base_surface_grids[grid_index].points);
276  }
277  MEM_freeN(reshape_smooth_context->base_surface_grids);
278 }
279 
281  const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
282 {
283  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
284 
285  const int grid_index = grid_coord->grid_index;
286  const int grid_size = reshape_context->top.grid_size;
287  const int grid_x = lround(grid_coord->u * (grid_size - 1));
288  const int grid_y = lround(grid_coord->v * (grid_size - 1));
289  const int grid_element_index = grid_y * grid_size + grid_x;
290 
291  SurfaceGrid *surface_grid = &reshape_smooth_context->base_surface_grids[grid_index];
292  return &surface_grid->points[grid_element_index];
293 }
294 
295 static void base_surface_grids_write(const MultiresReshapeSmoothContext *reshape_smooth_context,
296  const GridCoord *grid_coord,
297  float P[3],
298  float tangent_matrix[3][3])
299 {
300  SurfacePoint *point = base_surface_grids_read(reshape_smooth_context, grid_coord);
301  copy_v3_v3(point->P, P);
302  copy_m3_m3(point->tangent_matrix, tangent_matrix);
303 }
304 
307 /* -------------------------------------------------------------------- */
312  const MultiresReshapeSmoothContext *reshape_smooth_context,
313  const PTexCoord *ptex_coord,
314  const GridCoord *grid_coord,
315  void *userdata_v);
316 
319 
322 
326 
327 /* Find grid index which given face was created for. */
328 static int get_face_grid_index(const MultiresReshapeSmoothContext *reshape_smooth_context,
329  const Face *face)
330 {
331  const Corner *first_corner = &reshape_smooth_context->geometry.corners[face->start_corner_index];
332  const int grid_index = first_corner->grid_index;
333 
334 #ifndef NDEBUG
335  for (int face_corner = 0; face_corner < face->num_corners; ++face_corner) {
336  const int corner_index = face->start_corner_index + face_corner;
337  const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index];
338  BLI_assert(corner->grid_index == grid_index);
339  }
340 #endif
341 
342  return grid_index;
343 }
344 
345 static GridCoord *vertex_grid_coord_with_grid_index(const Vertex *vertex, const int grid_index)
346 {
347  for (int i = 0; i < vertex->num_grid_coords; ++i) {
348  if (vertex->grid_coords[i].grid_index == grid_index) {
349  return &vertex->grid_coords[i];
350  }
351  }
352  return NULL;
353 }
354 
355 /* Get grid coordinates which correspond to corners of the given face.
356  * All the grid coordinates will be from the same grid index. */
358  const MultiresReshapeSmoothContext *reshape_smooth_context,
359  const Face *face,
360  const GridCoord *grid_coords[])
361 {
362  BLI_assert(face->num_corners == 4);
363 
364  const int grid_index = get_face_grid_index(reshape_smooth_context, face);
365  BLI_assert(grid_index != -1);
366 
367  for (int i = 0; i < face->num_corners; ++i) {
368  const int corner_index = face->start_corner_index + i;
369  const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index];
370  grid_coords[i] = vertex_grid_coord_with_grid_index(corner->vertex, grid_index);
371  BLI_assert(grid_coords[i] != NULL);
372  }
373 }
374 
375 static float lerp(float t, float a, float b)
376 {
377  return (a + t * (b - a));
378 }
379 
381  const GridCoord *face_grid_coords[4],
382  const float u,
383  const float v)
384 {
385  /*
386  * v
387  * ^
388  * | (3) -------- (2)
389  * | | |
390  * | | |
391  * | | |
392  * | | |
393  * | (0) -------- (1)
394  * *--------------------------> u
395  */
396 
397  const float u01 = lerp(u, face_grid_coords[0]->u, face_grid_coords[1]->u);
398  const float u32 = lerp(u, face_grid_coords[3]->u, face_grid_coords[2]->u);
399 
400  const float v03 = lerp(v, face_grid_coords[0]->v, face_grid_coords[3]->v);
401  const float v12 = lerp(v, face_grid_coords[1]->v, face_grid_coords[2]->v);
402 
403  result->grid_index = face_grid_coords[0]->grid_index;
404  result->u = lerp(v, u01, u32);
405  result->v = lerp(u, v03, v12);
406 }
407 
408 static void foreach_toplevel_grid_coord_task(void *__restrict userdata_v,
409  const int face_index,
410  const TaskParallelTLS *__restrict UNUSED(tls))
411 {
412  ForeachHighLevelCoordTaskData *data = userdata_v;
413 
414  const MultiresReshapeSmoothContext *reshape_smooth_context = data->reshape_smooth_context;
415  const int inner_grid_size = data->inner_grid_size;
416  const float inner_grid_size_1_inv = data->inner_grid_size_1_inv;
417 
418  const Face *face = &reshape_smooth_context->geometry.faces[face_index];
419  const GridCoord *face_grid_coords[4];
420  grid_coords_from_face_vertices(reshape_smooth_context, face, face_grid_coords);
421 
422  for (int y = 0; y < inner_grid_size; ++y) {
423  const float ptex_v = (float)y * inner_grid_size_1_inv;
424  for (int x = 0; x < inner_grid_size; ++x) {
425  const float ptex_u = (float)x * inner_grid_size_1_inv;
426 
427  PTexCoord ptex_coord;
428  ptex_coord.ptex_face_index = face_index;
429  ptex_coord.u = ptex_u;
430  ptex_coord.v = ptex_v;
431 
432  GridCoord grid_coord;
433  interpolate_grid_coord(&grid_coord, face_grid_coords, ptex_u, ptex_v);
434 
435  data->callback(reshape_smooth_context, &ptex_coord, &grid_coord, data->callback_userdata_v);
436  }
437  }
438 }
439 
440 static void foreach_toplevel_grid_coord(const MultiresReshapeSmoothContext *reshape_smooth_context,
442  void *callback_userdata_v)
443 {
444  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
445  const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
446 
448  data.reshape_smooth_context = reshape_smooth_context;
449  data.inner_grid_size = (1 << level_difference) + 1;
450  data.inner_grid_size_1_inv = 1.0f / (float)(data.inner_grid_size - 1);
451  data.callback = callback;
452  data.callback_userdata_v = callback_userdata_v;
453 
454  TaskParallelSettings parallel_range_settings;
455  BLI_parallel_range_settings_defaults(&parallel_range_settings);
456  parallel_range_settings.min_iter_per_thread = 1;
457 
458  const int num_faces = reshape_smooth_context->geometry.num_faces;
460  0, num_faces, &data, foreach_toplevel_grid_coord_task, &parallel_range_settings);
461 }
462 
465 /* -------------------------------------------------------------------- */
472 static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_context)
473 {
474  return (1 << reshape_context->reshape.level) + 1;
475 }
476 
477 static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smooth_context)
478 {
479  return !ELEM(reshape_smooth_context->smoothing_type,
482 }
483 
484 /* Get crease which will be used for communication to OpenSubdiv topology.
485  * Note that simple subdivision treats all base edges as infinitely sharp. */
486 static char get_effective_crease_char(const MultiresReshapeSmoothContext *reshape_smooth_context,
487  const MEdge *base_edge)
488 {
489  if (!is_crease_supported(reshape_smooth_context)) {
490  return 255;
491  }
492  return base_edge->crease;
493 }
494 
495 static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context,
496  const float crease)
497 {
498  if (!is_crease_supported(reshape_smooth_context)) {
499  return 1.0f;
500  }
501  return crease;
502 }
503 
504 static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
505  const MultiresReshapeContext *reshape_context,
506  const eMultiresSubdivideModeType mode)
507 {
508  reshape_smooth_context->reshape_context = reshape_context;
509 
510  reshape_smooth_context->geometry.num_vertices = 0;
511  reshape_smooth_context->geometry.vertices = NULL;
512 
513  reshape_smooth_context->geometry.max_edges = 0;
514  reshape_smooth_context->geometry.num_edges = 0;
515  reshape_smooth_context->geometry.edges = NULL;
516 
517  reshape_smooth_context->geometry.num_corners = 0;
518  reshape_smooth_context->geometry.corners = NULL;
519 
520  reshape_smooth_context->geometry.num_faces = 0;
521  reshape_smooth_context->geometry.faces = NULL;
522 
523  linear_grids_init(&reshape_smooth_context->linear_delta_grids);
524 
525  reshape_smooth_context->non_loose_base_edge_map = NULL;
526  reshape_smooth_context->reshape_subdiv = NULL;
527  reshape_smooth_context->base_surface_grids = NULL;
528 
529  reshape_smooth_context->smoothing_type = mode;
530 }
531 
532 static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context)
533 {
534  if (reshape_smooth_context->geometry.vertices != NULL) {
535  for (int i = 0; i < reshape_smooth_context->geometry.num_vertices; ++i) {
536  MEM_SAFE_FREE(reshape_smooth_context->geometry.vertices[i].grid_coords);
537  }
538  }
539  MEM_SAFE_FREE(reshape_smooth_context->geometry.vertices);
540  MEM_SAFE_FREE(reshape_smooth_context->geometry.corners);
541  MEM_SAFE_FREE(reshape_smooth_context->geometry.faces);
542  MEM_SAFE_FREE(reshape_smooth_context->geometry.edges);
543 
544  linear_grids_free(&reshape_smooth_context->linear_delta_grids);
545 }
546 
547 static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_context)
548 {
549  if (reshape_smooth_context->reshape_subdiv == NULL) {
550  return;
551  }
552  BKE_subdiv_free(reshape_smooth_context->reshape_subdiv);
553 }
554 
555 static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context)
556 {
557  MEM_freeN(reshape_smooth_context->non_loose_base_edge_map);
558 
559  context_free_geometry(reshape_smooth_context);
560  context_free_subdiv(reshape_smooth_context);
561  base_surface_grids_free(reshape_smooth_context);
562 }
563 
564 static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
565  const int num_vertices,
566  const int num_edges,
567  const int num_loops,
568  const int num_polygons,
569  const int *UNUSED(subdiv_polygon_offset))
570 {
571  MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
572  const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ?
573  num_edges :
574  reshape_smooth_context->geometry.max_edges;
575 
576  /* NOTE: Calloc so the counters are re-set to 0 "for free". */
577  reshape_smooth_context->geometry.num_vertices = num_vertices;
578  reshape_smooth_context->geometry.vertices = MEM_calloc_arrayN(
579  num_vertices, sizeof(Vertex), "smooth vertices");
580 
581  reshape_smooth_context->geometry.max_edges = max_edges;
582  reshape_smooth_context->geometry.edges = MEM_malloc_arrayN(
583  max_edges, sizeof(Edge), "smooth edges");
584 
585  reshape_smooth_context->geometry.num_corners = num_loops;
586  reshape_smooth_context->geometry.corners = MEM_malloc_arrayN(
587  num_loops, sizeof(Corner), "smooth corners");
588 
589  reshape_smooth_context->geometry.num_faces = num_polygons;
590  reshape_smooth_context->geometry.faces = MEM_malloc_arrayN(
591  num_polygons, sizeof(Face), "smooth faces");
592 
593  return true;
594 }
595 
596 static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
597  const GridCoord *grid_coord,
598  const int coarse_vertex_index,
599  const int subdiv_vertex_index)
600 {
601  const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
602 
603  BLI_assert(subdiv_vertex_index < reshape_smooth_context->geometry.num_vertices);
604 
605  Vertex *vertex = &reshape_smooth_context->geometry.vertices[subdiv_vertex_index];
606 
607  vertex->grid_coords = MEM_reallocN(vertex->grid_coords,
608  sizeof(Vertex) * (vertex->num_grid_coords + 1));
609  vertex->grid_coords[vertex->num_grid_coords] = *grid_coord;
610  ++vertex->num_grid_coords;
611 
612  if (coarse_vertex_index == -1) {
613  return;
614  }
615 
616  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
617  const float *cd_vertex_crease = reshape_context->cd_vertex_crease;
618 
619  if (cd_vertex_crease == NULL) {
620  return;
621  }
622 
623  float crease = cd_vertex_crease[coarse_vertex_index];
624 
625  if (crease == 0.0f) {
626  return;
627  }
628 
629  crease = get_effective_crease_float(reshape_smooth_context, crease);
631 }
632 
633 /* TODO(sergey): De-duplicate with similar function in multires_reshape_vertcos.c */
634 static void foreach_vertex(const SubdivForeachContext *foreach_context,
635  const PTexCoord *ptex_coord,
636  const int coarse_vertex_index,
637  const int subdiv_vertex_index)
638 {
639  const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
640  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
641 
642  const GridCoord grid_coord = multires_reshape_ptex_coord_to_grid(reshape_context, ptex_coord);
643  const int face_index = multires_reshape_grid_to_face_index(reshape_context,
644  grid_coord.grid_index);
645 
646  const Mesh *base_mesh = reshape_context->base_mesh;
647  const MPoly *base_poly = &base_mesh->mpoly[face_index];
648  const int num_corners = base_poly->totloop;
649  const int start_grid_index = reshape_context->face_start_grid_index[face_index];
650  const int corner = grid_coord.grid_index - start_grid_index;
651 
652  if (grid_coord.u == 0.0f && grid_coord.v == 0.0f) {
653  for (int current_corner = 0; current_corner < num_corners; ++current_corner) {
654  GridCoord corner_grid_coord = grid_coord;
655  corner_grid_coord.grid_index = start_grid_index + current_corner;
657  foreach_context, &corner_grid_coord, coarse_vertex_index, subdiv_vertex_index);
658  }
659  return;
660  }
661 
662  foreach_single_vertex(foreach_context, &grid_coord, coarse_vertex_index, subdiv_vertex_index);
663 
664  if (grid_coord.u == 0.0f) {
665  GridCoord prev_grid_coord;
666  prev_grid_coord.grid_index = start_grid_index + ((corner + num_corners - 1) % num_corners);
667  prev_grid_coord.u = grid_coord.v;
668  prev_grid_coord.v = 0.0f;
669 
671  foreach_context, &prev_grid_coord, coarse_vertex_index, subdiv_vertex_index);
672  }
673 
674  if (grid_coord.v == 0.0f) {
675  GridCoord next_grid_coord;
676  next_grid_coord.grid_index = start_grid_index + ((corner + 1) % num_corners);
677  next_grid_coord.u = 0.0f;
678  next_grid_coord.v = grid_coord.u;
679 
681  foreach_context, &next_grid_coord, coarse_vertex_index, subdiv_vertex_index);
682  }
683 }
684 
685 static void foreach_vertex_inner(const struct SubdivForeachContext *foreach_context,
686  void *UNUSED(tls),
687  const int ptex_face_index,
688  const float ptex_face_u,
689  const float ptex_face_v,
690  const int UNUSED(coarse_poly_index),
691  const int UNUSED(coarse_corner),
692  const int subdiv_vertex_index)
693 {
694  const PTexCoord ptex_coord = {
695  .ptex_face_index = ptex_face_index,
696  .u = ptex_face_u,
697  .v = ptex_face_v,
698  };
699  foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
700 }
701 
702 static void foreach_vertex_every_corner(const struct SubdivForeachContext *foreach_context,
703  void *UNUSED(tls_v),
704  const int ptex_face_index,
705  const float ptex_face_u,
706  const float ptex_face_v,
707  const int coarse_vertex_index,
708  const int UNUSED(coarse_face_index),
709  const int UNUSED(coarse_face_corner),
710  const int subdiv_vertex_index)
711 {
712  const PTexCoord ptex_coord = {
713  .ptex_face_index = ptex_face_index,
714  .u = ptex_face_u,
715  .v = ptex_face_v,
716  };
717  foreach_vertex(foreach_context, &ptex_coord, coarse_vertex_index, subdiv_vertex_index);
718 }
719 
720 static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach_context,
721  void *UNUSED(tls_v),
722  const int ptex_face_index,
723  const float ptex_face_u,
724  const float ptex_face_v,
725  const int UNUSED(coarse_edge_index),
726  const int UNUSED(coarse_face_index),
727  const int UNUSED(coarse_face_corner),
728  const int subdiv_vertex_index)
729 {
730  const PTexCoord ptex_coord = {
731  .ptex_face_index = ptex_face_index,
732  .u = ptex_face_u,
733  .v = ptex_face_v,
734  };
735  foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
736 }
737 
738 static void foreach_loop(const struct SubdivForeachContext *foreach_context,
739  void *UNUSED(tls),
740  const int UNUSED(ptex_face_index),
741  const float UNUSED(ptex_face_u),
742  const float UNUSED(ptex_face_v),
743  const int UNUSED(coarse_loop_index),
744  const int coarse_poly_index,
745  const int coarse_corner,
746  const int subdiv_loop_index,
747  const int subdiv_vertex_index,
748  const int UNUSED(subdiv_edge_index))
749 {
750  MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
751  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
752 
753  BLI_assert(subdiv_loop_index < reshape_smooth_context->geometry.num_corners);
754 
755  Corner *corner = &reshape_smooth_context->geometry.corners[subdiv_loop_index];
756  corner->vertex = &reshape_smooth_context->geometry.vertices[subdiv_vertex_index];
757 
758  const int first_grid_index = reshape_context->face_start_grid_index[coarse_poly_index];
759  corner->grid_index = first_grid_index + coarse_corner;
760 }
761 
762 static void foreach_poly(const SubdivForeachContext *foreach_context,
763  void *UNUSED(tls),
764  const int UNUSED(coarse_poly_index),
765  const int subdiv_poly_index,
766  const int start_loop_index,
767  const int num_loops)
768 {
769  MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
770 
771  BLI_assert(subdiv_poly_index < reshape_smooth_context->geometry.num_faces);
772 
773  Face *face = &reshape_smooth_context->geometry.faces[subdiv_poly_index];
774  face->start_corner_index = start_loop_index;
775  face->num_corners = num_loops;
776 }
777 
778 static void foreach_vertex_of_loose_edge(const struct SubdivForeachContext *foreach_context,
779  void *UNUSED(tls),
780  const int UNUSED(coarse_edge_index),
781  const float UNUSED(u),
782  const int vertex_index)
783 {
784  const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
785  Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
786 
787  if (vertex->num_grid_coords != 0) {
788  vertex->is_infinite_sharp = true;
789  }
790 }
791 
792 static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
793  const int subdiv_v1,
794  const int subdiv_v2,
795  const char crease)
796 {
797  /* This is a bit overhead to use atomics in such a simple function called from many threads,
798  * but this allows to save quite measurable amount of memory. */
799  const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1);
800  BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges);
801 
802  Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
803  edge->v1 = subdiv_v1;
804  edge->v2 = subdiv_v2;
805  edge->sharpness = BKE_subdiv_crease_to_sharpness_char(crease);
806 }
807 
808 static void foreach_edge(const struct SubdivForeachContext *foreach_context,
809  void *UNUSED(tls),
810  const int coarse_edge_index,
811  const int UNUSED(subdiv_edge_index),
812  const bool is_loose,
813  const int subdiv_v1,
814  const int subdiv_v2)
815 {
816  MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
817  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
818 
819  if (reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR) {
820  if (!is_loose) {
821  store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, (char)255);
822  }
823  return;
824  }
825 
826  /* Ignore all inner face edges as they have sharpness of zero when using Catmull-Clark mode. In
827  * simple mode, all edges have maximum sharpness, so they can't be skipped. */
828  if (coarse_edge_index == ORIGINDEX_NONE &&
829  reshape_smooth_context->smoothing_type != MULTIRES_SUBDIVIDE_SIMPLE) {
830  return;
831  }
832  /* Ignore all loose edges as well, as they are not communicated to the OpenSubdiv. */
833  if (!BLI_BITMAP_TEST_BOOL(reshape_smooth_context->non_loose_base_edge_map, coarse_edge_index)) {
834  return;
835  }
836  /* Edges without crease are to be ignored as well. */
837  const Mesh *base_mesh = reshape_context->base_mesh;
838  const MEdge *base_edge = &base_mesh->medge[coarse_edge_index];
839  const char crease = get_effective_crease_char(reshape_smooth_context, base_edge);
840  if (crease == 0) {
841  return;
842  }
843  store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, crease);
844 }
845 
847 {
848  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
849  const Mesh *base_mesh = reshape_context->base_mesh;
850  const MPoly *base_mpoly = base_mesh->mpoly;
851  const MLoop *base_mloop = base_mesh->mloop;
852  const MEdge *base_edge = base_mesh->medge;
853 
854  reshape_smooth_context->non_loose_base_edge_map = BLI_BITMAP_NEW(base_mesh->totedge,
855  "non_loose_base_edge_map");
856 
857  int num_used_edges = 0;
858  for (int poly_index = 0; poly_index < base_mesh->totpoly; ++poly_index) {
859  const MPoly *base_poly = &base_mpoly[poly_index];
860  for (int corner = 0; corner < base_poly->totloop; corner++) {
861  const MLoop *loop = &base_mloop[base_poly->loopstart + corner];
862  if (!BLI_BITMAP_TEST_BOOL(reshape_smooth_context->non_loose_base_edge_map, loop->e)) {
863  BLI_BITMAP_ENABLE(reshape_smooth_context->non_loose_base_edge_map, loop->e);
864 
865  const char crease = get_effective_crease_char(reshape_smooth_context, &base_edge[loop->e]);
866  if (crease != 0) {
867  ++num_used_edges;
868  }
869  }
870  }
871  }
872 
873  const int resolution = get_reshape_level_resolution(reshape_context);
874  const int num_subdiv_vertices_per_base_edge = resolution - 2;
875  reshape_smooth_context->geometry.max_edges = num_used_edges *
876  (num_subdiv_vertices_per_base_edge + 1);
877 }
878 
879 static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context)
880 {
881  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
882 
883  SubdivForeachContext foreach_context = {
885  .vertex_inner = foreach_vertex_inner,
886  .vertex_every_corner = foreach_vertex_every_corner,
887  .vertex_every_edge = foreach_vertex_every_edge,
888  .loop = foreach_loop,
889  .poly = foreach_poly,
890  .vertex_of_loose_edge = foreach_vertex_of_loose_edge,
891  .edge = foreach_edge,
892  .user_data = reshape_smooth_context,
893  };
894 
895  geometry_init_loose_information(reshape_smooth_context);
896 
897  SubdivToMeshSettings mesh_settings;
898  mesh_settings.resolution = get_reshape_level_resolution(reshape_context);
899  mesh_settings.use_optimal_display = false;
900 
901  /* TODO(sergey): Tell the foreach() to ignore loose vertices. */
903  reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh);
904 }
905 
908 /* -------------------------------------------------------------------- */
913 {
914  return OSD_SCHEME_CATMARK;
915 }
916 
918  const struct OpenSubdiv_Converter *converter)
919 {
920  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
921  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
922  const SubdivSettings *settings = &reshape_context->subdiv->settings;
923 
925 }
926 
928  const OpenSubdiv_Converter *converter)
929 {
930  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
931  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
932  const SubdivSettings *settings = &reshape_context->subdiv->settings;
933 
935 }
936 
938 {
939  return false;
940 }
941 
942 static int get_num_faces(const OpenSubdiv_Converter *converter)
943 {
944  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
945 
946  return reshape_smooth_context->geometry.num_faces;
947 }
948 
949 static int get_num_vertices(const OpenSubdiv_Converter *converter)
950 {
951  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
952 
953  return reshape_smooth_context->geometry.num_vertices;
954 }
955 
956 static int get_num_face_vertices(const OpenSubdiv_Converter *converter, int face_index)
957 {
958  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
959  BLI_assert(face_index < reshape_smooth_context->geometry.num_faces);
960 
961  const Face *face = &reshape_smooth_context->geometry.faces[face_index];
962  return face->num_corners;
963 }
964 
965 static void get_face_vertices(const OpenSubdiv_Converter *converter,
966  int face_index,
967  int *face_vertices)
968 {
969  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
970  BLI_assert(face_index < reshape_smooth_context->geometry.num_faces);
971 
972  const Face *face = &reshape_smooth_context->geometry.faces[face_index];
973 
974  for (int i = 0; i < face->num_corners; ++i) {
975  const int corner_index = face->start_corner_index + i;
976  const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index];
977  face_vertices[i] = corner->vertex - reshape_smooth_context->geometry.vertices;
978  }
979 }
980 
981 static int get_num_edges(const struct OpenSubdiv_Converter *converter)
982 {
983  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
984  return reshape_smooth_context->geometry.num_edges;
985 }
986 
987 static void get_edge_vertices(const OpenSubdiv_Converter *converter,
988  const int edge_index,
989  int edge_vertices[2])
990 {
991  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
992  BLI_assert(edge_index < reshape_smooth_context->geometry.num_edges);
993 
994  const Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
995  edge_vertices[0] = edge->v1;
996  edge_vertices[1] = edge->v2;
997 }
998 
999 static float get_edge_sharpness(const OpenSubdiv_Converter *converter, const int edge_index)
1000 {
1001  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
1002  BLI_assert(edge_index < reshape_smooth_context->geometry.num_edges);
1003 
1004  const Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
1005  return edge->sharpness;
1006 }
1007 
1008 static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, const int vertex_index)
1009 {
1010  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
1011  BLI_assert(vertex_index < reshape_smooth_context->geometry.num_vertices);
1012 
1013  const Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
1014  return vertex->sharpness;
1015 }
1016 
1017 static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int vertex_index)
1018 {
1019  const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
1020 
1021  BLI_assert(vertex_index < reshape_smooth_context->geometry.num_vertices);
1022 
1023  const Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
1024  return vertex->is_infinite_sharp;
1025 }
1026 
1027 static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_context,
1028  OpenSubdiv_Converter *converter)
1029 {
1030  converter->getSchemeType = get_scheme_type;
1034 
1035  converter->getNumFaces = get_num_faces;
1036  converter->getNumEdges = get_num_edges;
1037  converter->getNumVertices = get_num_vertices;
1038 
1040  converter->getFaceVertices = get_face_vertices;
1041  converter->getFaceEdges = NULL;
1042 
1043  converter->getEdgeVertices = get_edge_vertices;
1044  converter->getNumEdgeFaces = NULL;
1045  converter->getEdgeFaces = NULL;
1046  converter->getEdgeSharpness = get_edge_sharpness;
1047 
1048  converter->getNumVertexEdges = NULL;
1049  converter->getVertexEdges = NULL;
1050  converter->getNumVertexFaces = NULL;
1051  converter->getVertexFaces = NULL;
1054 
1055  converter->getNumUVLayers = NULL;
1056  converter->precalcUVLayer = NULL;
1057  converter->finishUVLayer = NULL;
1058  converter->getNumUVCoordinates = NULL;
1059  converter->getFaceCornerUVIndex = NULL;
1060 
1061  converter->freeUserData = NULL;
1062 
1063  converter->user_data = (void *)reshape_smooth_context;
1064 }
1065 
1066 /* Create subdiv descriptor created for topology at a reshape level. */
1067 static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_context)
1068 {
1069  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1070  const SubdivSettings *settings = &reshape_context->subdiv->settings;
1071 
1072  OpenSubdiv_Converter converter;
1073  converter_init(reshape_smooth_context, &converter);
1074 
1075  Subdiv *reshape_subdiv = BKE_subdiv_new_from_converter(settings, &converter);
1076 
1077  OpenSubdiv_EvaluatorSettings evaluator_settings = {0};
1078  BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, NULL, &evaluator_settings);
1079 
1080  reshape_smooth_context->reshape_subdiv = reshape_subdiv;
1081 
1082  BKE_subdiv_converter_free(&converter);
1083 }
1084 
1085 /* Callback to provide coarse position for subdivision surface topology at a reshape level. */
1087  const MultiresReshapeSmoothContext *reshape_smooth_context,
1088  const Vertex *vertex,
1089  float r_P[3]);
1090 
1091 /* Refine subdivision surface topology at a reshape level for new coarse vertices positions. */
1092 static void reshape_subdiv_refine(const MultiresReshapeSmoothContext *reshape_smooth_context,
1093  ReshapeSubdivCoarsePositionCb coarse_position_cb)
1094 {
1095  Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv;
1096 
1097  /* TODO(sergey): For non-trivial coarse_position_cb we should multi-thread this loop. */
1098 
1099  const int num_vertices = reshape_smooth_context->geometry.num_vertices;
1100  for (int i = 0; i < num_vertices; ++i) {
1101  const Vertex *vertex = &reshape_smooth_context->geometry.vertices[i];
1102  float P[3];
1103  coarse_position_cb(reshape_smooth_context, vertex, P);
1104  reshape_subdiv->evaluator->setCoarsePositions(reshape_subdiv->evaluator, P, i, 1);
1105  }
1106  reshape_subdiv->evaluator->refine(reshape_subdiv->evaluator);
1107 }
1108 
1110 {
1111  if (vertex->num_grid_coords == 0) {
1112  /* This is a loose vertex, the coordinate is not important. */
1113  /* TODO(sergey): Once the subdiv_foreach() supports properly ignoring loose elements this
1114  * should become an assert instead. */
1115  return NULL;
1116  }
1117  /* NOTE: All grid coordinates will point to the same object position, so can be simple and use
1118  * first grid coordinate. */
1119  return &vertex->grid_coords[0];
1120 }
1121 
1122 /* Version of reshape_subdiv_refine() which uses coarse position from original grids. */
1124  const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3])
1125 {
1126  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1127  const GridCoord *grid_coord = reshape_subdiv_refine_vertex_grid_coord(vertex);
1128 
1129  /* Check whether this is a loose vertex. */
1130  if (grid_coord == NULL) {
1131  zero_v3(r_P);
1132  return;
1133  }
1134 
1135  float limit_P[3];
1136  float tangent_matrix[3][3];
1137  multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, limit_P, tangent_matrix);
1138 
1139  const ReshapeConstGridElement orig_grid_element =
1140  multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
1141 
1142  float D[3];
1143  mul_v3_m3v3(D, tangent_matrix, orig_grid_element.displacement);
1144 
1145  add_v3_v3v3(r_P, limit_P, D);
1146 }
1147 static void reshape_subdiv_refine_orig(const MultiresReshapeSmoothContext *reshape_smooth_context)
1148 {
1149  reshape_subdiv_refine(reshape_smooth_context, reshape_subdiv_refine_orig_P);
1150 }
1151 
1152 /* Version of reshape_subdiv_refine() which uses coarse position from final grids. */
1154  const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3])
1155 {
1156  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1157  const GridCoord *grid_coord = reshape_subdiv_refine_vertex_grid_coord(vertex);
1158 
1159  /* Check whether this is a loose vertex. */
1160  if (grid_coord == NULL) {
1161  zero_v3(r_P);
1162  return;
1163  }
1164 
1166  reshape_context, grid_coord);
1167 
1168  /* NOTE: At this point in reshape/propagate pipeline grid displacement is actually storing object
1169  * vertices coordinates. */
1170  copy_v3_v3(r_P, grid_element.displacement);
1171 }
1172 static void reshape_subdiv_refine_final(const MultiresReshapeSmoothContext *reshape_smooth_context)
1173 {
1174  reshape_subdiv_refine(reshape_smooth_context, reshape_subdiv_refine_final_P);
1175 }
1176 
1178  const MultiresReshapeSmoothContext *reshape_smooth_context,
1179  const PTexCoord *ptex_coord,
1180  const GridCoord *grid_coord,
1181  float limit_P[3],
1182  float r_tangent_matrix[3][3])
1183 {
1184  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1185 
1186  float dPdu[3], dPdv[3];
1188  ptex_coord->ptex_face_index,
1189  ptex_coord->u,
1190  ptex_coord->v,
1191  limit_P,
1192  dPdu,
1193  dPdv);
1194 
1195  const int face_index = multires_reshape_grid_to_face_index(reshape_context,
1196  grid_coord->grid_index);
1197  const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
1199  reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix);
1200 }
1201 
1204 /* -------------------------------------------------------------------- */
1209  const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
1210 {
1211  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1212  const ReshapeConstGridElement orig_grid_element =
1213  multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
1214 
1215  LinearGridElement linear_grid_element;
1216  linear_grid_element_init(&linear_grid_element);
1217 
1218  linear_grid_element.mask = orig_grid_element.mask;
1219 
1220  return linear_grid_element;
1221 }
1222 
1224  const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
1225 {
1226  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1228  reshape_context, grid_coord);
1229 
1230  LinearGridElement linear_grid_element;
1231  linear_grid_element_init(&linear_grid_element);
1232 
1233  if (final_grid_element.mask != NULL) {
1234  linear_grid_element.mask = *final_grid_element.mask;
1235  }
1236 
1237  return linear_grid_element;
1238 }
1239 
1240 /* Interpolate difference of the linear data.
1241  *
1242  * Will access final data and original data at the grid elements at the reshape level,
1243  * calculate difference between final and original, and linearly interpolate to get value at the
1244  * top level. */
1246  const MultiresReshapeSmoothContext *reshape_smooth_context,
1247  const GridCoord *grid_coord,
1249 {
1250  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1251 
1252  const int reshape_level = reshape_context->reshape.level;
1253  const int reshape_level_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
1254  const int reshape_level_grid_size_1 = reshape_level_grid_size - 1;
1255  const float reshape_level_grid_size_1_inv = 1.0f / (float)(reshape_level_grid_size_1);
1256 
1257  const float x_f = grid_coord->u * reshape_level_grid_size_1;
1258  const float y_f = grid_coord->v * reshape_level_grid_size_1;
1259 
1260  const int x_i = x_f;
1261  const int y_i = y_f;
1262  const int x_n_i = (x_i == reshape_level_grid_size - 1) ? (x_i) : (x_i + 1);
1263  const int y_n_i = (y_i == reshape_level_grid_size - 1) ? (y_i) : (y_i + 1);
1264 
1265  const int corners_int_coords[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}};
1266 
1267  LinearGridElement corner_elements[4];
1268  for (int i = 0; i < 4; ++i) {
1269  GridCoord corner_grid_coord;
1270  corner_grid_coord.grid_index = grid_coord->grid_index;
1271  corner_grid_coord.u = corners_int_coords[i][0] * reshape_level_grid_size_1_inv;
1272  corner_grid_coord.v = corners_int_coords[i][1] * reshape_level_grid_size_1_inv;
1273 
1274  const LinearGridElement orig_element = linear_grid_element_orig_get(reshape_smooth_context,
1275  &corner_grid_coord);
1276  const LinearGridElement final_element = linear_grid_element_final_get(reshape_smooth_context,
1277  &corner_grid_coord);
1278  linear_grid_element_sub(&corner_elements[i], &final_element, &orig_element);
1279  }
1280 
1281  const float u = x_f - x_i;
1282  const float v = y_f - y_i;
1283  const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
1284 
1285  linear_grid_element_interpolate(result, corner_elements, weights);
1286 }
1287 
1289  const MultiresReshapeSmoothContext *reshape_smooth_context,
1290  const PTexCoord *UNUSED(ptex_coord),
1291  const GridCoord *grid_coord,
1292  void *UNUSED(userdata_v))
1293 {
1294  LinearGridElement *linear_delta_element = linear_grid_element_get(
1295  &reshape_smooth_context->linear_delta_grids, grid_coord);
1296 
1297  linear_grid_element_delta_interpolate(reshape_smooth_context, grid_coord, linear_delta_element);
1298 }
1299 
1300 static void evaluate_linear_delta_grids(MultiresReshapeSmoothContext *reshape_smooth_context)
1301 {
1302  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1303  const int num_grids = reshape_context->num_grids;
1304  const int top_level = reshape_context->top.level;
1305 
1306  linear_grids_allocate(&reshape_smooth_context->linear_delta_grids, num_grids, top_level);
1307 
1309 }
1310 
1311 static void propagate_linear_data_delta(const MultiresReshapeSmoothContext *reshape_smooth_context,
1312  ReshapeGridElement *final_grid_element,
1313  const GridCoord *grid_coord)
1314 {
1315  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1316 
1317  LinearGridElement *linear_delta_element = linear_grid_element_get(
1318  &reshape_smooth_context->linear_delta_grids, grid_coord);
1319 
1320  const ReshapeConstGridElement orig_grid_element =
1321  multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
1322 
1323  if (final_grid_element->mask != NULL) {
1324  *final_grid_element->mask = clamp_f(
1325  orig_grid_element.mask + linear_delta_element->mask, 0.0f, 1.0f);
1326  }
1327 }
1328 
1331 /* -------------------------------------------------------------------- */
1336  const MultiresReshapeSmoothContext *reshape_smooth_context,
1337  const PTexCoord *ptex_coord,
1338  const GridCoord *grid_coord,
1339  void *UNUSED(userdata_v))
1340 {
1341  float limit_P[3];
1342  float tangent_matrix[3][3];
1344  reshape_smooth_context, ptex_coord, grid_coord, limit_P, tangent_matrix);
1345 
1346  base_surface_grids_write(reshape_smooth_context, grid_coord, limit_P, tangent_matrix);
1347 }
1348 
1349 static void evaluate_base_surface_grids(const MultiresReshapeSmoothContext *reshape_smooth_context)
1350 {
1352 }
1353 
1356 /* -------------------------------------------------------------------- */
1360 /* Evaluate final position of the original (pre-sculpt-edit) point position at a given grid
1361  * coordinate. */
1363  const MultiresReshapeSmoothContext *reshape_smooth_context,
1364  const GridCoord *grid_coord,
1365  float r_orig_final_P[3])
1366 {
1367  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1368 
1369  /* Element of an original MDISPS grid) */
1370  const ReshapeConstGridElement orig_grid_element =
1371  multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
1372 
1373  /* Limit surface of the base mesh. */
1374  float base_mesh_limit_P[3];
1375  float base_mesh_tangent_matrix[3][3];
1377  reshape_context, grid_coord, base_mesh_limit_P, base_mesh_tangent_matrix);
1378 
1379  /* Convert original displacement from tangent space to object space. */
1380  float orig_displacement[3];
1381  mul_v3_m3v3(orig_displacement, base_mesh_tangent_matrix, orig_grid_element.displacement);
1382 
1383  /* Final point = limit surface + displacement. */
1384  add_v3_v3v3(r_orig_final_P, base_mesh_limit_P, orig_displacement);
1385 }
1386 
1388  const MultiresReshapeSmoothContext *reshape_smooth_context,
1389  const PTexCoord *ptex_coord,
1390  const GridCoord *grid_coord,
1391  void *UNUSED(userdata_v))
1392 {
1393  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1394 
1395  /* Position of the original vertex at top level. */
1396  float orig_final_P[3];
1397  evaluate_final_original_point(reshape_smooth_context, grid_coord, orig_final_P);
1398 
1399  /* Original surface point on sculpt level (sculpt level before edits in sculpt mode). */
1400  const SurfacePoint *orig_sculpt_point = base_surface_grids_read(reshape_smooth_context,
1401  grid_coord);
1402 
1403  /* Difference between original top level and original sculpt level in object space. */
1404  float original_detail_delta[3];
1405  sub_v3_v3v3(original_detail_delta, orig_final_P, orig_sculpt_point->P);
1406 
1407  /* Difference between original top level and original sculpt level in tangent space of original
1408  * sculpt level. */
1409  float original_detail_delta_tangent[3];
1410  float original_sculpt_tangent_matrix_inv[3][3];
1411  invert_m3_m3(original_sculpt_tangent_matrix_inv, orig_sculpt_point->tangent_matrix);
1412  mul_v3_m3v3(
1413  original_detail_delta_tangent, original_sculpt_tangent_matrix_inv, original_detail_delta);
1414 
1415  /* Limit surface of smoothed (subdivided) edited sculpt level. */
1416  float smooth_limit_P[3];
1417  float smooth_tangent_matrix[3][3];
1419  reshape_smooth_context, ptex_coord, grid_coord, smooth_limit_P, smooth_tangent_matrix);
1420 
1421  /* Add original detail to the smoothed surface. */
1422  float smooth_delta[3];
1423  mul_v3_m3v3(smooth_delta, smooth_tangent_matrix, original_detail_delta_tangent);
1424 
1425  /* Grid element of the result.
1426  *
1427  * NOTE: Displacement is storing object space coordinate. */
1429  grid_coord);
1430 
1431  add_v3_v3v3(grid_element.displacement, smooth_limit_P, smooth_delta);
1432 
1433  /* Propagate non-coordinate data. */
1434  propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
1435 }
1436 
1438  const MultiresReshapeSmoothContext *reshape_smooth_context)
1439 {
1442 }
1443 
1445  const MultiresReshapeSmoothContext *reshape_smooth_context,
1446  const PTexCoord *ptex_coord,
1447  const GridCoord *grid_coord,
1448  void *UNUSED(userdata_v))
1449 {
1450  const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1451  Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv;
1452 
1454  grid_coord);
1455 
1456  /* Surface. */
1457  float P[3];
1459  reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P);
1460 
1461  copy_v3_v3(grid_element.displacement, P);
1462 
1463  /* Propagate non-coordinate data. */
1464  propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
1465 }
1466 
1468  const MultiresReshapeSmoothContext *reshape_smooth_context)
1469 {
1471  reshape_smooth_context, evaluate_higher_grid_positions_callback, NULL);
1472 }
1473 
1476 /* -------------------------------------------------------------------- */
1481  const MultiresReshapeContext *reshape_context)
1482 {
1483  const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
1484  if (level_difference == 0) {
1485  /* Early output. */
1486  return;
1487  }
1488 
1489  MultiresReshapeSmoothContext reshape_smooth_context;
1490  if (reshape_context->subdiv->settings.is_simple) {
1491  context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_SIMPLE);
1492  }
1493  else {
1494  context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_CATMULL_CLARK);
1495  }
1496 
1497  geometry_create(&reshape_smooth_context);
1498  evaluate_linear_delta_grids(&reshape_smooth_context);
1499 
1500  reshape_subdiv_create(&reshape_smooth_context);
1501 
1502  base_surface_grids_allocate(&reshape_smooth_context);
1503  reshape_subdiv_refine_orig(&reshape_smooth_context);
1504  evaluate_base_surface_grids(&reshape_smooth_context);
1505 
1506  reshape_subdiv_refine_final(&reshape_smooth_context);
1507  evaluate_higher_grid_positions_with_details(&reshape_smooth_context);
1508 
1509  context_free(&reshape_smooth_context);
1510 }
1511 
1513  const eMultiresSubdivideModeType mode)
1514 {
1515  const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
1516  if (level_difference == 0) {
1517  /* Early output. */
1518  return;
1519  }
1520 
1521  MultiresReshapeSmoothContext reshape_smooth_context;
1522  context_init(&reshape_smooth_context, reshape_context, mode);
1523 
1524  geometry_create(&reshape_smooth_context);
1525  evaluate_linear_delta_grids(&reshape_smooth_context);
1526 
1527  reshape_subdiv_create(&reshape_smooth_context);
1528 
1529  reshape_subdiv_refine_final(&reshape_smooth_context);
1530  evaluate_higher_grid_positions(&reshape_smooth_context);
1531 
1532  context_free(&reshape_smooth_context);
1533 }
1534 
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
#define ORIGINDEX_NONE
eMultiresSubdivideModeType
Definition: BKE_multires.h:195
@ MULTIRES_SUBDIVIDE_LINEAR
Definition: BKE_multires.h:198
@ MULTIRES_SUBDIVIDE_CATMULL_CLARK
Definition: BKE_multires.h:196
@ MULTIRES_SUBDIVIDE_SIMPLE
Definition: BKE_multires.h:197
BLI_INLINE int BKE_subdiv_grid_size_from_level(int level)
Definition: subdiv_inline.h:33
BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease)
Definition: subdiv_inline.h:90
void BKE_subdiv_free(Subdiv *subdiv)
Definition: subdiv.c:184
Subdiv * BKE_subdiv_new_from_converter(const SubdivSettings *settings, struct OpenSubdiv_Converter *converter)
Definition: subdiv.c:98
BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease)
Definition: subdiv_inline.h:95
@ SUBDIV_EVALUATOR_TYPE_CPU
bool BKE_subdiv_eval_begin(struct Subdiv *subdiv, eSubdivEvaluatorType evaluator_type, struct OpenSubdiv_EvaluatorCache *evaluator_cache, const struct OpenSubdiv_EvaluatorSettings *settings)
void BKE_subdiv_eval_limit_point(struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3])
Definition: subdiv_eval.c:280
void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_dPdu[3], float r_dPdv[3])
Definition: subdiv_eval.c:286
bool BKE_subdiv_foreach_subdiv_geometry(struct Subdiv *subdiv, const struct SubdivForeachContext *context, const struct SubdivToMeshSettings *mesh_settings, const struct Mesh *coarse_mesh)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
Definition: BLI_bitmap.h:74
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
#define BLI_INLINE
MINLINE float clamp_f(float value, float min, float max)
void copy_m3_m3(float m1[3][3], const float m2[3][3])
Definition: math_matrix.c:71
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1180
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:897
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
#define UNUSED(x)
#define ELEM(...)
_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
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x)
ATTR_WARN_UNUSED_RESULT const BMVert * v
DEGForeachIDComponentCallback callback
SyclQueue void void size_t num_bytes void
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
static float P(float k)
Definition: math_interp.c:25
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context, int grid_index)
ReshapeGridElement multires_reshape_grid_element_for_grid_coord(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context, int face_index, int corner, const float dPdu[3], const float dPdv[3], float r_tangent_matrix[3][3])
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord)
void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, float r_P[3], float r_tangent_matrix[3][3])
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context, const eMultiresSubdivideModeType mode)
static void foreach_vertex_every_corner(const struct SubdivForeachContext *foreach_context, void *UNUSED(tls_v), const int ptex_face_index, const float ptex_face_u, const float ptex_face_v, const int coarse_vertex_index, const int UNUSED(coarse_face_index), const int UNUSED(coarse_face_corner), const int subdiv_vertex_index)
static LinearGridElement linear_grid_element_final_get(const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
static void reshape_subdiv_evaluate_limit_at_grid(const MultiresReshapeSmoothContext *reshape_smooth_context, const PTexCoord *ptex_coord, const GridCoord *grid_coord, float limit_P[3], float r_tangent_matrix[3][3])
static int get_num_edges(const struct OpenSubdiv_Converter *converter)
void(* ForeachTopLevelGridCoordCallback)(const MultiresReshapeSmoothContext *reshape_smooth_context, const PTexCoord *ptex_coord, const GridCoord *grid_coord, void *userdata_v)
static void reshape_subdiv_refine_final_P(const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3])
static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach_context, void *UNUSED(tls_v), const int ptex_face_index, const float ptex_face_u, const float ptex_face_v, const int UNUSED(coarse_edge_index), const int UNUSED(coarse_face_index), const int UNUSED(coarse_face_corner), const int subdiv_vertex_index)
static void foreach_toplevel_grid_coord_task(void *__restrict userdata_v, const int face_index, const TaskParallelTLS *__restrict UNUSED(tls))
void multires_reshape_smooth_object_grids_with_details(const MultiresReshapeContext *reshape_context)
static void propagate_linear_data_delta(const MultiresReshapeSmoothContext *reshape_smooth_context, ReshapeGridElement *final_grid_element, const GridCoord *grid_coord)
static void reshape_subdiv_refine(const MultiresReshapeSmoothContext *reshape_smooth_context, ReshapeSubdivCoarsePositionCb coarse_position_cb)
static char get_effective_crease_char(const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge)
static bool specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
static LinearGridElement * linear_grid_element_get(const LinearGrids *linear_grids, const GridCoord *grid_coord)
struct LinearGrid LinearGrid
struct SurfacePoint SurfacePoint
struct Vertex Vertex
static float get_edge_sharpness(const OpenSubdiv_Converter *converter, const int edge_index)
struct MultiresReshapeSmoothContext MultiresReshapeSmoothContext
static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter *UNUSED(converter))
static void foreach_single_vertex(const SubdivForeachContext *foreach_context, const GridCoord *grid_coord, const int coarse_vertex_index, const int subdiv_vertex_index)
static void evaluate_higher_grid_positions_callback(const MultiresReshapeSmoothContext *reshape_smooth_context, const PTexCoord *ptex_coord, const GridCoord *grid_coord, void *UNUSED(userdata_v))
static void foreach_poly(const SubdivForeachContext *foreach_context, void *UNUSED(tls), const int UNUSED(coarse_poly_index), const int subdiv_poly_index, const int start_loop_index, const int num_loops)
static void linear_grids_free(LinearGrids *linear_grids)
static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_context)
static void linear_grid_element_sub(LinearGridElement *result, const LinearGridElement *a, const LinearGridElement *b)
static void evaluate_higher_grid_positions(const MultiresReshapeSmoothContext *reshape_smooth_context)
static LinearGridElement linear_grid_element_orig_get(const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
struct Corner Corner
static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation(const struct OpenSubdiv_Converter *converter)
static void foreach_toplevel_grid_coord(const MultiresReshapeSmoothContext *reshape_smooth_context, ForeachTopLevelGridCoordCallback callback, void *callback_userdata_v)
static void linear_grid_element_delta_interpolate(const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord, LinearGridElement *result)
static int get_num_faces(const OpenSubdiv_Converter *converter)
static void evaluate_base_surface_grids(const MultiresReshapeSmoothContext *reshape_smooth_context)
static void evaluate_higher_grid_positions_with_details(const MultiresReshapeSmoothContext *reshape_smooth_context)
BLI_INLINE const GridCoord * reshape_subdiv_refine_vertex_grid_coord(const Vertex *vertex)
static void linear_grid_element_interpolate(LinearGridElement *result, const LinearGridElement elements[4], const float weights[4])
static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context)
static void linear_grid_element_init(LinearGridElement *linear_grid_element)
static SurfacePoint * base_surface_grids_read(const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
struct ForeachTopLevelGridCoordTaskData ForeachHighLevelCoordTaskData
static void grid_coords_from_face_vertices(const MultiresReshapeSmoothContext *reshape_smooth_context, const Face *face, const GridCoord *grid_coords[])
static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context, const MultiresReshapeContext *reshape_context, const eMultiresSubdivideModeType mode)
struct SurfaceGrid SurfaceGrid
static GridCoord * vertex_grid_coord_with_grid_index(const Vertex *vertex, const int grid_index)
static int get_num_vertices(const OpenSubdiv_Converter *converter)
static void foreach_vertex_of_loose_edge(const struct SubdivForeachContext *foreach_context, void *UNUSED(tls), const int UNUSED(coarse_edge_index), const float UNUSED(u), const int vertex_index)
static void linear_grids_allocate(LinearGrids *linear_grids, int num_grids, int level)
static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context, const float crease)
static void foreach_edge(const struct SubdivForeachContext *foreach_context, void *UNUSED(tls), const int coarse_edge_index, const int UNUSED(subdiv_edge_index), const bool is_loose, const int subdiv_v1, const int subdiv_v2)
static void base_surface_grids_write(const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord, float P[3], float tangent_matrix[3][3])
static void evaluate_base_surface_grids_callback(const MultiresReshapeSmoothContext *reshape_smooth_context, const PTexCoord *ptex_coord, const GridCoord *grid_coord, void *UNUSED(userdata_v))
struct Edge Edge
static void base_surface_grids_free(MultiresReshapeSmoothContext *reshape_smooth_context)
static void reshape_subdiv_refine_final(const MultiresReshapeSmoothContext *reshape_smooth_context)
struct LinearGridElement LinearGridElement
static float lerp(float t, float a, float b)
static void evaluate_linear_delta_grids(MultiresReshapeSmoothContext *reshape_smooth_context)
struct LinearGrids LinearGrids
static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshape_smooth_context)
void() ReshapeSubdivCoarsePositionCb(const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3])
static void get_edge_vertices(const OpenSubdiv_Converter *converter, const int edge_index, int edge_vertices[2])
static void reshape_subdiv_refine_orig(const MultiresReshapeSmoothContext *reshape_smooth_context)
static int get_num_face_vertices(const OpenSubdiv_Converter *converter, int face_index)
static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context)
static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smooth_context)
static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context, const int subdiv_v1, const int subdiv_v2, const char crease)
static bool foreach_topology_info(const SubdivForeachContext *foreach_context, const int num_vertices, const int num_edges, const int num_loops, const int num_polygons, const int *UNUSED(subdiv_polygon_offset))
static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_context, OpenSubdiv_Converter *converter)
static void foreach_vertex_inner(const struct SubdivForeachContext *foreach_context, void *UNUSED(tls), const int ptex_face_index, const float ptex_face_u, const float ptex_face_v, const int UNUSED(coarse_poly_index), const int UNUSED(coarse_corner), const int subdiv_vertex_index)
static void evaluate_linear_delta_grids_callback(const MultiresReshapeSmoothContext *reshape_smooth_context, const PTexCoord *UNUSED(ptex_coord), const GridCoord *grid_coord, void *UNUSED(userdata_v))
static void linear_grids_init(LinearGrids *linear_grids)
static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_context)
static void foreach_loop(const struct SubdivForeachContext *foreach_context, void *UNUSED(tls), const int UNUSED(ptex_face_index), const float UNUSED(ptex_face_u), const float UNUSED(ptex_face_v), const int UNUSED(coarse_loop_index), const int coarse_poly_index, const int coarse_corner, const int subdiv_loop_index, const int subdiv_vertex_index, const int UNUSED(subdiv_edge_index))
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int vertex_index)
static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, const int vertex_index)
static void reshape_subdiv_refine_orig_P(const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3])
static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter)
static void foreach_vertex(const SubdivForeachContext *foreach_context, const PTexCoord *ptex_coord, const int coarse_vertex_index, const int subdiv_vertex_index)
static void evaluate_higher_grid_positions_with_details_callback(const MultiresReshapeSmoothContext *reshape_smooth_context, const PTexCoord *ptex_coord, const GridCoord *grid_coord, void *UNUSED(userdata_v))
struct Face Face
static void evaluate_final_original_point(const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord, float r_orig_final_P[3])
static int get_face_grid_index(const MultiresReshapeSmoothContext *reshape_smooth_context, const Face *face)
static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context)
static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context)
static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_context)
static void interpolate_grid_coord(GridCoord *result, const GridCoord *face_grid_coords[4], const float u, const float v)
static void get_face_vertices(const OpenSubdiv_Converter *converter, int face_index, int *face_vertices)
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
OpenSubdiv_FVarLinearInterpolation
OpenSubdiv_VtxBoundaryInterpolation
OpenSubdiv_SchemeType
@ OSD_SCHEME_CATMARK
const Vertex * vertex
const MultiresReshapeSmoothContext * reshape_smooth_context
ForeachTopLevelGridCoordCallback callback
LinearGridElement * elements
LinearGridElement * elements_storage
unsigned int e
struct MEdge * medge
int totedge
struct MLoop * mloop
int totpoly
struct MPoly * mpoly
struct MultiresReshapeContext::@99 reshape
const float * cd_vertex_crease
struct MultiresReshapeContext::@100 top
struct Subdiv * subdiv
const MultiresReshapeContext * reshape_context
eMultiresSubdivideModeType smoothing_type
struct MultiresReshapeSmoothContext::@102 geometry
int(* getNumVertexFaces)(const struct OpenSubdiv_Converter *converter, const int vertex_index)
bool(* specifiesFullTopology)(const struct OpenSubdiv_Converter *converter)
void(* freeUserData)(const struct OpenSubdiv_Converter *converter)
void(* getFaceVertices)(const struct OpenSubdiv_Converter *converter, const int face_index, int *face_vertices)
float(* getVertexSharpness)(const struct OpenSubdiv_Converter *converter, const int vertex_index)
void(* getFaceEdges)(const struct OpenSubdiv_Converter *converter, const int face_index, int *face_edges)
int(* getNumUVLayers)(const struct OpenSubdiv_Converter *converter)
int(* getNumVertexEdges)(const struct OpenSubdiv_Converter *converter, const int vertex_index)
OpenSubdiv_FVarLinearInterpolation(* getFVarLinearInterpolation)(const struct OpenSubdiv_Converter *converter)
void(* getEdgeVertices)(const struct OpenSubdiv_Converter *converter, const int edge_index, int edge_vertices[2])
OpenSubdiv_SchemeType(* getSchemeType)(const struct OpenSubdiv_Converter *converter)
bool(* isInfiniteSharpVertex)(const struct OpenSubdiv_Converter *converter, const int vertex_index)
void(* getVertexFaces)(const struct OpenSubdiv_Converter *converter, const int vertex_index, int *vertex_faces)
int(* getNumVertices)(const struct OpenSubdiv_Converter *converter)
float(* getEdgeSharpness)(const struct OpenSubdiv_Converter *converter, const int edge_index)
int(* getNumEdges)(const struct OpenSubdiv_Converter *converter)
int(* getNumFaces)(const struct OpenSubdiv_Converter *converter)
int(* getNumEdgeFaces)(const struct OpenSubdiv_Converter *converter, const int edge_index)
int(* getNumUVCoordinates)(const struct OpenSubdiv_Converter *converter)
void(* getVertexEdges)(const struct OpenSubdiv_Converter *converter, const int vertex_index, int *vertex_edges)
void(* finishUVLayer)(const struct OpenSubdiv_Converter *converter)
void(* getEdgeFaces)(const struct OpenSubdiv_Converter *converter, const int edge, int *edge_faces)
OpenSubdiv_VtxBoundaryInterpolation(* getVtxBoundaryInterpolation)(const struct OpenSubdiv_Converter *converter)
void(* precalcUVLayer)(const struct OpenSubdiv_Converter *converter, const int layer_index)
int(* getFaceCornerUVIndex)(const struct OpenSubdiv_Converter *converter, const int face_index, const int corner_index)
int(* getNumFaceVertices)(const struct OpenSubdiv_Converter *converter, const int face_index)
void(* setCoarsePositions)(struct OpenSubdiv_Evaluator *evaluator, const float *positions, const int start_vertex_index, const int num_vertices)
void(* refine)(struct OpenSubdiv_Evaluator *evaluator)
SubdivForeachTopologyInformationCb topology_info
SubdivSettings settings
Definition: BKE_subdiv.h:160
struct OpenSubdiv_Evaluator * evaluator
Definition: BKE_subdiv.h:166
SurfacePoint * points
float tangent_matrix[3][3]
GridCoord * grid_coords
int BKE_subdiv_converter_fvar_linear_from_settings(const SubdivSettings *settings)
void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter)
int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(const SubdivSettings *settings)
BLI_INLINE float D(const float *data, const int res[3], int x, int y, int z)
Definition: voxel.c:13