Blender V5.0
mesh_wrapper.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
22
23#include "BLI_math_matrix.h"
24#include "BLI_math_vector.h"
25#include "BLI_task.hh"
26#include "BLI_utildefines.h"
27
28#include "BKE_editmesh.hh"
29#include "BKE_editmesh_cache.hh"
30#include "BKE_lib_id.hh"
31#include "BKE_mesh.hh"
32#include "BKE_mesh_runtime.hh"
33#include "BKE_mesh_wrapper.hh"
34#include "BKE_modifier.hh"
35#include "BKE_subdiv.hh"
36#include "BKE_subdiv_mesh.hh"
38
39using blender::float3;
40using blender::Span;
41
42Mesh *BKE_mesh_wrapper_from_editmesh(std::shared_ptr<BMEditMesh> em,
43 const CustomData_MeshMasks *cd_mask_extra,
44 const Mesh *me_settings)
45{
46 Mesh *mesh = BKE_id_new_nomain<Mesh>(nullptr);
47 BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
49
50 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_BMESH;
51 if (cd_mask_extra) {
52 mesh->runtime->cd_mask_extra = *cd_mask_extra;
53 }
54
55 /* Use edit-mesh directly where possible. */
56 mesh->runtime->is_original_bmesh = true;
57
58 /* Until the mesh is modified destructively it can be considered "deformed". */
59 mesh->runtime->deformed_only = true;
60
61 mesh->runtime->edit_mesh = std::move(em);
62
63 /* Make sure we crash if these are ever used. */
64#ifndef NDEBUG
65 mesh->verts_num = INT_MAX;
66 mesh->edges_num = INT_MAX;
67 mesh->faces_num = INT_MAX;
68 mesh->corners_num = INT_MAX;
69#else
70 mesh->verts_num = 0;
71 mesh->edges_num = 0;
72 mesh->faces_num = 0;
73 mesh->corners_num = 0;
74#endif
75
76 return mesh;
77}
78
80{
81 if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) {
82 return;
83 }
84
85 /* Double checked lock. */
86 std::lock_guard lock{mesh->runtime->eval_mutex};
87 if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) {
88 return;
89 }
90
91 /* Must isolate multithreaded tasks while holding a mutex lock. */
93 if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
94 mesh->verts_num = 0;
95 mesh->edges_num = 0;
96 mesh->faces_num = 0;
97 mesh->corners_num = 0;
98
99 BLI_assert(mesh->runtime->edit_mesh != nullptr);
100 BLI_assert(mesh->runtime->edit_data != nullptr);
101
102 BMEditMesh *em = mesh->runtime->edit_mesh.get();
103 BM_mesh_bm_to_me_for_eval(*em->bm, *mesh, &mesh->runtime->cd_mask_extra);
104
105 /* Adding original index layers here assumes that all BMesh Mesh wrappers are created from
106 * original edit mode meshes (the only case where adding original indices makes sense).
107 * If that assumption is broken, the layers might be incorrect because they might not
108 * actually be "original".
109 *
110 * There is also a performance aspect, where this also assumes that original indices are
111 * always needed when converting a BMesh to a mesh with the mesh wrapper system. That might
112 * be wrong, but it's not harmful. */
114
115 blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
116 if (!edit_data.vert_positions.is_empty()) {
117 mesh->vert_positions_for_write().copy_from(edit_data.vert_positions);
118 mesh->runtime->is_original_bmesh = false;
119 }
120
121 mesh->runtime->edit_data.reset();
122 }
123 else if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) {
124 BLI_assert(!"Should not be converting subd wrapper to mdata wrapper");
125 }
126
127 /* Keep type assignment last, so that read-only access only uses the mdata code paths after all
128 * the underlying data has been initialized. */
129 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_MDATA;
130 });
131}
132
133/* -------------------------------------------------------------------- */
136
138{
139 switch (mesh->runtime->wrapper_type) {
141 return mesh->runtime->edit_data->vert_positions;
144 return mesh->vert_positions();
145 }
147 return {};
148}
149
151{
152 switch (mesh->runtime->wrapper_type) {
154 return BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh,
155 *mesh->runtime->edit_data);
158 return mesh->face_normals();
159 }
161 return {};
162}
163
165{
166 switch (mesh->runtime->wrapper_type) {
168 if (blender::bke::EditMeshData *edit_data = mesh->runtime->edit_data.get()) {
169 edit_data->vert_normals = {};
170 edit_data->face_centers = {};
171 edit_data->face_normals = {};
172 }
173 break;
176 mesh->tag_positions_changed();
177 break;
178 }
179}
180
182{
183 switch (mesh->runtime->wrapper_type) {
185 BMesh *bm = mesh->runtime->edit_mesh->bm;
186 const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
187 if (!edit_data.vert_positions.is_empty()) {
188 positions.copy_from(edit_data.vert_positions);
189 }
190 else {
191 BMIter iter;
192 BMVert *v;
193 int i;
195 copy_v3_v3(positions[i], v->co);
196 }
197 }
198 return;
199 }
202 positions.copy_from(mesh->vert_positions());
203 return;
204 }
205 }
207}
208
210 float (*vert_coords)[3],
211 int vert_coords_len,
212 const float mat[4][4])
213{
214 switch (mesh->runtime->wrapper_type) {
216 BMesh *bm = mesh->runtime->edit_mesh->bm;
217 BLI_assert(vert_coords_len == bm->totvert);
218 const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
219 if (!edit_data.vert_positions.is_empty()) {
220 for (int i = 0; i < vert_coords_len; i++) {
221 mul_v3_m4v3(vert_coords[i], mat, edit_data.vert_positions[i]);
222 }
223 }
224 else {
225 BMIter iter;
226 BMVert *v;
227 int i;
229 mul_v3_m4v3(vert_coords[i], mat, v->co);
230 }
231 }
232 return;
233 }
236 BLI_assert(vert_coords_len == mesh->verts_num);
237 const Span<float3> positions = mesh->vert_positions();
238 for (int i = 0; i < vert_coords_len; i++) {
239 mul_v3_m4v3(vert_coords[i], mat, positions[i]);
240 }
241 return;
242 }
243 }
245}
246
248
249/* -------------------------------------------------------------------- */
252
254{
255 switch (mesh->runtime->wrapper_type) {
257 return mesh->runtime->edit_mesh->bm->totvert;
260 return mesh->verts_num;
261 }
263 return -1;
264}
265
267{
268 switch (mesh->runtime->wrapper_type) {
270 return mesh->runtime->edit_mesh->bm->totedge;
273 return mesh->edges_num;
274 }
276 return -1;
277}
278
280{
281 switch (mesh->runtime->wrapper_type) {
283 return mesh->runtime->edit_mesh->bm->totloop;
286 return mesh->corners_num;
287 }
289 return -1;
290}
291
293{
294 switch (mesh->runtime->wrapper_type) {
296 return mesh->runtime->edit_mesh->bm->totface;
299 return mesh->faces_num;
300 }
302 return -1;
303}
304
306
307/* -------------------------------------------------------------------- */
310
312{
313 using namespace blender::bke;
314 SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data;
315 if (runtime_data->settings.level == 0) {
316 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD;
317 return mesh;
318 }
319
320 /* Initialize the settings before ensuring the descriptor as this is checked to decide whether
321 * subdivision is needed at all, and checking the descriptor status might involve checking if the
322 * data is out-of-date, which is a very expensive operation. */
323 subdiv::ToMeshSettings mesh_settings;
324 mesh_settings.resolution = runtime_data->resolution;
325 mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
326
327 if (mesh_settings.resolution < 3) {
328 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD;
329 return mesh;
330 }
331
333 runtime_data, mesh, false);
334 if (subdiv == nullptr) {
335 /* Happens on bad topology, but also on empty input mesh. */
336 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD;
337 return mesh;
338 }
339 const bool use_clnors = runtime_data->use_loop_normals;
340 if (use_clnors) {
341 /* If custom normals are present and the option is turned on calculate the split
342 * normals and clear flag so the normals get interpolated to the result mesh. */
344 &mesh->corner_data, CD_NORMAL, CD_CONSTRUCT, mesh->corners_num);
345 memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
346 }
347
348 Mesh *subdiv_mesh = subdiv::subdiv_to_mesh(subdiv, &mesh_settings, mesh);
349
350 if (use_clnors) {
352 *subdiv_mesh,
354 &subdiv_mesh->corner_data, CD_NORMAL, subdiv_mesh->corners_num)),
355 subdiv_mesh->corners_num});
357 }
358
359 if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
361 }
362
363 if (subdiv_mesh != mesh) {
364 /* Make sure that drivers can target shapekey properties. See #mesh_build_data for details. */
365 subdiv_mesh->key = mesh->key;
366
367 if (mesh->runtime->mesh_eval != nullptr) {
368 BKE_id_free(nullptr, mesh->runtime->mesh_eval);
369 }
370 mesh->runtime->mesh_eval = subdiv_mesh;
371 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD;
372 BLI_assert(mesh->runtime->mesh_eval != nullptr);
373 }
374
375 return mesh->runtime->mesh_eval;
376}
377
379{
380 if (mesh->runtime->subsurf_runtime_data == nullptr) {
381 return mesh;
382 }
383
384 if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) {
385 /* Subdiv evaluation might have been skipped, in which case the original mesh is ok. */
386 return (mesh->runtime->mesh_eval) ? mesh->runtime->mesh_eval : mesh;
387 }
388
389 /* Double checked lock. */
390 std::lock_guard lock{mesh->runtime->eval_mutex};
391 if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) {
392 return (mesh->runtime->mesh_eval) ? mesh->runtime->mesh_eval : mesh;
393 }
394
395 /* Must isolate multithreaded tasks while holding a mutex lock. */
396 Mesh *result;
398 return result;
399}
400
402{
403 /* This modifies the mesh, but it's lazy initialization protected by mutex lock
404 * so still read-only access in a sense. */
405 return BKE_mesh_wrapper_ensure_subdivision(const_cast<Mesh *>(mesh));
406}
407
@ CD_CONSTRUCT
void CustomData_free_layers(CustomData *data, eCustomDataType type)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
blender::Span< blender::float3 > BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMeshData &emd)
void BKE_id_free(Main *bmain, void *idv)
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1519
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
void BKE_mesh_ensure_default_orig_index_customdata_no_check(Mesh *mesh)
void BKE_mesh_runtime_ensure_edit_data(Mesh *mesh)
@ ME_WRAPPER_TYPE_MDATA
@ ME_WRAPPER_TYPE_SUBD
@ ME_WRAPPER_TYPE_BMESH
blender::bke::subdiv::Subdiv * BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data, const Mesh *mesh, bool for_draw_code)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define ELEM(...)
volatile int lock
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_VERTS_OF_MESH
BMesh const char void * data
BMesh * bm
void BM_mesh_bm_to_me_for_eval(BMesh &bm, Mesh &mesh, const CustomData_MeshMasks *cd_mask_extra)
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
Span< float3 > BKE_mesh_wrapper_vert_coords(const Mesh *mesh)
Span< float3 > BKE_mesh_wrapper_face_normals(Mesh *mesh)
static Mesh * mesh_wrapper_ensure_subdivision(Mesh *mesh)
void BKE_mesh_wrapper_vert_coords_copy(const Mesh *mesh, blender::MutableSpan< float3 > positions)
Mesh * BKE_mesh_wrapper_from_editmesh(std::shared_ptr< BMEditMesh > em, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings)
int BKE_mesh_wrapper_loop_len(const Mesh *mesh)
int BKE_mesh_wrapper_vert_len(const Mesh *mesh)
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
int BKE_mesh_wrapper_edge_len(const Mesh *mesh)
void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh)
void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *mesh, float(*vert_coords)[3], int vert_coords_len, const float mat[4][4])
int BKE_mesh_wrapper_face_len(const Mesh *mesh)
Mesh * BKE_mesh_wrapper_ensure_subdivision(Mesh *mesh)
void free(Subdiv *subdiv)
Definition subdiv.cc:190
Mesh * subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh *coarse_mesh)
void mesh_set_custom_normals_normalized(Mesh &mesh, MutableSpan< float3 > corner_normals)
void isolate_task(const Function &function)
Definition BLI_task.hh:248
VecBase< float, 3 > float3
int corners_num
int edges_num
MeshRuntimeHandle * runtime
CustomData corner_data
struct Key * key
int faces_num
int verts_num
blender::bke::subdiv::Settings settings
blender::bke::subdiv::Subdiv * subdiv_cpu
blender::bke::subdiv::Subdiv * subdiv_gpu
i
Definition text_draw.cc:230