Blender V4.3
mesh_runtime.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "BLI_array_utils.hh"
12#include "BLI_math_geom.h"
13#include "BLI_task.hh"
14
16#include "BKE_bvhutils.hh"
17#include "BKE_customdata.hh"
18#include "BKE_editmesh_cache.hh"
19#include "BKE_lib_id.hh"
20#include "BKE_mesh.hh"
21#include "BKE_mesh_mapping.hh"
22#include "BKE_mesh_runtime.hh"
23#include "BKE_shrinkwrap.hh"
24#include "BKE_subdiv_ccg.hh"
25
26using blender::float3;
28using blender::Span;
29
30/* -------------------------------------------------------------------- */
34namespace blender::bke {
35
36static void free_mesh_eval(MeshRuntime &mesh_runtime)
37{
38 if (mesh_runtime.mesh_eval != nullptr) {
39 BKE_id_free(nullptr, mesh_runtime.mesh_eval);
40 mesh_runtime.mesh_eval = nullptr;
41 }
42}
43
44static void free_bvh_cache(MeshRuntime &mesh_runtime)
45{
46 if (mesh_runtime.bvh_cache) {
47 bvhcache_free(mesh_runtime.bvh_cache);
48 mesh_runtime.bvh_cache = nullptr;
49 }
50}
51
52static void free_batch_cache(MeshRuntime &mesh_runtime)
53{
54 if (mesh_runtime.batch_cache) {
56 mesh_runtime.batch_cache = nullptr;
57 }
58}
59
60MeshRuntime::MeshRuntime() = default;
61
68
69static int reset_bits_and_count(MutableBitSpan bits, const Span<int> indices_to_reset)
70{
71 int count = bits.size();
72 for (const int i : indices_to_reset) {
73 if (bits[i]) {
74 bits[i].reset();
75 count--;
76 }
77 }
78 return count;
79}
80
81static void bit_vector_with_reset_bits_or_empty(const Span<int> indices_to_reset,
82 const int indexed_elems_num,
83 BitVector<> &r_bits,
84 int &r_count)
85{
86 r_bits.resize(0);
87 r_bits.resize(indexed_elems_num, true);
88 r_count = reset_bits_and_count(r_bits, indices_to_reset);
89 if (r_count == 0) {
90 r_bits.clear_and_shrink();
91 }
92}
93
97static void try_tag_verts_no_face_none(const Mesh &mesh)
98{
99 if (!mesh.runtime->loose_edges_cache.is_cached() || mesh.loose_edges().count > 0) {
100 return;
101 }
102 if (!mesh.runtime->loose_verts_cache.is_cached() || mesh.loose_verts().count > 0) {
103 return;
104 }
105 mesh.runtime->verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
107 r_data.count = 0;
108 });
109}
110
111} // namespace blender::bke
112
113blender::Span<int> Mesh::corner_to_face_map() const
114{
115 using namespace blender;
116 this->runtime->corner_to_face_map_cache.ensure([&](Array<int> &r_data) {
117 const OffsetIndices faces = this->faces();
119 });
120 return this->runtime->corner_to_face_map_cache.data();
121}
122
123blender::OffsetIndices<int> Mesh::vert_to_face_map_offsets() const
124{
125 using namespace blender;
126 this->runtime->vert_to_face_offset_cache.ensure([&](Array<int> &r_data) {
127 r_data = Array<int>(this->verts_num + 1, 0);
128 offset_indices::build_reverse_offsets(this->corner_verts(), r_data);
129 });
130 return OffsetIndices<int>(this->runtime->vert_to_face_offset_cache.data());
131}
132
133blender::GroupedSpan<int> Mesh::vert_to_face_map() const
134{
135 using namespace blender;
136 const OffsetIndices offsets = this->vert_to_face_map_offsets();
137 this->runtime->vert_to_face_map_cache.ensure([&](Array<int> &r_data) {
138 r_data.reinitialize(this->corners_num);
139 if (this->runtime->vert_to_corner_map_cache.is_cached() &&
140 this->runtime->corner_to_face_map_cache.is_cached())
141 {
142 /* The vertex to face cache can be built from the vertex to face corner
143 * and face corner to face maps if they are both already cached. */
144 array_utils::gather(this->runtime->corner_to_face_map_cache.data().as_span(),
145 this->runtime->vert_to_corner_map_cache.data().as_span(),
146 r_data.as_mutable_span());
147 }
148 else {
149 bke::mesh::build_vert_to_face_indices(this->faces(), this->corner_verts(), offsets, r_data);
150 }
151 });
152 return {offsets, this->runtime->vert_to_face_map_cache.data()};
153}
154
155blender::GroupedSpan<int> Mesh::vert_to_corner_map() const
156{
157 using namespace blender;
158 const OffsetIndices offsets = this->vert_to_face_map_offsets();
159 this->runtime->vert_to_corner_map_cache.ensure([&](Array<int> &r_data) {
160 r_data = bke::mesh::build_vert_to_corner_indices(this->corner_verts(), offsets);
161 });
162 return {offsets, this->runtime->vert_to_corner_map_cache.data()};
163}
164
165const blender::bke::LooseVertCache &Mesh::loose_verts() const
166{
167 using namespace blender::bke;
168 this->runtime->loose_verts_cache.ensure([&](LooseVertCache &r_data) {
169 const Span<int> verts = this->edges().cast<int>();
171 verts, this->verts_num, r_data.is_loose_bits, r_data.count);
172 });
173 return this->runtime->loose_verts_cache.data();
174}
175
176const blender::bke::LooseVertCache &Mesh::verts_no_face() const
177{
178 using namespace blender::bke;
179 this->runtime->verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
180 const Span<int> verts = this->corner_verts();
182 verts, this->verts_num, r_data.is_loose_bits, r_data.count);
183 });
184 return this->runtime->verts_no_face_cache.data();
185}
186
187bool Mesh::no_overlapping_topology() const
188{
189 return this->flag & ME_NO_OVERLAPPING_TOPOLOGY;
190}
191
192const blender::bke::LooseEdgeCache &Mesh::loose_edges() const
193{
194 using namespace blender::bke;
195 this->runtime->loose_edges_cache.ensure([&](LooseEdgeCache &r_data) {
196 const Span<int> edges = this->corner_edges();
198 edges, this->edges_num, r_data.is_loose_bits, r_data.count);
199 });
200 return this->runtime->loose_edges_cache.data();
201}
202
203void Mesh::tag_loose_verts_none() const
204{
205 using namespace blender::bke;
206 this->runtime->loose_verts_cache.ensure([&](LooseVertCache &r_data) {
208 r_data.count = 0;
209 });
211}
212
213void Mesh::tag_loose_edges_none() const
214{
215 using namespace blender::bke;
216 this->runtime->loose_edges_cache.ensure([&](LooseEdgeCache &r_data) {
218 r_data.count = 0;
219 });
221}
222
223void Mesh::tag_overlapping_none()
224{
225 using namespace blender::bke;
227}
228
229namespace blender::bke {
230
231void TrianglesCache::freeze()
232{
233 this->frozen = true;
234 this->dirty_while_frozen = false;
235}
236
237void TrianglesCache::unfreeze()
238{
239 this->frozen = false;
240 if (this->dirty_while_frozen) {
241 this->data.tag_dirty();
242 }
243 this->dirty_while_frozen = false;
244}
245
246void TrianglesCache::tag_dirty()
247{
248 if (this->frozen) {
249 this->dirty_while_frozen = true;
250 }
251 else {
252 this->data.tag_dirty();
253 }
254}
255
256} // namespace blender::bke
257
258blender::Span<blender::int3> Mesh::corner_tris() const
259{
260 this->runtime->corner_tris_cache.data.ensure([&](blender::Array<blender::int3> &r_data) {
261 const Span<float3> positions = this->vert_positions();
262 const blender::OffsetIndices faces = this->faces();
263 const Span<int> corner_verts = this->corner_verts();
264
265 r_data.reinitialize(poly_to_tri_count(faces.size(), corner_verts.size()));
266
268 blender::bke::mesh::corner_tris_calc(positions, faces, corner_verts, r_data);
269 }
270 else {
272 positions, faces, corner_verts, this->face_normals(), r_data);
273 }
274 });
275
276 return this->runtime->corner_tris_cache.data.data();
277}
278
279blender::Span<int> Mesh::corner_tri_faces() const
280{
281 using namespace blender;
282 this->runtime->corner_tri_faces_cache.ensure([&](blender::Array<int> &r_data) {
283 const OffsetIndices faces = this->faces();
284 r_data.reinitialize(poly_to_tri_count(faces.size(), this->corners_num));
286 });
287 return this->runtime->corner_tri_faces_cache.data();
288}
289
291{
292 /* Allow returning the size without calculating the cache. */
293 return poly_to_tri_count(mesh->faces_num, mesh->corners_num);
294}
295
297{
298 if (!mesh->runtime->edit_data) {
299 mesh->runtime->edit_data = std::make_unique<blender::bke::EditMeshData>();
300 }
301}
302
304{
305 using namespace blender::bke;
306 free_mesh_eval(*mesh->runtime);
307 free_batch_cache(*mesh->runtime);
308 mesh->runtime->edit_data.reset();
310}
311
313{
314 /* Tagging shared caches dirty will free the allocated data if there is only one user. */
315 free_bvh_cache(*mesh->runtime);
316 mesh->runtime->subdiv_ccg.reset();
317 mesh->runtime->bounds_cache.tag_dirty();
318 mesh->runtime->vert_to_face_offset_cache.tag_dirty();
319 mesh->runtime->vert_to_face_map_cache.tag_dirty();
320 mesh->runtime->vert_to_corner_map_cache.tag_dirty();
321 mesh->runtime->corner_to_face_map_cache.tag_dirty();
322 mesh->runtime->vert_normals_cache.tag_dirty();
323 mesh->runtime->face_normals_cache.tag_dirty();
324 mesh->runtime->corner_normals_cache.tag_dirty();
325 mesh->runtime->loose_edges_cache.tag_dirty();
326 mesh->runtime->loose_verts_cache.tag_dirty();
327 mesh->runtime->verts_no_face_cache.tag_dirty();
328 mesh->runtime->corner_tris_cache.data.tag_dirty();
329 mesh->runtime->corner_tri_faces_cache.tag_dirty();
330 mesh->runtime->shrinkwrap_boundary_cache.tag_dirty();
331 mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
332 mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
333 mesh->flag &= ~ME_NO_OVERLAPPING_TOPOLOGY;
334}
335
336void Mesh::tag_edges_split()
337{
338 /* Triangulation didn't change because vertex positions and loop vertex indices didn't change. */
339 free_bvh_cache(*this->runtime);
340 this->runtime->vert_normals_cache.tag_dirty();
341 this->runtime->subdiv_ccg.reset();
342 this->runtime->vert_to_face_offset_cache.tag_dirty();
343 this->runtime->vert_to_face_map_cache.tag_dirty();
344 this->runtime->vert_to_corner_map_cache.tag_dirty();
345 if (this->runtime->loose_edges_cache.is_cached() &&
346 this->runtime->loose_edges_cache.data().count != 0)
347 {
348 this->runtime->loose_edges_cache.tag_dirty();
349 }
350 if (this->runtime->loose_verts_cache.is_cached() &&
351 this->runtime->loose_verts_cache.data().count != 0)
352 {
353 this->runtime->loose_verts_cache.tag_dirty();
354 }
355 if (this->runtime->verts_no_face_cache.is_cached() &&
356 this->runtime->verts_no_face_cache.data().count != 0)
357 {
358 this->runtime->verts_no_face_cache.tag_dirty();
359 }
360 this->runtime->subsurf_face_dot_tags.clear_and_shrink();
361 this->runtime->subsurf_optimal_display_edges.clear_and_shrink();
362 this->runtime->shrinkwrap_boundary_cache.tag_dirty();
363}
364
365void Mesh::tag_sharpness_changed()
366{
367 this->runtime->corner_normals_cache.tag_dirty();
368}
369
370void Mesh::tag_custom_normals_changed()
371{
372 this->runtime->corner_normals_cache.tag_dirty();
373}
374
375void Mesh::tag_face_winding_changed()
376{
377 this->runtime->vert_normals_cache.tag_dirty();
378 this->runtime->face_normals_cache.tag_dirty();
379 this->runtime->corner_normals_cache.tag_dirty();
380 this->runtime->vert_to_corner_map_cache.tag_dirty();
381 this->runtime->shrinkwrap_boundary_cache.tag_dirty();
382}
383
384void Mesh::tag_positions_changed()
385{
386 this->runtime->vert_normals_cache.tag_dirty();
387 this->runtime->face_normals_cache.tag_dirty();
388 this->runtime->corner_normals_cache.tag_dirty();
389 this->runtime->shrinkwrap_boundary_cache.tag_dirty();
390 this->tag_positions_changed_no_normals();
391}
392
393void Mesh::tag_positions_changed_no_normals()
394{
395 free_bvh_cache(*this->runtime);
396 this->runtime->corner_tris_cache.tag_dirty();
397 this->runtime->bounds_cache.tag_dirty();
398 this->runtime->shrinkwrap_boundary_cache.tag_dirty();
399}
400
401void Mesh::tag_positions_changed_uniformly()
402{
403 /* The normals and triangulation didn't change, since all verts moved by the same amount. */
404 free_bvh_cache(*this->runtime);
405 this->runtime->bounds_cache.tag_dirty();
406}
407
408void Mesh::tag_topology_changed()
409{
411}
412
415/* -------------------------------------------------------------------- */
419/* Draw Engine */
420
422void (*BKE_mesh_batch_cache_free_cb)(void *batch_cache) = nullptr;
423
425{
426 if (mesh->runtime->batch_cache) {
428 }
429}
430void BKE_mesh_batch_cache_free(void *batch_cache)
431{
432 BKE_mesh_batch_cache_free_cb(batch_cache);
433}
434
437/* -------------------------------------------------------------------- */
441#ifndef NDEBUG
442
444{
445 const bool do_verbose = true;
446 const bool do_fixes = false;
447
448 bool is_valid = true;
449 bool changed = true;
450
451 if (do_verbose) {
452 printf("MESH: %s\n", mesh_eval->id.name + 2);
453 }
454
455 MutableSpan<float3> positions = mesh_eval->vert_positions_for_write();
456 MutableSpan<blender::int2> edges = mesh_eval->edges_for_write();
457 Span<int> face_offsets = mesh_eval->face_offsets();
458 Span<int> corner_verts = mesh_eval->corner_verts();
459 MutableSpan<int> corner_edges = mesh_eval->corner_edges_for_write();
460
462 &mesh_eval->vert_data,
463 mesh_eval->verts_num,
464 &mesh_eval->edge_data,
465 mesh_eval->edges_num,
466 &mesh_eval->corner_data,
467 mesh_eval->corners_num,
468 &mesh_eval->face_data,
469 mesh_eval->faces_num,
470 false, /* setting mask here isn't useful, gives false positives */
471 do_verbose,
472 do_fixes,
473 &changed);
474
475 MDeformVert *dverts = static_cast<MDeformVert *>(
478 mesh_eval,
479 reinterpret_cast<float(*)[3]>(positions.data()),
480 positions.size(),
481 edges.data(),
482 edges.size(),
484 &mesh_eval->fdata_legacy, CD_MFACE, mesh_eval->totface_legacy)),
485 mesh_eval->totface_legacy,
486 corner_verts.data(),
487 corner_edges.data(),
488 corner_verts.size(),
489 face_offsets.data(),
490 mesh_eval->faces_num,
491 dverts,
492 do_verbose,
493 do_fixes,
494 &changed);
495
496 BLI_assert(changed == false);
497
498 return is_valid;
499}
500
501#endif /* !NDEBUG */
502
void bvhcache_free(BVHCache *bvh_cache)
Definition bvhutils.cc:132
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void BKE_id_free(Main *bmain, void *idv)
void BKE_mesh_batch_cache_dirty_tag(Mesh *mesh, eMeshBatchDirtyMode mode)
void(* BKE_mesh_batch_cache_free_cb)(void *batch_cache)
bool BKE_mesh_validate_all_customdata(CustomData *vert_data, uint verts_num, CustomData *edge_data, uint edges_num, CustomData *corner_data, uint corners_num, CustomData *face_data, uint faces_num, bool check_meshmask, bool do_verbose, bool do_fixes, bool *r_change)
void(* BKE_mesh_batch_cache_dirty_tag_cb)(Mesh *mesh, eMeshBatchDirtyMode mode)
void BKE_mesh_batch_cache_free(void *batch_cache)
bool BKE_mesh_face_normals_are_dirty(const Mesh *mesh)
eMeshBatchDirtyMode
Definition BKE_mesh.h:37
bool BKE_mesh_validate_arrays(Mesh *mesh, float(*vert_positions)[3], unsigned int verts_num, blender::int2 *edges, unsigned int edges_num, MFace *legacy_faces, unsigned int legacy_faces_num, const int *corner_verts, int *corner_edges, unsigned int corners_num, const int *face_offsets, unsigned int faces_num, MDeformVert *dverts, bool do_verbose, bool do_fixes, bool *r_change)
bool BKE_mesh_runtime_is_valid(Mesh *mesh_eval)
void BKE_mesh_runtime_ensure_edit_data(Mesh *mesh)
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
int BKE_mesh_runtime_corner_tris_len(const Mesh *mesh)
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
@ CD_MDEFORMVERT
@ ME_NO_OVERLAPPING_TOPOLOGY
Read Guarded memory(de)allocation.
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
constexpr T * data() const
Definition BLI_span.hh:540
Span< NewT > constexpr cast() const
Definition BLI_span.hh:419
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
void resize(const int64_t new_size_in_bits, const bool value=false)
#define printf
static float verts[][3]
int count
static char faces[256]
void corner_tris_calc(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, MutableSpan< int3 > corner_tris)
Array< int > build_corner_to_face_map(OffsetIndices< int > faces)
Array< int > build_vert_to_corner_indices(Span< int > corner_verts, OffsetIndices< int > offsets)
void corner_tris_calc_with_normals(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< float3 > face_normals, MutableSpan< int3 > corner_tris)
void corner_tris_calc_face_indices(OffsetIndices< int > faces, MutableSpan< int > tri_faces)
static void try_tag_verts_no_face_none(const Mesh &mesh)
static void bit_vector_with_reset_bits_or_empty(const Span< int > indices_to_reset, const int indexed_elems_num, BitVector<> &r_bits, int &r_count)
static int reset_bits_and_count(MutableBitSpan bits, const Span< int > indices_to_reset)
static void free_batch_cache(MeshRuntime &mesh_runtime)
static void free_mesh_eval(MeshRuntime &mesh_runtime)
static void free_bvh_cache(MeshRuntime &mesh_runtime)
void build_reverse_offsets(Span< int > indices, MutableSpan< int > offsets)
char name[66]
Definition DNA_ID.h:425
int corners_num
CustomData edge_data
int edges_num
CustomData corner_data
CustomData face_data
CustomData vert_data
CustomData fdata_legacy
int totface_legacy
int faces_num
int verts_num
blender::BitVector is_loose_bits
uint8_t flag
Definition wm_window.cc:138