Blender V5.0
ed_util.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10#include <cstdlib>
11#include <cstring>
12
13#include "BLI_listbase.h"
14#include "BLI_path_utils.hh"
15#include "BLI_string_utf8.h"
16
17#include "BLT_translation.hh"
18
19#include "BKE_collection.hh"
20#include "BKE_global.hh"
21#include "BKE_layer.hh"
22#include "BKE_lib_id.hh"
23#include "BKE_lib_remap.hh"
24#include "BKE_main.hh"
25#include "BKE_material.hh"
26#include "BKE_multires.hh"
27#include "BKE_object.hh"
28#include "BKE_packedFile.hh"
29#include "BKE_paint.hh"
30#include "BKE_scene.hh"
31#include "BKE_screen.hh"
32#include "BKE_undo_system.hh"
33
34#include "DEG_depsgraph.hh"
35
36#include "ED_armature.hh"
37#include "ED_asset.hh"
38#include "ED_gpencil_legacy.hh"
39#include "ED_image.hh"
40#include "ED_mesh.hh"
41#include "ED_object.hh"
42#include "ED_paint.hh"
43#include "ED_screen.hh"
44#include "ED_screen_types.hh"
45#include "ED_sculpt.hh"
46#include "ED_space_api.hh"
47#include "ED_util.hh"
48#include "ED_view3d.hh"
49
50#include "UI_interface.hh"
52#include "UI_resources.hh"
53
54#include "RNA_access.hh"
55
56#include "WM_api.hh"
57#include "WM_types.hh"
58
59/* ********* general editor util functions, not BKE stuff please! ********* */
60
62{
63 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
64 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
67 BKE_view_layer_synced_ensure(scene, view_layer);
69 if (ob && (ob->mode & OB_MODE_TEXTURE_PAINT)) {
71 ED_paint_proj_mesh_data_check(*scene, *ob, nullptr, nullptr, nullptr, nullptr);
72 }
73
74 /* Stop animation from playing.
75 * TODO: There might be a way to keep the animation from playing, but sad->scene and
76 * sad->view_layer pointers are outdated and would need to be updated somehow. */
77 bScreen *animscreen = ED_screen_animation_playing(wm);
78 if (animscreen && animscreen->animtimer) {
79 WM_event_timer_remove(wm, win, animscreen->animtimer);
80 animscreen->animtimer = nullptr;
81 }
82
83 /* UI Updates. */
84 /* Flag local View3D's to check and exit if they are empty. */
85 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
86 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
87 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
88 if (sl->spacetype == SPACE_VIEW3D) {
89 View3D *v3d = reinterpret_cast<View3D *>(sl);
90 if (v3d->localvd) {
92 }
93 }
94 }
95 }
96 }
97 }
98}
99
101{
102 using namespace blender::ed;
104 Main *bmain = CTX_data_main(C);
105 Scene *scene = CTX_data_scene(C);
107
108 /* This is called during initialization, so we don't want to store any reports */
109 ReportList *reports = CTX_wm_reports(C);
110 int reports_flag_prev = reports->flag & ~RPT_STORE;
111
112 std::swap(reports->flag, reports_flag_prev);
113
114 /* Don't do undo pushes when calling an operator. */
115 wm->op_undo_depth++;
116
117 /* toggle on modes for objects that were saved with these enabled. for
118 * e.g. linked objects we have to ensure that they are actually the
119 * active object in this scene. */
121 LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
122 int mode = ob->mode;
123 if (mode == OB_MODE_OBJECT) {
124 continue;
125 }
126 if (BKE_object_has_mode_data(ob, eObjectMode(mode))) {
127 /* For multi-edit mode we may already have mode data. */
128 continue;
129 }
130
131 /* Reset object to Object mode, so that code below can properly re-switch it to its
132 * previous mode if possible, re-creating its mode data, etc. */
133 ID *ob_data = static_cast<ID *>(ob->data);
134 ob->mode = OB_MODE_OBJECT;
136
137 /* Object mode is enforced if there is no active object, or if the active object's type is
138 * different. */
139 if (obact == nullptr || ob->type != obact->type) {
140 continue;
141 }
142 /* Object mode is enforced for non-editable data (or their obdata). */
143 if (!BKE_id_is_editable(bmain, &ob->id) ||
144 (ob_data != nullptr && !BKE_id_is_editable(bmain, ob_data)))
145 {
146 continue;
147 }
148
149 /* Pose mode is very similar to Object one, we can apply it even on objects not in current
150 * scene. */
151 if (mode == OB_MODE_POSE) {
153 }
154
155 /* Other edit/paint/etc. modes are only settable for objects visible in active scene currently.
156 * Otherwise, they (and their obdata) may not be (fully) evaluated, which is mandatory for some
157 * modes like Sculpt.
158 * Ref. #98225. */
160 !BKE_scene_has_object(scene, ob) || (ob->visibility_flag & OB_HIDE_VIEWPORT) != 0)
161 {
162 continue;
163 }
164
165 if (mode == OB_MODE_EDIT) {
166 object::editmode_enter_ex(bmain, scene, ob, 0);
167 }
168 else if (mode & OB_MODE_ALL_SCULPT) {
169 if (obact == ob) {
170 if (mode == OB_MODE_SCULPT) {
172 *bmain, *depsgraph, *scene, *ob, true, reports);
173 }
174 else if (mode == OB_MODE_VERTEX_PAINT) {
175 ED_object_vpaintmode_enter_ex(*bmain, *depsgraph, *scene, *ob);
176 }
177 else if (mode == OB_MODE_WEIGHT_PAINT) {
178 ED_object_wpaintmode_enter_ex(*bmain, *depsgraph, *scene, *ob);
179 }
180 else {
182 }
183 }
184 else {
185 /* Create data for non-active objects which need it for
186 * mode-switching but don't yet support multi-editing. */
187 if (mode & OB_MODE_ALL_SCULPT) {
188 ob->mode = mode;
190 }
191 }
192 }
193 else {
194 /* TODO(@ideasman42): avoid operator calls. */
195 if (obact == ob) {
197 }
198 }
199 }
200
201 /* image editor paint mode */
202 if (scene) {
203 ED_space_image_paint_update(bmain, wm, scene);
204 }
205
206 /* Enforce a full redraw for the first time areas/regions get drawn. Further region init/refresh
207 * just triggers non-rebuild redraws (#RGN_DRAW_NO_REBUILD). Usually a full redraw would be
208 * triggered by a `NC_WM | ND_FILEREAD` notifier, but if a startup script calls an operator that
209 * redraws the window, notifiers are not handled before the operator runs. See #98461. */
210 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
211 const bScreen *screen = WM_window_get_active_screen(win);
212
213 ED_screen_areas_iter (win, screen, area) {
214 ED_area_tag_redraw(area);
215 }
216 }
217
219
220 std::swap(reports->flag, reports_flag_prev);
221 wm->op_undo_depth--;
222}
223
224void ED_editors_exit(Main *bmain, bool do_undo_system)
225{
226 using namespace blender::ed;
227 if (!bmain) {
228 return;
229 }
230
231 /* Frees all edit-mode undo-steps. */
232 if (do_undo_system && G_MAIN->wm.first) {
233 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
234 /* normally we don't check for null undo stack,
235 * do here since it may run in different context. */
236 if (wm->runtime->undo_stack) {
237 BKE_undosys_stack_destroy(wm->runtime->undo_stack);
238 wm->runtime->undo_stack = nullptr;
239 }
240 }
241
242 /* On undo, tag for update so the depsgraph doesn't use stale edit-mode data,
243 * this is possible when mixing edit-mode and memory-file undo.
244 *
245 * By convention, objects are not left in edit-mode - so this isn't often problem in practice,
246 * since exiting edit-mode will tag the objects too.
247 *
248 * However there is no guarantee the active object _never_ changes while in edit-mode.
249 * Python for example can do this, some callers to #object::base_activate
250 * don't handle modes either (doing so isn't always practical).
251 *
252 * To reproduce the problem where stale data is used, see: #84920. */
253 LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
254 if (object::editmode_free_ex(bmain, ob)) {
255 if (do_undo_system == false) {
257 }
258 }
259 }
260
261 /* global in meshtools... */
264}
265
267 Object *ob,
268 bool for_render,
269 bool check_needs_flush)
270{
271 using namespace blender::ed;
272 bool has_edited = false;
273 if (ob->mode & OB_MODE_SCULPT) {
274 /* Don't allow flushing while in the middle of a stroke (frees data in use).
275 * Auto-save prevents this from happening but scripts
276 * may cause a flush on saving: #53986. */
277 if (ob->sculpt != nullptr && ob->sculpt->cache == nullptr) {
278 if (check_needs_flush && !ob->sculpt->needs_flush_to_id) {
279 return false;
280 }
281 ob->sculpt->needs_flush_to_id = false;
282
283 /* flush multires changes (for sculpt) */
285 has_edited = true;
286
287 if (for_render) {
288 /* flush changes from dynamic topology sculpt */
290 }
291 else {
292 /* Set reorder=false so that saving the file doesn't reorder
293 * the BMesh's elements */
295 }
296 }
297 }
298 else if (ob->mode & OB_MODE_EDIT) {
299
300 char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(static_cast<ID *>(ob->data));
301 if (needs_flush_ptr != nullptr) {
302 if (check_needs_flush && (*needs_flush_ptr == 0)) {
303 return false;
304 }
305 *needs_flush_ptr = 0;
306 }
307
308 /* get editmode results */
309 has_edited = true;
310 object::editmode_load(bmain, ob);
311 }
312 return has_edited;
313}
314
316{
317 return ED_editors_flush_edits_for_object_ex(bmain, ob, false, false);
318}
319
320bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_flush)
321{
322 bool has_edited = false;
323
324 /* loop through all data to find edit mode or object mode, because during
325 * exiting we might not have a context for edit object and multiple sculpt
326 * objects can exist at the same time */
327 LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
328 has_edited |= ED_editors_flush_edits_for_object_ex(bmain, ob, for_render, check_needs_flush);
329 }
330
331 bmain->is_memfile_undo_flush_needed = false;
332
333 return has_edited;
334}
335
337{
338 return ED_editors_flush_edits_ex(bmain, false, false);
339}
340
341/* ***** XXX: functions are using old blender names, cleanup later ***** */
342
344 bool shift, bool ctrl, float *val, float fac1, float fac2, float fac3, int invert)
345{
346 /* fac1 is for 'nothing', fac2 for CTRL, fac3 for SHIFT */
347 if (invert) {
348 ctrl = !ctrl;
349 }
350
351 if (ctrl && shift) {
352 if (fac3 != 0.0f) {
353 *val = fac3 * floorf(*val / fac3 + 0.5f);
354 }
355 }
356 else if (ctrl) {
357 if (fac2 != 0.0f) {
358 *val = fac2 * floorf(*val / fac2 + 0.5f);
359 }
360 }
361 else {
362 if (fac1 != 0.0f) {
363 *val = fac1 * floorf(*val / fac1 + 0.5f);
364 }
365 }
366}
367
369 const char *opname,
370 const char *id_name,
371 const char *abs_name,
372 const char *folder,
373 PackedFile *pf)
374{
375 Main *bmain = CTX_data_main(C);
376 PointerRNA props_ptr;
377 uiPopupMenu *pup;
378 uiLayout *layout;
379 char line[FILE_MAX + 100];
380 wmOperatorType *ot = WM_operatortype_find(opname, true);
381 const char *blendfile_path = BKE_main_blendfile_path(bmain);
382
383 pup = UI_popup_menu_begin(C, IFACE_("Unpack File"), ICON_NONE);
384 layout = UI_popup_menu_layout(pup);
385
386 props_ptr = layout->op(
388 RNA_enum_set(&props_ptr, "method", PF_REMOVE);
389 RNA_string_set(&props_ptr, "id", id_name);
390
391 if (blendfile_path[0] != '\0') {
392 char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
393
394 BLI_path_split_file_part(abs_name, fi, sizeof(fi));
395 BLI_path_join(local_name, sizeof(local_name), "//", folder, fi);
396 if (!STREQ(abs_name, local_name)) {
397 switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) {
398 case PF_CMP_NOFILE:
399 SNPRINTF_UTF8(line, IFACE_("Create %s"), local_name);
400 props_ptr = layout->op(
402 RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
403 RNA_string_set(&props_ptr, "id", id_name);
404
405 break;
406 case PF_CMP_EQUAL:
407 SNPRINTF_UTF8(line, IFACE_("Use %s (identical)"), local_name);
408 props_ptr = layout->op(
410 RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
411 RNA_string_set(&props_ptr, "id", id_name);
412
413 break;
414 case PF_CMP_DIFFERS:
415 SNPRINTF_UTF8(line, IFACE_("Use %s (differs)"), local_name);
416 props_ptr = layout->op(
418 RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
419 RNA_string_set(&props_ptr, "id", id_name);
420
421 SNPRINTF_UTF8(line, IFACE_("Overwrite %s"), local_name);
422 props_ptr = layout->op(
424 RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
425 RNA_string_set(&props_ptr, "id", id_name);
426 break;
427 }
428 }
429 }
430
431 switch (BKE_packedfile_compare_to_file(blendfile_path, abs_name, pf)) {
432 case PF_CMP_NOFILE:
433 SNPRINTF_UTF8(line, IFACE_("Create %s"), abs_name);
434 props_ptr = layout->op(
436 RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
437 RNA_string_set(&props_ptr, "id", id_name);
438 break;
439 case PF_CMP_EQUAL:
440 SNPRINTF_UTF8(line, IFACE_("Use %s (identical)"), abs_name);
441 props_ptr = layout->op(
443 RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
444 RNA_string_set(&props_ptr, "id", id_name);
445 break;
446 case PF_CMP_DIFFERS:
447 SNPRINTF_UTF8(line, IFACE_("Use %s (differs)"), abs_name);
448 props_ptr = layout->op(
450 RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
451 RNA_string_set(&props_ptr, "id", id_name);
452
453 SNPRINTF_UTF8(line, IFACE_("Overwrite %s"), abs_name);
454 props_ptr = layout->op(
456 RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
457 RNA_string_set(&props_ptr, "id", id_name);
458 break;
459 }
460
461 UI_popup_menu_end(C, pup);
462}
463
465 SpaceLink *sl,
466 const blender::bke::id::IDRemapper &mappings)
467{
469 if (st && st->id_remap) {
470 st->id_remap(area, sl, mappings);
471 }
472}
473
474void ED_spacedata_id_remap_single(ScrArea *area, SpaceLink *sl, ID *old_id, ID *new_id)
475{
477
478 if (st && st->id_remap) {
480 mappings.add(old_id, new_id);
481 st->id_remap(area, sl, mappings);
482 }
483}
bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
Depsgraph * CTX_data_expect_evaluated_depsgraph(const bContext *C)
ReportList * CTX_wm_reports(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)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define G_MAIN
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
bool BKE_scene_has_object(Scene *scene, Object *ob)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2523
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
General operations, lookup, etc. for materials.
void BKE_texpaint_slots_refresh_object(Scene *scene, Object *ob)
void multires_flush_sculpt_updates(Object *object)
Definition multires.cc:270
General operations, lookup, etc. for blender objects.
bool BKE_object_has_mode_data(const Object *ob, eObjectMode object_mode)
void BKE_object_sculpt_data_create(Object *ob)
char * BKE_object_data_editmode_flush_ptr_get(ID *id)
@ PF_CMP_EQUAL
@ PF_CMP_NOFILE
@ PF_CMP_DIFFERS
ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, const char *filepath_rel, const PackedFile *pf)
@ PF_USE_ORIGINAL
@ PF_USE_LOCAL
@ PF_REMOVE
@ PF_WRITE_ORIGINAL
@ PF_WRITE_LOCAL
void BKE_sculptsession_bm_to_me(Object *ob)
Definition paint.cc:2275
void BKE_sculptsession_bm_to_me_for_render(Object *object)
Definition paint.cc:2310
@ RPT_STORE
Definition BKE_report.hh:56
SpaceType * BKE_spacetype_from_id(int spaceid)
Definition screen.cc:257
void BKE_undosys_stack_destroy(UndoStack *ustack)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define LISTBASE_FOREACH(type, var, list)
#define FILE_MAX
#define BLI_path_join(...)
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
#define FILE_MAXDIR
#define SNPRINTF_UTF8(dst, format,...)
#define STREQ(a, b)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
eObjectMode
@ OB_MODE_EDIT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_SCULPT
@ OB_MODE_POSE
@ OB_MODE_TEXTURE_PAINT
@ OB_MODE_OBJECT
@ OB_MODE_VERTEX_PAINT
#define OB_MODE_ALL_SCULPT
@ OB_HIDE_VIEWPORT
@ SPACE_VIEW3D
@ V3D_RUNTIME_LOCAL_MAYBE_EMPTY
void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
void ED_mesh_mirror_topo_table_end(Object *ob)
Definition meshtools.cc:258
void ED_mesh_mirror_spatial_table_end(Object *ob)
void ED_object_wpaintmode_enter_ex(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
void ED_object_vpaintmode_enter_ex(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
bool ED_paint_proj_mesh_data_check(Scene &scene, Object &ob, bool *r_has_uvs, bool *r_has_mat, bool *r_has_tex, bool *r_has_stencil)
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
#define ED_screen_areas_iter(win, screen, area_name)
Definition ED_screen.hh:296
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
#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
BPy_StructRNA * depsgraph
void add(ID *old_id, ID *new_id)
void ED_editors_exit(Main *bmain, bool do_undo_system)
Definition ed_util.cc:224
bool ED_editors_flush_edits_for_object(Main *bmain, Object *ob)
Definition ed_util.cc:315
void ED_spacedata_id_remap_single(ScrArea *area, SpaceLink *sl, ID *old_id, ID *new_id)
Definition ed_util.cc:474
bool ED_editors_flush_edits_for_object_ex(Main *bmain, Object *ob, bool for_render, bool check_needs_flush)
Definition ed_util.cc:266
bool ED_editors_flush_edits(Main *bmain)
Definition ed_util.cc:336
void unpack_menu(bContext *C, const char *opname, const char *id_name, const char *abs_name, const char *folder, PackedFile *pf)
Definition ed_util.cc:368
void apply_keyb_grid(bool shift, bool ctrl, float *val, float fac1, float fac2, float fac3, int invert)
Definition ed_util.cc:343
void ED_editors_init_for_undo(Main *bmain)
Definition ed_util.cc:61
void ED_spacedata_id_remap(ScrArea *area, SpaceLink *sl, const blender::bke::id::IDRemapper &mappings)
Definition ed_util.cc:464
bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_flush)
Definition ed_util.cc:320
void ED_editors_init(bContext *C)
Definition ed_util.cc:100
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
bool editmode_free_ex(Main *bmain, Object *obedit)
bool editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag)
bool mode_set(bContext *C, eObjectMode mode)
bool editmode_load(Main *bmain, Object *obedit)
void object_sculpt_mode_enter(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, bool force_dyntopo, ReportList *reports)
bool ED_object_posemode_enter_ex(Main *bmain, Object *ob)
Definition pose_edit.cc:77
#define floorf
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
Definition DNA_ID.h:414
void * first
ListBase wm
Definition BKE_main.hh:307
bool is_memfile_undo_flush_needed
Definition BKE_main.hh:213
ListBase screens
Definition BKE_main.hh:292
ListBase objects
Definition BKE_main.hh:280
struct SculptSession * sculpt
struct Collection * master_collection
bool needs_flush_to_id
Definition BKE_paint.hh:501
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
void(* id_remap)(ScrArea *area, SpaceLink *sl, const blender::bke::id::IDRemapper &mappings)
View3D_Runtime runtime
struct View3D * localvd
struct wmTimer * animtimer
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
wmOperatorType * ot
Definition wm_files.cc:4237
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Scene * WM_window_get_active_scene(const wmWindow *win)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
bScreen * WM_window_get_active_screen(const wmWindow *win)