Blender V4.5
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
8
9#include "BLI_array_utils.hh"
10#include "BLI_math_geom.h"
11
13#include "BKE_bvhutils.hh"
14#include "BKE_customdata.hh"
15#include "BKE_editmesh_cache.hh"
16#include "BKE_lib_id.hh"
17#include "BKE_mesh.hh"
18#include "BKE_mesh_mapping.hh"
19#include "BKE_mesh_runtime.hh"
20#include "BKE_shrinkwrap.hh"
21#include "BKE_subdiv_ccg.hh"
22
23using blender::float3;
25using blender::Span;
26
27/* -------------------------------------------------------------------- */
30
31namespace blender::bke {
32
33static void free_mesh_eval(MeshRuntime &mesh_runtime)
34{
35 if (mesh_runtime.mesh_eval != nullptr) {
36 BKE_id_free(nullptr, mesh_runtime.mesh_eval);
37 mesh_runtime.mesh_eval = nullptr;
38 }
39}
40
41static void free_batch_cache(MeshRuntime &mesh_runtime)
42{
43 if (mesh_runtime.batch_cache) {
45 mesh_runtime.batch_cache = nullptr;
46 }
47}
48
49static void free_bvh_caches(MeshRuntime &mesh_runtime)
50{
51 mesh_runtime.bvh_cache_verts.tag_dirty();
52 mesh_runtime.bvh_cache_edges.tag_dirty();
53 mesh_runtime.bvh_cache_faces.tag_dirty();
54 mesh_runtime.bvh_cache_corner_tris.tag_dirty();
56 mesh_runtime.bvh_cache_loose_verts.tag_dirty();
58 mesh_runtime.bvh_cache_loose_edges.tag_dirty();
60}
61
62MeshRuntime::MeshRuntime() = default;
63
69
70static int reset_bits_and_count(MutableBitSpan bits, const Span<int> indices_to_reset)
71{
72 int count = bits.size();
73 for (const int i : indices_to_reset) {
74 if (bits[i]) {
75 bits[i].reset();
76 count--;
77 }
78 }
79 return count;
80}
81
82static void bit_vector_with_reset_bits_or_empty(const Span<int> indices_to_reset,
83 const int indexed_elems_num,
84 BitVector<> &r_bits,
85 int &r_count)
86{
87 r_bits.resize(0);
88 r_bits.resize(indexed_elems_num, true);
89 r_count = reset_bits_and_count(r_bits, indices_to_reset);
90 if (r_count == 0) {
91 r_bits.clear_and_shrink();
92 }
93}
94
99{
100 if (!mesh.runtime->loose_edges_cache.is_cached() || mesh.loose_edges().count > 0) {
101 return;
102 }
103 if (!mesh.runtime->loose_verts_cache.is_cached() || mesh.loose_verts().count > 0) {
104 return;
105 }
106 mesh.runtime->verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
108 r_data.count = 0;
109 });
110}
111
112} // namespace blender::bke
113
114blender::Span<int> Mesh::corner_to_face_map() const
115{
116 using namespace blender;
117 this->runtime->corner_to_face_map_cache.ensure([&](Array<int> &r_data) {
118 const OffsetIndices faces = this->faces();
120 });
121 return this->runtime->corner_to_face_map_cache.data();
122}
123
124blender::OffsetIndices<int> Mesh::vert_to_face_map_offsets() const
125{
126 using namespace blender;
127 this->runtime->vert_to_face_offset_cache.ensure([&](Array<int> &r_data) {
128 r_data = Array<int>(this->verts_num + 1, 0);
129 offset_indices::build_reverse_offsets(this->corner_verts(), r_data);
130 });
131 return OffsetIndices<int>(this->runtime->vert_to_face_offset_cache.data());
132}
133
134blender::GroupedSpan<int> Mesh::vert_to_face_map() const
135{
136 using namespace blender;
137 const OffsetIndices offsets = this->vert_to_face_map_offsets();
138 this->runtime->vert_to_face_map_cache.ensure([&](Array<int> &r_data) {
139 r_data.reinitialize(this->corners_num);
140 if (this->runtime->vert_to_corner_map_cache.is_cached() &&
141 this->runtime->corner_to_face_map_cache.is_cached())
142 {
143 /* The vertex to face cache can be built from the vertex to face corner
144 * and face corner to face maps if they are both already cached. */
145 array_utils::gather(this->runtime->corner_to_face_map_cache.data().as_span(),
146 this->runtime->vert_to_corner_map_cache.data().as_span(),
147 r_data.as_mutable_span());
148 }
149 else {
150 bke::mesh::build_vert_to_face_indices(this->faces(), this->corner_verts(), offsets, r_data);
151 }
152 });
153 return {offsets, this->runtime->vert_to_face_map_cache.data()};
154}
155
156blender::GroupedSpan<int> Mesh::vert_to_corner_map() const
157{
158 using namespace blender;
159 const OffsetIndices offsets = this->vert_to_face_map_offsets();
160 this->runtime->vert_to_corner_map_cache.ensure([&](Array<int> &r_data) {
161 r_data = bke::mesh::build_vert_to_corner_indices(this->corner_verts(), offsets);
162 });
163 return {offsets, this->runtime->vert_to_corner_map_cache.data()};
164}
165
166const blender::bke::LooseVertCache &Mesh::loose_verts() const
167{
168 using namespace blender::bke;
169 this->runtime->loose_verts_cache.ensure([&](LooseVertCache &r_data) {
170 const Span<int> verts = this->edges().cast<int>();
172 verts, this->verts_num, r_data.is_loose_bits, r_data.count);
173 });
174 return this->runtime->loose_verts_cache.data();
175}
176
177const blender::bke::LooseVertCache &Mesh::verts_no_face() const
178{
179 using namespace blender::bke;
180 this->runtime->verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
181 const Span<int> verts = this->corner_verts();
183 verts, this->verts_num, r_data.is_loose_bits, r_data.count);
184 });
185 return this->runtime->verts_no_face_cache.data();
186}
187
188bool Mesh::no_overlapping_topology() const
189{
190 return this->flag & ME_NO_OVERLAPPING_TOPOLOGY;
191}
192
193const blender::bke::LooseEdgeCache &Mesh::loose_edges() const
194{
195 using namespace blender::bke;
196 this->runtime->loose_edges_cache.ensure([&](LooseEdgeCache &r_data) {
197 const Span<int> edges = this->corner_edges();
199 edges, this->edges_num, r_data.is_loose_bits, r_data.count);
200 });
201 return this->runtime->loose_edges_cache.data();
202}
203
204void Mesh::tag_loose_verts_none() const
205{
206 using namespace blender::bke;
207 this->runtime->loose_verts_cache.ensure([&](LooseVertCache &r_data) {
209 r_data.count = 0;
210 });
212}
213
214void Mesh::tag_loose_edges_none() const
215{
216 using namespace blender::bke;
217 this->runtime->loose_edges_cache.ensure([&](LooseEdgeCache &r_data) {
219 r_data.count = 0;
220 });
222}
223
224void Mesh::tag_overlapping_none()
225{
226 using namespace blender::bke;
228}
229
230namespace blender::bke {
231
233{
234 this->frozen = true;
235 this->dirty_while_frozen = false;
236}
237
239{
240 this->frozen = false;
241 if (this->dirty_while_frozen) {
242 this->data.tag_dirty();
243 }
244 this->dirty_while_frozen = false;
245}
246
248{
249 if (this->frozen) {
250 this->dirty_while_frozen = true;
251 }
252 else {
253 this->data.tag_dirty();
254 }
255}
256
257} // namespace blender::bke
258
259blender::Span<blender::int3> Mesh::corner_tris() const
260{
261 this->runtime->corner_tris_cache.data.ensure([&](blender::Array<blender::int3> &r_data) {
262 const Span<float3> positions = this->vert_positions();
263 const blender::OffsetIndices faces = this->faces();
264 const Span<int> corner_verts = this->corner_verts();
265
266 r_data.reinitialize(poly_to_tri_count(faces.size(), corner_verts.size()));
267
269 blender::bke::mesh::corner_tris_calc(positions, faces, corner_verts, r_data);
270 }
271 else {
273 positions, faces, corner_verts, this->face_normals(), r_data);
274 }
275 });
276
277 return this->runtime->corner_tris_cache.data.data();
278}
279
280blender::Span<int> Mesh::corner_tri_faces() const
281{
282 using namespace blender;
283 this->runtime->corner_tri_faces_cache.ensure([&](blender::Array<int> &r_data) {
284 const OffsetIndices faces = this->faces();
285 r_data.reinitialize(poly_to_tri_count(faces.size(), this->corners_num));
287 });
288 return this->runtime->corner_tri_faces_cache.data();
289}
290
292{
293 /* Allow returning the size without calculating the cache. */
294 return poly_to_tri_count(mesh->faces_num, mesh->corners_num);
295}
296
298{
299 if (!mesh->runtime->edit_data) {
300 mesh->runtime->edit_data = std::make_unique<blender::bke::EditMeshData>();
301 }
302}
303
305{
306 using namespace blender::bke;
307 free_mesh_eval(*mesh->runtime);
308 free_batch_cache(*mesh->runtime);
309 mesh->runtime->edit_data.reset();
311}
312
314{
315 /* Tagging shared caches dirty will free the allocated data if there is only one user. */
316 free_bvh_caches(*mesh->runtime);
317 mesh->runtime->subdiv_ccg.reset();
318 mesh->runtime->bounds_cache.tag_dirty();
319 mesh->runtime->vert_to_face_offset_cache.tag_dirty();
320 mesh->runtime->vert_to_face_map_cache.tag_dirty();
321 mesh->runtime->vert_to_corner_map_cache.tag_dirty();
322 mesh->runtime->corner_to_face_map_cache.tag_dirty();
323 mesh->runtime->vert_normals_cache.tag_dirty();
324 mesh->runtime->vert_normals_true_cache.tag_dirty();
325 mesh->runtime->face_normals_cache.tag_dirty();
326 mesh->runtime->face_normals_true_cache.tag_dirty();
327 mesh->runtime->corner_normals_cache.tag_dirty();
328 mesh->runtime->loose_edges_cache.tag_dirty();
329 mesh->runtime->loose_verts_cache.tag_dirty();
330 mesh->runtime->verts_no_face_cache.tag_dirty();
331 mesh->runtime->corner_tris_cache.data.tag_dirty();
332 mesh->runtime->corner_tri_faces_cache.tag_dirty();
333 mesh->runtime->shrinkwrap_boundary_cache.tag_dirty();
334 mesh->runtime->max_material_index.tag_dirty();
335 mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
336 mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
338}
339
340void Mesh::tag_edges_split()
341{
342 /* Triangulation didn't change because vertex positions and loop vertex indices didn't change. */
343 free_bvh_caches(*this->runtime);
344 this->runtime->vert_normals_cache.tag_dirty();
345 this->runtime->corner_normals_cache.tag_dirty();
346 this->runtime->subdiv_ccg.reset();
347 this->runtime->vert_to_face_offset_cache.tag_dirty();
348 this->runtime->vert_to_face_map_cache.tag_dirty();
349 this->runtime->vert_to_corner_map_cache.tag_dirty();
350 if (this->runtime->loose_edges_cache.is_cached() &&
351 this->runtime->loose_edges_cache.data().count != 0)
352 {
353 this->runtime->loose_edges_cache.tag_dirty();
354 }
355 if (this->runtime->loose_verts_cache.is_cached() &&
356 this->runtime->loose_verts_cache.data().count != 0)
357 {
358 this->runtime->loose_verts_cache.tag_dirty();
359 }
360 if (this->runtime->verts_no_face_cache.is_cached() &&
361 this->runtime->verts_no_face_cache.data().count != 0)
362 {
363 this->runtime->verts_no_face_cache.tag_dirty();
364 }
365 this->runtime->subsurf_face_dot_tags.clear_and_shrink();
366 this->runtime->subsurf_optimal_display_edges.clear_and_shrink();
367 this->runtime->shrinkwrap_boundary_cache.tag_dirty();
368}
369
370void Mesh::tag_sharpness_changed()
371{
372 this->runtime->vert_normals_cache.tag_dirty();
373 this->runtime->face_normals_cache.tag_dirty();
374 this->runtime->corner_normals_cache.tag_dirty();
375}
376
377void Mesh::tag_custom_normals_changed()
378{
379 this->runtime->vert_normals_cache.tag_dirty();
380 this->runtime->face_normals_cache.tag_dirty();
381 this->runtime->corner_normals_cache.tag_dirty();
382}
383
384void Mesh::tag_face_winding_changed()
385{
386 this->runtime->vert_normals_cache.tag_dirty();
387 this->runtime->face_normals_cache.tag_dirty();
388 this->runtime->vert_normals_true_cache.tag_dirty();
389 this->runtime->face_normals_true_cache.tag_dirty();
390 this->runtime->corner_normals_cache.tag_dirty();
391 this->runtime->vert_to_corner_map_cache.tag_dirty();
392 this->runtime->shrinkwrap_boundary_cache.tag_dirty();
393}
394
395void Mesh::tag_positions_changed()
396{
397 this->runtime->vert_normals_cache.tag_dirty();
398 this->runtime->face_normals_cache.tag_dirty();
399 this->runtime->vert_normals_true_cache.tag_dirty();
400 this->runtime->face_normals_true_cache.tag_dirty();
401 this->runtime->corner_normals_cache.tag_dirty();
402 this->runtime->shrinkwrap_boundary_cache.tag_dirty();
403 this->tag_positions_changed_no_normals();
404}
405
406void Mesh::tag_positions_changed_no_normals()
407{
408 free_bvh_caches(*this->runtime);
409 this->runtime->corner_tris_cache.tag_dirty();
410 this->runtime->bounds_cache.tag_dirty();
411 this->runtime->shrinkwrap_boundary_cache.tag_dirty();
412}
413
414void Mesh::tag_positions_changed_uniformly()
415{
416 /* The normals and triangulation didn't change, since all verts moved by the same amount. */
417 free_bvh_caches(*this->runtime);
418 this->runtime->bounds_cache.tag_dirty();
419}
420
421void Mesh::tag_topology_changed()
422{
424}
425
426void Mesh::tag_visibility_changed()
427{
428 this->runtime->bvh_cache_corner_tris_no_hidden.tag_dirty();
429 this->runtime->bvh_cache_loose_verts_no_hidden.tag_dirty();
430 this->runtime->bvh_cache_loose_edges_no_hidden.tag_dirty();
431}
432
433void Mesh::tag_material_index_changed()
434{
435 this->runtime->max_material_index.tag_dirty();
436}
437
439
440/* -------------------------------------------------------------------- */
443
444/* Draw Engine */
445
447void (*BKE_mesh_batch_cache_free_cb)(void *batch_cache) = nullptr;
448
450{
451 if (mesh->runtime->batch_cache) {
453 }
454
455 /* Also tag batch cache for subdivided mesh, if it exists this will be
456 * the mesh that is actually being drawn. */
457 Mesh *mesh_eval = mesh->runtime->mesh_eval;
458 if (mesh_eval && mesh_eval->runtime->batch_cache) {
459 BKE_mesh_batch_cache_dirty_tag_cb(mesh_eval, mode);
460 }
461}
462void BKE_mesh_batch_cache_free(void *batch_cache)
463{
464 BKE_mesh_batch_cache_free_cb(batch_cache);
465}
466
468
469/* -------------------------------------------------------------------- */
472
473#ifndef NDEBUG
474
476{
477 const bool do_verbose = true;
478 const bool do_fixes = false;
479
480 bool is_valid = true;
481 bool changed = true;
482
483 if (do_verbose) {
484 printf("MESH: %s\n", mesh_eval->id.name + 2);
485 }
486
487 MutableSpan<float3> positions = mesh_eval->vert_positions_for_write();
488 MutableSpan<blender::int2> edges = mesh_eval->edges_for_write();
489 Span<int> face_offsets = mesh_eval->face_offsets();
490 Span<int> corner_verts = mesh_eval->corner_verts();
491 MutableSpan<int> corner_edges = mesh_eval->corner_edges_for_write();
492
494 &mesh_eval->vert_data,
495 mesh_eval->verts_num,
496 &mesh_eval->edge_data,
497 mesh_eval->edges_num,
498 &mesh_eval->corner_data,
499 mesh_eval->corners_num,
500 &mesh_eval->face_data,
501 mesh_eval->faces_num,
502 false, /* setting mask here isn't useful, gives false positives */
503 do_verbose,
504 do_fixes,
505 &changed);
506
507 MDeformVert *dverts = static_cast<MDeformVert *>(
509 is_valid &= BKE_mesh_validate_arrays(
510 mesh_eval,
511 reinterpret_cast<float(*)[3]>(positions.data()),
512 positions.size(),
513 edges.data(),
514 edges.size(),
516 &mesh_eval->fdata_legacy, CD_MFACE, mesh_eval->totface_legacy)),
517 mesh_eval->totface_legacy,
518 corner_verts.data(),
519 corner_edges.data(),
520 corner_verts.size(),
521 face_offsets.data(),
522 mesh_eval->faces_num,
523 dverts,
524 do_verbose,
525 do_fixes,
526 &changed);
527
528 BLI_assert(changed == false);
529
530 return is_valid;
531}
532
533#endif /* !NDEBUG */
534
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)
eMeshBatchDirtyMode
Definition BKE_mesh.h:37
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)
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:46
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
@ CD_MDEFORMVERT
@ ME_NO_OVERLAPPING_TOPOLOGY
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr T * data() const
Definition BLI_span.hh:539
Span< NewT > constexpr cast() const
Definition BLI_span.hh:418
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
void resize(const int64_t new_size_in_bits, const bool value=false)
static float verts[][3]
#define this
#define printf(...)
int count
static char faces[256]
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void build_vert_to_face_indices(OffsetIndices< int > faces, Span< int > corner_verts, OffsetIndices< int > offsets, MutableSpan< int > face_indices)
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_bvh_caches(MeshRuntime &mesh_runtime)
static void free_batch_cache(MeshRuntime &mesh_runtime)
static void free_mesh_eval(MeshRuntime &mesh_runtime)
void build_reverse_offsets(Span< int > indices, MutableSpan< int > offsets)
VecBase< float, 3 > float3
char name[66]
Definition DNA_ID.h:415
int corners_num
CustomData edge_data
int edges_num
MeshRuntimeHandle * runtime
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
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_loose_verts
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_loose_edges_no_hidden
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_corner_tris
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_edges
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_verts
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_loose_verts_no_hidden
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_loose_edges
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_faces
SharedCache< std::unique_ptr< BVHTree, BVHTreeDeleter > > bvh_cache_corner_tris_no_hidden
SharedCache< Array< int3 > > data
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:139