Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-12-27 19:26:09 +0300
committerJacques Lucke <jacques@blender.org>2021-12-27 19:26:09 +0300
commit1c9d8fcb477c5aea5555781cc209d60da126f48f (patch)
tree0dfd7e47181b1750d9f6521ef71150ae7178fce5 /source/blender/editors/render/render_preview.c
parent644e6c7a3e99ae1d43edb25a7d4c3ed86727faba (diff)
Render: move editor/render module to c++
Doing this in preparation for some work on asset preview generation. Differential Revision: https://developer.blender.org/D13676
Diffstat (limited to 'source/blender/editors/render/render_preview.c')
-rw-r--r--source/blender/editors/render/render_preview.c1914
1 files changed, 0 insertions, 1914 deletions
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
deleted file mode 100644
index 409430d28f1..00000000000
--- a/source/blender/editors/render/render_preview.c
+++ /dev/null
@@ -1,1914 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edrend
- */
-
-/* global includes */
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef WIN32
-# include <unistd.h>
-#else
-# include <io.h>
-#endif
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "PIL_time.h"
-
-#include "BLO_readfile.h"
-
-#include "DNA_brush_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
-#include "DNA_light_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_world_types.h"
-
-#include "BKE_animsys.h"
-#include "BKE_appdir.h"
-#include "BKE_armature.h"
-#include "BKE_brush.h"
-#include "BKE_colortools.h"
-#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_icons.h"
-#include "BKE_idprop.h"
-#include "BKE_image.h"
-#include "BKE_layer.h"
-#include "BKE_lib_id.h"
-#include "BKE_light.h"
-#include "BKE_main.h"
-#include "BKE_material.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-#include "BKE_texture.h"
-#include "BKE_world.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_thumbs.h"
-
-#include "BIF_glutil.h"
-
-#include "GPU_shader.h"
-
-#include "RE_engine.h"
-#include "RE_pipeline.h"
-#include "RE_texture.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_armature.h"
-#include "ED_datafiles.h"
-#include "ED_render.h"
-#include "ED_screen.h"
-#include "ED_view3d.h"
-#include "ED_view3d_offscreen.h"
-
-#include "UI_interface_icons.h"
-
-#ifndef NDEBUG
-/* Used for database init assert(). */
-# include "BLI_threads.h"
-#endif
-
-static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect);
-
-/* -------------------------------------------------------------------- */
-/** \name Local Structs
- * \{ */
-
-typedef struct ShaderPreview {
- /* from wmJob */
- void *owner;
- short *stop, *do_update;
-
- Scene *scene;
- ID *id, *id_copy;
- ID *parent;
- MTex *slot;
-
- /* datablocks with nodes need full copy during preview render, glsl uses it too */
- Material *matcopy;
- Tex *texcopy;
- Light *lampcopy;
- World *worldcopy;
-
- /** Copy of the active objects #Object.color */
- float color[4];
-
- int sizex, sizey;
- uint *pr_rect;
- int pr_method;
- bool own_id_copy;
-
- Main *bmain;
- Main *pr_main;
-} ShaderPreview;
-
-typedef struct IconPreviewSize {
- struct IconPreviewSize *next, *prev;
- int sizex, sizey;
- uint *rect;
-} IconPreviewSize;
-
-typedef struct IconPreview {
- Main *bmain;
- Depsgraph *depsgraph; /* May be NULL (see #WM_OT_previews_ensure). */
- Scene *scene;
- void *owner;
- ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
- ListBase sizes;
-
- /* May be NULL, is used for rendering IDs that require some other object for it to be applied on
- * before the ID can be represented as an image, for example when rendering an Action. */
- struct Object *active_object;
-} IconPreview;
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Preview for Buttons
- * \{ */
-
-static Main *G_pr_main = NULL;
-static Main *G_pr_main_grease_pencil = NULL;
-
-#ifndef WITH_HEADLESS
-static Main *load_main_from_memory(const void *blend, int blend_size)
-{
- const int fileflags = G.fileflags;
- Main *bmain = NULL;
- BlendFileData *bfd;
-
- G.fileflags |= G_FILE_NO_UI;
- bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, NULL);
- if (bfd) {
- bmain = bfd->main;
-
- MEM_freeN(bfd);
- }
- G.fileflags = fileflags;
-
- return bmain;
-}
-#endif
-
-void ED_preview_ensure_dbase(void)
-{
-#ifndef WITH_HEADLESS
- static bool base_initialized = false;
- BLI_assert(BLI_thread_is_main());
- if (!base_initialized) {
- G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size);
- G_pr_main_grease_pencil = load_main_from_memory(datatoc_preview_grease_pencil_blend,
- datatoc_preview_grease_pencil_blend_size);
- base_initialized = true;
- }
-#endif
-}
-
-static bool check_engine_supports_preview(Scene *scene)
-{
- RenderEngineType *type = RE_engines_find(scene->r.engine);
- return (type->flag & RE_USE_PREVIEW) != 0;
-}
-
-static bool preview_method_is_render(int pr_method)
-{
- return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
-}
-
-void ED_preview_free_dbase(void)
-{
- if (G_pr_main) {
- BKE_main_free(G_pr_main);
- }
-
- if (G_pr_main_grease_pencil) {
- BKE_main_free(G_pr_main_grease_pencil);
- }
-}
-
-static Scene *preview_get_scene(Main *pr_main)
-{
- if (pr_main == NULL) {
- return NULL;
- }
-
- return pr_main->scenes.first;
-}
-
-static const char *preview_collection_name(const ePreviewType pr_type)
-{
- switch (pr_type) {
- case MA_FLAT:
- return "Flat";
- case MA_SPHERE:
- return "Sphere";
- case MA_CUBE:
- return "Cube";
- case MA_SHADERBALL:
- return "Shader Ball";
- case MA_CLOTH:
- return "Cloth";
- case MA_FLUID:
- return "Fluid";
- case MA_SPHERE_A:
- return "World Sphere";
- case MA_LAMP:
- return "Lamp";
- case MA_SKY:
- return "Sky";
- case MA_HAIR:
- return "Hair";
- case MA_ATMOS:
- return "Atmosphere";
- default:
- BLI_assert_msg(0, "Unknown preview type");
- return "";
- }
-}
-
-static bool render_engine_supports_ray_visibility(const Scene *sce)
-{
- return !STREQ(sce->r.engine, RE_engine_id_BLENDER_EEVEE);
-}
-
-static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type)
-{
- /* Set appropriate layer as visible. */
- LayerCollection *lc = view_layer->layer_collections.first;
- const char *collection_name = preview_collection_name(pr_type);
-
- for (lc = lc->layer_collections.first; lc; lc = lc->next) {
- if (STREQ(lc->collection->id.name + 2, collection_name)) {
- lc->collection->flag &= ~COLLECTION_HIDE_RENDER;
- }
- else {
- lc->collection->flag |= COLLECTION_HIDE_RENDER;
- }
- }
-}
-
-static const char *preview_floor_material_name(const Scene *scene,
- const ePreviewRenderMethod pr_method)
-{
- if (pr_method == PR_ICON_RENDER && render_engine_supports_ray_visibility(scene)) {
- return "FloorHidden";
- }
- return "Floor";
-}
-
-static void switch_preview_floor_material(Main *pr_main,
- Mesh *me,
- const Scene *scene,
- const ePreviewRenderMethod pr_method)
-{
- if (me->totcol == 0) {
- return;
- }
-
- const char *material_name = preview_floor_material_name(scene, pr_method);
- Material *mat = BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2);
- if (mat) {
- me->mat[0] = mat;
- }
-}
-
-static void switch_preview_floor_visibility(Main *pr_main,
- const Scene *scene,
- ViewLayer *view_layer,
- const ePreviewRenderMethod pr_method)
-{
- /* Hide floor for icon renders. */
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- if (STREQ(base->object->id.name + 2, "Floor")) {
- base->object->visibility_flag &= ~OB_HIDE_RENDER;
- if (pr_method == PR_ICON_RENDER) {
- if (!render_engine_supports_ray_visibility(scene)) {
- base->object->visibility_flag |= OB_HIDE_RENDER;
- }
- }
- if (base->object->type == OB_MESH) {
- switch_preview_floor_material(pr_main, base->object->data, scene, pr_method);
- }
- }
- }
-}
-
-static void set_preview_visibility(Main *pr_main,
- Scene *scene,
- ViewLayer *view_layer,
- const ePreviewType pr_type,
- const ePreviewRenderMethod pr_method)
-{
- switch_preview_collection_visibilty(view_layer, pr_type);
- switch_preview_floor_visibility(pr_main, scene, view_layer, pr_method);
- BKE_layer_collection_sync(scene, view_layer);
-}
-
-static World *preview_get_localized_world(ShaderPreview *sp, World *world)
-{
- if (world == NULL) {
- return NULL;
- }
- if (sp->worldcopy != NULL) {
- return sp->worldcopy;
- }
-
- ID *id_copy = BKE_id_copy_ex(NULL,
- &world->id,
- NULL,
- LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
- LIB_ID_COPY_NO_ANIMDATA);
- sp->worldcopy = (World *)id_copy;
- BLI_addtail(&sp->pr_main->worlds, sp->worldcopy);
- return sp->worldcopy;
-}
-
-static ID *duplicate_ids(ID *id, const bool allow_failure)
-{
- if (id == NULL) {
- /* Non-ID preview render. */
- return NULL;
- }
-
- switch (GS(id->name)) {
- case ID_OB:
- case ID_MA:
- case ID_TE:
- case ID_LA:
- case ID_WO: {
- BLI_assert(BKE_previewimg_id_supports_jobs(id));
- ID *id_copy = BKE_id_copy_ex(
- NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
- return id_copy;
- }
- /* These support threading, but don't need duplicating. */
- case ID_IM:
- case ID_BR:
- BLI_assert(BKE_previewimg_id_supports_jobs(id));
- return NULL;
- default:
- if (!allow_failure) {
- BLI_assert_msg(0, "ID type preview not supported.");
- }
- return NULL;
- }
-}
-
-static const char *preview_world_name(const Scene *sce,
- const ID_Type id_type,
- const ePreviewRenderMethod pr_method)
-{
- /* When rendering material icons the floor will not be shown in the output. Cycles will use a
- * material trick to show the floor in the reflections, but hide the floor for camera rays. For
- * Eevee we use a transparent world that has a projected grid.
- *
- * In the future when Eevee supports vulkan raytracing we can re-evaluate and perhaps remove this
- * approximation.
- */
- if (id_type == ID_MA && pr_method == PR_ICON_RENDER &&
- !render_engine_supports_ray_visibility(sce)) {
- return "WorldFloor";
- }
- return "World";
-}
-
-static World *preview_get_world(Main *pr_main,
- const Scene *sce,
- const ID_Type id_type,
- const ePreviewRenderMethod pr_method)
-{
- World *result = NULL;
- const char *world_name = preview_world_name(sce, id_type, pr_method);
- result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2);
-
- /* No world found return first world. */
- if (result == NULL) {
- result = pr_main->worlds.first;
- }
-
- BLI_assert_msg(result, "Preview file has no world.");
- return result;
-}
-
-static void preview_sync_exposure(World *dst, const World *src)
-{
- BLI_assert(dst);
- BLI_assert(src);
- dst->exp = src->exp;
- dst->range = src->range;
-}
-
-static World *preview_prepare_world(Main *pr_main,
- const Scene *sce,
- const World *world,
- const ID_Type id_type,
- const ePreviewRenderMethod pr_method)
-{
- World *result = preview_get_world(pr_main, sce, id_type, pr_method);
- if (world) {
- preview_sync_exposure(result, world);
- }
- return result;
-}
-
-/* call this with a pointer to initialize preview scene */
-/* call this with NULL to restore assigned ID pointers in preview scene */
-static Scene *preview_prepare_scene(
- Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
-{
- Scene *sce;
- Main *pr_main = sp->pr_main;
-
- memcpy(pr_main->filepath, BKE_main_blendfile_path(bmain), sizeof(pr_main->filepath));
-
- sce = preview_get_scene(pr_main);
- if (sce) {
- ViewLayer *view_layer = sce->view_layers.first;
-
- /* Only enable the combined renderpass */
- view_layer->passflag = SCE_PASS_COMBINED;
- view_layer->eevee.render_passes = 0;
-
- /* this flag tells render to not execute depsgraph or ipos etc */
- sce->r.scemode |= R_BUTS_PREVIEW;
- BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine));
-
- sce->r.color_mgt_flag = scene->r.color_mgt_flag;
- BKE_color_managed_display_settings_copy(&sce->display_settings, &scene->display_settings);
-
- BKE_color_managed_view_settings_free(&sce->view_settings);
- BKE_color_managed_view_settings_copy(&sce->view_settings, &scene->view_settings);
-
- if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO) {
- sce->r.alphamode = R_ALPHAPREMUL;
- }
- else {
- sce->r.alphamode = R_ADDSKY;
- }
-
- sce->r.cfra = scene->r.cfra;
-
- /* Setup the world. */
- sce->world = preview_prepare_world(pr_main, sce, scene->world, id_type, sp->pr_method);
-
- if (id_type == ID_TE) {
- /* Texture is not actually rendered with engine, just set dummy value. */
- BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
- }
-
- if (id_type == ID_MA) {
- Material *mat = NULL, *origmat = (Material *)id;
-
- if (origmat) {
- /* work on a copy */
- BLI_assert(sp->id_copy != NULL);
- mat = sp->matcopy = (Material *)sp->id_copy;
- sp->id_copy = NULL;
- BLI_addtail(&pr_main->materials, mat);
-
- /* Use current scene world for lighting. */
- if (mat->pr_flag == MA_PREVIEW_WORLD && sp->pr_method == PR_BUTS_RENDER) {
- /* Use current scene world to light sphere. */
- sce->world = preview_get_localized_world(sp, scene->world);
- }
- else if (sce->world && sp->pr_method != PR_ICON_RENDER) {
- /* Use a default world color. Using the current
- * scene world can be slow if it has big textures. */
- sce->world->use_nodes = false;
- sce->world->horr = 0.05f;
- sce->world->horg = 0.05f;
- sce->world->horb = 0.05f;
- }
-
- /* For grease pencil, always use sphere for icon renders. */
- const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER &&
- sp->pr_main == G_pr_main_grease_pencil) ?
- MA_SPHERE_A :
- mat->pr_type;
- set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
- }
- else {
- sce->display.render_aa = SCE_DISPLAY_AA_OFF;
- }
-
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- if (base->object->id.name[2] == 'p') {
- /* copy over object color, in case material uses it */
- copy_v4_v4(base->object->color, sp->color);
-
- if (OB_TYPE_SUPPORT_MATERIAL(base->object->type)) {
- /* don't use BKE_object_material_assign, it changed mat->id.us, which shows in the UI
- */
- Material ***matar = BKE_object_material_array_p(base->object);
- int actcol = max_ii(base->object->actcol - 1, 0);
-
- if (matar && actcol < base->object->totcol) {
- (*matar)[actcol] = mat;
- }
- }
- else if (base->object->type == OB_LAMP) {
- base->flag |= BASE_VISIBLE_DEPSGRAPH;
- }
- }
- }
- }
- else if (id_type == ID_TE) {
- Tex *tex = NULL, *origtex = (Tex *)id;
-
- if (origtex) {
- BLI_assert(sp->id_copy != NULL);
- tex = sp->texcopy = (Tex *)sp->id_copy;
- sp->id_copy = NULL;
- BLI_addtail(&pr_main->textures, tex);
- }
- }
- else if (id_type == ID_LA) {
- Light *la = NULL, *origla = (Light *)id;
-
- /* work on a copy */
- if (origla) {
- BLI_assert(sp->id_copy != NULL);
- la = sp->lampcopy = (Light *)sp->id_copy;
- sp->id_copy = NULL;
- BLI_addtail(&pr_main->lights, la);
- }
-
- set_preview_visibility(pr_main, sce, view_layer, MA_LAMP, sp->pr_method);
-
- if (sce->world) {
- /* Only use lighting from the light. */
- sce->world->use_nodes = false;
- sce->world->horr = 0.0f;
- sce->world->horg = 0.0f;
- sce->world->horb = 0.0f;
- }
-
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- if (base->object->id.name[2] == 'p') {
- if (base->object->type == OB_LAMP) {
- base->object->data = la;
- }
- }
- }
- }
- else if (id_type == ID_WO) {
- World *wrld = NULL, *origwrld = (World *)id;
-
- if (origwrld) {
- BLI_assert(sp->id_copy != NULL);
- wrld = sp->worldcopy = (World *)sp->id_copy;
- sp->id_copy = NULL;
- BLI_addtail(&pr_main->worlds, wrld);
- }
-
- set_preview_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method);
- sce->world = wrld;
- }
-
- return sce;
- }
-
- return NULL;
-}
-
-/* new UI convention: draw is in pixel space already. */
-/* uses UI_BTYPE_ROUNDBOX button in block to get the rect */
-static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect, rcti *newrect)
-{
- Render *re;
- RenderView *rv;
- RenderResult rres;
- char name[32];
- int offx = 0;
- int newx = BLI_rcti_size_x(rect);
- int newy = BLI_rcti_size_y(rect);
- bool ok = false;
-
- if (!split || first) {
- sprintf(name, "Preview %p", (void *)area);
- }
- else {
- sprintf(name, "SecondPreview %p", (void *)area);
- }
-
- if (split) {
- if (first) {
- offx = 0;
- newx = newx / 2;
- }
- else {
- offx = newx / 2;
- newx = newx - newx / 2;
- }
- }
-
- /* test if something rendered ok */
- re = RE_GetRender(name);
-
- if (re == NULL) {
- return false;
- }
-
- RE_AcquireResultImageViews(re, &rres);
-
- if (!BLI_listbase_is_empty(&rres.views)) {
- /* material preview only needs monoscopy (view 0) */
- rv = RE_RenderViewGetById(&rres, 0);
- }
- else {
- /* possible the job clears the views but we're still drawing T45496 */
- rv = NULL;
- }
-
- if (rv && rv->rectf) {
-
- if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) {
-
- newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx);
- newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
-
- if (rres.rectx && rres.recty) {
- uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
- "ed_preview_draw_rect");
- float fx = rect->xmin + offx;
- float fy = rect->ymin;
-
- /* material preview only needs monoscopy (view 0) */
- RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0);
-
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(
- &state, fx, fy, rres.rectx, rres.recty, GPU_RGBA8, false, rect_byte, 1.0f, 1.0f, NULL);
-
- MEM_freeN(rect_byte);
-
- ok = 1;
- }
- }
- }
-
- RE_ReleaseResultImageViews(re, &rres);
-
- return ok;
-}
-
-void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, rcti *rect)
-{
- if (idp) {
- wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *area = CTX_wm_area(C);
- ID *id = (ID *)idp;
- ID *parent = (ID *)parentp;
- MTex *slot = (MTex *)slotp;
- SpaceProperties *sbuts = CTX_wm_space_properties(C);
- ShaderPreview *sp = WM_jobs_customdata(wm, area);
- rcti newrect;
- int ok;
- int newx = BLI_rcti_size_x(rect);
- int newy = BLI_rcti_size_y(rect);
-
- newrect.xmin = rect->xmin;
- newrect.xmax = rect->xmin;
- newrect.ymin = rect->ymin;
- newrect.ymax = rect->ymin;
-
- if (parent) {
- ok = ed_preview_draw_rect(area, 1, 1, rect, &newrect);
- ok &= ed_preview_draw_rect(area, 1, 0, rect, &newrect);
- }
- else {
- ok = ed_preview_draw_rect(area, 0, 0, rect, &newrect);
- }
-
- if (ok) {
- *rect = newrect;
- }
-
- /* start a new preview render job if signaled through sbuts->preview,
- * if no render result was found and no preview render job is running,
- * or if the job is running and the size of preview changed */
- if ((sbuts != NULL && sbuts->preview) ||
- (!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
- (sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) {
- if (sbuts != NULL) {
- sbuts->preview = 0;
- }
- ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Object Preview
- * \{ */
-
-struct ObjectPreviewData {
- /* The main for the preview, not of the current file. */
- Main *pr_main;
- /* Copy of the object to create the preview for. The copy is for thread safety (and to insert
- * it into an own main). */
- Object *object;
- /* Current frame. */
- int cfra;
- int sizex;
- int sizey;
-};
-
-static bool object_preview_is_type_supported(const Object *ob)
-{
- return OB_TYPE_IS_GEOMETRY(ob->type);
-}
-
-static Object *object_preview_camera_create(Main *preview_main,
- ViewLayer *view_layer,
- Object *preview_object)
-{
- Object *camera = BKE_object_add(preview_main, view_layer, OB_CAMERA, "Preview Camera");
-
- float rotmat[3][3];
- float dummyscale[3];
- mat4_to_loc_rot_size(camera->loc, rotmat, dummyscale, preview_object->obmat);
-
- /* Camera is Y up, so needs additional rotations to obliquely face the front. */
- float drotmat[3][3];
- const float eul[3] = {M_PI * 0.4f, 0.0f, M_PI * 0.1f};
- eul_to_mat3(drotmat, eul);
- mul_m3_m3_post(rotmat, drotmat);
-
- camera->rotmode = ROT_MODE_QUAT;
- mat3_to_quat(camera->quat, rotmat);
-
- /* Nice focal length for close portraiture. */
- ((Camera *)camera->data)->lens = 85;
-
- return camera;
-}
-
-static Scene *object_preview_scene_create(const struct ObjectPreviewData *preview_data,
- Depsgraph **r_depsgraph)
-{
- Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene");
- /* Preview need to be in the current frame to get a thumbnail similar of what
- * viewport displays. */
- CFRA = preview_data->cfra;
-
- ViewLayer *view_layer = scene->view_layers.first;
- Depsgraph *depsgraph = DEG_graph_new(
- preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
-
- BLI_assert(preview_data->object != NULL);
- BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
-
- BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
-
- Object *camera_object = object_preview_camera_create(
- preview_data->pr_main, view_layer, preview_data->object);
-
- scene->camera = camera_object;
- scene->r.xsch = preview_data->sizex;
- scene->r.ysch = preview_data->sizey;
- scene->r.size = 100;
-
- Base *preview_base = BKE_view_layer_base_find(view_layer, preview_data->object);
- /* For 'view selected' below. */
- preview_base->flag |= BASE_SELECTED;
-
- DEG_graph_build_from_view_layer(depsgraph);
- DEG_evaluate_on_refresh(depsgraph);
-
- ED_view3d_camera_to_view_selected(preview_data->pr_main, depsgraph, scene, camera_object);
-
- BKE_scene_graph_update_tagged(depsgraph, preview_data->pr_main);
-
- *r_depsgraph = depsgraph;
- return scene;
-}
-
-static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
-{
- Main *preview_main = BKE_main_new();
- const float pixelsize_old = U.pixelsize;
- char err_out[256] = "unknown";
-
- BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
-
- struct ObjectPreviewData preview_data = {
- .pr_main = preview_main,
- /* Act on a copy. */
- .object = (Object *)preview->id_copy,
- .cfra = preview->scene->r.cfra,
- .sizex = preview_sized->sizex,
- .sizey = preview_sized->sizey,
- };
- Depsgraph *depsgraph;
- Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
-
- /* Ownership is now ours. */
- preview->id_copy = NULL;
-
- U.pixelsize = 2.0f;
-
- View3DShading shading;
- BKE_screen_view3d_shading_init(&shading);
- /* Enable shadows, makes it a bit easier to see the shape. */
- shading.flag |= V3D_SHADING_SHADOW;
-
- ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(
- depsgraph,
- DEG_get_evaluated_scene(depsgraph),
- &shading,
- OB_TEXTURE,
- DEG_get_evaluated_object(depsgraph, scene->camera),
- preview_sized->sizex,
- preview_sized->sizey,
- IB_rect,
- V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS,
- R_ALPHAPREMUL,
- NULL,
- NULL,
- err_out);
- /* TODO: color-management? */
-
- U.pixelsize = pixelsize_old;
-
- if (ibuf) {
- icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
- IMB_freeImBuf(ibuf);
- }
-
- DEG_graph_free(depsgraph);
- BKE_main_free(preview_main);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Action Preview
- * \{ */
-
-static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
-{
- Object *object = preview->active_object;
- if (object == NULL) {
- WM_report(RPT_WARNING, "No active object, unable to apply the Action before rendering");
- return NULL;
- }
- if (object->pose == NULL) {
- WM_reportf(RPT_WARNING,
- "Object %s has no pose, unable to apply the Action before rendering",
- object->id.name + 2);
- return NULL;
- }
-
- /* Create a backup of the current pose. */
- struct bAction *action = (struct bAction *)preview->id;
- struct PoseBackup *pose_backup = ED_pose_backup_create_all_bones(object, action);
-
- /* Apply the Action as pose, so that it can be rendered. This assumes the Action represents a
- * single pose, and that thus the evaluation time doesn't matter. */
- AnimationEvalContext anim_eval_context = {preview->depsgraph, 0.0f};
- BKE_pose_apply_action_all_bones(object, action, &anim_eval_context);
-
- /* Force evaluation of the new pose, before the preview is rendered. */
- DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
- DEG_evaluate_on_refresh(preview->depsgraph);
-
- return pose_backup;
-}
-
-static void action_preview_render_cleanup(IconPreview *preview, struct PoseBackup *pose_backup)
-{
- if (pose_backup == NULL) {
- return;
- }
- ED_pose_backup_restore(pose_backup);
- ED_pose_backup_free(pose_backup);
-
- DEG_id_tag_update(&preview->active_object->id, ID_RECALC_GEOMETRY);
-}
-
-/* Render a pose from the scene camera. It is assumed that the scene camera is
- * capturing the pose. The pose is applied temporarily to the current object
- * before rendering. */
-static void action_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
-{
- char err_out[256] = "";
-
- Depsgraph *depsgraph = preview->depsgraph;
- /* Not all code paths that lead to this function actually provide a depsgraph.
- * The "Refresh Asset Preview" button (ED_OT_lib_id_generate_preview) does,
- * but WM_OT_previews_ensure does not. */
- BLI_assert(depsgraph != NULL);
- BLI_assert(preview->scene == DEG_get_input_scene(depsgraph));
-
- /* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */
- struct PoseBackup *pose_backup = action_preview_render_prepare(preview);
-
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *camera_eval = scene_eval->camera;
- if (camera_eval == NULL) {
- printf("Scene has no camera, unable to render preview of %s without it.\n",
- preview->id->name + 2);
- return;
- }
-
- /* This renders with the Workbench engine settings stored on the Scene. */
- ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
- scene_eval,
- NULL,
- OB_SOLID,
- camera_eval,
- preview_sized->sizex,
- preview_sized->sizey,
- IB_rect,
- V3D_OFSDRAW_NONE,
- R_ADDSKY,
- NULL,
- NULL,
- err_out);
-
- action_preview_render_cleanup(preview, pose_backup);
-
- if (err_out[0] != '\0') {
- printf("Error rendering Action %s preview: %s\n", preview->id->name + 2, err_out);
- }
-
- if (ibuf) {
- icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
- IMB_freeImBuf(ibuf);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name New Shader Preview System
- * \{ */
-
-/* inside thread, called by renderer, sets job update value */
-static void shader_preview_update(void *spv,
- RenderResult *UNUSED(rr),
- volatile struct rcti *UNUSED(rect))
-{
- ShaderPreview *sp = spv;
-
- *(sp->do_update) = true;
-}
-
-/* called by renderer, checks job value */
-static int shader_preview_break(void *spv)
-{
- ShaderPreview *sp = spv;
-
- return *(sp->stop);
-}
-
-static void shader_preview_updatejob(void *UNUSED(spv))
-{
-}
-
-/* Renders texture directly to render buffer. */
-static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Render *re)
-{
- /* Setup output buffer. */
- int width = sp->sizex;
- int height = sp->sizey;
-
- /* This is needed otherwise no RenderResult is created. */
- sce->r.scemode &= ~R_BUTS_PREVIEW;
- RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, width, height, NULL);
- RE_SetScene(re, sce);
-
- /* Create buffer in empty RenderView created in the init step. */
- RenderResult *rr = RE_AcquireResultWrite(re);
- RenderView *rv = (RenderView *)rr->views.first;
- rv->rectf = MEM_callocN(sizeof(float[4]) * width * height, "texture render result");
- RE_ReleaseResult(re);
-
- /* Get texture image pool (if any) */
- struct ImagePool *img_pool = BKE_image_pool_new();
- BKE_texture_fetch_images_for_pool(tex, img_pool);
-
- /* Fill in image buffer. */
- float *rect_float = rv->rectf;
- float tex_coord[3] = {0.0f, 0.0f, 0.0f};
- bool color_manage = true;
-
- for (int y = 0; y < height; y++) {
- /* Tex coords between -1.0f and 1.0f. */
- tex_coord[1] = ((float)y / (float)height) * 2.0f - 1.0f;
-
- for (int x = 0; x < width; x++) {
- tex_coord[0] = ((float)x / (float)height) * 2.0f - 1.0f;
-
- /* Evaluate texture at tex_coord. */
- TexResult texres = {0};
- BKE_texture_get_value_ex(sce, tex, tex_coord, &texres, img_pool, color_manage);
-
- rect_float[0] = texres.tr;
- rect_float[1] = texres.tg;
- rect_float[2] = texres.tb;
- rect_float[3] = texres.talpha ? texres.ta : 1.0f;
-
- rect_float += 4;
- }
-
- /* Check if we should cancel texture preview. */
- if (shader_preview_break(sp)) {
- break;
- }
- }
-
- BKE_image_pool_free(img_pool);
-}
-
-static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int first)
-{
- Render *re;
- Scene *sce;
- float oldlens;
- short idtype = GS(id->name);
- char name[32];
- int sizex;
- Main *pr_main = sp->pr_main;
-
- /* in case of split preview, use border render */
- if (split) {
- if (first) {
- sizex = sp->sizex / 2;
- }
- else {
- sizex = sp->sizex - sp->sizex / 2;
- }
- }
- else {
- sizex = sp->sizex;
- }
-
- /* we have to set preview variables first */
- sce = preview_get_scene(pr_main);
- if (sce) {
- sce->r.xsch = sizex;
- sce->r.ysch = sp->sizey;
- sce->r.size = 100;
- }
-
- /* get the stuff from the builtin preview dbase */
- sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
- if (sce == NULL) {
- return;
- }
-
- if (!split || first) {
- sprintf(name, "Preview %p", sp->owner);
- }
- else {
- sprintf(name, "SecondPreview %p", sp->owner);
- }
- re = RE_GetRender(name);
-
- /* full refreshed render from first tile */
- if (re == NULL) {
- re = RE_NewRender(name);
- }
-
- /* sce->r gets copied in RE_InitState! */
- sce->r.scemode &= ~(R_MATNODE_PREVIEW | R_TEXNODE_PREVIEW);
- sce->r.scemode &= ~R_NO_IMAGE_LOAD;
-
- if (sp->pr_method == PR_ICON_RENDER) {
- sce->r.scemode |= R_NO_IMAGE_LOAD;
- sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
- }
- else { /* PR_BUTS_RENDER */
- sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
- }
-
- /* Callbacks are cleared on GetRender(). */
- if (sp->pr_method == PR_BUTS_RENDER) {
- RE_display_update_cb(re, sp, shader_preview_update);
- }
- /* set this for all previews, default is react to G.is_break still */
- RE_test_break_cb(re, sp, shader_preview_break);
-
- /* lens adjust */
- oldlens = ((Camera *)sce->camera->data)->lens;
- if (sizex > sp->sizey) {
- ((Camera *)sce->camera->data)->lens *= (float)sp->sizey / (float)sizex;
- }
-
- /* entire cycle for render engine */
- if (idtype == ID_TE) {
- shader_preview_texture(sp, (Tex *)id, sce, re);
- }
- else {
- /* Render preview scene */
- RE_PreviewRender(re, pr_main, sce);
- }
-
- ((Camera *)sce->camera->data)->lens = oldlens;
-
- /* handle results */
- if (sp->pr_method == PR_ICON_RENDER) {
- // char *rct = (char *)(sp->pr_rect + 32 * 16 + 16);
-
- if (sp->pr_rect) {
- RE_ResultGet32(re, sp->pr_rect);
- }
- }
-
- /* unassign the pointers, reset vars */
- preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp);
-
- /* XXX bad exception, end-exec is not being called in render, because it uses local main. */
-#if 0
- if (idtype == ID_TE) {
- Tex *tex = (Tex *)id;
- if (tex->use_nodes && tex->nodetree)
- ntreeEndExecTree(tex->nodetree);
- }
-#endif
-}
-
-/* runs inside thread for material and icons */
-static void shader_preview_startjob(void *customdata, short *stop, short *do_update)
-{
- ShaderPreview *sp = customdata;
-
- sp->stop = stop;
- sp->do_update = do_update;
-
- if (sp->parent) {
- shader_preview_render(sp, sp->id, 1, 1);
- shader_preview_render(sp, sp->parent, 1, 0);
- }
- else {
- shader_preview_render(sp, sp->id, 0, 0);
- }
-
- *do_update = true;
-}
-
-static void preview_id_copy_free(ID *id)
-{
- struct IDProperty *properties;
- /* get rid of copied ID */
- properties = IDP_GetProperties(id, false);
- if (properties) {
- IDP_FreePropertyContent_ex(properties, false);
- MEM_freeN(properties);
- }
- BKE_libblock_free_datablock(id, 0);
- MEM_freeN(id);
-}
-
-static void shader_preview_free(void *customdata)
-{
- ShaderPreview *sp = customdata;
- Main *pr_main = sp->pr_main;
- ID *main_id_copy = NULL;
- ID *sub_id_copy = NULL;
-
- if (sp->matcopy) {
- main_id_copy = (ID *)sp->matcopy;
- BLI_remlink(&pr_main->materials, sp->matcopy);
- }
- if (sp->texcopy) {
- BLI_assert(main_id_copy == NULL);
- main_id_copy = (ID *)sp->texcopy;
- BLI_remlink(&pr_main->textures, sp->texcopy);
- }
- if (sp->worldcopy) {
- /* worldcopy is also created for material with `Preview World` enabled */
- if (main_id_copy) {
- sub_id_copy = (ID *)sp->worldcopy;
- }
- else {
- main_id_copy = (ID *)sp->worldcopy;
- }
- BLI_remlink(&pr_main->worlds, sp->worldcopy);
- }
- if (sp->lampcopy) {
- BLI_assert(main_id_copy == NULL);
- main_id_copy = (ID *)sp->lampcopy;
- BLI_remlink(&pr_main->lights, sp->lampcopy);
- }
- if (sp->own_id_copy) {
- if (sp->id_copy) {
- preview_id_copy_free(sp->id_copy);
- }
- if (main_id_copy) {
- preview_id_copy_free(main_id_copy);
- }
- if (sub_id_copy) {
- preview_id_copy_free(sub_id_copy);
- }
- }
-
- MEM_freeN(sp);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Icon Preview
- * \{ */
-
-static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
-{
- static const int flags = IB_rect | IB_multilayer | IB_metadata;
-
- char path[FILE_MAX];
- const char *folder;
-
- if (!(brush->icon_imbuf)) {
- if (brush->flag & BRUSH_CUSTOM_ICON) {
-
- if (brush->icon_filepath[0]) {
- /* First use the path directly to try and load the file. */
-
- BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath));
- BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
-
- /* Use default color-spaces for brushes. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
-
- /* otherwise lets try to find it in other directories */
- if (!(brush->icon_imbuf)) {
- folder = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons");
-
- BLI_make_file_string(
- BKE_main_blendfile_path_from_global(), path, folder, brush->icon_filepath);
-
- if (path[0]) {
- /* Use default color spaces. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
- }
- }
-
- if (brush->icon_imbuf) {
- BKE_icon_changed(BKE_icon_id_ensure(&brush->id));
- }
- }
- }
- }
-
- if (!(brush->icon_imbuf)) {
- brush->id.icon_id = 0;
- }
-
- return brush->icon_imbuf;
-}
-
-static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
-{
- struct ImBuf *ima;
- uint *drect, *srect;
- float scaledx, scaledy;
- short ex, ey, dx, dy;
-
- /* paranoia test */
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- return;
- }
-
- /* Waste of cpu cycles... but the imbuf API has no other way to scale fast (ton). */
- ima = IMB_dupImBuf(ibuf);
-
- if (!ima) {
- return;
- }
-
- if (ima->x > ima->y) {
- scaledx = (float)w;
- scaledy = ((float)ima->y / (float)ima->x) * (float)w;
- }
- else {
- scaledx = ((float)ima->x / (float)ima->y) * (float)h;
- scaledy = (float)h;
- }
-
- /* Scaling down must never assign zero width/height, see: T89868. */
- ex = MAX2(1, (short)scaledx);
- ey = MAX2(1, (short)scaledy);
-
- dx = (w - ex) / 2;
- dy = (h - ey) / 2;
-
- IMB_scalefastImBuf(ima, ex, ey);
-
- /* if needed, convert to 32 bits */
- if (ima->rect == NULL) {
- IMB_rect_from_float(ima);
- }
-
- srect = ima->rect;
- drect = rect;
-
- drect += dy * w + dx;
- for (; ey > 0; ey--) {
- memcpy(drect, srect, ex * sizeof(int));
- drect += w;
- srect += ima->x;
- }
-
- IMB_freeImBuf(ima);
-}
-
-static void set_alpha(char *cp, int sizex, int sizey, char alpha)
-{
- int a, size = sizex * sizey;
-
- for (a = 0; a < size; a++, cp += 4) {
- cp[3] = alpha;
- }
-}
-
-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);
-
- BLI_assert(id != NULL);
-
- if (idtype == ID_IM) {
- Image *ima = (Image *)id;
- ImBuf *ibuf = NULL;
- ImageUser iuser;
- BKE_imageuser_default(&iuser);
-
- if (ima == NULL) {
- return;
- }
-
- /* setup dummy image user */
- 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 && ibuf->rect_float == 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 = icon_preview_imbuf_from_brush(br);
-
- memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(uint));
-
- 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 if (idtype == ID_SCR) {
- bScreen *screen = (bScreen *)id;
-
- ED_screen_preview_render(screen, 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);
- }
- }
- }
-}
-
-/* use same function for icon & shader, so the job manager
- * does not run two of them at the same time. */
-
-static void common_preview_startjob(void *customdata,
- short *stop,
- short *do_update,
- float *UNUSED(progress))
-{
- ShaderPreview *sp = customdata;
-
- if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED)) {
- icon_preview_startjob(customdata, stop, do_update);
- }
- else {
- shader_preview_startjob(customdata, stop, do_update);
- }
-}
-
-/**
- * Some ID types already have their own, more focused rendering (only objects right now). This is
- * for the other ones, which all share #ShaderPreview and some functions.
- */
-static void other_id_types_preview_render(IconPreview *ip,
- IconPreviewSize *cur_size,
- const int pr_method,
- short *stop,
- short *do_update,
- float *progress)
-{
- ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
-
- /* These types don't use the ShaderPreview mess, they have their own types and functions. */
- BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
-
- /* construct shader preview from image size and previewcustomdata */
- sp->scene = ip->scene;
- sp->owner = ip->owner;
- sp->sizex = cur_size->sizex;
- sp->sizey = cur_size->sizey;
- sp->pr_method = pr_method;
- sp->pr_rect = cur_size->rect;
- sp->id = ip->id;
- sp->id_copy = ip->id_copy;
- sp->bmain = ip->bmain;
- sp->own_id_copy = false;
- Material *ma = NULL;
-
- if (sp->pr_method == PR_ICON_RENDER) {
- BLI_assert(ip->id);
-
- /* grease pencil use its own preview file */
- if (GS(ip->id->name) == ID_MA) {
- ma = (Material *)ip->id;
- }
-
- if ((ma == NULL) || (ma->gp_style == NULL)) {
- sp->pr_main = G_pr_main;
- }
- else {
- sp->pr_main = G_pr_main_grease_pencil;
- }
- }
-
- common_preview_startjob(sp, stop, do_update, progress);
- shader_preview_free(sp);
-}
-
-/* exported functions */
-
-/**
- * Find the index to map \a icon_size to data in \a preview_image.
- */
-static int icon_previewimg_size_index_get(const IconPreviewSize *icon_size,
- const PreviewImage *preview_image)
-{
- for (int i = 0; i < NUM_ICON_SIZES; i++) {
- if ((preview_image->w[i] == icon_size->sizex) && (preview_image->h[i] == icon_size->sizey)) {
- return i;
- }
- }
-
- BLI_assert_msg(0, "The searched icon size does not match any in the preview image");
- return -1;
-}
-
-static void icon_preview_startjob_all_sizes(void *customdata,
- short *stop,
- short *do_update,
- float *progress)
-{
- IconPreview *ip = (IconPreview *)customdata;
- IconPreviewSize *cur_size;
-
- for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
- PreviewImage *prv = ip->owner;
- /* Is this a render job or a deferred loading job? */
- const int pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : PR_ICON_RENDER;
-
- if (*stop) {
- break;
- }
-
- if (prv->tag & PRV_TAG_DEFFERED_DELETE) {
- /* Non-thread-protected reading is not an issue here. */
- continue;
- }
-
- /* check_engine_supports_preview() checks whether the engine supports "preview mode" (think:
- * Material Preview). This check is only relevant when the render function called below is
- * going to use such a mode. Object and Action render functions use Solid mode, though, so
- * they can skip this test. */
- /* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
- * necessary to know here what happens inside lower-level functions. */
- const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
- if (!use_solid_render_mode && preview_method_is_render(pr_method) &&
- !check_engine_supports_preview(ip->scene)) {
- continue;
- }
-
-#ifndef NDEBUG
- {
- int size_index = icon_previewimg_size_index_get(cur_size, prv);
- BLI_assert(!BKE_previewimg_is_finished(prv, size_index));
- }
-#endif
-
- if (ip->id != NULL) {
- switch (GS(ip->id->name)) {
- case ID_OB:
- if (object_preview_is_type_supported((Object *)ip->id)) {
- /* Much simpler than the ShaderPreview mess used for other ID types. */
- object_preview_render(ip, cur_size);
- continue;
- }
- break;
- case ID_AC:
- action_preview_render(ip, cur_size);
- continue;
- default:
- /* Fall through to the same code as the `ip->id == NULL` case. */
- break;
- }
- }
- other_id_types_preview_render(ip, cur_size, pr_method, stop, do_update, progress);
- }
-}
-
-static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
-{
- IconPreviewSize *cur_size = ip->sizes.first, *new_size;
-
- while (cur_size) {
- if (cur_size->sizex == sizex && cur_size->sizey == sizey) {
- /* requested size is already in list, no need to add it again */
- return;
- }
-
- cur_size = cur_size->next;
- }
-
- new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize");
- new_size->sizex = sizex;
- new_size->sizey = sizey;
- new_size->rect = rect;
-
- BLI_addtail(&ip->sizes, new_size);
-}
-
-static void icon_preview_endjob(void *customdata)
-{
- IconPreview *ip = customdata;
-
- if (ip->id) {
-
- if (GS(ip->id->name) == ID_BR) {
- WM_main_add_notifier(NC_BRUSH | NA_EDITED, ip->id);
- }
-#if 0
- if (GS(ip->id->name) == ID_MA) {
- Material *ma = (Material *)ip->id;
- PreviewImage *prv_img = ma->preview;
- int i;
-
- /* signal to gpu texture */
- for (i = 0; i < NUM_ICON_SIZES; i++) {
- if (prv_img->gputexture[i]) {
- GPU_texture_free(prv_img->gputexture[i]);
- prv_img->gputexture[i] = NULL;
- WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ip->id);
- }
- }
- }
-#endif
- }
-
- if (ip->owner) {
- PreviewImage *prv_img = ip->owner;
- prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING;
-
- LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) {
- int size_index = icon_previewimg_size_index_get(icon_size, prv_img);
- BKE_previewimg_finish(prv_img, size_index);
- }
-
- if (prv_img->tag & PRV_TAG_DEFFERED_DELETE) {
- BLI_assert(prv_img->tag & PRV_TAG_DEFFERED);
- BKE_previewimg_deferred_release(prv_img);
- }
- }
-}
-
-static void icon_preview_free(void *customdata)
-{
- IconPreview *ip = (IconPreview *)customdata;
-
- if (ip->id_copy) {
- preview_id_copy_free(ip->id_copy);
- }
-
- BLI_freelistN(&ip->sizes);
- MEM_freeN(ip);
-}
-
-bool ED_preview_id_is_supported(const ID *id)
-{
- if (id == NULL) {
- return false;
- }
-
- if (GS(id->name) == ID_OB) {
- return object_preview_is_type_supported((const Object *)id);
- }
- return BKE_previewimg_id_get_p(id) != NULL;
-}
-
-void ED_preview_icon_render(
- const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
-{
- IconPreview ip = {NULL};
- short stop = false, update = false;
- float progress = 0.0f;
-
- ED_preview_ensure_dbase();
-
- ip.bmain = CTX_data_main(C);
- ip.scene = scene;
- ip.depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ip.owner = BKE_previewimg_id_ensure(id);
- ip.id = id;
- /* Control isn't given back to the caller until the preview is done. So we don't need to copy
- * the ID to avoid thread races. */
- ip.id_copy = duplicate_ids(id, true);
- ip.active_object = CTX_data_active_object(C);
-
- icon_preview_add_size(&ip, rect, sizex, sizey);
-
- icon_preview_startjob_all_sizes(&ip, &stop, &update, &progress);
-
- icon_preview_endjob(&ip);
-
- BLI_freelistN(&ip.sizes);
- if (ip.id_copy != NULL) {
- preview_id_copy_free(ip.id_copy);
- }
-}
-
-void ED_preview_icon_job(
- const bContext *C, void *owner, ID *id, uint *rect, int sizex, int sizey, const bool delay)
-{
- wmJob *wm_job;
- IconPreview *ip, *old_ip;
-
- ED_preview_ensure_dbase();
-
- /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
- wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- owner,
- "Icon Preview",
- WM_JOB_EXCL_RENDER,
- WM_JOB_TYPE_RENDER_PREVIEW);
-
- ip = MEM_callocN(sizeof(IconPreview), "icon preview");
-
- /* render all resolutions from suspended job too */
- old_ip = WM_jobs_customdata_get(wm_job);
- if (old_ip) {
- BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
- }
-
- /* customdata for preview thread */
- ip->bmain = CTX_data_main(C);
- ip->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ip->scene = DEG_get_input_scene(ip->depsgraph);
- ip->active_object = CTX_data_active_object(C);
- ip->owner = owner;
- ip->id = id;
- ip->id_copy = duplicate_ids(id, false);
-
- icon_preview_add_size(ip, rect, sizex, sizey);
-
- /* Special threading hack:
- * warn main code that this preview is being rendered and cannot be freed... */
- {
- PreviewImage *prv_img = owner;
- if (prv_img->tag & PRV_TAG_DEFFERED) {
- prv_img->tag |= PRV_TAG_DEFFERED_RENDERING;
- }
- }
-
- /* setup job */
- WM_jobs_customdata_set(wm_job, ip, icon_preview_free);
- WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
- /* Wait 2s to start rendering icon previews, to not bog down user interaction.
- * Particularly important for heavy scenes and Eevee using OpenGL that blocks
- * the user interface drawing. */
- WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0);
- WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
-}
-
-void ED_preview_shader_job(const bContext *C,
- void *owner,
- ID *id,
- ID *parent,
- MTex *slot,
- int sizex,
- int sizey,
- int method)
-{
- Object *ob = CTX_data_active_object(C);
- wmJob *wm_job;
- ShaderPreview *sp;
- Scene *scene = CTX_data_scene(C);
- const ID_Type id_type = GS(id->name);
-
- BLI_assert(BKE_previewimg_id_supports_jobs(id));
-
- /* Use workspace render only for buttons Window,
- * since the other previews are related to the datablock. */
-
- if (preview_method_is_render(method) && !check_engine_supports_preview(scene)) {
- return;
- }
-
- ED_preview_ensure_dbase();
-
- wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- owner,
- "Shader Preview",
- WM_JOB_EXCL_RENDER,
- WM_JOB_TYPE_RENDER_PREVIEW);
- sp = MEM_callocN(sizeof(ShaderPreview), "shader preview");
-
- /* customdata for preview thread */
- sp->scene = scene;
- sp->owner = owner;
- sp->sizex = sizex;
- sp->sizey = sizey;
- sp->pr_method = method;
- sp->id = id;
- sp->id_copy = duplicate_ids(id, false);
- sp->own_id_copy = true;
- sp->parent = parent;
- sp->slot = slot;
- sp->bmain = CTX_data_main(C);
- Material *ma = NULL;
-
- /* hardcoded preview .blend for Eevee + Cycles, this should be solved
- * once with custom preview .blend path for external engines */
-
- /* grease pencil use its own preview file */
- if (id_type == ID_MA) {
- ma = (Material *)id;
- }
-
- if ((ma == NULL) || (ma->gp_style == NULL)) {
- sp->pr_main = G_pr_main;
- }
- else {
- sp->pr_main = G_pr_main_grease_pencil;
- }
-
- if (ob && ob->totcol) {
- copy_v4_v4(sp->color, ob->color);
- }
- else {
- ARRAY_SET_ITEMS(sp->color, 0.0f, 0.0f, 0.0f, 1.0f);
- }
-
- /* setup job */
- WM_jobs_customdata_set(wm_job, sp, shader_preview_free);
- WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
- WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL);
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
-}
-
-void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
-{
- if (wm) {
- /* This is called to stop all preview jobs before scene data changes, to
- * avoid invalid memory access. */
- WM_jobs_kill(wm, NULL, common_preview_startjob);
- WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes);
- }
-}
-
-typedef struct PreviewRestartQueueEntry {
- struct PreviewRestartQueueEntry *next, *prev;
-
- enum eIconSizes size;
- ID *id;
-} PreviewRestartQueueEntry;
-
-static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
-
-void ED_preview_restart_queue_free(void)
-{
- BLI_freelistN(&G_restart_previews_queue);
-}
-
-void ED_preview_restart_queue_add(ID *id, enum eIconSizes size)
-{
- PreviewRestartQueueEntry *queue_entry = MEM_mallocN(sizeof(*queue_entry), __func__);
- queue_entry->size = size;
- queue_entry->id = id;
- BLI_addtail(&G_restart_previews_queue, queue_entry);
-}
-
-void ED_preview_restart_queue_work(const bContext *C)
-{
- LISTBASE_FOREACH_MUTABLE (PreviewRestartQueueEntry *, queue_entry, &G_restart_previews_queue) {
- PreviewImage *preview = BKE_previewimg_id_get(queue_entry->id);
- if (!preview) {
- continue;
- }
- if (preview->flag[queue_entry->size] & PRV_USER_EDITED) {
- /* Don't touch custom previews. */
- continue;
- }
-
- BKE_previewimg_clear_single(preview, queue_entry->size);
- UI_icon_render_id(C, NULL, queue_entry->id, queue_entry->size, true);
-
- BLI_freelinkN(&G_restart_previews_queue, queue_entry);
- }
-}
-
-/** \} */