Blender V4.3
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
23#include "MEM_guardedalloc.h"
24
25#include "DNA_modifier_types.h"
26#include "DNA_object_types.h"
27
28#include "BLI_ghash.h"
29#include "BLI_math_matrix.h"
30#include "BLI_math_vector.h"
31#include "BLI_math_vector.hh"
32#include "BLI_task.hh"
33#include "BLI_threads.h"
34#include "BLI_utildefines.h"
35
36#include "BKE_editmesh.hh"
37#include "BKE_editmesh_cache.hh"
38#include "BKE_lib_id.hh"
39#include "BKE_mesh.hh"
40#include "BKE_mesh_runtime.hh"
41#include "BKE_mesh_wrapper.hh"
42#include "BKE_modifier.hh"
43#include "BKE_object.hh"
44#include "BKE_subdiv.hh"
45#include "BKE_subdiv_mesh.hh"
47
48#include "DEG_depsgraph.hh"
50
51using blender::float3;
52using blender::Span;
53
54Mesh *BKE_mesh_wrapper_from_editmesh(std::shared_ptr<BMEditMesh> em,
55 const CustomData_MeshMasks *cd_mask_extra,
56 const Mesh *me_settings)
57{
58 Mesh *mesh = static_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
59 BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
61
62 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_BMESH;
63 if (cd_mask_extra) {
64 mesh->runtime->cd_mask_extra = *cd_mask_extra;
65 }
66
67 /* Use edit-mesh directly where possible. */
68 mesh->runtime->is_original_bmesh = true;
69
70 /* Until the mesh is modified destructively it can be considered "deformed". */
71 mesh->runtime->deformed_only = true;
72
73 mesh->runtime->edit_mesh = std::move(em);
74
75 /* Make sure we crash if these are ever used. */
76#ifndef NDEBUG
77 mesh->verts_num = INT_MAX;
78 mesh->edges_num = INT_MAX;
79 mesh->faces_num = INT_MAX;
80 mesh->corners_num = INT_MAX;
81#else
82 mesh->verts_num = 0;
83 mesh->edges_num = 0;
84 mesh->faces_num = 0;
85 mesh->corners_num = 0;
86#endif
87
88 return mesh;
89}
90
92{
93 std::lock_guard lock{mesh->runtime->eval_mutex};
94 if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) {
95 return;
96 }
97
98 /* Must isolate multithreaded tasks while holding a mutex lock. */
100 switch (static_cast<eMeshWrapperType>(mesh->runtime->wrapper_type)) {
101 case ME_WRAPPER_TYPE_MDATA:
102 case ME_WRAPPER_TYPE_SUBD: {
103 break; /* Quiet warning. */
104 }
106 mesh->verts_num = 0;
107 mesh->edges_num = 0;
108 mesh->faces_num = 0;
109 mesh->corners_num = 0;
110
111 BLI_assert(mesh->runtime->edit_mesh != nullptr);
112 BLI_assert(mesh->runtime->edit_data != nullptr);
113
114 BMEditMesh *em = mesh->runtime->edit_mesh.get();
115 BM_mesh_bm_to_me_for_eval(*em->bm, *mesh, &mesh->runtime->cd_mask_extra);
116
117 /* Adding original index layers here assumes that all BMesh Mesh wrappers are created from
118 * original edit mode meshes (the only case where adding original indices makes sense).
119 * If that assumption is broken, the layers might be incorrect because they might not
120 * actually be "original".
121 *
122 * There is also a performance aspect, where this also assumes that original indices are
123 * always needed when converting a BMesh to a mesh with the mesh wrapper system. That might
124 * be wrong, but it's not harmful. */
126
127 blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
128 if (!edit_data.vert_positions.is_empty()) {
129 mesh->vert_positions_for_write().copy_from(edit_data.vert_positions);
130 mesh->runtime->is_original_bmesh = false;
131 }
132
133 mesh->runtime->edit_data.reset();
134 break;
135 }
136 }
137
138 /* Keep type assignment last, so that read-only access only uses the mdata code paths after all
139 * the underlying data has been initialized. */
140 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_MDATA;
141 });
142}
143
144/* -------------------------------------------------------------------- */
149{
150 switch (mesh->runtime->wrapper_type) {
152 return mesh->runtime->edit_data->vert_positions;
155 return mesh->vert_positions();
156 }
158 return {};
159}
160
162{
163 switch (mesh->runtime->wrapper_type) {
165 return BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh,
166 *mesh->runtime->edit_data);
169 return mesh->face_normals();
170 }
172 return {};
173}
174
176{
177 switch (mesh->runtime->wrapper_type) {
179 if (blender::bke::EditMeshData *edit_data = mesh->runtime->edit_data.get()) {
180 edit_data->vert_normals = {};
181 edit_data->face_centers = {};
182 edit_data->face_normals = {};
183 }
184 break;
187 mesh->tag_positions_changed();
188 break;
189 }
190}
191
193{
194 switch (mesh->runtime->wrapper_type) {
196 BMesh *bm = mesh->runtime->edit_mesh->bm;
197 const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
198 if (!edit_data.vert_positions.is_empty()) {
199 positions.copy_from(edit_data.vert_positions);
200 }
201 else {
202 BMIter iter;
203 BMVert *v;
204 int i;
206 copy_v3_v3(positions[i], v->co);
207 }
208 }
209 return;
210 }
213 positions.copy_from(mesh->vert_positions());
214 return;
215 }
216 }
218}
219
221 float (*vert_coords)[3],
222 int vert_coords_len,
223 const float mat[4][4])
224{
225 switch (mesh->runtime->wrapper_type) {
227 BMesh *bm = mesh->runtime->edit_mesh->bm;
228 BLI_assert(vert_coords_len == bm->totvert);
229 const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
230 if (!edit_data.vert_positions.is_empty()) {
231 for (int i = 0; i < vert_coords_len; i++) {
232 mul_v3_m4v3(vert_coords[i], mat, edit_data.vert_positions[i]);
233 }
234 }
235 else {
236 BMIter iter;
237 BMVert *v;
238 int i;
240 mul_v3_m4v3(vert_coords[i], mat, v->co);
241 }
242 }
243 return;
244 }
247 BLI_assert(vert_coords_len == mesh->verts_num);
248 const Span<float3> positions = mesh->vert_positions();
249 for (int i = 0; i < vert_coords_len; i++) {
250 mul_v3_m4v3(vert_coords[i], mat, positions[i]);
251 }
252 return;
253 }
254 }
256}
257
260/* -------------------------------------------------------------------- */
265{
266 switch (mesh->runtime->wrapper_type) {
268 return mesh->runtime->edit_mesh->bm->totvert;
271 return mesh->verts_num;
272 }
274 return -1;
275}
276
278{
279 switch (mesh->runtime->wrapper_type) {
281 return mesh->runtime->edit_mesh->bm->totedge;
284 return mesh->edges_num;
285 }
287 return -1;
288}
289
291{
292 switch (mesh->runtime->wrapper_type) {
294 return mesh->runtime->edit_mesh->bm->totloop;
297 return mesh->corners_num;
298 }
300 return -1;
301}
302
304{
305 switch (mesh->runtime->wrapper_type) {
307 return mesh->runtime->edit_mesh->bm->totface;
310 return mesh->faces_num;
311 }
313 return -1;
314}
315
318/* -------------------------------------------------------------------- */
323{
324 using namespace blender::bke;
325 SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)mesh->runtime->subsurf_runtime_data;
326 if (runtime_data == nullptr || runtime_data->settings.level == 0) {
327 return mesh;
328 }
329
330 /* Initialize the settings before ensuring the descriptor as this is checked to decide whether
331 * subdivision is needed at all, and checking the descriptor status might involve checking if the
332 * data is out-of-date, which is a very expensive operation. */
333 subdiv::ToMeshSettings mesh_settings;
334 mesh_settings.resolution = runtime_data->resolution;
335 mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
336
337 if (mesh_settings.resolution < 3) {
338 return mesh;
339 }
340
342 runtime_data, mesh, false);
343 if (subdiv == nullptr) {
344 /* Happens on bad topology, but also on empty input mesh. */
345 return mesh;
346 }
347 const bool use_clnors = runtime_data->use_loop_normals;
348 if (use_clnors) {
349 /* If custom normals are present and the option is turned on calculate the split
350 * normals and clear flag so the normals get interpolated to the result mesh. */
351 void *data = CustomData_add_layer(
352 &mesh->corner_data, CD_NORMAL, CD_CONSTRUCT, mesh->corners_num);
353 memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
354 }
355
356 Mesh *subdiv_mesh = subdiv::subdiv_to_mesh(subdiv, &mesh_settings, mesh);
357
358 if (use_clnors) {
359 BKE_mesh_set_custom_normals(subdiv_mesh,
360 static_cast<float(*)[3]>(CustomData_get_layer_for_write(
361 &subdiv_mesh->corner_data, CD_NORMAL, mesh->corners_num)));
362 CustomData_free_layers(&subdiv_mesh->corner_data, CD_NORMAL, mesh->corners_num);
363 }
364
365 if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
366 subdiv::free(subdiv);
367 }
368
369 if (subdiv_mesh != mesh) {
370 if (mesh->runtime->mesh_eval != nullptr) {
371 BKE_id_free(nullptr, mesh->runtime->mesh_eval);
372 }
373 mesh->runtime->mesh_eval = subdiv_mesh;
374 mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD;
375 }
376
377 return mesh->runtime->mesh_eval;
378}
379
381{
382 std::lock_guard lock{mesh->runtime->eval_mutex};
383
384 if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) {
385 return mesh->runtime->mesh_eval;
386 }
387
388 Mesh *result;
389
390 /* Must isolate multithreaded tasks while holding a mutex lock. */
392
393 return result;
394}
395
@ CD_CONSTRUCT
void CustomData_free_layers(CustomData *data, eCustomDataType type, int totelem)
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:1487
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
void BKE_mesh_set_custom_normals(Mesh *mesh, float(*r_custom_loop_normals)[3])
void BKE_mesh_ensure_default_orig_index_customdata_no_check(Mesh *mesh)
void BKE_mesh_runtime_ensure_edit_data(Mesh *mesh)
eMeshWrapperType
@ ME_WRAPPER_TYPE_MDATA
@ ME_WRAPPER_TYPE_SUBD
@ ME_WRAPPER_TYPE_BMESH
General operations, lookup, etc. for blender objects.
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:97
#define BLI_assert(a)
Definition BLI_assert.h:50
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(...)
@ ID_ME
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
volatile int lock
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_VERTS_OF_MESH
ATTR_WARN_UNUSED_RESULT 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
bool is_empty() const
Definition BLI_array.hh:253
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 isolate_task(const Function &function)
Definition BLI_task.hh:226
float co[3]
int totvert
MeshRuntimeHandle * runtime
CustomData corner_data
blender::bke::subdiv::Settings settings
blender::bke::subdiv::Subdiv * subdiv_cpu
blender::bke::subdiv::Subdiv * subdiv_gpu