diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 2b075128fef..b642b61fcdc 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -132,6 +132,7 @@ class INFO_MT_file(Menu): layout.operator_context = 'INVOKE_AREA' layout.operator("wm.link", text="Link", icon='LINK_BLEND') layout.operator("wm.append", text="Append", icon='APPEND_BLEND') + layout.menu("INFO_MT_file_previews") layout.separator() @@ -195,6 +196,15 @@ class INFO_MT_file_external_data(Menu): layout.operator("file.find_missing_files") +class INFO_MT_file_previews(Menu): + bl_label = "Data Previews" + + def draw(self, context): + layout = self.layout + + layout.operator("wm.previews_ensure") + + class INFO_MT_game(Menu): bl_label = "Game" diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 32fa641e3ae..de3843c91eb 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -72,7 +72,7 @@ void ED_preview_init_dbase(void); void ED_preview_free_dbase(void); void ED_preview_shader_job(const struct bContext *C, void *owner, struct ID *id, struct ID *parent, struct MTex *slot, int sizex, int sizey, int method); -void ED_preview_icon_render(const struct bContext *C, void *owner, struct ID *id, unsigned int *rect, int sizex, int sizey); +void ED_preview_icon_render(struct Scene *scene, struct ID *id, unsigned int *rect, int sizex, int sizey); void ED_preview_icon_job(const struct bContext *C, void *owner, struct ID *id, unsigned int *rect, int sizex, int sizey); void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain); diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index 2ba3d309aa7..74927428363 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -64,7 +64,8 @@ void UI_icons_init(int first_dyn_id); int UI_icon_get_width(int icon_id); int UI_icon_get_height(int icon_id); -void UI_id_icon_render(const struct bContext *C, struct ID *id, const bool big, const bool use_job); +void UI_id_icon_render( + const struct bContext *C, struct Scene *scene, struct ID *id, const bool big, const bool use_job); void UI_icon_draw(float x, float y, int icon_id); void UI_icon_draw_preview(float x, float y, int icon_id); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index ac9abe8e781..679681cb372 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -931,7 +931,8 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size) /* only called when icon has changed */ /* only call with valid pointer from UI_icon_draw */ -static void icon_set_image(const bContext *C, ID *id, PreviewImage *prv_img, enum eIconSizes size, const bool use_job) +static void icon_set_image( + const bContext *C, Scene *scene, ID *id, PreviewImage *prv_img, enum eIconSizes size, const bool use_job) { if (!prv_img) { if (G.debug & G_DEBUG) @@ -946,8 +947,11 @@ static void icon_set_image(const bContext *C, ID *id, PreviewImage *prv_img, enu ED_preview_icon_job(C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]); } else { + if (!scene) { + scene = CTX_data_scene(C); + } /* Immediate version */ - ED_preview_icon_render(C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]); + ED_preview_icon_render(scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]); } } @@ -1155,25 +1159,26 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al } } -static void ui_id_preview_image_render_size(const bContext *C, ID *id, PreviewImage *pi, int size, const bool use_job) +static void ui_id_preview_image_render_size( + const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job) { if ((pi->changed[size] || !pi->rect[size])) { /* changed only ever set by dynamic icons */ /* create the rect if necessary */ - icon_set_image(C, id, pi, size, use_job); + icon_set_image(C, scene, id, pi, size, use_job); pi->changed[size] = 0; } } -void UI_id_icon_render(const bContext *C, ID *id, const bool big, const bool use_job) +void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big, const bool use_job) { PreviewImage *pi = BKE_previewimg_get(id); if (pi) { if (big) - ui_id_preview_image_render_size(C, id, pi, ICON_SIZE_PREVIEW, use_job); /* bigger preview size */ + ui_id_preview_image_render_size(C, scene, id, pi, ICON_SIZE_PREVIEW, use_job); /* bigger preview size */ else - ui_id_preview_image_render_size(C, id, pi, ICON_SIZE_ICON, use_job); /* icon size */ + ui_id_preview_image_render_size(C, scene, id, pi, ICON_SIZE_ICON, use_job); /* icon size */ } } @@ -1189,7 +1194,7 @@ static void ui_id_brush_render(const bContext *C, ID *id) /* check if rect needs to be created; changed * only set by dynamic icons */ if ((pi->changed[i] || !pi->rect[i])) { - icon_set_image(C, id, pi, i, true); + icon_set_image(C, NULL, id, pi, i, true); pi->changed[i] = 0; } } @@ -1265,7 +1270,7 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big) case ID_LA: /* fall through */ iconid = BKE_icon_getid(id); /* checks if not exists, or changed */ - UI_id_icon_render(C, id, big, true); + UI_id_icon_render(C, NULL, id, big, true); break; default: break; diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 8833d76fde2..ea80a07fdd4 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -1098,14 +1098,13 @@ static void icon_preview_free(void *customdata) MEM_freeN(ip); } -void ED_preview_icon_render(const bContext *C, void *UNUSED(owner), ID *id, unsigned int *rect, int sizex, int sizey) +void ED_preview_icon_render(Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey) { IconPreview ip = {0}; short stop = false, update = false; float progress = 0.0f; - /* customdata for preview thread */ - ip.scene = CTX_data_scene(C); + ip.scene = scene; ip.owner = id; ip.id = id; diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index fabb69b8eff..c1c31f6795d 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -101,7 +101,6 @@ #include "GHOST_Path-api.h" #include "UI_interface.h" -#include "UI_interface_icons.h" #include "UI_view2d.h" #include "GPU_draw.h" @@ -895,24 +894,6 @@ bool write_crash_blend(void) } } -static void UNUSED_FUNCTION(wm_ensure_previews)(bContext *C, Main *mainvar) -{ - ListBase *lb[] = {&mainvar->mat, &mainvar->tex, &mainvar->image, &mainvar->world, &mainvar->lamp, NULL}; - ID *id; - int i; - - for (i = 0; lb[i]; i++) { - for (id = lb[i]->first; id; id = id->next) { - /* Only preview non-library datablocks, lib ones do not pertain to this .blend file! - * Same goes for ID with no user. */ - if (!id->lib && (id->us != 0)) { - UI_id_icon_render(C, id, false, false); - UI_id_icon_render(C, id, true, false); - } - } - } -} - /** * \see #wm_homefile_write_exec wraps #BLO_write_file in a similar way. */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 5b944a7b1ec..02a029fc3f3 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -61,6 +61,7 @@ #include "BLI_blenlib.h" #include "BLI_dial.h" #include "BLI_dynstr.h" /*for WM_operator_pystring */ +#include "BLI_linklist_stack.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -76,6 +77,7 @@ #include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_material.h" @@ -105,6 +107,7 @@ #include "RNA_enum_types.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "UI_resources.h" #include "WM_api.h" @@ -4705,6 +4708,90 @@ static void WM_OT_dependency_relations(wmOperatorType *ot) ot->exec = dependency_relations_exec; } +/* *************************** Mat/tex/etc. previews generation ************* */ + +typedef struct PreviewsIDEnsureStack { + Scene *scene; + + BLI_LINKSTACK_DECLARE(id_stack, ID *); +} PreviewsIDEnsureStack; + +static void previews_id_ensure(bContext *C, Scene *scene, ID *id) +{ + BLI_assert(ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)); + + /* Only preview non-library datablocks, lib ones do not pertain to this .blend file! + * Same goes for ID with no user. */ + if (!id->lib && (id->us != 0)) { + UI_id_icon_render(C, scene, id, false, false); + UI_id_icon_render(C, scene, id, true, false); + } +} + +static bool previews_id_ensure_callback(void *todo_v, ID **idptr, int UNUSED(cd_flag)) +{ + PreviewsIDEnsureStack *todo = todo_v; + ID *id = *idptr; + + if (id && (id->flag & LIB_DOIT)) { + if (ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)) { + previews_id_ensure(NULL, todo->scene, id); + } + id->flag &= ~LIB_DOIT; /* Tag the ID as done in any case. */ + BLI_LINKSTACK_PUSH(todo->id_stack, id); + } + + return true; +} + +static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + ListBase *lb[] = {&bmain->mat, &bmain->tex, &bmain->image, &bmain->world, &bmain->lamp, NULL}; + PreviewsIDEnsureStack preview_id_stack; + Scene *scene; + ID *id; + int i; + + /* We use LIB_DOIT to check whether we have already handled a given ID or not. */ + BKE_main_id_flag_all(bmain, LIB_DOIT, true); + + BLI_LINKSTACK_INIT(preview_id_stack.id_stack); + + for (scene = bmain->scene.first; scene; scene = scene->id.next) { + preview_id_stack.scene = scene; + id = (ID *)scene; + + do { + /* This will loop over all IDs linked by current one, render icons for them if needed, + * and add them to 'todo' preview_id_stack. */ + BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_stack, IDWALK_READONLY); + } while((id = BLI_LINKSTACK_POP(preview_id_stack.id_stack))); + } + + BLI_LINKSTACK_FREE(preview_id_stack.id_stack); + + /* Check a last time for ID not used (fake users only, in theory), and + * do our best for those, using current scene... */ + for (i = 0; lb[i]; i++) { + for (id = lb[i]->first; id; id = id->next) { + previews_id_ensure(C, NULL, id); + } + } + + return OPERATOR_FINISHED; +} + +static void WM_OT_previews_ensure(wmOperatorType *ot) +{ + ot->name = "Refresh DataBlock Previews"; + ot->idname = "WM_OT_previews_ensure"; + ot->description = "Ensure datablock previews are available and up-to-date " + "(to be saved in .blend file, only for some types like materials, textures, etc.)"; + + ot->exec = previews_ensure_exec; +} + /* ******************************************************* */ static void operatortype_ghash_free_cb(wmOperatorType *ot) @@ -4768,6 +4855,7 @@ void wm_operatortype_init(void) #if defined(WIN32) WM_operatortype_append(WM_OT_console_toggle); #endif + WM_operatortype_append(WM_OT_previews_ensure); } /* circleselect-like modal operators */