Blender V5.0
sculpt_dyntopo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#include "sculpt_dyntopo.hh"
9
10#include <cstdlib>
11
12#include "BLT_translation.hh"
13
14#include "DNA_modifier_types.h"
15
16#include "BKE_context.hh"
17#include "BKE_global.hh"
18#include "BKE_mesh.hh"
19#include "BKE_modifier.hh"
20#include "BKE_object.hh"
21#include "BKE_paint.hh"
22#include "BKE_paint_bvh.hh"
23#include "BKE_particle.h"
24#include "BKE_pointcache.h"
25#include "BKE_scene.hh"
26
27#include "DEG_depsgraph.hh"
28
29#include "WM_api.hh"
30#include "WM_types.hh"
31
32#include "ED_undo.hh"
33
34#include "sculpt_intern.hh"
35#include "sculpt_undo.hh"
36
37#include "UI_interface.hh"
39#include "UI_resources.hh"
40
41#include "bmesh.hh"
42#include "bmesh_tools.hh"
43
45
47{
48 if (bm->totloop != bm->totface * 3) {
52 4,
53 false,
54 nullptr,
55 nullptr,
56 nullptr);
57 }
58}
59
60void enable_ex(Main &bmain, Depsgraph &depsgraph, Object &ob)
61{
62 SculptSession &ss = *ob.sculpt;
63 Mesh *mesh = static_cast<Mesh *>(ob.data);
65
67
68 /* Dynamic topology doesn't ensure selection state is valid, so remove #36280. */
70
71 /* Create triangles-only BMesh. */
72 BMeshCreateParams create_params{};
73 create_params.use_toolflags = false;
74 ss.bm = BM_mesh_create(&allocsize, &create_params);
75
76 BMeshFromMeshParams convert_params{};
77 convert_params.calc_face_normal = true;
78 convert_params.calc_vert_normal = true;
79 convert_params.use_shapekey = true;
80 convert_params.active_shapekey = ob.shapenr;
81 BM_mesh_bm_from_me(ss.bm, mesh, &convert_params);
82 triangulate(ss.bm);
83
84 BM_data_layer_ensure_named(ss.bm, &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
85
86 /* Make sure the data for existing faces are initialized. */
87 if (mesh->faces_num != ss.bm->totface) {
89 }
90
91 /* Enable dynamic topology. */
93
94 /* Enable logging for undo/redo. */
95 ss.bm_log = BM_log_create(ss.bm);
96
97 /* Update dependency graph, so modifiers that depend on dyntopo being enabled
98 * are re-evaluated and the #bke::pbvh::Tree is re-created. */
101}
102
109static void disable(
110 Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, undo::StepData *undo_step)
111{
112 SculptSession &ss = *ob.sculpt;
113 Mesh *mesh = static_cast<Mesh *>(ob.data);
114
115 if (BMesh *bm = ss.bm) {
116 BM_data_layer_free_named(bm, &bm->vdata, ".sculpt_dyntopo_node_id_vertex");
117 BM_data_layer_free_named(bm, &bm->pdata, ".sculpt_dyntopo_node_id_face");
118 }
119
121
122 if (undo_step) {
124 }
125 else {
127 }
128
129 /* Clear data. */
131
132 /* Typically valid but with global-undo they can be nullptr, see: #36234. */
133 if (ss.bm) {
134 BM_mesh_free(ss.bm);
135 ss.bm = nullptr;
136 }
137 if (ss.bm_log) {
139 ss.bm_log = nullptr;
140 }
141
144
145 /* Update dependency graph, so modifiers that depend on dyntopo being enabled
146 * are re-evaluated and the #bke::pbvh::Tree is re-created. */
149}
150
152{
153 Main *bmain = CTX_data_main(C);
155 Scene *scene = CTX_data_scene(C);
157 disable(*bmain, *depsgraph, *scene, *ob, undo_step);
158}
159
160void disable_with_undo(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
161{
162 /* This is an unlikely situation to happen in normal usage, though with application handlers
163 * it is possible that a user is attempting to exit the current object mode. See #146398 */
164 if (ob.sculpt && ob.sculpt->bm) {
165 /* May be false in background mode. */
166 const bool use_undo = G.background ? (ED_undo_stack_get() != nullptr) : true;
167 if (use_undo) {
168 undo::push_begin_ex(scene, ob, "Dynamic topology disable");
170 }
171 disable(bmain, depsgraph, scene, ob, nullptr);
172 if (use_undo) {
173 undo::push_end(ob);
174 }
175 }
176}
177
178static void enable_with_undo(Main &bmain, Depsgraph &depsgraph, const Scene &scene, Object &ob)
179{
180 SculptSession &ss = *ob.sculpt;
181 if (ss.bm == nullptr) {
182 /* May be false in background mode. */
183 const bool use_undo = G.background ? (ED_undo_stack_get() != nullptr) : true;
184 if (use_undo) {
185 undo::push_begin_ex(scene, ob, "Dynamic topology enable");
186 }
187 enable_ex(bmain, depsgraph, ob);
188 if (use_undo) {
190 undo::push_end(ob);
191 }
192 }
193}
194
196{
197 Main &bmain = *CTX_data_main(C);
199 Scene &scene = *CTX_data_scene(C);
201 SculptSession &ss = *ob.sculpt;
202
203 WM_cursor_wait(true);
204
205 if (ss.bm) {
206 disable_with_undo(bmain, depsgraph, scene, ob);
207 }
208 else {
209 enable_with_undo(bmain, depsgraph, scene, ob);
210 }
211
212 WM_cursor_wait(false);
214
215 return OPERATOR_FINISHED;
216}
217
219{
220 if (layer.type == CD_PROP_FLOAT && STREQ(layer.name, ".sculpt_mask")) {
221 return true;
222 }
225 }
226 return ELEM(layer.type, CD_ORIGINDEX);
227}
228
230{
231 return std::all_of(layers.begin(), layers.end(), [&](const CustomDataLayer &layer) {
232 return dyntopo_supports_layer(layer);
233 });
234}
235
237{
238 Mesh *mesh = static_cast<Mesh *>(ob.data);
239 SculptSession &ss = *ob.sculpt;
240
242
243 BLI_assert(ss.bm == nullptr);
245
246 if (!dyntopo_supports_customdata_layers({mesh->vert_data.layers, mesh->vert_data.totlayer})) {
247 flag |= VDATA;
248 }
249 if (!dyntopo_supports_customdata_layers({mesh->edge_data.layers, mesh->edge_data.totlayer})) {
250 flag |= EDATA;
251 }
252 if (!dyntopo_supports_customdata_layers({mesh->face_data.layers, mesh->face_data.totlayer})) {
253 flag |= LDATA;
254 }
255 if (!dyntopo_supports_customdata_layers({mesh->corner_data.layers, mesh->corner_data.totlayer}))
256 {
257 flag |= LDATA;
258 }
259
260 {
261 VirtualModifierData virtual_modifier_data;
262 ModifierData *md = BKE_modifiers_get_virtual_modifierlist(&ob, &virtual_modifier_data);
263
264 /* Exception for shape keys because we can edit those. */
265 for (; md; md = md->next) {
268 continue;
269 }
270
272 flag |= MODIFIER;
273 break;
274 }
275 }
276 }
277
278 return flag;
279}
280
282 wmOperator *op,
283 const wmEvent * /*event*/)
284{
286 SculptSession &ss = *ob.sculpt;
287
288 if (!ss.bm) {
289 Scene &scene = *CTX_data_scene(C);
290 const WarnFlag flag = check_attribute_warning(scene, ob);
291
292 if (flag & (VDATA | EDATA | LDATA)) {
294 C,
295 op,
296 RPT_("Attribute Data Detected"),
297 RPT_("Dyntopo will not preserve colors, UVs, or other attributes"),
298 IFACE_("Enable"),
300 false);
301 }
302
303 if (flag & MODIFIER) {
305 C,
306 op,
307 RPT_("Generative Modifiers Detected!"),
308 RPT_("Keeping the modifiers will increase polycount when returning to object mode"),
309 IFACE_("Enable"),
311 false);
312 }
313 }
314
316}
317
319{
320 /* Identifiers. */
321 ot->name = "Dynamic Topology Toggle";
322 ot->idname = "SCULPT_OT_dynamic_topology_toggle";
323 ot->description = "Dynamic topology alters the mesh topology while sculpting";
324
325 /* API callbacks. */
328 ot->poll = SCULPT_mode_poll;
329
331}
332
333} // namespace blender::ed::sculpt_paint::dyntopo
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
eCustomDataMask CD_TYPE_AS_MASK(eCustomDataType type)
void BKE_mesh_mselect_clear(Mesh *mesh)
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
const ModifierTypeInfo * BKE_modifier_get_info(ModifierType type)
ModifierData * BKE_modifiers_get_virtual_modifierlist(const Object *ob, VirtualModifierData *data)
General operations, lookup, etc. for blender objects.
void BKE_sculptsession_bm_to_me(Object *ob)
Definition paint.cc:2275
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2286
A BVH for high poly meshes.
void BKE_particlesystem_reset_all(struct Object *object)
#define PTCACHE_RESET_OUTDATED
int BKE_ptcache_object_reset(struct Scene *scene, struct Object *ob, int mode)
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2621
#define BLI_assert(a)
Definition BLI_assert.h:46
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
#define STREQ(a, b)
#define RPT_(msgid)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define CD_MASK_PROP_ALL
@ CD_PROP_FLOAT
@ ME_SCULPT_DYNAMIC_TOPOLOGY
@ MOD_TRIANGULATE_QUAD_BEAUTY
@ eModifierMode_Realtime
@ MOD_TRIANGULATE_NGON_EARCLIP
@ OPERATOR_FINISHED
UndoStack * ED_undo_stack_get()
Definition ed_undo.cc:442
#define C
Definition RandGen.cpp:29
@ ALERT_ICON_WARNING
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_TOOLSETTINGS
Definition WM_types.hh:449
bool BM_data_layer_free_named(BMesh *bm, CustomData *data, StringRef name)
void BM_data_layer_ensure_named(BMesh *bm, CustomData *data, int type, const StringRef name)
BMesh * bm
void BM_log_free(BMLog *log)
Definition bmesh_log.cc:497
BMLog * BM_log_create(BMesh *bm)
Definition bmesh_log.cc:392
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
#define BMALLOC_TEMPLATE_FROM_ME(...)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
void BM_mesh_normals_update(BMesh *bm)
void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method, const int min_vertices, const bool tag_only, BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_facemap_double_out)
BPy_StructRNA * depsgraph
constexpr const T * end() const
Definition BLI_span.hh:224
constexpr const T * begin() const
Definition BLI_span.hh:220
#define G(x, y, z)
void enable_ex(Main &bmain, Depsgraph &depsgraph, Object &ob)
void disable_with_undo(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
static void disable(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, undo::StepData *undo_step)
static bool dyntopo_supports_layer(const CustomDataLayer &layer)
WarnFlag check_attribute_warning(Scene &scene, Object &ob)
static wmOperatorStatus sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *)
void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
static bool dyntopo_supports_customdata_layers(const Span< CustomDataLayer > layers)
static wmOperatorStatus sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void enable_with_undo(Main &bmain, Depsgraph &depsgraph, const Scene &scene, Object &ob)
void push_begin_ex(const Scene &, Object &ob, const char *name)
void push_node(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::Node *node, const Type type)
void restore_from_bmesh_enter_geometry(const StepData &step_data, Mesh &mesh)
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3677
CustomData vdata
int totface
struct ModifierData * next
ModifierTypeType type
struct SculptSession * sculpt
BMLog * bm_log
Definition BKE_paint.hh:392
void WM_cursor_wait(bool val)
void WM_main_add_notifier(uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
wmOperatorStatus WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
uint8_t flag
Definition wm_window.cc:145