/** * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing. */ PreviewImage *BKE_previewimg_cached_thumbnail_read( const char *name, const char *path, const int source, bool force_update) { PreviewImage *prv = NULL; void **prv_p; prv_p = BLI_ghash_lookup_p(gCachedPreviews, name); if (prv_p) { prv = *prv_p; BLI_assert(prv); } if (prv && force_update) { const char *prv_deferred_data = PRV_DEFERRED_DATA(prv); if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) { /* If same path, no need to re-allocate preview, just clear it up. */ BKE_previewimg_clear(prv); } else { BKE_previewimg_free(&prv); } } if (!prv) { /* We pack needed data for lazy loading (source type, in a single char, and path). */ const size_t deferred_data_size = strlen(path) + 2; char *deferred_data; prv = previewimg_create_ex(deferred_data_size); deferred_data = PRV_DEFERRED_DATA(prv); deferred_data[0] = source; memcpy(&deferred_data[1], path, deferred_data_size - 1); force_update = true; } if (force_update) { if (prv_p) { *prv_p = prv; } else { BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv); } } return prv; }
/** Handle deferred (lazy) loading/generation of preview image, if needed. * For now, only used with file thumbnails. */ void BKE_previewimg_ensure(PreviewImage *prv, const int size) { if (prv->use_deferred) { const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]); const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]); if (do_icon || do_preview) { ImBuf *thumb; char *prv_deferred_data = PRV_DEFERRED_DATA(prv); int source = prv_deferred_data[0]; char *path = &prv_deferred_data[1]; int icon_w, icon_h; thumb = IMB_thumb_manage(path, THB_LARGE, source); if (thumb) { /* PreviewImage assumes premultiplied alhpa... */ IMB_premultiply_alpha(thumb); if (do_preview) { prv->w[ICON_SIZE_PREVIEW] = thumb->x; prv->h[ICON_SIZE_PREVIEW] = thumb->y; prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect); prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED); } if (do_icon) { if (thumb->x > thumb->y) { icon_w = ICON_RENDER_DEFAULT_HEIGHT; icon_h = (thumb->y * icon_w) / thumb->x + 1; } else if (thumb->x < thumb->y) { icon_h = ICON_RENDER_DEFAULT_HEIGHT; icon_w = (thumb->x * icon_h) / thumb->y + 1; } else { icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT; } IMB_scaleImBuf(thumb, icon_w, icon_h); prv->w[ICON_SIZE_ICON] = icon_w; prv->h[ICON_SIZE_ICON] = icon_h; prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect); prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED); } IMB_freeImBuf(thumb); } } } }
static void icon_preview_startjob(void *customdata, short *stop, short *do_update) { ShaderPreview *sp = customdata; if (sp->pr_method == PR_ICON_DEFERRED) { PreviewImage *prv = sp->owner; ImBuf *thumb; char *deferred_data = PRV_DEFERRED_DATA(prv); int source = deferred_data[0]; char *path = &deferred_data[1]; // printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path); thumb = IMB_thumb_manage(path, THB_LARGE, source); if (thumb) { /* PreviewImage assumes premultiplied alhpa... */ IMB_premultiply_alpha(thumb); icon_copy_rect(thumb, sp->sizex, sp->sizey, sp->pr_rect); IMB_freeImBuf(thumb); } } else { ID *id = sp->id; short idtype = GS(id->name); if (idtype == ID_IM) { Image *ima = (Image *)id; ImBuf *ibuf = NULL; ImageUser iuser = {NULL}; /* ima->ok is zero when Image cannot load */ if (ima == NULL || ima->ok == 0) return; /* setup dummy image user */ iuser.ok = iuser.framenr = 1; iuser.scene = sp->scene; /* elubie: this needs to be changed: here image is always loaded if not * already there. Very expensive for large images. Need to find a way to * only get existing ibuf */ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); if (ibuf == NULL || ibuf->rect == NULL) { BKE_image_release_ibuf(ima, ibuf, NULL); return; } icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect); *do_update = true; BKE_image_release_ibuf(ima, ibuf, NULL); } else if (idtype == ID_BR) { Brush *br = (Brush *)id; br->icon_imbuf = get_brush_icon(br); memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int)); if (!(br->icon_imbuf) || !(br->icon_imbuf->rect)) return; icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect); *do_update = true; } else { /* re-use shader job */ shader_preview_startjob(customdata, stop, do_update); /* world is rendered with alpha=0, so it wasn't displayed * this could be render option for sky to, for later */ if (idtype == ID_WO) { set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255); } else if (idtype == ID_MA) { Material *ma = (Material *)id; if (ma->material_type == MA_TYPE_HALO) set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255); } } } }