Blender V5.0
subdiv_ccg.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2018 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_subdiv_ccg.hh"
10
11#include "MEM_guardedalloc.h"
12
14#include "BLI_index_mask.hh"
15#include "BLI_math_bits.h"
16#include "BLI_math_geom.h"
17#include "BLI_math_vector.h"
18#include "BLI_set.hh"
19#include "BLI_task.hh"
20#include "BLI_vector_set.hh"
21
22#include "BKE_ccg.hh"
23#include "BKE_mesh.hh"
24#include "BKE_subdiv.hh"
25#include "BKE_subdiv_eval.hh"
26
27#ifdef WITH_OPENSUBDIV
29#endif
30
31using blender::Array;
32using blender::float3;
39using blender::Span;
40using blender::Vector;
42using namespace blender::bke::subdiv;
43using namespace blender::bke::ccg;
44
45/* -------------------------------------------------------------------- */
48
49#ifdef WITH_OPENSUBDIV
50
51static void subdiv_ccg_average_inner_face_grids(SubdivCCG &subdiv_ccg,
52 const CCGKey &key,
53 const IndexRange face);
54
55void subdiv_ccg_average_faces_boundaries_and_corners(SubdivCCG &subdiv_ccg,
56 const CCGKey &key,
57 const IndexMask &face_mask);
58
60
61/* -------------------------------------------------------------------- */
64
65/* TODO(sergey): Make it more accessible function. */
66static int topology_refiner_count_face_corners(
67 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner)
68{
69 const int num_faces = topology_refiner->base_level().GetNumFaces();
70 int num_corners = 0;
71 for (int face_index = 0; face_index < num_faces; face_index++) {
72 num_corners += topology_refiner->base_level().GetFaceVertices(face_index).size();
73 }
74 return num_corners;
75}
76
77/* NOTE: Grid size and layer flags are to be filled in before calling this
78 * function. */
79static void subdiv_ccg_alloc_elements(SubdivCCG &subdiv_ccg,
81 const SubdivToCCGSettings &settings)
82{
83 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv.topology_refiner;
84 /* Allocate memory for surface grids. */
85 const int64_t num_grids = topology_refiner_count_face_corners(topology_refiner);
86 const int64_t grid_size = grid_size_from_level(subdiv_ccg.level);
87 const int64_t grid_area = grid_size * grid_size;
88 subdiv_ccg.positions.reinitialize(num_grids * grid_area);
89 if (settings.need_normal) {
90 subdiv_ccg.normals.reinitialize(num_grids * grid_area);
91 }
92 if (settings.need_mask) {
93 subdiv_ccg.masks.reinitialize(num_grids * grid_area);
94 }
95 /* TODO(sergey): Allocate memory for loose elements. */
96}
97
99
100/* -------------------------------------------------------------------- */
103
104static void subdiv_ccg_eval_grid_element_limit(Subdiv &subdiv,
105 SubdivCCG &subdiv_ccg,
106 const int ptex_face_index,
107 const float u,
108 const float v,
109 const int element)
110{
111 if (subdiv.displacement_evaluator != nullptr) {
112 subdiv_ccg.positions[element] = eval_final_point(&subdiv, ptex_face_index, u, v);
113 }
114 else if (!subdiv_ccg.normals.is_empty()) {
116 ptex_face_index,
117 u,
118 v,
119 subdiv_ccg.positions[element],
120 subdiv_ccg.normals[element]);
121 }
122 else {
123 subdiv_ccg.positions[element] = eval_limit_point(&subdiv, ptex_face_index, u, v);
124 }
125}
126
127static void subdiv_ccg_eval_grid_element_mask(SubdivCCG &subdiv_ccg,
128 SubdivCCGMaskEvaluator *mask_evaluator,
129 const int ptex_face_index,
130 const float u,
131 const float v,
132 const int element)
133{
134 if (subdiv_ccg.masks.is_empty()) {
135 return;
136 }
137 if (mask_evaluator != nullptr) {
138 subdiv_ccg.masks[element] = mask_evaluator->eval_mask(mask_evaluator, ptex_face_index, u, v);
139 }
140 else {
141 subdiv_ccg.masks[element] = 0.0f;
142 }
143}
144
145static void subdiv_ccg_eval_grid_element(Subdiv &subdiv,
146 SubdivCCG &subdiv_ccg,
147 SubdivCCGMaskEvaluator *mask_evaluator,
148 const int ptex_face_index,
149 const float u,
150 const float v,
151 const int element)
152{
153 subdiv_ccg_eval_grid_element_limit(subdiv, subdiv_ccg, ptex_face_index, u, v, element);
154 subdiv_ccg_eval_grid_element_mask(subdiv_ccg, mask_evaluator, ptex_face_index, u, v, element);
155}
156
157static void subdiv_ccg_eval_regular_grid(Subdiv &subdiv,
158 SubdivCCG &subdiv_ccg,
159 const Span<int> face_ptex_offset,
160 SubdivCCGMaskEvaluator *mask_evaluator,
161 const int face_index)
162{
163 const int ptex_face_index = face_ptex_offset[face_index];
164 const int grid_size = subdiv_ccg.grid_size;
165 const int grid_area = subdiv_ccg.grid_area;
166 const float grid_size_1_inv = 1.0f / (grid_size - 1);
167 const IndexRange face = subdiv_ccg.faces[face_index];
168 for (int corner = 0; corner < face.size(); corner++) {
169 const int grid_index = face.start() + corner;
170 const IndexRange range = grid_range(grid_area, grid_index);
171 for (int y = 0; y < grid_size; y++) {
172 const float grid_v = y * grid_size_1_inv;
173 for (int x = 0; x < grid_size; x++) {
174 const float grid_u = x * grid_size_1_inv;
175 float u, v;
176 rotate_grid_to_quad(corner, grid_u, grid_v, &u, &v);
177 const int element = range[CCG_grid_xy_to_index(grid_size, x, y)];
178 subdiv_ccg_eval_grid_element(
179 subdiv, subdiv_ccg, mask_evaluator, ptex_face_index, u, v, element);
180 }
181 }
182 }
183}
184
185static void subdiv_ccg_eval_special_grid(Subdiv &subdiv,
186 SubdivCCG &subdiv_ccg,
187 const Span<int> face_ptex_offset,
188 SubdivCCGMaskEvaluator *mask_evaluator,
189 const int face_index)
190{
191 const int grid_size = subdiv_ccg.grid_size;
192 const int grid_area = subdiv_ccg.grid_area;
193 const float grid_size_1_inv = 1.0f / (grid_size - 1);
194 const IndexRange face = subdiv_ccg.faces[face_index];
195 for (int corner = 0; corner < face.size(); corner++) {
196 const int grid_index = face.start() + corner;
197 const int ptex_face_index = face_ptex_offset[face_index] + corner;
198 const IndexRange range = grid_range(grid_area, grid_index);
199 for (int y = 0; y < grid_size; y++) {
200 const float u = 1.0f - (y * grid_size_1_inv);
201 for (int x = 0; x < grid_size; x++) {
202 const float v = 1.0f - (x * grid_size_1_inv);
203 const int element = range[CCG_grid_xy_to_index(grid_size, x, y)];
204 subdiv_ccg_eval_grid_element(
205 subdiv, subdiv_ccg, mask_evaluator, ptex_face_index, u, v, element);
206 }
207 }
208 }
209}
210
211static bool subdiv_ccg_evaluate_grids(SubdivCCG &subdiv_ccg,
212 Subdiv &subdiv,
213 SubdivCCGMaskEvaluator *mask_evaluator)
214{
215 using namespace blender;
216 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv.topology_refiner;
217 const int num_faces = topology_refiner->base_level().GetNumFaces();
218 const Span<int> face_ptex_offset = face_ptex_offset_get(&subdiv);
219 BLI_assert(face_ptex_offset.size() == subdiv_ccg.faces.size() + 1);
220 threading::parallel_for(IndexRange(num_faces), 1024, [&](const IndexRange range) {
221 for (const int face_index : range) {
222 if (subdiv_ccg.faces[face_index].size() == 4) {
223 subdiv_ccg_eval_regular_grid(
224 subdiv, subdiv_ccg, face_ptex_offset, mask_evaluator, face_index);
225 }
226 else {
227 subdiv_ccg_eval_special_grid(
228 subdiv, subdiv_ccg, face_ptex_offset, mask_evaluator, face_index);
229 }
230 }
231 });
232 /* If displacement is used, need to calculate normals after all final
233 * coordinates are known. */
234 if (subdiv.displacement_evaluator != nullptr) {
236 }
237 return true;
238}
239
240static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG &subdiv_ccg, const int num_edges)
241{
243}
244
245static SubdivCCGCoord subdiv_ccg_coord(int grid_index, int x, int y)
246{
247 SubdivCCGCoord coord{};
248 coord.grid_index = grid_index;
249 coord.x = x;
250 coord.y = y;
251 return coord;
252}
253
254/* Returns storage where boundary elements are to be stored. */
255static MutableSpan<SubdivCCGCoord> subdiv_ccg_adjacent_edge_add_face(
256 const int num_elements, SubdivCCGAdjacentEdge &adjacent_edge)
257{
258 Array<SubdivCCGCoord> coords(num_elements);
259 adjacent_edge.boundary_coords.append(std::move(coords));
260 return adjacent_edge.boundary_coords[adjacent_edge.boundary_coords.size() - 1];
261}
262
263static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG &subdiv_ccg)
264{
265 Subdiv *subdiv = subdiv_ccg.subdiv;
266 const OffsetIndices<int> faces = subdiv_ccg.faces;
267 const OpenSubdiv::Far::TopologyLevel &base_level = subdiv->topology_refiner->base_level();
268 const int num_edges = base_level.GetNumEdges();
269 const int grid_size = subdiv_ccg.grid_size;
270 if (num_edges == 0) {
271 /* Early output, nothing to do in this case. */
272 return;
273 }
274 subdiv_ccg_allocate_adjacent_edges(subdiv_ccg, num_edges);
275
276 /* Store adjacency for all faces. */
277 for (const int face_index : faces.index_range()) {
278 const IndexRange face = faces[face_index];
279 const int num_face_grids = face.size();
280 const OpenSubdiv::Far::ConstIndexArray face_vertices = base_level.GetFaceVertices(face_index);
281 /* Note that order of edges is same as order of MLoops, which also
282 * means it's the same as order of grids. */
283 const OpenSubdiv::Far::ConstIndexArray face_edges = base_level.GetFaceEdges(face_index);
284 /* Store grids adjacency for this edge. */
285 for (int corner = 0; corner < num_face_grids; corner++) {
286 const int vertex_index = face_vertices[corner];
287 const int edge_index = face_edges[corner];
288 const OpenSubdiv::Far::ConstIndexArray edge_vertices = base_level.GetEdgeVertices(
289 edge_index);
290 const bool is_edge_flipped = (edge_vertices[0] != vertex_index);
291 /* Grid which is adjacent to the current corner. */
292 const int current_grid_index = face.start() + corner;
293 /* Grid which is adjacent to the next corner. */
294 const int next_grid_index = face.start() + (corner + 1) % num_face_grids;
295 /* Add new face to the adjacent edge. */
296 SubdivCCGAdjacentEdge &adjacent_edge = subdiv_ccg.adjacent_edges[edge_index];
297 MutableSpan<SubdivCCGCoord> boundary_coords = subdiv_ccg_adjacent_edge_add_face(
298 grid_size * 2, adjacent_edge);
299 /* Fill CCG elements along the edge. */
300 int boundary_element_index = 0;
301 if (is_edge_flipped) {
302 for (int i = 0; i < grid_size; i++) {
303 boundary_coords[boundary_element_index++] = subdiv_ccg_coord(
304 next_grid_index, grid_size - i - 1, grid_size - 1);
305 }
306 for (int i = 0; i < grid_size; i++) {
307 boundary_coords[boundary_element_index++] = subdiv_ccg_coord(
308 current_grid_index, grid_size - 1, i);
309 }
310 }
311 else {
312 for (int i = 0; i < grid_size; i++) {
313 boundary_coords[boundary_element_index++] = subdiv_ccg_coord(
314 current_grid_index, grid_size - 1, grid_size - i - 1);
315 }
316 for (int i = 0; i < grid_size; i++) {
317 boundary_coords[boundary_element_index++] = subdiv_ccg_coord(
318 next_grid_index, i, grid_size - 1);
319 }
320 }
321 }
322 }
323}
324
325static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG &subdiv_ccg, const int num_vertices)
326{
327 subdiv_ccg.adjacent_verts = Array<SubdivCCGAdjacentVertex>(num_vertices,
329}
330
331/* Returns storage where corner elements are to be stored. This is a pointer
332 * to the actual storage. */
333static void subdiv_ccg_adjacent_vertex_add_face(SubdivCCGAdjacentVertex &adjacent_vertex,
334 const int grid_index,
335 const short x,
336 const short y)
337{
338 adjacent_vertex.corner_coords.append(SubdivCCGCoord{grid_index, x, y});
339}
340
341static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG &subdiv_ccg)
342{
343 Subdiv *subdiv = subdiv_ccg.subdiv;
344 const OffsetIndices<int> faces = subdiv_ccg.faces;
345 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
346 const int num_vertices = topology_refiner->base_level().GetNumVertices();
347 const int grid_size = subdiv_ccg.grid_size;
348 if (num_vertices == 0) {
349 /* Early output, nothing to do in this case. */
350 return;
351 }
352 subdiv_ccg_allocate_adjacent_vertices(subdiv_ccg, num_vertices);
353 /* Store adjacency for all faces. */
354 for (const int face_index : faces.index_range()) {
355 const IndexRange face = faces[face_index];
356 const int num_face_grids = face.size();
357 const OpenSubdiv::Far::ConstIndexArray face_vertices =
358 topology_refiner->base_level().GetFaceVertices(face_index);
359 for (int corner = 0; corner < num_face_grids; corner++) {
360 const int vertex_index = face_vertices[corner];
361 /* Grid which is adjacent to the current corner. */
362 const int grid_index = face.start() + corner;
363 /* Add new face to the adjacent edge. */
364 SubdivCCGAdjacentVertex &adjacent_vertex = subdiv_ccg.adjacent_verts[vertex_index];
365 subdiv_ccg_adjacent_vertex_add_face(
366 adjacent_vertex, grid_index, grid_size - 1, grid_size - 1);
367 }
368 }
369}
370
371static void subdiv_ccg_init_faces_neighborhood(SubdivCCG &subdiv_ccg)
372{
373 subdiv_ccg_init_faces_edge_neighborhood(subdiv_ccg);
374 subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg);
375}
376
377#endif
378
380
381/* -------------------------------------------------------------------- */
384
385std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(Subdiv &subdiv,
386 const SubdivToCCGSettings &settings,
387 const Mesh &coarse_mesh,
388 SubdivCCGMaskEvaluator *mask_evaluator)
389{
390#ifdef WITH_OPENSUBDIV
392 std::unique_ptr<SubdivCCG> subdiv_ccg = std::make_unique<SubdivCCG>();
393 subdiv_ccg->subdiv = &subdiv;
394 subdiv_ccg->level = bitscan_forward_i(settings.resolution - 1);
395 subdiv_ccg->grid_size = grid_size_from_level(subdiv_ccg->level);
396 subdiv_ccg->grid_area = subdiv_ccg->grid_size * subdiv_ccg->grid_size;
397 subdiv_ccg->faces = coarse_mesh.faces();
398 subdiv_ccg->grids_num = subdiv_ccg->faces.total_size();
399 subdiv_ccg->grid_to_face_map = coarse_mesh.corner_to_face_map();
400 if (coarse_mesh.corners_num) {
401 BLI_assert(subdiv.topology_refiner);
402 subdiv_ccg_alloc_elements(*subdiv_ccg, subdiv, settings);
403 subdiv_ccg_init_faces_neighborhood(*subdiv_ccg);
404 if (!subdiv_ccg_evaluate_grids(*subdiv_ccg, subdiv, mask_evaluator)) {
406 return nullptr;
407 }
408 }
410 return subdiv_ccg;
411#else
412 UNUSED_VARS(subdiv, settings, coarse_mesh, mask_evaluator);
413 return {};
414#endif
415}
416
418 const SubdivToCCGSettings &settings,
419 const Mesh &coarse_mesh)
420{
421 /* Make sure evaluator is ready. */
424 if (coarse_mesh.faces_num) {
425 return nullptr;
426 }
427 }
429 SubdivCCGMaskEvaluator mask_evaluator;
430 bool has_mask = BKE_subdiv_ccg_mask_init_from_paint(&mask_evaluator, &coarse_mesh);
431 std::unique_ptr<SubdivCCG> subdiv_ccg = BKE_subdiv_to_ccg(
432 subdiv, settings, coarse_mesh, has_mask ? &mask_evaluator : nullptr);
433 if (has_mask) {
434 mask_evaluator.free(&mask_evaluator);
435 }
436 if (!subdiv_ccg) {
437 return nullptr;
438 }
439 Mesh *result = BKE_mesh_copy_for_eval(coarse_mesh);
440 result->runtime->subdiv_ccg = std::move(subdiv_ccg);
441 return result;
442}
443
445{
446 if (this->subdiv != nullptr) {
447 free(this->subdiv);
448 }
449}
450
451CCGKey BKE_subdiv_ccg_key(const SubdivCCG & /*subdiv_ccg*/, int level)
452{
453#ifdef WITH_OPENSUBDIV
454 /* Most #CCGKey fields are unused for #SubdivCCG but still used in other areas of Blender.
455 * Initialize them to invalid values to catch mistaken use more easily. */
456 CCGKey key;
457 key.level = level;
458 key.elem_size = -1;
459 key.grid_size = grid_size_from_level(level);
460 key.grid_area = key.grid_size * key.grid_size;
461 key.grid_bytes = -1;
462
463 key.normal_offset = -1;
464 key.mask_offset = -1;
465
466 key.has_normals = false;
467 key.has_mask = false;
468 return key;
469#else
470 UNUSED_VARS(level);
471 return {};
472#endif
473}
474
476{
477 return BKE_subdiv_ccg_key(subdiv_ccg, subdiv_ccg.level);
478}
479
481
482/* -------------------------------------------------------------------- */
485
486#ifdef WITH_OPENSUBDIV
487
488/* Evaluate high-res face normals, for faces which corresponds to grid elements
489 *
490 * {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}}
491 *
492 * The result is stored in normals storage from TLS. */
493static void subdiv_ccg_recalc_inner_face_normals(const SubdivCCG &subdiv_ccg,
494 MutableSpan<float3> face_normals,
495 const int corner)
496{
497 const int grid_size = subdiv_ccg.grid_size;
498 const int grid_area = subdiv_ccg.grid_area;
499 const int grid_size_1 = grid_size - 1;
500 const Span grid_positions = subdiv_ccg.positions.as_span().slice(grid_range(grid_area, corner));
501 for (int y = 0; y < grid_size - 1; y++) {
502 for (int x = 0; x < grid_size - 1; x++) {
503 const int face_index = y * grid_size_1 + x;
504 float *face_normal = face_normals[face_index];
505 normal_quad_v3(face_normal,
506 grid_positions[CCG_grid_xy_to_index(grid_size, x, y + 1)],
507 grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y + 1)],
508 grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y)],
509 grid_positions[CCG_grid_xy_to_index(grid_size, x, y)]);
510 }
511 }
512}
513
514/* Average normals at every grid element, using adjacent faces normals. */
515static void subdiv_ccg_average_inner_face_normals(SubdivCCG &subdiv_ccg,
516 const Span<float3> face_normals,
517 const int corner)
518{
519 const int grid_size = subdiv_ccg.grid_size;
520 const int grid_area = subdiv_ccg.grid_area;
521 const int grid_size_1 = grid_size - 1;
522 MutableSpan grid_normals = subdiv_ccg.normals.as_mutable_span().slice(
523 grid_range(grid_area, corner));
524 for (int y = 0; y < grid_size; y++) {
525 for (int x = 0; x < grid_size; x++) {
526 float normal_acc[3] = {0.0f, 0.0f, 0.0f};
527 int counter = 0;
528 /* Accumulate normals of all adjacent faces. */
529 if (x < grid_size_1 && y < grid_size_1) {
530 add_v3_v3(normal_acc, face_normals[y * grid_size_1 + x]);
531 counter++;
532 }
533 if (x >= 1) {
534 if (y < grid_size_1) {
535 add_v3_v3(normal_acc, face_normals[y * grid_size_1 + (x - 1)]);
536 counter++;
537 }
538 if (y >= 1) {
539 add_v3_v3(normal_acc, face_normals[(y - 1) * grid_size_1 + (x - 1)]);
540 counter++;
541 }
542 }
543 if (y >= 1 && x < grid_size_1) {
544 add_v3_v3(normal_acc, face_normals[(y - 1) * grid_size_1 + x]);
545 counter++;
546 }
547 /* Normalize and store. */
548 mul_v3_v3fl(grid_normals[CCG_grid_xy_to_index(grid_size, x, y)], normal_acc, 1.0f / counter);
549 }
550 }
551}
552
553/* Recalculate normals which corresponds to non-boundaries elements of grids. */
554static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
555{
556 using namespace blender;
557 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
558
559 const int grid_size_1 = subdiv_ccg.grid_size - 1;
561 [&]() { return Array<float3>(grid_size_1 * grid_size_1); });
562
563 const OffsetIndices<int> faces = subdiv_ccg.faces;
564 face_mask.foreach_segment(GrainSize(512), [&](const IndexMaskSegment segment) {
565 MutableSpan<float3> face_normals = face_normals_tls.local();
566 for (const int face_index : segment) {
567 const IndexRange face = faces[face_index];
568 for (const int grid_index : face) {
569 subdiv_ccg_recalc_inner_face_normals(subdiv_ccg, face_normals, grid_index);
570 subdiv_ccg_average_inner_face_normals(subdiv_ccg, face_normals, grid_index);
571 }
572 subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
573 }
574 });
575}
576
577#endif
578
580{
581#ifdef WITH_OPENSUBDIV
582 if (subdiv_ccg.normals.is_empty()) {
583 /* Grids don't have normals, can do early output. */
584 return;
585 }
586 subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg, subdiv_ccg.faces.index_range());
588#else
589 UNUSED_VARS(subdiv_ccg);
590#endif
591}
592
593void BKE_subdiv_ccg_update_normals(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
594{
595#ifdef WITH_OPENSUBDIV
596 if (subdiv_ccg.normals.is_empty()) {
597 /* Grids don't have normals, can do early output. */
598 return;
599 }
600 if (face_mask.is_empty()) {
601 /* No faces changed, so nothing to do here. */
602 return;
603 }
604 subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg, face_mask);
605
606 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
607 subdiv_ccg_average_faces_boundaries_and_corners(subdiv_ccg, key, face_mask);
608#else
609 UNUSED_VARS(subdiv_ccg, face_mask);
610#endif
611}
612
614
615/* -------------------------------------------------------------------- */
618
619#ifdef WITH_OPENSUBDIV
620
621static void average_grid_element_value_v3(float a[3], float b[3])
622{
623 add_v3_v3(a, b);
624 mul_v3_fl(a, 0.5f);
625 copy_v3_v3(b, a);
626}
627
628static void average_grid_element(SubdivCCG &subdiv_ccg,
629 const int grid_element_a,
630 const int grid_element_b)
631{
632 average_grid_element_value_v3(subdiv_ccg.positions[grid_element_a],
633 subdiv_ccg.positions[grid_element_b]);
634 if (!subdiv_ccg.normals.is_empty()) {
635 average_grid_element_value_v3(subdiv_ccg.normals[grid_element_a],
636 subdiv_ccg.normals[grid_element_b]);
637 }
638 if (!subdiv_ccg.masks.is_empty()) {
639 float mask = (subdiv_ccg.masks[grid_element_a] + subdiv_ccg.masks[grid_element_b]) * 0.5f;
640 subdiv_ccg.masks[grid_element_a] = mask;
641 subdiv_ccg.masks[grid_element_b] = mask;
642 }
643}
644
645/* Accumulator to hold data during averaging. */
646struct GridElementAccumulator {
647 float3 co;
648 float3 no;
649 float mask;
650};
651
652static void element_accumulator_init(GridElementAccumulator &accumulator)
653{
654 zero_v3(accumulator.co);
655 zero_v3(accumulator.no);
656 accumulator.mask = 0.0f;
657}
658
659static void element_accumulator_add(GridElementAccumulator &accumulator,
660 const SubdivCCG &subdiv_ccg,
661 const int elem)
662{
663 accumulator.co += subdiv_ccg.positions[elem];
664 if (!subdiv_ccg.normals.is_empty()) {
665 accumulator.no += subdiv_ccg.normals[elem];
666 }
667 if (!subdiv_ccg.masks.is_empty()) {
668 accumulator.mask += subdiv_ccg.masks[elem];
669 }
670}
671
672static void element_accumulator_mul_fl(GridElementAccumulator &accumulator, const float f)
673{
674 mul_v3_fl(accumulator.co, f);
675 mul_v3_fl(accumulator.no, f);
676 accumulator.mask *= f;
677}
678
679static void element_accumulator_copy(SubdivCCG &subdiv_ccg,
680 const int destination,
681 const GridElementAccumulator &accumulator)
682{
683 subdiv_ccg.positions[destination] = accumulator.co;
684 if (!subdiv_ccg.normals.is_empty()) {
685 subdiv_ccg.normals[destination] = accumulator.no;
686 }
687 if (!subdiv_ccg.masks.is_empty()) {
688 subdiv_ccg.masks[destination] = accumulator.mask;
689 }
690}
691
692static void subdiv_ccg_average_inner_face_grids(SubdivCCG &subdiv_ccg,
693 const CCGKey &key,
694 const IndexRange face)
695{
696 const int num_face_grids = face.size();
697 const int grid_size = subdiv_ccg.grid_size;
698 int prev_grid = face.start() + num_face_grids - 1;
699 /* Average boundary between neighbor grid. */
700 for (const int grid : face) {
701 for (int i = 1; i < grid_size; i++) {
702 const int prev_grid_element = grid_xy_to_vert(key, prev_grid, i, 0);
703 const int grid_element = grid_xy_to_vert(key, grid, 0, i);
704 average_grid_element(subdiv_ccg, prev_grid_element, grid_element);
705 }
706 prev_grid = grid;
707 }
708 /* Average all grids centers into a single accumulator, and share it.
709 * Guarantees correct and smooth averaging in the center. */
710 GridElementAccumulator center_accumulator;
711 element_accumulator_init(center_accumulator);
712 for (const int grid : face) {
713 const int grid_center_element = grid_xy_to_vert(key, grid, 0, 0);
714 element_accumulator_add(center_accumulator, subdiv_ccg, grid_center_element);
715 }
716 element_accumulator_mul_fl(center_accumulator, 1.0f / num_face_grids);
717 for (const int grid : face) {
718 const int grid_center_element = grid_xy_to_vert(key, grid, 0, 0);
719 element_accumulator_copy(subdiv_ccg, grid_center_element, center_accumulator);
720 }
721}
722
723static void subdiv_ccg_average_grids_boundary(SubdivCCG &subdiv_ccg,
724 const CCGKey &key,
725 const SubdivCCGAdjacentEdge &adjacent_edge,
727{
728 const int num_adjacent_faces = adjacent_edge.boundary_coords.size();
729 const int grid_size2 = subdiv_ccg.grid_size * 2;
730 if (num_adjacent_faces == 1) {
731 /* Nothing to average with. */
732 return;
733 }
734 for (int i = 1; i < grid_size2 - 1; i++) {
735 element_accumulator_init(accumulators[i]);
736 }
737 for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
738 for (int i = 1; i < grid_size2 - 1; i++) {
739 const int grid_element = adjacent_edge.boundary_coords[face_index][i].to_index(key);
740 element_accumulator_add(accumulators[i], subdiv_ccg, grid_element);
741 }
742 }
743 for (int i = 1; i < grid_size2 - 1; i++) {
744 element_accumulator_mul_fl(accumulators[i], 1.0f / num_adjacent_faces);
745 }
746 /* Copy averaged value to all the other faces. */
747 for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
748 for (int i = 1; i < grid_size2 - 1; i++) {
749 const int grid_element = adjacent_edge.boundary_coords[face_index][i].to_index(key);
750 element_accumulator_copy(subdiv_ccg, grid_element, accumulators[i]);
751 }
752 }
753}
754
755static void subdiv_ccg_average_grids_corners(SubdivCCG &subdiv_ccg,
756 const CCGKey &key,
757 const SubdivCCGAdjacentVertex &adjacent_vertex)
758{
759 const int num_adjacent_faces = adjacent_vertex.corner_coords.size();
760 if (num_adjacent_faces == 1) {
761 /* Nothing to average with. */
762 return;
763 }
764 GridElementAccumulator accumulator;
765 element_accumulator_init(accumulator);
766 for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
767 const int grid_element = adjacent_vertex.corner_coords[face_index].to_index(key);
768 element_accumulator_add(accumulator, subdiv_ccg, grid_element);
769 }
770 element_accumulator_mul_fl(accumulator, 1.0f / num_adjacent_faces);
771 /* Copy averaged value to all the other faces. */
772 for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
773 const int grid_element = adjacent_vertex.corner_coords[face_index].to_index(key);
774 element_accumulator_copy(subdiv_ccg, grid_element, accumulator);
775 }
776}
777
778static void subdiv_ccg_average_boundaries(SubdivCCG &subdiv_ccg,
779 const CCGKey &key,
780 const IndexMask &adjacent_edge_mask)
781{
782 using namespace blender;
784 [&]() { return Array<GridElementAccumulator>(subdiv_ccg.grid_size * 2); });
785
786 adjacent_edge_mask.foreach_segment(GrainSize(1024), [&](const IndexMaskSegment segment) {
787 MutableSpan<GridElementAccumulator> accumulators = all_accumulators.local();
788 for (const int i : segment) {
789 const SubdivCCGAdjacentEdge &adjacent_edge = subdiv_ccg.adjacent_edges[i];
790 subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, accumulators);
791 }
792 });
793}
794
795static void subdiv_ccg_average_corners(SubdivCCG &subdiv_ccg,
796 const CCGKey &key,
797 const IndexMask &adjacent_vert_mask)
798{
799 using namespace blender;
800 adjacent_vert_mask.foreach_index(GrainSize(1024), [&](const int i) {
801 const SubdivCCGAdjacentVertex &adjacent_vert = subdiv_ccg.adjacent_verts[i];
802 subdiv_ccg_average_grids_corners(subdiv_ccg, key, adjacent_vert);
803 });
804}
805
806#endif
807
809{
810#ifdef WITH_OPENSUBDIV
811 using namespace blender;
812 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
813 /* Average inner boundaries of grids (within one face), across faces
814 * from different face-corners. */
815 BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, subdiv_ccg.faces.index_range());
816 subdiv_ccg_average_boundaries(subdiv_ccg, key, subdiv_ccg.adjacent_edges.index_range());
817 subdiv_ccg_average_corners(subdiv_ccg, key, subdiv_ccg.adjacent_verts.index_range());
818#else
819 UNUSED_VARS(subdiv_ccg);
820#endif
821}
822
823#ifdef WITH_OPENSUBDIV
824
825static void subdiv_ccg_affected_face_adjacency(SubdivCCG &subdiv_ccg,
826 const IndexMask &face_mask,
827 blender::Set<int> &adjacent_verts,
828 blender::Set<int> &adjacent_edges)
829{
830 Subdiv *subdiv = subdiv_ccg.subdiv;
831 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
832
833 face_mask.foreach_index([&](const int face_index) {
834 const OpenSubdiv::Far::ConstIndexArray face_vertices =
835 topology_refiner->base_level().GetFaceVertices(face_index);
836 adjacent_verts.add_multiple({face_vertices.begin(), face_vertices.size()});
837
838 const OpenSubdiv::Far::ConstIndexArray face_edges =
839 topology_refiner->base_level().GetFaceEdges(face_index);
840 adjacent_edges.add_multiple({face_edges.begin(), face_edges.size()});
841 });
842}
843
844void subdiv_ccg_average_faces_boundaries_and_corners(SubdivCCG &subdiv_ccg,
845 const CCGKey &key,
846 const IndexMask &face_mask)
847{
848 blender::Set<int> adjacent_vert_set;
849 blender::Set<int> adjacent_edge_set;
850 subdiv_ccg_affected_face_adjacency(subdiv_ccg, face_mask, adjacent_vert_set, adjacent_edge_set);
851
852 Vector<int> adjacent_verts(adjacent_vert_set.begin(), adjacent_vert_set.end());
853 Vector<int> adjacent_edges(adjacent_edge_set.begin(), adjacent_edge_set.end());
854
855 std::sort(adjacent_verts.begin(), adjacent_verts.end());
856 std::sort(adjacent_edges.begin(), adjacent_edges.end());
857
858 IndexMaskMemory memory;
859 subdiv_ccg_average_boundaries(
860 subdiv_ccg, key, IndexMask::from_indices(adjacent_edges.as_span(), memory));
861
862 subdiv_ccg_average_corners(
863 subdiv_ccg, key, IndexMask::from_indices(adjacent_verts.as_span(), memory));
864}
865
866#endif
867
868void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
869{
870#ifdef WITH_OPENSUBDIV
871 using namespace blender;
872 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
873 face_mask.foreach_index(GrainSize(512), [&](const int face_index) {
874 subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, subdiv_ccg.faces[face_index]);
875 });
876 /* TODO(sergey): Only average elements which are adjacent to modified
877 * faces. */
878 subdiv_ccg_average_boundaries(subdiv_ccg, key, subdiv_ccg.adjacent_edges.index_range());
879 subdiv_ccg_average_corners(subdiv_ccg, key, subdiv_ccg.adjacent_verts.index_range());
880#else
881 UNUSED_VARS(subdiv_ccg, face_mask);
882#endif
883}
884
886 int &r_num_vertices,
887 int &r_num_edges,
888 int &r_num_faces,
889 int &r_num_loops)
890{
891 const int num_grids = subdiv_ccg.grids_num;
892 const int grid_size = subdiv_ccg.grid_size;
893 const int grid_area = grid_size * grid_size;
894 const int num_edges_per_grid = 2 * (grid_size * (grid_size - 1));
895 r_num_vertices = num_grids * grid_area;
896 r_num_edges = num_grids * num_edges_per_grid;
897 r_num_faces = num_grids * (grid_size - 1) * (grid_size - 1);
898 r_num_loops = r_num_faces * 4;
899}
900
902
903/* -------------------------------------------------------------------- */
906
907void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord &coord)
908{
909 printf("%s: grid index: %d, coord: (%d, %d)\n", message, coord.grid_index, coord.x, coord.y);
910}
911
912bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
913{
914 if (coord.grid_index < 0 || coord.grid_index >= subdiv_ccg.grids_num) {
915 return false;
916 }
917 const int grid_size = subdiv_ccg.grid_size;
918 if (coord.x < 0 || coord.x >= grid_size) {
919 return false;
920 }
921 if (coord.y < 0 || coord.y >= grid_size) {
922 return false;
923 }
924 return true;
925}
926
928 const int num_unique,
929 const int num_duplicates)
930{
931 const int size = num_unique + num_duplicates;
932 neighbors.coords.reinitialize(size);
933 neighbors.num_duplicates = num_duplicates;
934}
935
936/* Check whether given coordinate belongs to a grid corner. */
937BLI_INLINE bool is_corner_grid_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
938{
939 const int grid_size_1 = subdiv_ccg.grid_size - 1;
940 return (coord.x == 0 && coord.y == 0) || (coord.x == 0 && coord.y == grid_size_1) ||
941 (coord.x == grid_size_1 && coord.y == grid_size_1) ||
942 (coord.x == grid_size_1 && coord.y == 0);
943}
944
945/* Check whether given coordinate belongs to a grid boundary. */
946BLI_INLINE bool is_boundary_grid_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
947{
948 const int grid_size_1 = subdiv_ccg.grid_size - 1;
949 return coord.x == 0 || coord.y == 0 || coord.x == grid_size_1 || coord.y == grid_size_1;
950}
951
952/* Check whether coordinate is at the boundary between two grids of the same face. */
954 const SubdivCCGCoord &coord)
955{
956 const int grid_size_1 = subdiv_ccg.grid_size - 1;
957 if (coord.x == 0) {
958 return coord.y > 0 && coord.y < grid_size_1;
959 }
960 if (coord.y == 0) {
961 return coord.x > 0 && coord.x < grid_size_1;
962 }
963 return false;
964}
965
967 const SubdivCCGCoord &coord)
968{
969 BLI_assert(coord.y > 0);
970 SubdivCCGCoord result = coord;
971 result.y -= 1;
972 return result;
973}
975 const SubdivCCGCoord &coord)
976{
977 UNUSED_VARS_NDEBUG(subdiv_ccg);
978 BLI_assert(coord.y < subdiv_ccg.grid_size - 1);
979 SubdivCCGCoord result = coord;
980 result.y += 1;
981 return result;
982}
983
985 const SubdivCCGCoord &coord)
986{
987 BLI_assert(coord.x > 0);
988 SubdivCCGCoord result = coord;
989 result.x -= 1;
990 return result;
991}
993 const SubdivCCGCoord &coord)
994{
995 UNUSED_VARS_NDEBUG(subdiv_ccg);
996 BLI_assert(coord.x < subdiv_ccg.grid_size - 1);
997 SubdivCCGCoord result = coord;
998 result.x += 1;
999 return result;
1000}
1001
1002#ifdef WITH_OPENSUBDIV
1003
1004/* For the input coordinate which is at the boundary of the grid do one step inside. */
1005static SubdivCCGCoord coord_step_inside_from_boundary(const SubdivCCG &subdiv_ccg,
1006 const SubdivCCGCoord &coord)
1007
1008{
1009 SubdivCCGCoord result = coord;
1010 const int grid_size_1 = subdiv_ccg.grid_size - 1;
1011 if (result.x == grid_size_1) {
1012 --result.x;
1013 }
1014 else if (result.y == grid_size_1) {
1015 --result.y;
1016 }
1017 else if (result.x == 0) {
1018 ++result.x;
1019 }
1020 else if (result.y == 0) {
1021 ++result.y;
1022 }
1023 else {
1024 BLI_assert_msg(0, "non-boundary element given");
1025 }
1026 return result;
1027}
1028
1030int next_grid_index_from_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
1031{
1032 const IndexRange face = subdiv_ccg.faces[subdiv_ccg.grid_to_face_map[coord.grid_index]];
1033 const int face_grid_index = coord.grid_index;
1034 int next_face_grid_index = face_grid_index + 1 - face.start();
1035 if (next_face_grid_index == face.size()) {
1036 next_face_grid_index = 0;
1037 }
1038 return face.start() + next_face_grid_index;
1039}
1040BLI_INLINE int prev_grid_index_from_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
1041{
1042 const IndexRange face = subdiv_ccg.faces[subdiv_ccg.grid_to_face_map[coord.grid_index]];
1043 const int face_grid_index = coord.grid_index;
1044 int prev_face_grid_index = face_grid_index - 1 - face.start();
1045 if (prev_face_grid_index < 0) {
1046 prev_face_grid_index = face.size() - 1;
1047 }
1048 return face.start() + prev_face_grid_index;
1049}
1050
1051/* Simple case of getting neighbors of a corner coordinate: the corner is a face center, so
1052 * can only iterate over grid of a single face, without looking into adjacency. */
1053static void neighbor_coords_corner_center_get(const SubdivCCG &subdiv_ccg,
1054 const SubdivCCGCoord &coord,
1055 const bool include_duplicates,
1056 SubdivCCGNeighbors &r_neighbors)
1057{
1058 const IndexRange face = subdiv_ccg.faces[subdiv_ccg.grid_to_face_map[coord.grid_index]];
1059 const int num_adjacent_grids = face.size();
1060
1062 r_neighbors, num_adjacent_grids, (include_duplicates) ? num_adjacent_grids - 1 : 0);
1063
1064 int duplicate_face_grid_index = num_adjacent_grids;
1065 for (int face_grid_index = 0; face_grid_index < num_adjacent_grids; ++face_grid_index) {
1066 SubdivCCGCoord neighbor_coord;
1067 neighbor_coord.grid_index = face.start() + face_grid_index;
1068 neighbor_coord.x = 1;
1069 neighbor_coord.y = 0;
1070 r_neighbors.coords[face_grid_index] = neighbor_coord;
1071
1072 if (include_duplicates && neighbor_coord.grid_index != coord.grid_index) {
1073 neighbor_coord.x = 0;
1074 r_neighbors.coords[duplicate_face_grid_index++] = neighbor_coord;
1075 }
1076 }
1077}
1078
1079/* Get index within adjacent_verts array for the given CCG coordinate. */
1080static int adjacent_vertex_index_from_coord(const SubdivCCG &subdiv_ccg,
1081 const SubdivCCGCoord &coord)
1082{
1083 Subdiv *subdiv = subdiv_ccg.subdiv;
1084 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
1085
1086 const int face_index = subdiv_ccg.grid_to_face_map[coord.grid_index];
1087 const IndexRange face = subdiv_ccg.faces[face_index];
1088 const int face_grid_index = coord.grid_index - face.start();
1089
1090 const OpenSubdiv::Far::ConstIndexArray face_vertices =
1091 topology_refiner->base_level().GetFaceVertices(face_index);
1092
1093 const int adjacent_vertex_index = face_vertices[face_grid_index];
1094 return adjacent_vertex_index;
1095}
1096
1097/* The corner is adjacent to a coarse vertex. */
1098static void neighbor_coords_corner_vertex_get(const SubdivCCG &subdiv_ccg,
1099 const SubdivCCGCoord &coord,
1100 const bool include_duplicates,
1101 SubdivCCGNeighbors &r_neighbors)
1102{
1103 Subdiv *subdiv = subdiv_ccg.subdiv;
1104 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
1105
1106 const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord);
1107 const OpenSubdiv::Far::ConstIndexArray vertex_edges =
1108 topology_refiner->base_level().GetVertexEdges(adjacent_vertex_index);
1109
1110 const SubdivCCGAdjacentVertex &adjacent_vert = subdiv_ccg.adjacent_verts[adjacent_vertex_index];
1111 const int num_adjacent_faces = adjacent_vert.corner_coords.size();
1112
1114 r_neighbors, vertex_edges.size(), (include_duplicates) ? num_adjacent_faces - 1 : 0);
1115
1116 for (int i = 0; i < vertex_edges.size(); ++i) {
1117 const int edge_index = vertex_edges[i];
1118
1119 /* Use very first grid of every edge. */
1120 const int edge_face_index = 0;
1121
1122 /* Depending edge orientation we use first (zero-based) or previous-to-last point. */
1123 const OpenSubdiv::Far::ConstIndexArray edge_vertices_indices =
1124 topology_refiner->base_level().GetEdgeVertices(edge_index);
1125 int edge_point_index, duplicate_edge_point_index;
1126 if (edge_vertices_indices[0] == adjacent_vertex_index) {
1127 duplicate_edge_point_index = 0;
1128 edge_point_index = duplicate_edge_point_index + 1;
1129 }
1130 else {
1131 /* Edge "consists" of 2 grids, which makes it 2 * grid_size elements per edge.
1132 * The index of last edge element is 2 * grid_size - 1 (due to zero-based indices),
1133 * and we are interested in previous to last element. */
1134 duplicate_edge_point_index = subdiv_ccg.grid_size * 2 - 1;
1135 edge_point_index = duplicate_edge_point_index - 1;
1136 }
1137
1138 const SubdivCCGAdjacentEdge &adjacent_edge = subdiv_ccg.adjacent_edges[edge_index];
1139 r_neighbors.coords[i] = adjacent_edge.boundary_coords[edge_face_index][edge_point_index];
1140 }
1141
1142 if (include_duplicates) {
1143 /* Add duplicates of the current grid vertex in adjacent faces if requested. */
1144 for (int i = 0, duplicate_i = vertex_edges.size(); i < num_adjacent_faces; i++) {
1145 SubdivCCGCoord neighbor_coord = adjacent_vert.corner_coords[i];
1146 if (neighbor_coord.grid_index != coord.grid_index) {
1147 r_neighbors.coords[duplicate_i++] = neighbor_coord;
1148 }
1149 }
1150 }
1151}
1152
1153static int adjacent_edge_index_from_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
1154{
1155 Subdiv *subdiv = subdiv_ccg.subdiv;
1156 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
1157
1158 const int face_index = subdiv_ccg.grid_to_face_map[coord.grid_index];
1159 const IndexRange face = subdiv_ccg.faces[face_index];
1160 const int face_grid_index = coord.grid_index - face.start();
1161
1162 const OpenSubdiv::Far::ConstIndexArray face_edges = topology_refiner->base_level().GetFaceEdges(
1163 face_index);
1164
1165 const int grid_size_1 = subdiv_ccg.grid_size - 1;
1166 int adjacent_edge_index = -1;
1167 if (coord.x == grid_size_1) {
1168 adjacent_edge_index = face_edges[face_grid_index];
1169 }
1170 else {
1171 BLI_assert(coord.y == grid_size_1);
1172 adjacent_edge_index = face_edges[face_grid_index == 0 ? face.size() - 1 : face_grid_index - 1];
1173 }
1174
1175 return adjacent_edge_index;
1176}
1177
1178static int adjacent_edge_point_index_from_coord(const SubdivCCG &subdiv_ccg,
1179 const SubdivCCGCoord &coord,
1180 const int adjacent_edge_index)
1181{
1182 Subdiv *subdiv = subdiv_ccg.subdiv;
1183 const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
1184
1185 const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord);
1186 const OpenSubdiv::Far::ConstIndexArray edge_vertices_indices =
1187 topology_refiner->base_level().GetEdgeVertices(adjacent_edge_index);
1188
1189 /* Vertex index of an edge which is used to see whether edge points in the right direction.
1190 * Tricky part here is that depending whether input coordinate is a maximum X or Y coordinate
1191 * of the grid we need to use different edge direction.
1192 * Basically, the edge adjacent to a previous loop needs to point opposite direction. */
1193 int directional_edge_vertex_index = -1;
1194
1195 const int grid_size_1 = subdiv_ccg.grid_size - 1;
1196 int adjacent_edge_point_index = -1;
1197 if (coord.x == grid_size_1) {
1198 adjacent_edge_point_index = subdiv_ccg.grid_size - coord.y - 1;
1199 directional_edge_vertex_index = edge_vertices_indices[0];
1200 }
1201 else {
1202 BLI_assert(coord.y == grid_size_1);
1203 adjacent_edge_point_index = subdiv_ccg.grid_size + coord.x;
1204 directional_edge_vertex_index = edge_vertices_indices[1];
1205 }
1206
1207 /* Flip the index if the edge points opposite direction. */
1208 if (adjacent_vertex_index != directional_edge_vertex_index) {
1209 const int num_edge_points = subdiv_ccg.grid_size * 2;
1210 adjacent_edge_point_index = num_edge_points - adjacent_edge_point_index - 1;
1211 }
1212
1213 return adjacent_edge_point_index;
1214}
1215
1216/* Adjacent edge has two points in the middle which corresponds to grid corners, but which are
1217 * the same point in the final geometry.
1218 * So need to use extra step when calculating next/previous points, so we don't go from a corner
1219 * of one grid to a corner of adjacent grid. */
1220static int next_adjacent_edge_point_index(const SubdivCCG &subdiv_ccg, const int point_index)
1221{
1222 if (point_index == subdiv_ccg.grid_size - 1) {
1223 return point_index + 2;
1224 }
1225 return point_index + 1;
1226}
1227static int prev_adjacent_edge_point_index(const SubdivCCG &subdiv_ccg, const int point_index)
1228{
1229 if (point_index == subdiv_ccg.grid_size) {
1230 return point_index - 2;
1231 }
1232 return point_index - 1;
1233}
1234
1235/* When the point index corresponds to a grid corner, returns the point index which corresponds to
1236 * the corner of the adjacent grid, as the adjacent edge has two separate points for each grid
1237 * corner at the middle of the edge. */
1238static int adjacent_grid_corner_point_index_on_edge(const SubdivCCG &subdiv_ccg,
1239 const int point_index)
1240{
1241 if (point_index == subdiv_ccg.grid_size) {
1242 return point_index - 1;
1243 }
1244 return point_index + 1;
1245}
1246
1247/* Common implementation of neighbor calculation when input coordinate is at the edge between two
1248 * coarse faces, but is not at the coarse vertex. */
1249static void neighbor_coords_edge_get(const SubdivCCG &subdiv_ccg,
1250 const SubdivCCGCoord &coord,
1251 const bool include_duplicates,
1252 SubdivCCGNeighbors &r_neighbors)
1253
1254{
1255 const bool is_corner = is_corner_grid_coord(subdiv_ccg, coord);
1256 const int adjacent_edge_index = adjacent_edge_index_from_coord(subdiv_ccg, coord);
1257 const SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg.adjacent_edges[adjacent_edge_index];
1258
1259 /* 2 neighbor points along the edge, plus one inner point per every adjacent grid. */
1260 const int num_adjacent_faces = adjacent_edge->boundary_coords.size();
1261 int num_duplicates = 0;
1262 if (include_duplicates) {
1263 num_duplicates += num_adjacent_faces - 1;
1264 if (is_corner) {
1265 /* When the coord is a grid corner, add an extra duplicate per adjacent grid in all adjacent
1266 * faces to the edge. */
1267 num_duplicates += num_adjacent_faces;
1268 }
1269 }
1270 subdiv_ccg_neighbors_init(r_neighbors, num_adjacent_faces + 2, num_duplicates);
1271
1272 const int point_index = adjacent_edge_point_index_from_coord(
1273 subdiv_ccg, coord, adjacent_edge_index);
1274 const int point_index_duplicate = adjacent_grid_corner_point_index_on_edge(subdiv_ccg,
1275 point_index);
1276
1277 const int next_point_index = next_adjacent_edge_point_index(subdiv_ccg, point_index);
1278 const int prev_point_index = prev_adjacent_edge_point_index(subdiv_ccg, point_index);
1279
1280 int duplicate_i = num_adjacent_faces;
1281 for (int i = 0; i < num_adjacent_faces; ++i) {
1282 const Span<SubdivCCGCoord> boundary_coords = adjacent_edge->boundary_coords[i];
1283 /* One step into the grid from the edge for each adjacent face. */
1284 SubdivCCGCoord grid_coord = boundary_coords[point_index];
1285 r_neighbors.coords[i + 2] = coord_step_inside_from_boundary(subdiv_ccg, grid_coord);
1286
1287 if (grid_coord.grid_index == coord.grid_index) {
1288 /* Previous and next along the edge for the current grid. */
1289 r_neighbors.coords[0] = boundary_coords[prev_point_index];
1290 r_neighbors.coords[1] = boundary_coords[next_point_index];
1291 }
1292 else if (include_duplicates) {
1293 /* Same coordinate on neighboring grids if requested. */
1294 r_neighbors.coords[duplicate_i + 2] = grid_coord;
1295 duplicate_i++;
1296 }
1297
1298 /* When it is a corner, add the duplicate of the adjacent grid in the same face. */
1299 if (include_duplicates && is_corner) {
1300 SubdivCCGCoord duplicate_corner_grid_coord = boundary_coords[point_index_duplicate];
1301 r_neighbors.coords[duplicate_i + 2] = duplicate_corner_grid_coord;
1302 duplicate_i++;
1303 }
1304 }
1305 BLI_assert(duplicate_i - num_adjacent_faces == num_duplicates);
1306}
1307
1308/* The corner is at the middle of edge between faces. */
1309static void neighbor_coords_corner_edge_get(const SubdivCCG &subdiv_ccg,
1310 const SubdivCCGCoord &coord,
1311 const bool include_duplicates,
1312 SubdivCCGNeighbors &r_neighbors)
1313{
1314 neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1315}
1316
1317/* Input coordinate is at one of 4 corners of its grid corners. */
1318static void neighbor_coords_corner_get(const SubdivCCG &subdiv_ccg,
1319 const SubdivCCGCoord &coord,
1320 const bool include_duplicates,
1321 SubdivCCGNeighbors &r_neighbors)
1322{
1323 if (coord.x == 0 && coord.y == 0) {
1324 neighbor_coords_corner_center_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1325 }
1326 else {
1327 const int grid_size_1 = subdiv_ccg.grid_size - 1;
1328 if (coord.x == grid_size_1 && coord.y == grid_size_1) {
1329 neighbor_coords_corner_vertex_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1330 }
1331 else {
1332 neighbor_coords_corner_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1333 }
1334 }
1335}
1336
1337/* Simple case of getting neighbors of a boundary coordinate: the input coordinate is at the
1338 * boundary between two grids of the same face and there is no need to check adjacency with
1339 * other faces. */
1340static void neighbor_coords_boundary_inner_get(const SubdivCCG &subdiv_ccg,
1341 const SubdivCCGCoord &coord,
1342 const bool include_duplicates,
1343 SubdivCCGNeighbors &r_neighbors)
1344{
1345 subdiv_ccg_neighbors_init(r_neighbors, 4, (include_duplicates) ? 1 : 0);
1346
1347 if (coord.x == 0) {
1348 r_neighbors.coords[0] = coord_at_prev_row(subdiv_ccg, coord);
1349 r_neighbors.coords[1] = coord_at_next_row(subdiv_ccg, coord);
1350 r_neighbors.coords[2] = coord_at_next_col(subdiv_ccg, coord);
1351
1352 r_neighbors.coords[3].grid_index = prev_grid_index_from_coord(subdiv_ccg, coord);
1353 r_neighbors.coords[3].x = coord.y;
1354 r_neighbors.coords[3].y = 1;
1355
1356 if (include_duplicates) {
1357 r_neighbors.coords[4] = r_neighbors.coords[3];
1358 r_neighbors.coords[4].y = 0;
1359 }
1360 }
1361 else if (coord.y == 0) {
1362 r_neighbors.coords[0] = coord_at_prev_col(subdiv_ccg, coord);
1363 r_neighbors.coords[1] = coord_at_next_col(subdiv_ccg, coord);
1364 r_neighbors.coords[2] = coord_at_next_row(subdiv_ccg, coord);
1365
1366 r_neighbors.coords[3].grid_index = next_grid_index_from_coord(subdiv_ccg, coord);
1367 r_neighbors.coords[3].x = 1;
1368 r_neighbors.coords[3].y = coord.x;
1369
1370 if (include_duplicates) {
1371 r_neighbors.coords[4] = r_neighbors.coords[3];
1372 r_neighbors.coords[4].x = 0;
1373 }
1374 }
1375}
1376
1377/* Input coordinate is on an edge between two faces. Need to check adjacency. */
1378static void neighbor_coords_boundary_outer_get(const SubdivCCG &subdiv_ccg,
1379 const SubdivCCGCoord &coord,
1380 const bool include_duplicates,
1381 SubdivCCGNeighbors &r_neighbors)
1382{
1383 neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1384}
1385
1386/* Input coordinate is at one of 4 boundaries of its grid.
1387 * It could either be an inner boundary (which connects face center to the face edge) or could be
1388 * a part of coarse face edge. */
1389static void neighbor_coords_boundary_get(const SubdivCCG &subdiv_ccg,
1390 const SubdivCCGCoord &coord,
1391 const bool include_duplicates,
1392 SubdivCCGNeighbors &r_neighbors)
1393{
1394 if (is_inner_edge_grid_coordinate(subdiv_ccg, coord)) {
1395 neighbor_coords_boundary_inner_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1396 }
1397 else {
1398 neighbor_coords_boundary_outer_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1399 }
1400}
1401
1402/* Input coordinate is inside of its grid, all the neighbors belong to the same grid. */
1403static void neighbor_coords_inner_get(const SubdivCCG &subdiv_ccg,
1404 const SubdivCCGCoord &coord,
1405 SubdivCCGNeighbors &r_neighbors)
1406{
1407 subdiv_ccg_neighbors_init(r_neighbors, 4, 0);
1408
1409 r_neighbors.coords[0] = coord_at_prev_row(subdiv_ccg, coord);
1410 r_neighbors.coords[1] = coord_at_next_row(subdiv_ccg, coord);
1411 r_neighbors.coords[2] = coord_at_prev_col(subdiv_ccg, coord);
1412 r_neighbors.coords[3] = coord_at_next_col(subdiv_ccg, coord);
1413}
1414
1415#endif
1416
1418 const SubdivCCGCoord &coord,
1419 const bool include_duplicates,
1420 SubdivCCGNeighbors &r_neighbors)
1421{
1422#ifdef WITH_OPENSUBDIV
1423 BLI_assert(coord.grid_index >= 0);
1424 BLI_assert(coord.grid_index < subdiv_ccg.grids_num);
1425 BLI_assert(coord.x >= 0);
1426 BLI_assert(coord.x < subdiv_ccg.grid_size);
1427 BLI_assert(coord.y >= 0);
1428 BLI_assert(coord.y < subdiv_ccg.grid_size);
1429
1430 if (is_corner_grid_coord(subdiv_ccg, coord)) {
1431 neighbor_coords_corner_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1432 }
1433 else if (is_boundary_grid_coord(subdiv_ccg, coord)) {
1434 neighbor_coords_boundary_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
1435 }
1436 else {
1437 neighbor_coords_inner_get(subdiv_ccg, coord, r_neighbors);
1438 }
1439
1440# ifndef NDEBUG
1441 for (const int i : r_neighbors.coords.index_range()) {
1442 BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, r_neighbors.coords[i]));
1443 }
1444# endif
1445#else
1446 UNUSED_VARS(subdiv_ccg, coord, include_duplicates, r_neighbors);
1447#endif
1448}
1449
1451 const SubdivCCGCoord &coord,
1452 const blender::Span<int> corner_verts,
1454 int &r_v1,
1455 int &r_v2)
1456{
1457 const int grid_size_1 = subdiv_ccg.grid_size - 1;
1458 const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, coord.grid_index);
1459 const blender::IndexRange face = faces[face_index];
1460 r_v1 = corner_verts[coord.grid_index];
1461
1462 const int corner = blender::bke::mesh::face_find_corner_from_vert(face, corner_verts, r_v1);
1463 if (coord.x == grid_size_1) {
1464 const int next = blender::bke::mesh::face_corner_next(face, corner);
1465 r_v2 = corner_verts[next];
1466 }
1467 if (coord.y == grid_size_1) {
1468 const int prev = blender::bke::mesh::face_corner_prev(face, corner);
1469 r_v2 = corner_verts[prev];
1470 }
1471}
1472
1474 const SubdivCCG &subdiv_ccg,
1475 const SubdivCCGCoord &coord,
1476 const blender::Span<int> corner_verts,
1478 int &r_v1,
1479 int &r_v2)
1480{
1481
1482 const int grid_size_1 = subdiv_ccg.grid_size - 1;
1483 if (is_corner_grid_coord(subdiv_ccg, coord)) {
1484 if (coord.x == 0 && coord.y == 0) {
1485 /* Grid corner in the center of a face. */
1487 }
1488 if (coord.x == grid_size_1 && coord.y == grid_size_1) {
1489 /* Grid corner adjacent to a coarse mesh vertex. */
1490 r_v1 = r_v2 = corner_verts[coord.grid_index];
1492 }
1493 /* Grid corner adjacent to the middle of a coarse mesh edge. */
1494 adjacent_vertices_index_from_adjacent_edge(subdiv_ccg, coord, corner_verts, faces, r_v1, r_v2);
1496 }
1497
1498 if (is_boundary_grid_coord(subdiv_ccg, coord)) {
1499 if (!is_inner_edge_grid_coordinate(subdiv_ccg, coord)) {
1500 /* Grid boundary adjacent to a coarse mesh edge. */
1502 subdiv_ccg, coord, corner_verts, faces, r_v1, r_v2);
1504 }
1505 }
1507}
1508
1510 const Span<int> corner_verts,
1511 const blender::BitSpan boundary_verts,
1512 const SubdivCCG &subdiv_ccg,
1513 const SubdivCCGCoord coord)
1514{
1515 int v1, v2;
1517 subdiv_ccg, coord, corner_verts, faces, v1, v2);
1518 switch (adjacency) {
1520 return boundary_verts[v1];
1522 return boundary_verts[v1] && boundary_verts[v2];
1524 return false;
1525 }
1527 return false;
1528}
1529
1531{
1532 if (subdiv_ccg.grid_hidden.is_empty()) {
1533 const int grid_area = subdiv_ccg.grid_area;
1534 subdiv_ccg.grid_hidden = blender::BitGroupVector<>(subdiv_ccg.grids_num, grid_area, false);
1535 }
1536 return subdiv_ccg.grid_hidden;
1537}
1538
1540{
1541 subdiv_ccg.grid_hidden = {};
1542}
1543
1544static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG &subdiv_ccg,
1545 const SubdivCCGCoord &coord,
1546 int &r_ptex_face_index,
1547 float &r_u,
1548 float &r_v)
1549{
1550 Subdiv *subdiv = subdiv_ccg.subdiv;
1551
1552 const float grid_size = subdiv_ccg.grid_size;
1553 const float grid_size_1_inv = 1.0f / (grid_size - 1);
1554
1555 const float grid_u = coord.x * grid_size_1_inv;
1556 const float grid_v = coord.y * grid_size_1_inv;
1557
1558 const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, coord.grid_index);
1559 const OffsetIndices<int> faces = subdiv_ccg.faces;
1560 const IndexRange face = faces[face_index];
1561 const Span<int> face_ptex_offset = face_ptex_offset_get(subdiv);
1562 r_ptex_face_index = face_ptex_offset[face_index];
1563
1564 const float corner = coord.grid_index - face.start();
1565
1566 if (face.size() == 4) {
1567 rotate_grid_to_quad(corner, grid_u, grid_v, &r_u, &r_v);
1568 }
1569 else {
1570 r_ptex_face_index += corner;
1571 r_u = 1.0f - grid_v;
1572 r_v = 1.0f - grid_u;
1573 }
1574}
1575
1577 const CCGKey &key,
1578 const int grid_index,
1579 const MutableSpan<float3> r_limit_positions)
1580{
1581 SubdivCCGCoord coord{};
1582 coord.grid_index = grid_index;
1583 for (const int y : IndexRange(key.grid_size)) {
1584 for (const int x : IndexRange(key.grid_size)) {
1585 const int i = CCG_grid_xy_to_index(key.grid_size, x, y);
1586 coord.x = x;
1587 coord.y = y;
1588
1589 int ptex_face_index;
1590 float u, v;
1591 subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, ptex_face_index, u, v);
1592
1593 r_limit_positions[i] = eval_limit_point(subdiv_ccg.subdiv, ptex_face_index, u, v);
1594 }
1595 }
1596}
1597
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Definition BKE_ccg.hh:73
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG &subdiv_ccg, const int grid_index)
SubdivCCGAdjacencyType
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define BLI_INLINE
MINLINE int bitscan_forward_i(int a)
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:58
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
IndexRange index_range() const
Definition BLI_array.hh:360
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
bool is_empty() const
Definition BLI_array.hh:264
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
bool is_empty() const
void foreach_index(Fn &&fn) const
void foreach_segment(Fn &&fn) const
int64_t size() const
void append(const T &value)
constexpr int64_t size() const
constexpr int64_t start() const
Iterator begin() const
Definition BLI_set.hh:480
Iterator end() const
Definition BLI_set.hh:490
void add_multiple(Span< Key > keys)
Definition BLI_set.hh:287
constexpr int64_t size() const
Definition BLI_span.hh:252
IndexRange index_range() const
void reinitialize(const int64_t new_size)
const OpenSubdiv::Far::TopologyLevel & base_level() const
#define printf(...)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong * next
static char faces[256]
IndexRange grid_range(const int grid_area, const int grid)
int grid_xy_to_vert(const CCGKey &key, const int grid, const int x, const int y)
int face_corner_prev(const IndexRange face, const int corner)
Definition BKE_mesh.hh:306
int face_find_corner_from_vert(const IndexRange face, const Span< int > corner_verts, const int vert)
Definition BKE_mesh.hh:327
int face_corner_next(const IndexRange face, const int corner)
Definition BKE_mesh.hh:315
void free(Subdiv *subdiv)
Definition subdiv.cc:190
float3 eval_final_point(Subdiv *subdiv, int ptex_face_index, float u, float v)
bool eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, eSubdivEvaluatorType evaluator_type, Span< float3 > coarse_vert_positions={}, OpenSubdiv_EvaluatorCache *evaluator_cache=nullptr)
float3 eval_limit_point(Subdiv *subdiv, int ptex_face_index, float u, float v)
BLI_INLINE void rotate_grid_to_quad(int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v)
void eval_limit_point_and_normal(Subdiv *subdiv, int ptex_face_index, float u, float v, float3 &r_P, float3 &r_N)
BLI_INLINE int grid_size_from_level(int level)
void stats_begin(SubdivStats *stats, StatsValue value)
void stats_end(SubdivStats *stats, StatsValue value)
Span< int > face_ptex_offset_get(Subdiv *subdiv)
Definition subdiv.cc:214
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< float, 3 > float3
int has_mask
Definition BKE_ccg.hh:48
int mask_offset
Definition BKE_ccg.hh:45
int grid_size
Definition BKE_ccg.hh:33
int grid_bytes
Definition BKE_ccg.hh:37
int grid_area
Definition BKE_ccg.hh:35
int level
Definition BKE_ccg.hh:26
int normal_offset
Definition BKE_ccg.hh:41
int elem_size
Definition BKE_ccg.hh:30
int has_normals
Definition BKE_ccg.hh:47
int corners_num
int faces_num
blender::Vector< blender::Array< SubdivCCGCoord > > boundary_coords
blender::Vector< SubdivCCGCoord > corner_coords
float(* eval_mask)(SubdivCCGMaskEvaluator *mask_evaluator, int ptex_face_index, float u, float v)
void(* free)(SubdivCCGMaskEvaluator *mask_evaluator)
SubdivCCGNeighborCoords coords
blender::Array< blender::float3 > normals
blender::BitGroupVector grid_hidden
blender::Array< float > masks
blender::Array< SubdivCCGAdjacentVertex > adjacent_verts
blender::bke::subdiv::Subdiv * subdiv
blender::OffsetIndices< int > faces
blender::Array< SubdivCCGAdjacentEdge > adjacent_edges
blender::Span< int > grid_to_face_map
blender::Array< blender::float3 > positions
void BKE_subdiv_ccg_update_normals(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG &, const SubdivCCGCoord &coord)
BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors &neighbors, const int num_unique, const int num_duplicates)
void BKE_subdiv_ccg_recalc_normals(SubdivCCG &subdiv_ccg)
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
Mesh * BKE_subdiv_to_ccg_mesh(Subdiv &subdiv, const SubdivToCCGSettings &settings, const Mesh &coarse_mesh)
static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, int &r_ptex_face_index, float &r_u, float &r_v)
bool BKE_subdiv_ccg_coord_is_mesh_boundary(const OffsetIndices< int > faces, const Span< int > corner_verts, const blender::BitSpan boundary_verts, const SubdivCCG &subdiv_ccg, const SubdivCCGCoord coord)
blender::BitGroupVector & BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg)
BLI_INLINE bool is_inner_edge_grid_coordinate(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
static void adjacent_vertices_index_from_adjacent_edge(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, const blender::Span< int > corner_verts, const blender::OffsetIndices< int > faces, int &r_v1, int &r_v2)
void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord &coord)
void BKE_subdiv_ccg_eval_limit_positions(const SubdivCCG &subdiv_ccg, const CCGKey &key, const int grid_index, const MutableSpan< float3 > r_limit_positions)
BLI_INLINE bool is_corner_grid_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
CCGKey BKE_subdiv_ccg_key(const SubdivCCG &, int level)
SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, const blender::Span< int > corner_verts, const blender::OffsetIndices< int > faces, int &r_v1, int &r_v2)
bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
void BKE_subdiv_ccg_topology_counters(const SubdivCCG &subdiv_ccg, int &r_num_vertices, int &r_num_edges, int &r_num_faces, int &r_num_loops)
void BKE_subdiv_ccg_average_grids(SubdivCCG &subdiv_ccg)
BLI_INLINE bool is_boundary_grid_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
BLI_INLINE SubdivCCGCoord coord_at_next_col(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, const bool include_duplicates, SubdivCCGNeighbors &r_neighbors)
BLI_INLINE SubdivCCGCoord coord_at_next_row(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
std::unique_ptr< SubdivCCG > BKE_subdiv_to_ccg(Subdiv &subdiv, const SubdivToCCGSettings &settings, const Mesh &coarse_mesh, SubdivCCGMaskEvaluator *mask_evaluator)
BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG &, const SubdivCCGCoord &coord)
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG &subdiv_ccg)
i
Definition text_draw.cc:230