Python handlers: Pass depsgraph to events where it makes sense
The goal is to make it possible to access evaluated datablocks at a corresponding context. For example, be able to check evaluated state if an object used for rendering. Allows to write scripts in a safe manner for T63548 and T60094. Reviewers: brecht Differential Revision: https://developer.blender.org/D5726
This commit is contained in:
parent
022de797f1
commit
a650258158
|
@ -21,8 +21,10 @@
|
|||
#ifndef __BKE_CALLBACKS_H__
|
||||
#define __BKE_CALLBACKS_H__
|
||||
|
||||
struct Depsgraph;
|
||||
struct ID;
|
||||
struct Main;
|
||||
struct PointerRNA;
|
||||
|
||||
/**
|
||||
* Common suffix uses:
|
||||
|
@ -59,12 +61,21 @@ typedef enum {
|
|||
|
||||
typedef struct bCallbackFuncStore {
|
||||
struct bCallbackFuncStore *next, *prev;
|
||||
void (*func)(struct Main *, struct ID *, void *arg);
|
||||
void (*func)(struct Main *, struct PointerRNA **, const int num_pointers, void *arg);
|
||||
void *arg;
|
||||
short alloc;
|
||||
} bCallbackFuncStore;
|
||||
|
||||
void BKE_callback_exec(struct Main *bmain, struct ID *self, eCbEvent evt);
|
||||
void BKE_callback_exec(struct Main *bmain,
|
||||
struct PointerRNA **pointers,
|
||||
const int num_pointers,
|
||||
eCbEvent evt);
|
||||
void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt);
|
||||
void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt);
|
||||
void BKE_callback_exec_id_depsgraph(struct Main *bmain,
|
||||
struct ID *id,
|
||||
struct Depsgraph *depsgraph,
|
||||
eCbEvent evt);
|
||||
void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
|
||||
|
||||
void BKE_callback_global_init(void);
|
||||
|
|
|
@ -25,18 +25,55 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_types.h"
|
||||
#include "RNA_access.h"
|
||||
|
||||
static ListBase callback_slots[BKE_CB_EVT_TOT] = {{NULL}};
|
||||
|
||||
void BKE_callback_exec(struct Main *bmain, struct ID *self, eCbEvent evt)
|
||||
void BKE_callback_exec(struct Main *bmain,
|
||||
struct PointerRNA **pointers,
|
||||
const int num_pointers,
|
||||
eCbEvent evt)
|
||||
{
|
||||
ListBase *lb = &callback_slots[evt];
|
||||
bCallbackFuncStore *funcstore;
|
||||
|
||||
for (funcstore = lb->first; funcstore; funcstore = funcstore->next) {
|
||||
funcstore->func(bmain, self, funcstore->arg);
|
||||
funcstore->func(bmain, pointers, num_pointers, funcstore->arg);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt)
|
||||
{
|
||||
BKE_callback_exec(bmain, NULL, 0, evt);
|
||||
}
|
||||
|
||||
void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt)
|
||||
{
|
||||
PointerRNA id_ptr;
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
|
||||
PointerRNA *pointers[1] = {&id_ptr};
|
||||
|
||||
BKE_callback_exec(bmain, pointers, 1, evt);
|
||||
}
|
||||
|
||||
void BKE_callback_exec_id_depsgraph(struct Main *bmain,
|
||||
struct ID *id,
|
||||
struct Depsgraph *depsgraph,
|
||||
eCbEvent evt)
|
||||
{
|
||||
PointerRNA id_ptr;
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
|
||||
PointerRNA depsgraph_ptr;
|
||||
RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr);
|
||||
|
||||
PointerRNA *pointers[2] = {&id_ptr, &depsgraph_ptr};
|
||||
|
||||
BKE_callback_exec(bmain, pointers, 2, evt);
|
||||
}
|
||||
|
||||
void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
|
||||
{
|
||||
ListBase *lb = &callback_slots[evt];
|
||||
|
|
|
@ -1309,7 +1309,7 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
|
|||
|
||||
bool run_callbacks = DEG_id_type_any_updated(depsgraph);
|
||||
if (run_callbacks) {
|
||||
BKE_callback_exec(bmain, &scene->id, BKE_CB_EVT_DEPSGRAPH_UPDATE_PRE);
|
||||
BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_DEPSGRAPH_UPDATE_PRE);
|
||||
}
|
||||
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
|
@ -1327,7 +1327,8 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
|
|||
BKE_scene_update_sound(depsgraph, bmain);
|
||||
/* Notify python about depsgraph update. */
|
||||
if (run_callbacks) {
|
||||
BKE_callback_exec(bmain, &scene->id, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST);
|
||||
BKE_callback_exec_id_depsgraph(
|
||||
bmain, &scene->id, depsgraph, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST);
|
||||
}
|
||||
/* Inform editors about possible changes. */
|
||||
DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
|
||||
|
@ -1362,7 +1363,7 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
|
|||
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
|
||||
|
||||
/* Keep this first. */
|
||||
BKE_callback_exec(bmain, &scene->id, BKE_CB_EVT_FRAME_CHANGE_PRE);
|
||||
BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_FRAME_CHANGE_PRE);
|
||||
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
/* Update animated image textures for particles, modifiers, gpu, etc,
|
||||
|
@ -1384,7 +1385,7 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
|
|||
|
||||
/* Notify editors and python about recalc. */
|
||||
if (pass == 0) {
|
||||
BKE_callback_exec(bmain, &scene->id, BKE_CB_EVT_FRAME_CHANGE_POST);
|
||||
BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST);
|
||||
}
|
||||
|
||||
/* Inform editors about possible changes. */
|
||||
|
|
|
@ -172,7 +172,7 @@ static int ed_undo_step_impl(
|
|||
/* Note: ignore grease pencil for now. */
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wm->op_undo_depth++;
|
||||
BKE_callback_exec(
|
||||
BKE_callback_exec_id(
|
||||
bmain, &scene->id, (step_for_callback > 0) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
|
||||
wm->op_undo_depth--;
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ static int ed_undo_step_impl(
|
|||
Main *bmain = CTX_data_main(C);
|
||||
scene = CTX_data_scene(C);
|
||||
wm->op_undo_depth++;
|
||||
BKE_callback_exec(
|
||||
BKE_callback_exec_id(
|
||||
bmain, &scene->id, step_for_callback > 0 ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
|
||||
wm->op_undo_depth--;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,10 @@ static AppView *view = NULL;
|
|||
static FreestyleLineSet lineset_buffer;
|
||||
static bool lineset_copied = false;
|
||||
|
||||
static void load_post_callback(struct Main * /*main*/, struct ID * /*id*/, void * /*arg*/)
|
||||
static void load_post_callback(struct Main * /*main*/,
|
||||
struct PointerRNA ** /*pointers*/,
|
||||
const int /*num_pointers*/,
|
||||
void * /*arg*/)
|
||||
{
|
||||
lineset_copied = false;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,10 @@
|
|||
|
||||
#include "BPY_extern.h"
|
||||
|
||||
void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg);
|
||||
void bpy_app_generic_callback(struct Main *main,
|
||||
struct PointerRNA **pointers,
|
||||
const int num_pointers,
|
||||
void *arg);
|
||||
|
||||
static PyTypeObject BlenderAppCbType;
|
||||
|
||||
|
@ -290,32 +293,58 @@ void BPY_app_handlers_reset(const short do_all)
|
|||
PyGILState_Release(gilstate);
|
||||
}
|
||||
|
||||
static PyObject *choose_arguments(PyObject *func, PyObject *args_all, PyObject *args_single)
|
||||
{
|
||||
if (!PyFunction_Check(func)) {
|
||||
return args_all;
|
||||
}
|
||||
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
|
||||
if (code->co_argcount == 1) {
|
||||
return args_single;
|
||||
}
|
||||
return args_all;
|
||||
}
|
||||
|
||||
/* the actual callback - not necessarily called from py */
|
||||
void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *arg)
|
||||
void bpy_app_generic_callback(struct Main *UNUSED(main),
|
||||
struct PointerRNA **pointers,
|
||||
const int num_pointers,
|
||||
void *arg)
|
||||
{
|
||||
PyObject *cb_list = py_cb_array[POINTER_AS_INT(arg)];
|
||||
if (PyList_GET_SIZE(cb_list) > 0) {
|
||||
PyGILState_STATE gilstate = PyGILState_Ensure();
|
||||
|
||||
PyObject *args = PyTuple_New(1); /* save python creating each call */
|
||||
const int num_arguments = 2;
|
||||
PyObject *args_all = PyTuple_New(num_arguments); /* save python creating each call */
|
||||
PyObject *args_single = PyTuple_New(1);
|
||||
PyObject *func;
|
||||
PyObject *ret;
|
||||
Py_ssize_t pos;
|
||||
|
||||
/* setup arguments */
|
||||
if (id) {
|
||||
PointerRNA id_ptr;
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&id_ptr));
|
||||
for (int i = 0; i < num_pointers; ++i) {
|
||||
PyTuple_SET_ITEM(args_all, i, pyrna_struct_CreatePyObject(pointers[i]));
|
||||
}
|
||||
for (int i = num_pointers; i < num_arguments; ++i) {
|
||||
PyTuple_SET_ITEM(args_all, i, Py_INCREF_RET(Py_None));
|
||||
}
|
||||
|
||||
if (num_pointers == 0) {
|
||||
PyTuple_SET_ITEM(args_single, 0, Py_INCREF_RET(Py_None));
|
||||
}
|
||||
else if (num_pointers == 1) {
|
||||
args_single = args_all;
|
||||
}
|
||||
else {
|
||||
PyTuple_SET_ITEM(args, 0, Py_INCREF_RET(Py_None));
|
||||
PyTuple_SET_ITEM(args_single, 0, pyrna_struct_CreatePyObject(pointers[0]));
|
||||
}
|
||||
|
||||
/* Iterate the list and run the callbacks
|
||||
* note: don't store the list size since the scripts may remove themselves */
|
||||
for (pos = 0; pos < PyList_GET_SIZE(cb_list); pos++) {
|
||||
func = PyList_GET_ITEM(cb_list, pos);
|
||||
PyObject *args = choose_arguments(func, args_all, args_single);
|
||||
ret = PyObject_Call(func, args, NULL);
|
||||
if (ret == NULL) {
|
||||
/* Don't set last system variables because they might cause some
|
||||
|
@ -332,7 +361,10 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *ar
|
|||
}
|
||||
}
|
||||
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(args_all);
|
||||
if (args_single != args_all) {
|
||||
Py_DECREF(args_single);
|
||||
}
|
||||
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
|
|||
|
||||
/* NOTE: using G_MAIN seems valid here???
|
||||
* Not sure it's actually even used anyway, we could as well pass NULL? */
|
||||
BKE_callback_exec(G_MAIN, NULL, BKE_CB_EVT_RENDER_STATS);
|
||||
BKE_callback_exec_null(G_MAIN, BKE_CB_EVT_RENDER_STATS);
|
||||
|
||||
fputc('\n', stdout);
|
||||
fflush(stdout);
|
||||
|
@ -2090,7 +2090,7 @@ void RE_RenderFrame(Render *re,
|
|||
int frame,
|
||||
const bool write_still)
|
||||
{
|
||||
BKE_callback_exec(re->main, (ID *)scene, BKE_CB_EVT_RENDER_INIT);
|
||||
BKE_callback_exec_id(re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
|
||||
|
||||
/* Ugly global still...
|
||||
* is to prevent preview events and signal subsurfs etc to make full resol. */
|
||||
|
@ -2103,9 +2103,9 @@ void RE_RenderFrame(Render *re,
|
|||
const RenderData rd = scene->r;
|
||||
MEM_reset_peak_memory();
|
||||
|
||||
render_init_depsgraph(re);
|
||||
BKE_callback_exec_id(re->main, &scene->id, BKE_CB_EVT_RENDER_PRE);
|
||||
|
||||
BKE_callback_exec(re->main, (ID *)scene, BKE_CB_EVT_RENDER_PRE);
|
||||
render_init_depsgraph(re);
|
||||
|
||||
do_render_all_options(re);
|
||||
|
||||
|
@ -2131,14 +2131,14 @@ void RE_RenderFrame(Render *re,
|
|||
}
|
||||
|
||||
/* keep after file save */
|
||||
BKE_callback_exec(re->main, (ID *)scene, BKE_CB_EVT_RENDER_POST);
|
||||
BKE_callback_exec_id(re->main, &scene->id, BKE_CB_EVT_RENDER_POST);
|
||||
if (write_still) {
|
||||
BKE_callback_exec(re->main, (ID *)scene, BKE_CB_EVT_RENDER_WRITE);
|
||||
BKE_callback_exec_id(re->main, &scene->id, BKE_CB_EVT_RENDER_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_callback_exec(
|
||||
re->main, (ID *)scene, G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
|
||||
BKE_callback_exec_id(
|
||||
re->main, &scene->id, G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
|
||||
|
||||
RE_CleanAfterRender(re);
|
||||
|
||||
|
@ -2429,7 +2429,7 @@ static int do_write_image_or_movie(Render *re,
|
|||
|
||||
/* NOTE: using G_MAIN seems valid here???
|
||||
* Not sure it's actually even used anyway, we could as well pass NULL? */
|
||||
BKE_callback_exec(G_MAIN, NULL, BKE_CB_EVT_RENDER_STATS);
|
||||
BKE_callback_exec_null(G_MAIN, BKE_CB_EVT_RENDER_STATS);
|
||||
|
||||
BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime - render_time);
|
||||
printf(" (Saving: %s)\n", name);
|
||||
|
@ -2495,7 +2495,7 @@ void RE_RenderAnim(Render *re,
|
|||
const bool is_multiview_name = ((rd.scemode & R_MULTIVIEW) != 0 &&
|
||||
(rd.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL));
|
||||
|
||||
BKE_callback_exec(re->main, (ID *)scene, BKE_CB_EVT_RENDER_INIT);
|
||||
BKE_callback_exec_id(re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
|
||||
|
||||
/* do not fully call for each frame, it initializes & pops output window */
|
||||
if (!render_initialize_from_main(re, &rd, bmain, scene, single_layer, camera_override, 0, 1)) {
|
||||
|
@ -2660,8 +2660,8 @@ void RE_RenderAnim(Render *re,
|
|||
|
||||
re->r.cfra = scene->r.cfra; /* weak.... */
|
||||
|
||||
/* run callbacs before rendering, before the scene is updated */
|
||||
BKE_callback_exec(re->main, (ID *)scene, BKE_CB_EVT_RENDER_PRE);
|
||||
/* run callbacks before rendering, before the scene is updated */
|
||||
BKE_callback_exec_id(re->main, &scene->id, BKE_CB_EVT_RENDER_PRE);
|
||||
|
||||
do_render_all_options(re);
|
||||
totrendered++;
|
||||
|
@ -2712,8 +2712,8 @@ void RE_RenderAnim(Render *re,
|
|||
|
||||
if (G.is_break == false) {
|
||||
/* keep after file save */
|
||||
BKE_callback_exec(re->main, (ID *)scene, BKE_CB_EVT_RENDER_POST);
|
||||
BKE_callback_exec(re->main, (ID *)scene, BKE_CB_EVT_RENDER_WRITE);
|
||||
BKE_callback_exec_id(re->main, &scene->id, BKE_CB_EVT_RENDER_POST);
|
||||
BKE_callback_exec_id(re->main, &scene->id, BKE_CB_EVT_RENDER_WRITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2731,8 +2731,8 @@ void RE_RenderAnim(Render *re,
|
|||
|
||||
re->flag &= ~R_ANIMATION;
|
||||
|
||||
BKE_callback_exec(
|
||||
re->main, (ID *)scene, G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
|
||||
BKE_callback_exec_id(
|
||||
re->main, &scene->id, G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
|
||||
BKE_sound_reset_scene_specs(re->pipeline_scene_eval);
|
||||
|
||||
RE_CleanAfterRender(re);
|
||||
|
|
|
@ -537,16 +537,16 @@ static void wm_file_read_post(bContext *C,
|
|||
|
||||
if (use_userdef) {
|
||||
if (is_factory_startup) {
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_LOAD_FACTORY_USERDEF_POST);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_USERDEF_POST);
|
||||
}
|
||||
}
|
||||
|
||||
if (use_data) {
|
||||
/* important to do before NULL'ing the context */
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_VERSION_UPDATE);
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_LOAD_POST);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_POST);
|
||||
if (is_factory_startup) {
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,7 +609,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
|
|||
|
||||
WM_cursor_wait(1);
|
||||
|
||||
BKE_callback_exec(CTX_data_main(C), NULL, BKE_CB_EVT_LOAD_PRE);
|
||||
BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
|
||||
BLI_timer_on_file_load();
|
||||
|
||||
UI_view2d_zoom_cache_reset();
|
||||
|
@ -807,7 +807,7 @@ void wm_homefile_read(bContext *C,
|
|||
}
|
||||
|
||||
if (use_data) {
|
||||
BKE_callback_exec(CTX_data_main(C), NULL, BKE_CB_EVT_LOAD_PRE);
|
||||
BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
|
||||
BLI_timer_on_file_load();
|
||||
|
||||
G.relbase_valid = 0;
|
||||
|
@ -1368,7 +1368,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
|
|||
|
||||
/* Call pre-save callbacks before writing preview,
|
||||
* that way you can generate custom file thumbnail. */
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_SAVE_PRE);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
|
||||
|
||||
/* Enforce full override check/generation on file save. */
|
||||
BKE_main_override_library_operations_create(bmain, true);
|
||||
|
@ -1421,7 +1421,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
|
|||
wm_history_file_update();
|
||||
}
|
||||
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_SAVE_POST);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
|
||||
|
||||
/* run this function after because the file cant be written before the blend is */
|
||||
if (ibuf_thumb) {
|
||||
|
@ -1646,7 +1646,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_SAVE_PRE);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
|
||||
|
||||
/* check current window and close it if temp */
|
||||
if (win && WM_window_is_temp_screen(win)) {
|
||||
|
@ -1674,7 +1674,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
|
|||
|
||||
G.save_over = 0;
|
||||
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_SAVE_POST);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
|
|
@ -378,10 +378,10 @@ void WM_init(bContext *C, int argc, const char **argv)
|
|||
* note that recovering the last session does its own callbacks. */
|
||||
CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
|
||||
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_VERSION_UPDATE);
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_LOAD_POST);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_POST);
|
||||
if (is_factory_startup) {
|
||||
BKE_callback_exec(bmain, NULL, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST);
|
||||
BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST);
|
||||
}
|
||||
|
||||
wm_file_read_report(C, bmain);
|
||||
|
|
Loading…
Reference in New Issue