Blender V4.5
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"
38#include "UI_resources.hh"
39
40#include "bmesh.hh"
41#include "bmesh_tools.hh"
42
44
46{
47 if (bm->totloop != bm->totface * 3) {
51 4,
52 false,
53 nullptr,
54 nullptr,
55 nullptr);
56 }
57}
58
59void enable_ex(Main &bmain, Depsgraph &depsgraph, Object &ob)
60{
61 SculptSession &ss = *ob.sculpt;
62 Mesh *mesh = static_cast<Mesh *>(ob.data);
64
66
67 /* Dynamic topology doesn't ensure selection state is valid, so remove #36280. */
69
70 /* Create triangles-only BMesh. */
71 BMeshCreateParams create_params{};
72 create_params.use_toolflags = false;
73 ss.bm = BM_mesh_create(&allocsize, &create_params);
74
75 BMeshFromMeshParams convert_params{};
76 convert_params.calc_face_normal = true;
77 convert_params.calc_vert_normal = true;
78 convert_params.use_shapekey = true;
79 convert_params.active_shapekey = ob.shapenr;
80 BM_mesh_bm_from_me(ss.bm, mesh, &convert_params);
81 triangulate(ss.bm);
82
83 BM_data_layer_ensure_named(ss.bm, &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
84
85 /* Make sure the data for existing faces are initialized. */
86 if (mesh->faces_num != ss.bm->totface) {
88 }
89
90 /* Enable dynamic topology. */
92
93 /* Enable logging for undo/redo. */
94 ss.bm_log = BM_log_create(ss.bm);
95
96 /* Update dependency graph, so modifiers that depend on dyntopo being enabled
97 * are re-evaluated and the #bke::pbvh::Tree is re-created. */
100}
101
108static void disable(
109 Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, undo::StepData *undo_step)
110{
111 SculptSession &ss = *ob.sculpt;
112 Mesh *mesh = static_cast<Mesh *>(ob.data);
113
114 if (BMesh *bm = ss.bm) {
115 BM_data_layer_free_named(bm, &bm->vdata, ".sculpt_dyntopo_node_id_vertex");
116 BM_data_layer_free_named(bm, &bm->pdata, ".sculpt_dyntopo_node_id_face");
117 }
118
120
121 if (undo_step) {
123 }
124 else {
126 }
127
128 /* Clear data. */
130
131 /* Typically valid but with global-undo they can be nullptr, see: #36234. */
132 if (ss.bm) {
133 BM_mesh_free(ss.bm);
134 ss.bm = nullptr;
135 }
136 if (ss.bm_log) {
138 ss.bm_log = nullptr;
139 }
140
143
144 /* Update dependency graph, so modifiers that depend on dyntopo being enabled
145 * are re-evaluated and the #bke::pbvh::Tree is re-created. */
148}
149
151{
152 Main *bmain = CTX_data_main(C);
154 Scene *scene = CTX_data_scene(C);
156 disable(*bmain, *depsgraph, *scene, *ob, undo_step);
157}
158
159void disable_with_undo(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
160{
161 SculptSession &ss = *ob.sculpt;
162 if (ss.bm != nullptr) {
163 /* May be false in background mode. */
164 const bool use_undo = G.background ? (ED_undo_stack_get() != nullptr) : true;
165 if (use_undo) {
166 undo::push_begin_ex(scene, ob, "Dynamic topology disable");
168 }
169 disable(bmain, depsgraph, scene, ob, nullptr);
170 if (use_undo) {
171 undo::push_end(ob);
172 }
173 }
174}
175
176static void enable_with_undo(Main &bmain, Depsgraph &depsgraph, const Scene &scene, Object &ob)
177{
178 SculptSession &ss = *ob.sculpt;
179 if (ss.bm == nullptr) {
180 /* May be false in background mode. */
181 const bool use_undo = G.background ? (ED_undo_stack_get() != nullptr) : true;
182 if (use_undo) {
183 undo::push_begin_ex(scene, ob, "Dynamic topology enable");
184 }
185 enable_ex(bmain, depsgraph, ob);
186 if (use_undo) {
188 undo::push_end(ob);
189 }
190 }
191}
192
194{
195 Main &bmain = *CTX_data_main(C);
197 Scene &scene = *CTX_data_scene(C);
199 SculptSession &ss = *ob.sculpt;
200
201 WM_cursor_wait(true);
202
203 if (ss.bm) {
204 disable_with_undo(bmain, depsgraph, scene, ob);
205 }
206 else {
207 enable_with_undo(bmain, depsgraph, scene, ob);
208 }
209
210 WM_cursor_wait(false);
212
213 return OPERATOR_FINISHED;
214}
215
217{
218 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
219 uiLayout *layout = UI_popup_menu_layout(pup);
220
221 if (flag & (VDATA | EDATA | LDATA)) {
222 const char *msg_error = RPT_("Attribute Data Detected");
223 const char *msg = RPT_("Dyntopo will not preserve colors, UVs, or other attributes");
224 layout->label(msg_error, ICON_INFO);
225 layout->label(msg, ICON_NONE);
226 layout->separator();
227 }
228
229 if (flag & MODIFIER) {
230 const char *msg_error = RPT_("Generative Modifiers Detected!");
231 const char *msg = RPT_(
232 "Keeping the modifiers will increase polycount when returning to object mode");
233
234 layout->label(msg_error, ICON_INFO);
235 layout->label(msg, ICON_NONE);
236 layout->separator();
237 }
238
239 layout->op(ot, IFACE_("OK"), ICON_NONE, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE);
240
241 UI_popup_menu_end(C, pup);
242
243 return OPERATOR_INTERFACE;
244}
245
247{
248 if (layer.type == CD_PROP_FLOAT && STREQ(layer.name, ".sculpt_mask")) {
249 return true;
250 }
253 }
254 return ELEM(layer.type, CD_ORIGINDEX);
255}
256
258{
259 return std::all_of(layers.begin(), layers.end(), [&](const CustomDataLayer &layer) {
260 return dyntopo_supports_layer(layer);
261 });
262}
263
265{
266 Mesh *mesh = static_cast<Mesh *>(ob.data);
267 SculptSession &ss = *ob.sculpt;
268
270
271 BLI_assert(ss.bm == nullptr);
273
274 if (!dyntopo_supports_customdata_layers({mesh->vert_data.layers, mesh->vert_data.totlayer})) {
275 flag |= VDATA;
276 }
277 if (!dyntopo_supports_customdata_layers({mesh->edge_data.layers, mesh->edge_data.totlayer})) {
278 flag |= EDATA;
279 }
280 if (!dyntopo_supports_customdata_layers({mesh->face_data.layers, mesh->face_data.totlayer})) {
281 flag |= LDATA;
282 }
283 if (!dyntopo_supports_customdata_layers({mesh->corner_data.layers, mesh->corner_data.totlayer}))
284 {
285 flag |= LDATA;
286 }
287
288 {
289 VirtualModifierData virtual_modifier_data;
290 ModifierData *md = BKE_modifiers_get_virtual_modifierlist(&ob, &virtual_modifier_data);
291
292 /* Exception for shape keys because we can edit those. */
293 for (; md; md = md->next) {
296 continue;
297 }
298
300 flag |= MODIFIER;
301 break;
302 }
303 }
304 }
305
306 return flag;
307}
308
310 wmOperator *op,
311 const wmEvent * /*event*/)
312{
314 SculptSession &ss = *ob.sculpt;
315
316 if (!ss.bm) {
317 Scene &scene = *CTX_data_scene(C);
318 const WarnFlag flag = check_attribute_warning(scene, ob);
319
320 if (flag) {
321 /* The mesh has customdata that will be lost, let the user confirm this is OK. */
322 return dyntopo_warning_popup(C, op->type, flag);
323 }
324 }
325
327}
328
330{
331 /* Identifiers. */
332 ot->name = "Dynamic Topology Toggle";
333 ot->idname = "SCULPT_OT_dynamic_topology_toggle";
334 ot->description = "Dynamic topology alters the mesh topology while sculpting";
335
336 /* API callbacks. */
339 ot->poll = SCULPT_mode_poll;
340
342}
343
344} // 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)
#define CD_TYPE_AS_MASK(_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, bool reorder)
Definition paint.cc:2135
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2146
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:2618
#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:982
@ CD_PROP_FLOAT
@ ME_SCULPT_DYNAMIC_TOPOLOGY
@ eModifierMode_Realtime
@ MOD_TRIANGULATE_NGON_EARCLIP
@ MOD_TRIANGULATE_QUAD_BEAUTY
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
UndoStack * ED_undo_stack_get()
Definition ed_undo.cc:441
#define C
Definition RandGen.cpp:29
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
#define UI_ITEM_NONE
#define NC_SCENE
Definition WM_types.hh:375
#define ND_TOOLSETTINGS
Definition WM_types.hh:446
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:245
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
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:524
BMLog * BM_log_create(BMesh *bm)
Definition bmesh_log.cc:419
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 CD_MASK_PROP_ALL
#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 wmOperatorStatus dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum WarnFlag flag)
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:3660
CustomData vdata
int totface
struct ModifierData * next
ModifierTypeType type
struct SculptSession * sculpt
BMLog * bm_log
Definition BKE_paint.hh:412
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, wmOperatorCallContext context, eUI_Item_Flag flag)
void label(blender::StringRef name, int icon)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
struct wmOperatorType * type
void WM_cursor_wait(bool val)
void WM_main_add_notifier(uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4226
uint8_t flag
Definition wm_window.cc:139