Blender V5.0
render_preview.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9/* global includes */
10
11#include <algorithm>
12#include <atomic>
13#include <cmath>
14#include <cstdlib>
15#include <cstring>
16#include <list>
17
18#ifndef WIN32
19# include <unistd.h>
20#else
21# include <io.h>
22#endif
23#include "MEM_guardedalloc.h"
24
25#include "BLI_math_matrix.h"
26#include "BLI_math_rotation.h"
27#include "BLI_path_utils.hh"
28#include "BLI_rect.h"
29#include "BLI_string.h"
30#include "BLI_string_utf8.h"
31#include "BLI_utildefines.h"
32
33#include "BLT_translation.hh"
34
35#include "BLO_readfile.hh"
36
37#include "DNA_camera_types.h"
39#include "DNA_light_types.h"
40#include "DNA_material_types.h"
41#include "DNA_mesh_types.h"
42#include "DNA_node_types.h"
43#include "DNA_object_types.h"
44#include "DNA_scene_types.h"
45#include "DNA_screen_types.h"
46#include "DNA_space_types.h"
47#include "DNA_world_types.h"
48
49#include "BKE_animsys.h"
50#include "BKE_armature.hh"
51#include "BKE_brush.hh"
52#include "BKE_collection.hh"
53#include "BKE_colortools.hh"
54#include "BKE_context.hh"
55#include "BKE_global.hh"
56#include "BKE_icons.h"
57#include "BKE_idprop.hh"
58#include "BKE_image.hh"
59#include "BKE_layer.hh"
60#include "BKE_lib_id.hh"
61#include "BKE_library.hh"
62#include "BKE_light.h"
63#include "BKE_main.hh"
64#include "BKE_material.hh"
65#include "BKE_node.hh"
66#include "BKE_object.hh"
67#include "BKE_pose_backup.h"
68#include "BKE_preview_image.hh"
69#include "BKE_report.hh"
70#include "BKE_scene.hh"
71#include "BKE_screen.hh"
72#include "BKE_texture.h"
73#include "BKE_world.h"
74
75#include "BLI_math_vector.h"
76
77#include "DEG_depsgraph.hh"
80
81#include "IMB_imbuf.hh"
82#include "IMB_imbuf_types.hh"
83#include "IMB_thumbs.hh"
84
85#include "BIF_glutil.hh"
86
87#include "RE_engine.h"
88#include "RE_pipeline.h"
89#include "RE_texture.h"
90
91#include "WM_api.hh"
92#include "WM_types.hh"
93
94#include "ED_datafiles.h"
95#include "ED_render.hh"
96#include "ED_screen.hh"
97#include "ED_view3d.hh"
99
100#include "UI_interface_icons.hh"
101
102#include "ANIM_action.hh"
103#include "ANIM_pose.hh"
104
105#ifndef NDEBUG
106/* Used for database init assert(). */
107# include "BLI_threads.h"
108#endif
109
110static void icon_copy_rect(const ImBuf *ibuf, uint w, uint h, uint *rect);
111
112/* -------------------------------------------------------------------- */
115
117 /* from wmJob */
118 const void *owner;
120
125
126 /* Data-blocks with nodes need full copy during preview render, GLSL uses it too. */
131
133 float color[4];
134
139
142};
143
149
152 Depsgraph *depsgraph; /* May be nullptr (see #WM_OT_previews_ensure). */
154 void *owner;
159
160 /* May be nullptr, is used for rendering IDs that require some other object for it to be applied
161 * on before the ID can be represented as an image, for example when rendering an Action. */
163};
164
166
167/* -------------------------------------------------------------------- */
170
172
173#ifndef WITH_HEADLESS
174static Main *load_main_from_memory(const void *blend, int blend_size)
175{
176 const int fileflags = G.fileflags;
177 Main *bmain = nullptr;
178 BlendFileData *bfd;
179
180 G.fileflags |= G_FILE_NO_UI;
181 bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr);
182 if (bfd) {
183 bmain = bfd->main;
184 MEM_delete(bfd);
185 }
186 G.fileflags = fileflags;
187
188 return bmain;
189}
190#endif
191
192void ED_preview_ensure_dbase(const bool with_gpencil)
193{
194#ifndef WITH_HEADLESS
195 static bool base_initialized = false;
196 static bool base_initialized_gpencil = false;
198 if (!base_initialized) {
200 base_initialized = true;
201 }
202 if (!base_initialized_gpencil && with_gpencil) {
205 base_initialized_gpencil = true;
206 }
207#else
208 UNUSED_VARS(with_gpencil);
209#endif
210}
211
213{
215 return (type->flag & RE_USE_PREVIEW) != 0;
216}
217
219{
220 return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
221}
222
224{
225 if (G.pr_main) {
226 BKE_main_free(G.pr_main);
227 }
228
231 }
232}
233
234static Scene *preview_get_scene(Main *pr_main)
235{
236 if (pr_main == nullptr) {
237 return nullptr;
238 }
239
240 return static_cast<Scene *>(pr_main->scenes.first);
241}
242
243const char *ED_preview_collection_name(const ePreviewType pr_type)
244{
245 switch (pr_type) {
246 case MA_FLAT:
247 return "Flat";
248 case MA_SPHERE:
249 return "Sphere";
250 case MA_CUBE:
251 return "Cube";
252 case MA_SHADERBALL:
253 return "Shader Ball";
254 case MA_CLOTH:
255 return "Cloth";
256 case MA_FLUID:
257 return "Fluid";
258 case MA_SPHERE_A:
259 return "World Sphere";
260 case MA_LAMP:
261 return "Lamp";
262 case MA_SKY:
263 return "Sky";
264 case MA_HAIR:
265 return "Hair";
266 case MA_ATMOS:
267 return "Atmosphere";
268 default:
269 BLI_assert_msg(0, "Unknown preview type");
270 return "";
271 }
272}
273
275{
277}
278
279static void switch_preview_collection_visibility(ViewLayer *view_layer, const ePreviewType pr_type)
280{
281 /* Set appropriate layer as visible. */
282 LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first);
283 const char *collection_name = ED_preview_collection_name(pr_type);
284
285 for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) {
286 if (STREQ(lc->collection->id.name + 2, collection_name)) {
288 }
289 else {
291 }
292 }
293}
294
295static const char *preview_floor_material_name(const Scene *scene,
296 const ePreviewRenderMethod pr_method)
297{
298 if (pr_method == PR_ICON_RENDER && render_engine_supports_ray_visibility(scene)) {
299 return "FloorHidden";
300 }
301 return "Floor";
302}
303
305 Mesh *mesh,
306 const Scene *scene,
307 const ePreviewRenderMethod pr_method)
308{
309 if (mesh->totcol == 0) {
310 return;
311 }
312
313 const char *material_name = preview_floor_material_name(scene, pr_method);
314 Material *mat = static_cast<Material *>(
315 BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2));
316 if (mat) {
317 mesh->mat[0] = mat;
318 }
319}
320
322 const Scene *scene,
323 ViewLayer *view_layer,
324 const ePreviewRenderMethod pr_method)
325{
326 /* Hide floor for icon renders. */
327 BKE_view_layer_synced_ensure(scene, view_layer);
329 if (STREQ(base->object->id.name + 2, "Floor")) {
330 base->object->visibility_flag &= ~OB_HIDE_RENDER;
331 if (pr_method == PR_ICON_RENDER) {
333 base->object->visibility_flag |= OB_HIDE_RENDER;
334 }
335 }
336 if (base->object->type == OB_MESH) {
338 pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method);
339 }
340 }
341 }
342}
343
345 Scene *scene,
346 ViewLayer *view_layer,
347 const ePreviewType pr_type,
348 const ePreviewRenderMethod pr_method)
349{
350 switch_preview_collection_visibility(view_layer, pr_type);
351 switch_preview_floor_visibility(pr_main, scene, view_layer, pr_method);
352 BKE_layer_collection_sync(scene, view_layer);
353}
354
356{
357 if (world == nullptr) {
358 return nullptr;
359 }
360 if (sp->worldcopy != nullptr) {
361 return sp->worldcopy;
362 }
363
364 ID *id_copy = BKE_id_copy_ex(nullptr,
365 &world->id,
366 nullptr,
369 sp->worldcopy = (World *)id_copy;
371 return sp->worldcopy;
372}
373
375{
376 using namespace blender::bke;
377
378 World *world = BKE_world_add(pr_main, "SimpleWorld");
379 bNodeTree *ntree = world->nodetree;
381 nullptr, &world->id, "World Nodetree", "ShaderNodeTree");
382
383 bNode *background = node_add_node(nullptr, *ntree, "ShaderNodeBackground");
384 bNode *output = node_add_node(nullptr, *ntree, "ShaderNodeOutputWorld");
385 node_add_link(*world->nodetree,
386 *background,
387 *node_find_socket(*background, SOCK_OUT, "Background"),
388 *output,
389 *node_find_socket(*output, SOCK_IN, "Surface"));
390 node_set_active(*ntree, *output);
391
392 world->nodetree = ntree;
393 return world;
394}
395
396void ED_preview_world_simple_set_rgb(World *world, const float color[4])
397{
398 BLI_assert(world != nullptr);
399
400 bNode *background = blender::bke::node_find_node_by_name(*world->nodetree, "Background");
401 BLI_assert(background != nullptr);
402
403 auto color_socket = static_cast<bNodeSocketValueRGBA *>(
405 copy_v4_v4(color_socket->value, color);
406}
407
408static ID *duplicate_ids(ID *id, const bool allow_failure)
409{
410 if (id == nullptr) {
411 /* Non-ID preview render. */
412 return nullptr;
413 }
414
415 switch (GS(id->name)) {
416 case ID_OB:
417 case ID_MA:
418 case ID_TE:
419 case ID_LA:
420 case ID_WO: {
422 ID *id_copy = BKE_id_copy_ex(nullptr,
423 id,
424 nullptr,
427 return id_copy;
428 }
429 case ID_GR: {
430 /* Doesn't really duplicate the collection. Just creates a collection instance empty. */
432 Object *instance_empty = BKE_object_add_only_object(nullptr, OB_EMPTY, nullptr);
433 instance_empty->instance_collection = (Collection *)id;
434 instance_empty->transflag |= OB_DUPLICOLLECTION;
435 return &instance_empty->id;
436 }
437 /* These support threading, but don't need duplicating. */
438 case ID_IM:
440 return nullptr;
441 default:
442 if (!allow_failure) {
443 BLI_assert_msg(0, "ID type preview not supported.");
444 }
445 return nullptr;
446 }
447}
448
449static const char *preview_world_name(const Scene *sce,
450 const ID_Type id_type,
451 const ePreviewRenderMethod pr_method)
452{
453 /* When rendering material icons the floor will not be shown in the output. Cycles will use a
454 * material trick to show the floor in the reflections, but hide the floor for camera rays. For
455 * Eevee we use a transparent world that has a projected grid.
456 *
457 * In the future when Eevee supports VULKAN ray-tracing we can re-evaluate and perhaps remove
458 * this approximation.
459 */
460 if (id_type == ID_MA && pr_method == PR_ICON_RENDER &&
462 {
463 return "WorldFloor";
464 }
465 return "World";
466}
467
468static World *preview_get_world(Main *pr_main,
469 const Scene *sce,
470 const ID_Type id_type,
471 const ePreviewRenderMethod pr_method)
472{
473 World *result = nullptr;
474 const char *world_name = preview_world_name(sce, id_type, pr_method);
475 result = static_cast<World *>(
476 BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2));
477
478 /* No world found return first world. */
479 if (result == nullptr) {
480 result = static_cast<World *>(pr_main->worlds.first);
481 }
482
483 BLI_assert_msg(result, "Preview file has no world.");
484 return result;
485}
486
487static void preview_sync_exposure(World *dst, const World *src)
488{
489 BLI_assert(dst);
490 BLI_assert(src);
491 dst->exp = src->exp;
492 dst->range = src->range;
493}
494
496 const Scene *scene,
497 const World *world,
498 const ID_Type id_type,
499 const ePreviewRenderMethod pr_method)
500{
501 World *result = preview_get_world(pr_main, scene, id_type, pr_method);
502 if (world) {
504 }
505 return result;
506}
507
508/* call this with a pointer to initialize preview scene */
509/* call this with nullptr to restore assigned ID pointers in preview scene */
511 Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
512{
513 Scene *sce;
514 Main *pr_main = sp->pr_main;
515
516 memcpy(pr_main->filepath, BKE_main_blendfile_path(bmain), sizeof(pr_main->filepath));
517
518 sce = preview_get_scene(pr_main);
519 if (sce) {
520 ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first);
521
522 /* Only enable the combined render-pass. */
523 view_layer->passflag = SCE_PASS_COMBINED;
524 view_layer->eevee.render_passes = 0;
525
526 /* This flag tells render to not execute depsgraph or F-Curves etc. */
527 sce->r.scemode |= R_BUTS_PREVIEW;
528 STRNCPY_UTF8(sce->r.engine, scene->r.engine);
529
530 sce->r.color_mgt_flag = scene->r.color_mgt_flag;
532
535
536 if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO) {
538 }
539 else {
540 sce->r.alphamode = R_ADDSKY;
541 }
542
543 sce->r.cfra = scene->r.cfra;
544
545 /* Setup the world. */
547 pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method);
548
549 if (id_type == ID_TE) {
550 /* Texture is not actually rendered with engine, just set dummy value. */
552 }
553
554 if (id_type == ID_MA) {
555 Material *mat = nullptr, *origmat = (Material *)id;
556
557 if (origmat) {
558 /* work on a copy */
559 BLI_assert(sp->id_copy != nullptr);
560 mat = sp->matcopy = (Material *)sp->id_copy;
561 sp->id_copy = nullptr;
562 BLI_addtail(&pr_main->materials, mat);
563
564 /* Use current scene world for lighting. */
565 if (mat->pr_flag == MA_PREVIEW_WORLD && sp->pr_method == PR_BUTS_RENDER) {
566 /* Use current scene world to light sphere. */
567 sce->world = preview_get_localized_world(sp, scene->world);
568 }
569 else if (sce->world && sp->pr_method != PR_ICON_RENDER) {
570 /* Use a default world color. Using the current
571 * scene world can be slow if it has big textures. */
573
574 /* Use brighter world color for grease pencil. */
575 if (sp->pr_main == G_pr_main_grease_pencil) {
576 const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
578 }
579 else {
580 const float dark[4] = {0.05f, 0.05f, 0.05f, 0.05f};
582 }
583 }
584
585 const ePreviewType preview_type = static_cast<ePreviewType>(mat->pr_type);
586 ED_preview_set_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
587 }
588 else {
590 }
591 BKE_view_layer_synced_ensure(sce, view_layer);
593 if (base->object->id.name[2] == 'p') {
594 /* copy over object color, in case material uses it */
595 copy_v4_v4(base->object->color, sp->color);
596
597 if (OB_TYPE_SUPPORT_MATERIAL(base->object->type)) {
598 /* don't use BKE_object_material_assign, it changed mat->id.us, which shows in the UI
599 */
600 Material ***matar = BKE_object_material_array_p(base->object);
601 int actcol = max_ii(base->object->actcol - 1, 0);
602
603 if (matar && actcol < base->object->totcol) {
604 (*matar)[actcol] = mat;
605 }
606 }
607 else if (base->object->type == OB_LAMP) {
609 }
610 }
611 }
612 }
613 else if (id_type == ID_TE) {
614 Tex *tex = nullptr, *origtex = (Tex *)id;
615
616 if (origtex) {
617 BLI_assert(sp->id_copy != nullptr);
618 tex = sp->texcopy = (Tex *)sp->id_copy;
619 sp->id_copy = nullptr;
620 BLI_addtail(&pr_main->textures, tex);
621 }
622 }
623 else if (id_type == ID_LA) {
624 Light *la = nullptr, *origla = (Light *)id;
625
626 /* work on a copy */
627 if (origla) {
628 BLI_assert(sp->id_copy != nullptr);
629 la = sp->lampcopy = (Light *)sp->id_copy;
630 sp->id_copy = nullptr;
631 BLI_addtail(&pr_main->lights, la);
632 }
633
634 ED_preview_set_visibility(pr_main, sce, view_layer, MA_LAMP, sp->pr_method);
635
636 if (sce->world) {
637 /* Only use lighting from the light. */
639 const float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
641 }
642
643 BKE_view_layer_synced_ensure(sce, view_layer);
645 if (base->object->id.name[2] == 'p') {
646 if (base->object->type == OB_LAMP) {
647 base->object->data = la;
648 }
649 }
650 }
651 }
652 else if (id_type == ID_WO) {
653 World *wrld = nullptr, *origwrld = (World *)id;
654
655 if (origwrld) {
656 BLI_assert(sp->id_copy != nullptr);
657 wrld = sp->worldcopy = (World *)sp->id_copy;
658 sp->id_copy = nullptr;
659 BLI_addtail(&pr_main->worlds, wrld);
660 }
661
662 ED_preview_set_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method);
663 sce->world = wrld;
664 }
665
666 return sce;
667 }
668
669 return nullptr;
670}
671
672/* new UI convention: draw is in pixel space already. */
673/* uses ButType::Roundbox button in block to get the rect */
675 Scene *scene, const void *owner, int split, int first, const rcti *rect, rcti *newrect)
676{
677 Render *re;
678 RenderView *rv;
679 RenderResult rres;
680 int offx = 0;
681 int newx = BLI_rcti_size_x(rect);
682 int newy = BLI_rcti_size_y(rect);
683 const void *split_owner = (!split || first) ? owner : (char *)owner + 1;
684 bool ok = false;
685
686 if (split) {
687 if (first) {
688 offx = 0;
689 newx = newx / 2;
690 }
691 else {
692 offx = newx / 2;
693 newx = newx - newx / 2;
694 }
695 }
696
697 /* test if something rendered ok */
698 re = RE_GetRender(split_owner);
699
700 if (re == nullptr) {
701 return false;
702 }
703
705
706 if (!BLI_listbase_is_empty(&rres.views)) {
707 /* material preview only needs monoscopy (view 0) */
708 rv = RE_RenderViewGetById(&rres, 0);
709 }
710 else {
711 /* possible the job clears the views but we're still drawing #45496 */
712 rv = nullptr;
713 }
714
715 if (rv && rv->ibuf) {
716 if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) {
717 newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx);
718 newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
719
720 if (rres.rectx && rres.recty) {
721 float fx = rect->xmin + offx;
722 float fy = rect->ymin;
723
725 rv->ibuf, fx, fy, false, &scene->view_settings, &scene->display_settings, 1.0f, 1.0f);
726
727 ok = true;
728 }
729 }
730 }
731
733
734 return ok;
735}
736
738 const bContext *C, void *idp, void *parentp, void *slotp, uiPreview *ui_preview, rcti *rect)
739{
740 if (idp) {
741 Scene *scene = CTX_data_scene(C);
743 ID *id = (ID *)idp;
744 ID *parent = (ID *)parentp;
745 MTex *slot = (MTex *)slotp;
747 const void *owner = CTX_wm_area(C);
748 ShaderPreview *sp = static_cast<ShaderPreview *>(
750 rcti newrect;
751 bool ok;
752 int newx = BLI_rcti_size_x(rect);
753 int newy = BLI_rcti_size_y(rect);
754
755 newrect.xmin = rect->xmin;
756 newrect.xmax = rect->xmin;
757 newrect.ymin = rect->ymin;
758 newrect.ymax = rect->ymin;
759
760 if (parent) {
761 ok = ed_preview_draw_rect(scene, owner, 1, 1, rect, &newrect);
762 ok &= ed_preview_draw_rect(scene, owner, 1, 0, rect, &newrect);
763 }
764 else {
765 ok = ed_preview_draw_rect(scene, owner, 0, 0, rect, &newrect);
766 }
767
768 if (ok) {
769 *rect = newrect;
770 }
771
772 /* start a new preview render job if signaled through sbuts->preview,
773 * if no render result was found and no preview render job is running,
774 * or if the job is running and the size of preview changed */
775 if ((sbuts != nullptr && sbuts->preview) || (ui_preview->tag & UI_PREVIEW_TAG_DIRTY) ||
776 (!ok && !WM_jobs_test(wm, owner, WM_JOB_TYPE_RENDER_PREVIEW)) ||
777 (sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2)))
778 {
779 if (sbuts != nullptr) {
780 sbuts->preview = 0;
781 }
782 ED_preview_shader_job(C, owner, id, parent, slot, newx, newy, PR_BUTS_RENDER);
783 ui_preview->tag &= ~UI_PREVIEW_TAG_DIRTY;
784 }
785 }
786}
787
788void ED_previews_tag_dirty_by_id(const Main &bmain, const ID &id)
789{
790 LISTBASE_FOREACH (const bScreen *, screen, &bmain.screens) {
791 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
792 LISTBASE_FOREACH (const ARegion *, region, &area->regionbase) {
793 LISTBASE_FOREACH (uiPreview *, preview, &region->ui_previews) {
794 if (preview->id_session_uid == id.session_uid) {
795 preview->tag |= UI_PREVIEW_TAG_DIRTY;
796 }
797 }
798 }
799 }
800 }
801}
802
804
805/* -------------------------------------------------------------------- */
808
810 /* The main for the preview, not of the current file. */
812 /* Copy of the object to create the preview for. The copy is for thread safety (and to insert
813 * it into its own main). */
815 /* Current frame. */
816 int cfra;
817 int sizex;
818 int sizey;
819};
820
822{
823 return OB_TYPE_IS_GEOMETRY(ob->type);
824}
825
827 Scene *scene,
828 ViewLayer *view_layer,
829 Object *preview_object)
830{
831 Object *camera = BKE_object_add(preview_main, scene, view_layer, OB_CAMERA, "Preview Camera");
832
833 float rotmat[3][3];
834 float dummy_scale[3];
835 mat4_to_loc_rot_size(camera->loc, rotmat, dummy_scale, preview_object->object_to_world().ptr());
836
837 /* Camera is Y up, so needs additional rotations to obliquely face the front. */
838 float drotmat[3][3];
839 const float eul[3] = {M_PI * 0.4f, 0.0f, M_PI * 0.1f};
840 eul_to_mat3(drotmat, eul);
841 mul_m3_m3_post(rotmat, drotmat);
842
843 camera->rotmode = ROT_MODE_QUAT;
844 mat3_to_quat(camera->quat, rotmat);
845
846 /* Nice focal length for close portraiture. */
847 ((Camera *)camera->data)->lens = 85;
848
849 return camera;
850}
851
853 Depsgraph **r_depsgraph)
854{
855 Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene");
856 /* Preview need to be in the current frame to get a thumbnail similar of what
857 * viewport displays. */
858 scene->r.cfra = preview_data->cfra;
859
860 ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
861 Depsgraph *depsgraph = DEG_graph_new(
862 preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
863
864 BLI_assert(preview_data->object != nullptr);
865 BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
866
867 BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
868
869 Object *camera_object = object_preview_camera_create(
870 preview_data->pr_main, scene, view_layer, preview_data->object);
871
872 scene->camera = camera_object;
873 scene->r.xsch = preview_data->sizex;
874 scene->r.ysch = preview_data->sizey;
875 scene->r.size = 100;
876
877 BKE_view_layer_synced_ensure(scene, view_layer);
878 Base *preview_base = BKE_view_layer_base_find(view_layer, preview_data->object);
879 /* For 'view selected' below. */
880 preview_base->flag |= BASE_SELECTED;
881
884
886 preview_data->pr_main, depsgraph, scene, camera_object);
887
889
890 *r_depsgraph = depsgraph;
891 return scene;
892}
893
894static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
895{
896 Main *preview_main = BKE_main_new();
897 char err_out[256] = "unknown";
898
899 BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
900
901 ObjectPreviewData preview_data = {};
902 preview_data.pr_main = preview_main;
903 /* Act on a copy. */
904 preview_data.object = (Object *)preview->id_copy;
905 preview_data.cfra = preview->scene->r.cfra;
906 preview_data.sizex = preview_sized->sizex;
907 preview_data.sizey = preview_sized->sizey;
908
909 Depsgraph *depsgraph;
910 Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
911
912 /* Ownership is now ours. */
913 preview->id_copy = nullptr;
914
915 View3DShading shading;
917 /* Enable shadows, makes it a bit easier to see the shape. */
918 shading.flag |= V3D_SHADING_SHADOW;
919
922 &shading,
925 preview_sized->sizex,
926 preview_sized->sizey,
930 nullptr,
931 nullptr,
932 nullptr,
933 err_out);
934 /* TODO: color-management? */
935
936 if (ibuf) {
937 icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
938 IMB_freeImBuf(ibuf);
939 }
940
942 BKE_main_free(preview_main);
943}
944
946
947/* -------------------------------------------------------------------- */
954
956
957/* -------------------------------------------------------------------- */
960
962{
963 Object *object = preview->active_object;
964 if (object == nullptr) {
965 WM_global_report(RPT_WARNING, "No active object, unable to apply the Action before rendering");
966 return nullptr;
967 }
968 if (object->pose == nullptr) {
970 "Object %s has no pose, unable to apply the Action before rendering",
971 object->id.name + 2);
972 return nullptr;
973 }
974
975 /* Create a backup of the current pose. */
976 blender::animrig::Action &pose_action = reinterpret_cast<bAction *>(preview->id)->wrap();
977
978 if (pose_action.slot_array_num == 0) {
979 WM_global_report(RPT_WARNING, "Action has no data, cannot render preview");
980 return nullptr;
981 }
982
984 pose_action);
985 PoseBackup *pose_backup = BKE_pose_backup_create_all_bones({object}, &pose_action);
986
987 /* Apply the Action as pose, so that it can be rendered. This assumes the Action represents a
988 * single pose, and that thus the evaluation time doesn't matter. */
989 AnimationEvalContext anim_eval_context = {preview->depsgraph, 0.0f};
991 object, &pose_action, slot.handle, &anim_eval_context);
992
993 /* Force evaluation of the new pose, before the preview is rendered. */
996
997 return pose_backup;
998}
999
1000static void action_preview_render_cleanup(IconPreview *preview, PoseBackup *pose_backup)
1001{
1002 if (pose_backup == nullptr) {
1003 return;
1004 }
1005 BKE_pose_backup_restore(pose_backup);
1006 BKE_pose_backup_free(pose_backup);
1007
1009}
1010
1011/* Render a pose from the scene camera. It is assumed that the scene camera is
1012 * capturing the pose. The pose is applied temporarily to the current object
1013 * before rendering. */
1014static void action_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
1015{
1016 char err_out[256] = "";
1017
1018 Depsgraph *depsgraph = preview->depsgraph;
1019 /* Not all code paths that lead to this function actually provide a depsgraph.
1020 * The "Refresh Asset Preview" button (#ED_OT_lib_id_generate_preview) does,
1021 * but #WM_OT_previews_ensure does not. */
1022 BLI_assert(depsgraph != nullptr);
1024
1025 /* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */
1026 PoseBackup *pose_backup = action_preview_render_prepare(preview);
1027
1029 Object *camera_eval = scene_eval->camera;
1030 if (camera_eval == nullptr) {
1031 printf("Scene has no camera, unable to render preview of %s without it.\n",
1032 preview->id->name + 2);
1033 action_preview_render_cleanup(preview, pose_backup);
1034 return;
1035 }
1036
1037 /* This renders with the Workbench engine settings stored on the Scene. */
1039 scene_eval,
1040 nullptr,
1041 OB_SOLID,
1042 camera_eval,
1043 preview_sized->sizex,
1044 preview_sized->sizey,
1047 R_ADDSKY,
1048 nullptr,
1049 nullptr,
1050 nullptr,
1051 err_out);
1052
1053 action_preview_render_cleanup(preview, pose_backup);
1054
1055 if (err_out[0] != '\0') {
1056 printf("Error rendering Action %s preview: %s\n", preview->id->name + 2, err_out);
1057 }
1058
1059 if (ibuf) {
1060 icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
1061 IMB_freeImBuf(ibuf);
1062 }
1063}
1064
1066
1067/* -------------------------------------------------------------------- */
1070
1071static bool scene_preview_is_supported(const Scene *scene)
1072{
1073 return scene->camera != nullptr;
1074}
1075
1077 IconPreviewSize *preview_sized,
1078 ReportList *reports)
1079{
1080 Depsgraph *depsgraph = preview->depsgraph;
1081 /* Not all code paths that lead to this function actually provide a depsgraph.
1082 * The "Refresh Asset Preview" button (#ED_OT_lib_id_generate_preview) does,
1083 * but #WM_OT_previews_ensure does not. */
1084 BLI_assert(depsgraph != nullptr);
1085 BLI_assert(preview->id != nullptr);
1086
1088 Object *camera_eval = scene_eval->camera;
1089 if (camera_eval == nullptr) {
1090 BKE_reportf(reports,
1091 RPT_ERROR,
1092 "Scene has no camera, unable to render preview of %s without it.",
1093 BKE_id_name(*preview->id));
1094 return;
1095 }
1096
1097 char err_out[256] = "";
1098 /* This renders with the Workbench engine settings stored on the Scene. */
1100 scene_eval,
1101 nullptr,
1102 OB_SOLID,
1103 camera_eval,
1104 preview_sized->sizex,
1105 preview_sized->sizey,
1108 R_ADDSKY,
1109 nullptr,
1110 nullptr,
1111 nullptr,
1112 err_out);
1113
1114 if (err_out[0] != '\0') {
1115 BKE_reportf(reports,
1116 RPT_ERROR,
1117 "Error rendering Scene %s preview: %s.",
1118 BKE_id_name(*preview->id),
1119 err_out);
1120 }
1121
1122 if (ibuf) {
1123 icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
1124 IMB_freeImBuf(ibuf);
1125 }
1126}
1127
1129
1130/* -------------------------------------------------------------------- */
1133
1134/* inside thread, called by renderer, sets job update value */
1135static void shader_preview_update(void *spv, RenderResult * /*rr*/, rcti * /*rect*/)
1136{
1137 ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
1138
1139 *(sp->do_update) = true;
1140}
1141
1142/* called by renderer, checks job value */
1143static bool shader_preview_break(void *spv)
1144{
1145 ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
1146
1147 return *(sp->stop);
1148}
1149
1150static void shader_preview_updatejob(void * /*spv*/) {}
1151
1152/* Renders texture directly to render buffer. */
1153static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Render *re)
1154{
1155 /* Setup output buffer. */
1156 int width = sp->sizex;
1157 int height = sp->sizey;
1158
1159 /* This is needed otherwise no RenderResult is created. */
1160 sce->r.scemode &= ~R_BUTS_PREVIEW;
1161 RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr);
1162 RE_SetScene(re, sce);
1163
1164 /* Create buffer in empty RenderView created in the init step. */
1166 RenderView *rv = (RenderView *)rr->views.first;
1167 ImBuf *rv_ibuf = RE_RenderViewEnsureImBuf(rr, rv);
1169 MEM_calloc_arrayN<float>(4 * width * height, "texture render result"),
1171 RE_ReleaseResult(re);
1172
1173 /* Get texture image pool (if any) */
1174 ImagePool *img_pool = BKE_image_pool_new();
1175 BKE_texture_fetch_images_for_pool(tex, img_pool);
1176
1177 /* Fill in image buffer. */
1178 float *rect_float = rv_ibuf->float_buffer.data;
1179 float tex_coord[3] = {0.0f, 0.0f, 0.0f};
1180
1181 for (int y = 0; y < height; y++) {
1182 /* Tex coords between -1.0f and 1.0f. */
1183 tex_coord[1] = (float(y) / float(height)) * 2.0f - 1.0f;
1184
1185 for (int x = 0; x < width; x++) {
1186 tex_coord[0] = (float(x) / float(height)) * 2.0f - 1.0f;
1187
1188 /* Evaluate texture at tex_coord. */
1189 TexResult texres = {0};
1190 BKE_texture_get_value_ex(tex, tex_coord, &texres, img_pool, true);
1191 copy_v4_fl4(rect_float,
1192 texres.trgba[0],
1193 texres.trgba[1],
1194 texres.trgba[2],
1195 texres.talpha ? texres.trgba[3] : 1.0f);
1196
1197 rect_float += 4;
1198 }
1199
1200 /* Check if we should cancel texture preview. */
1201 if (shader_preview_break(sp)) {
1202 break;
1203 }
1204 }
1205
1206 BKE_image_pool_free(img_pool);
1207}
1208
1209static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int first)
1210{
1211 Render *re;
1212 Scene *sce;
1213 float oldlens;
1214 short idtype = GS(id->name);
1215 int sizex;
1216 Main *pr_main = sp->pr_main;
1217
1218 /* in case of split preview, use border render */
1219 if (split) {
1220 if (first) {
1221 sizex = sp->sizex / 2;
1222 }
1223 else {
1224 sizex = sp->sizex - sp->sizex / 2;
1225 }
1226 }
1227 else {
1228 sizex = sp->sizex;
1229 }
1230
1231 /* we have to set preview variables first */
1232 sce = preview_get_scene(pr_main);
1233 if (sce) {
1234 sce->r.xsch = sizex;
1235 sce->r.ysch = sp->sizey;
1236 sce->r.size = 100;
1237 }
1238
1239 /* get the stuff from the builtin preview dbase */
1240 sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
1241 if (sce == nullptr) {
1242 return;
1243 }
1244
1245 const void *split_owner = (!split || first) ? sp->owner : (char *)sp->owner + 1;
1246 re = RE_GetRender(split_owner);
1247
1248 /* full refreshed render from first tile */
1249 if (re == nullptr) {
1250 re = RE_NewRender(split_owner);
1251 }
1252
1253 /* sce->r gets copied in RE_InitState! */
1255 sce->r.scemode &= ~R_NO_IMAGE_LOAD;
1256
1257 if (sp->pr_method == PR_ICON_RENDER) {
1258 sce->r.scemode |= R_NO_IMAGE_LOAD;
1260 }
1261 else { /* PR_BUTS_RENDER */
1263 }
1264
1265 /* Callbacks are cleared on GetRender(). */
1266 if (sp->pr_method == PR_BUTS_RENDER) {
1268 }
1269 /* set this for all previews, default is react to G.is_break still */
1271
1272 /* lens adjust */
1273 oldlens = ((Camera *)sce->camera->data)->lens;
1274 if (sizex > sp->sizey) {
1275 ((Camera *)sce->camera->data)->lens *= float(sp->sizey) / float(sizex);
1276 }
1277
1278 /* entire cycle for render engine */
1279 if (idtype == ID_TE) {
1280 shader_preview_texture(sp, (Tex *)id, sce, re);
1281 }
1282 else {
1283 /* Render preview scene */
1284 RE_PreviewRender(re, pr_main, sce);
1285 }
1286
1287 ((Camera *)sce->camera->data)->lens = oldlens;
1288
1289 /* handle results */
1290 if (sp->pr_method == PR_ICON_RENDER) {
1291 // char *rct = (char *)(sp->pr_rect + 32 * 16 + 16);
1292
1293 if (sp->pr_rect) {
1294 RE_ResultGet32(re, sp->pr_rect);
1295 }
1296 }
1297
1298 /* unassign the pointers, reset vars */
1299 preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp);
1300
1301 /* XXX bad exception, end-exec is not being called in render, because it uses local main. */
1302#if 0
1303 if (idtype == ID_TE) {
1304 Tex *tex = (Tex *)id;
1305 if (tex->use_nodes && tex->nodetree) {
1306 ntreeEndExecTree(tex->nodetree);
1307 }
1308 }
1309#endif
1310}
1311
1312/* runs inside thread for material and icons */
1313static void shader_preview_startjob(void *customdata, bool *stop, bool *do_update)
1314{
1315 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1316
1317 sp->stop = stop;
1318 sp->do_update = do_update;
1319
1320 if (sp->parent) {
1321 shader_preview_render(sp, sp->id, 1, 1);
1322 shader_preview_render(sp, sp->parent, 1, 0);
1323 }
1324 else {
1325 shader_preview_render(sp, sp->id, 0, 0);
1326 }
1327
1328 *do_update = true;
1329}
1330
1331static void preview_id_copy_free(ID *id)
1332{
1334 BKE_libblock_free_data(id, false);
1335 MEM_freeN(id);
1336}
1337
1338static void shader_preview_free(void *customdata)
1339{
1340 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1341 Main *pr_main = sp->pr_main;
1342 ID *main_id_copy = nullptr;
1343 ID *sub_id_copy = nullptr;
1344
1345 if (sp->matcopy) {
1346 main_id_copy = (ID *)sp->matcopy;
1347 BLI_remlink(&pr_main->materials, sp->matcopy);
1348 }
1349 if (sp->texcopy) {
1350 BLI_assert(main_id_copy == nullptr);
1351 main_id_copy = (ID *)sp->texcopy;
1352 BLI_remlink(&pr_main->textures, sp->texcopy);
1353 }
1354 if (sp->worldcopy) {
1355 /* worldcopy is also created for material with `Preview World` enabled */
1356 if (main_id_copy) {
1357 sub_id_copy = (ID *)sp->worldcopy;
1358 }
1359 else {
1360 main_id_copy = (ID *)sp->worldcopy;
1361 }
1362 BLI_remlink(&pr_main->worlds, sp->worldcopy);
1363 }
1364 if (sp->lampcopy) {
1365 BLI_assert(main_id_copy == nullptr);
1366 main_id_copy = (ID *)sp->lampcopy;
1367 BLI_remlink(&pr_main->lights, sp->lampcopy);
1368 }
1369 if (sp->own_id_copy) {
1370 if (sp->id_copy) {
1372 }
1373 if (main_id_copy) {
1374 preview_id_copy_free(main_id_copy);
1375 }
1376 if (sub_id_copy) {
1377 preview_id_copy_free(sub_id_copy);
1378 }
1379 }
1380
1381 MEM_freeN(sp);
1382}
1383
1385
1386/* -------------------------------------------------------------------- */
1389
1390static void icon_copy_rect(const ImBuf *ibuf, uint w, uint h, uint *rect)
1391{
1392 if (ibuf == nullptr ||
1393 (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr) || rect == nullptr)
1394 {
1395 return;
1396 }
1397
1398 float scaledx, scaledy;
1399 if (ibuf->x > ibuf->y) {
1400 scaledx = float(w);
1401 scaledy = (float(ibuf->y) / float(ibuf->x)) * float(w);
1402 }
1403 else {
1404 scaledx = (float(ibuf->x) / float(ibuf->y)) * float(h);
1405 scaledy = float(h);
1406 }
1407
1408 /* Scaling down must never assign zero width/height, see: #89868. */
1409 int ex = std::max<int>(1, scaledx);
1410 int ey = std::max<int>(1, scaledy);
1411
1412 int dx = (w - ex) / 2;
1413 int dy = (h - ey) / 2;
1414
1415 ImBuf *ima = IMB_scale_into_new(ibuf, ex, ey, IMBScaleFilter::Nearest, false);
1416 if (ima == nullptr) {
1417 return;
1418 }
1419
1420 /* if needed, convert to 32 bits */
1421 if (ima->byte_buffer.data == nullptr) {
1423 }
1424
1425 const uint *srect = reinterpret_cast<const uint *>(ima->byte_buffer.data);
1426 uint *drect = rect;
1427
1428 drect += dy * w + dx;
1429 for (; ey > 0; ey--) {
1430 memcpy(drect, srect, ex * sizeof(int));
1431 drect += w;
1432 srect += ima->x;
1433 }
1434
1435 IMB_freeImBuf(ima);
1436}
1437
1438static void set_alpha(char *cp, int sizex, int sizey, char alpha)
1439{
1440 int a, size = sizex * sizey;
1441
1442 for (a = 0; a < size; a++, cp += 4) {
1443 cp[3] = alpha;
1444 }
1445}
1446
1447static void icon_preview_startjob(void *customdata, bool *stop, bool *do_update)
1448{
1449 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1450
1451 if (sp->pr_method == PR_ICON_DEFERRED) {
1453 return;
1454 }
1455
1456 ID *id = sp->id;
1457 short idtype = GS(id->name);
1458
1459 BLI_assert(id != nullptr);
1460
1461 if (idtype == ID_IM) {
1462 Image *ima = (Image *)id;
1463 ImBuf *ibuf = nullptr;
1464 ImageUser iuser;
1465 BKE_imageuser_default(&iuser);
1466
1467 if (ima == nullptr) {
1468 return;
1469 }
1470
1471 /* setup dummy image user */
1472 iuser.framenr = 1;
1473 iuser.scene = sp->scene;
1474
1475 /* NOTE(@elubie): this needs to be changed: here image is always loaded if not
1476 * already there. Very expensive for large images. Need to find a way to
1477 * only get existing `ibuf`. */
1478 ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
1479 if (ibuf == nullptr ||
1480 (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr))
1481 {
1482 BKE_image_release_ibuf(ima, ibuf, nullptr);
1483 return;
1484 }
1485
1486 icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
1487
1488 *do_update = true;
1489
1490 BKE_image_release_ibuf(ima, ibuf, nullptr);
1491 }
1492 else {
1493 /* re-use shader job */
1494 shader_preview_startjob(customdata, stop, do_update);
1495
1496 /* world is rendered with alpha=0, so it wasn't displayed
1497 * this could be render option for sky to, for later */
1498 if (idtype == ID_WO) {
1499 set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
1500 }
1501 }
1502}
1503
1504/* use same function for icon & shader, so the job manager
1505 * does not run two of them at the same time. */
1506
1507static void common_preview_startjob(void *customdata, wmJobWorkerStatus *worker_status)
1508{
1509 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1510
1512 icon_preview_startjob(customdata, &worker_status->stop, &worker_status->do_update);
1513 }
1514 else {
1515 shader_preview_startjob(customdata, &worker_status->stop, &worker_status->do_update);
1516 }
1517}
1518
1524 IconPreviewSize *cur_size,
1525 const ePreviewRenderMethod pr_method,
1526 wmJobWorkerStatus *worker_status)
1527{
1528 ShaderPreview *sp = MEM_callocN<ShaderPreview>("Icon ShaderPreview");
1529
1530 /* These types don't use the ShaderPreview mess, they have their own types and functions. */
1531 BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
1532
1533 /* Construct shader preview from image size and preview custom-data. */
1534 sp->scene = ip->scene;
1535 sp->owner = ip->owner;
1536 sp->sizex = cur_size->sizex;
1537 sp->sizey = cur_size->sizey;
1538 sp->pr_method = pr_method;
1539 sp->pr_rect = cur_size->rect;
1540 sp->id = ip->id;
1541 sp->id_copy = ip->id_copy;
1542 sp->bmain = ip->bmain;
1543 sp->own_id_copy = false;
1544 Material *ma = nullptr;
1545
1546 if (sp->pr_method == PR_ICON_RENDER) {
1547 BLI_assert(ip->id);
1548
1549 /* grease pencil use its own preview file */
1550 if (GS(ip->id->name) == ID_MA) {
1551 ma = (Material *)ip->id;
1552 }
1553
1554 if ((ma == nullptr) || (ma->gp_style == nullptr)) {
1555 sp->pr_main = G.pr_main;
1556 }
1557 else {
1559 }
1560 }
1561
1562 common_preview_startjob(sp, worker_status);
1564}
1565
1566/* exported functions */
1567
1572 const PreviewImage *preview_image)
1573{
1574 for (int i = 0; i < NUM_ICON_SIZES; i++) {
1575 if ((preview_image->w[i] == icon_size->sizex) && (preview_image->h[i] == icon_size->sizey)) {
1576 return i;
1577 }
1578 }
1579
1580 BLI_assert_msg(0, "The searched icon size does not match any in the preview image");
1581 return -1;
1582}
1583
1584static void icon_preview_startjob_all_sizes(void *customdata, wmJobWorkerStatus *worker_status)
1585{
1586 IconPreview *ip = (IconPreview *)customdata;
1587
1588 LISTBASE_FOREACH (IconPreviewSize *, cur_size, &ip->sizes) {
1589 PreviewImage *prv = static_cast<PreviewImage *>(ip->owner);
1590 /* Is this a render job or a deferred loading job? */
1591 const ePreviewRenderMethod pr_method = (prv->runtime->deferred_loading_data) ?
1594
1595 if (worker_status->stop) {
1596 break;
1597 }
1598
1599 if (prv->runtime->tag & PRV_TAG_DEFFERED_DELETE) {
1600 /* Non-thread-protected reading is not an issue here. */
1601 continue;
1602 }
1603
1604 /* check_engine_supports_preview() checks whether the engine supports "preview mode" (think:
1605 * Material Preview). This check is only relevant when the render function called below is
1606 * going to use such a mode. Group, Object and Action render functions use Solid mode, though,
1607 * so they can skip this test. Same is true for Images and Brushes, they can also skip this
1608 * test since their preview is just pulled from ImBuf which is not dependent on the render
1609 * engine. */
1610 /* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
1611 * necessary to know here what happens inside lower-level functions. */
1612 const bool use_solid_render_mode = (ip->id != nullptr) &&
1613 ELEM(GS(ip->id->name), ID_OB, ID_AC, ID_IM, ID_GR, ID_SCE);
1614 if (!use_solid_render_mode && preview_method_is_render(pr_method) &&
1616 {
1617 continue;
1618 }
1619
1620 /* Workaround: Skip preview renders for linked IDs. Preview rendering can be slow and even
1621 * freeze the UI (e.g. on Eevee shader compilation). And since the result will never be stored
1622 * in a file, it's done every time the file is reloaded, so this becomes a frequent annoyance.
1623 */
1624 if (!use_solid_render_mode && ip->id && !ID_IS_EDITABLE(ip->id)) {
1625 continue;
1626 }
1627
1628#ifndef NDEBUG
1629 {
1630 int size_index = icon_previewimg_size_index_get(cur_size, prv);
1631 BLI_assert(!BKE_previewimg_is_finished(prv, size_index));
1632 }
1633#endif
1634
1635 if (ip->id != nullptr) {
1636 switch (GS(ip->id->name)) {
1637 case ID_OB:
1639 /* Much simpler than the ShaderPreview mess used for other ID types. */
1640 object_preview_render(ip, cur_size);
1641 }
1642 continue;
1643 case ID_GR:
1645 reinterpret_cast<const Collection *>(ip->id)));
1646 /* A collection instance empty was created, so this can just reuse the object preview
1647 * rendering. */
1648 object_preview_render(ip, cur_size);
1649 continue;
1650 case ID_AC:
1651 action_preview_render(ip, cur_size);
1652 continue;
1653 case ID_SCE:
1654 scene_preview_render(ip, cur_size, worker_status->reports);
1655 continue;
1656 default:
1657 /* Fall through to the same code as the `ip->id == nullptr` case. */
1658 break;
1659 }
1660 }
1661 other_id_types_preview_render(ip, cur_size, pr_method, worker_status);
1662 }
1663}
1664
1665static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
1666{
1667 IconPreviewSize *cur_size = static_cast<IconPreviewSize *>(ip->sizes.first);
1668
1669 while (cur_size) {
1670 if (cur_size->sizex == sizex && cur_size->sizey == sizey) {
1671 /* requested size is already in list, no need to add it again */
1672 return;
1673 }
1674
1675 cur_size = cur_size->next;
1676 }
1677
1678 IconPreviewSize *new_size = MEM_callocN<IconPreviewSize>("IconPreviewSize");
1679 new_size->sizex = sizex;
1680 new_size->sizey = sizey;
1681 new_size->rect = rect;
1682
1683 BLI_addtail(&ip->sizes, new_size);
1684}
1685
1686static void icon_preview_endjob(void *customdata)
1687{
1688 IconPreview *ip = static_cast<IconPreview *>(customdata);
1689
1690 if (ip->id) {
1691
1692#if 0
1693 if (GS(ip->id->name) == ID_MA) {
1694 Material *ma = (Material *)ip->id;
1695 PreviewImage *prv_img = ma->preview;
1696 int i;
1697
1698 /* signal to gpu texture */
1699 for (i = 0; i < NUM_ICON_SIZES; i++) {
1700 if (prv_img->gputexture[i]) {
1701 GPU_texture_free(prv_img->gputexture[i]);
1702 prv_img->gputexture[i] = nullptr;
1704 }
1705 }
1706 }
1707#endif
1708 }
1709
1710 if (ip->owner) {
1711 PreviewImage *prv_img = static_cast<PreviewImage *>(ip->owner);
1712 prv_img->runtime->tag &= ~PRV_TAG_DEFFERED_RENDERING;
1713
1714 LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) {
1715 int size_index = icon_previewimg_size_index_get(icon_size, prv_img);
1716 BKE_previewimg_finish(prv_img, size_index);
1717 }
1718
1719 if (prv_img->runtime->tag & PRV_TAG_DEFFERED_DELETE) {
1720 BLI_assert(prv_img->runtime->deferred_loading_data);
1722 }
1723 }
1724}
1725
1736 struct RequestedPreview {
1737 PreviewImage *preview;
1739 eIconSizes icon_size;
1741 std::atomic<bool> done = false;
1744 std::atomic<bool> failure = false;
1745
1746 RequestedPreview(PreviewImage *preview, eIconSizes icon_size)
1747 : preview(preview), icon_size(icon_size)
1748 {
1749 }
1750 };
1751
1753 ThreadQueue *todo_queue_; /* RequestedPreview * */
1756 std::list<RequestedPreview> requested_previews_;
1757
1758 public:
1761
1763 static void load_jobless(PreviewImage *preview, eIconSizes icon_size);
1764
1765 void push_load_request(PreviewImage *preview, eIconSizes icon_size);
1766
1767 private:
1768 static void run_fn(void *customdata, wmJobWorkerStatus *worker_status);
1769 static void update_fn(void *customdata);
1770 static void end_fn(void *customdata);
1771 static void free_fn(void *customdata);
1772
1774 static void finish_request(RequestedPreview &request);
1775};
1776
1778
1783
1785{
1786 wmJob *wm_job = WM_jobs_get(
1787 wm, win, nullptr, "Loading previews...", eWM_JobFlag(0), WM_JOB_TYPE_LOAD_PREVIEW);
1788
1789 if (!WM_jobs_is_running(wm_job)) {
1790 PreviewLoadJob *job_data = MEM_new<PreviewLoadJob>("PreviewLoadJobData");
1791
1792 WM_jobs_customdata_set(wm_job, job_data, free_fn);
1793 WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
1794 WM_jobs_callbacks(wm_job, run_fn, nullptr, update_fn, end_fn);
1795
1796 WM_jobs_start(wm, wm_job);
1797 }
1798
1799 return *static_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job));
1800}
1801
1803{
1804 PreviewLoadJob job_data{};
1805
1806 job_data.push_load_request(preview, icon_size);
1807
1808 wmJobWorkerStatus worker_status = {};
1809 run_fn(&job_data, &worker_status);
1810 update_fn(&job_data);
1811 end_fn(&job_data);
1812}
1813
1815{
1816 BLI_assert(preview->runtime->deferred_loading_data);
1817
1818 preview->flag[icon_size] |= PRV_RENDERING;
1819 /* Warn main thread code that this preview is being rendered and cannot be freed. */
1820 preview->runtime->tag |= PRV_TAG_DEFFERED_RENDERING;
1821
1822 requested_previews_.emplace_back(preview, icon_size);
1824 todo_queue_, &requested_previews_.back(), BLI_THREAD_QUEUE_WORK_PRIORITY_NORMAL);
1825}
1826
1827void PreviewLoadJob::run_fn(void *customdata, wmJobWorkerStatus *worker_status)
1828{
1829 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1830
1832
1833 while (RequestedPreview *request = static_cast<RequestedPreview *>(
1834 BLI_thread_queue_pop_timeout(job_data->todo_queue_, 100)))
1835 {
1836 if (worker_status->stop) {
1837 break;
1838 }
1839
1840 PreviewImage *preview = request->preview;
1841
1842 const std::optional<int> source = BKE_previewimg_deferred_thumb_source_get(preview);
1843 const char *filepath = BKE_previewimg_deferred_filepath_get(preview);
1844
1845 if (!source || !filepath) {
1846 continue;
1847 }
1848
1849 // printf("loading deferred %dx%d preview for %s\n", request->sizex, request->sizey, filepath);
1850
1851 IMB_thumb_path_lock(filepath);
1852 ImBuf *thumb = IMB_thumb_manage(filepath, THB_LARGE, ThumbSource(*source));
1853 IMB_thumb_path_unlock(filepath);
1854
1855 if (thumb) {
1856 /* PreviewImage assumes premultiplied alpha. */
1857 IMB_premultiply_alpha(thumb);
1858
1859 if (ED_preview_use_image_size(preview, request->icon_size)) {
1860 preview->w[request->icon_size] = thumb->x;
1861 preview->h[request->icon_size] = thumb->y;
1862 BLI_assert(preview->rect[request->icon_size] == nullptr);
1863 preview->rect[request->icon_size] = (uint *)MEM_dupallocN(thumb->byte_buffer.data);
1864 }
1865 else {
1866 icon_copy_rect(thumb,
1867 preview->w[request->icon_size],
1868 preview->h[request->icon_size],
1869 preview->rect[request->icon_size]);
1870 }
1871 IMB_freeImBuf(thumb);
1872 }
1873 else {
1874 request->failure = true;
1875 }
1876
1877 request->done = true;
1878 worker_status->do_update = true;
1879 }
1880
1882}
1883
1884/* Only execute on the main thread! */
1885void PreviewLoadJob::finish_request(RequestedPreview &request)
1886{
1887 PreviewImage *preview = request.preview;
1888
1889 preview->runtime->tag &= ~PRV_TAG_DEFFERED_RENDERING;
1890 if (request.failure) {
1891 preview->runtime->tag |= PRV_TAG_DEFFERED_INVALID;
1892 }
1893 BKE_previewimg_finish(preview, request.icon_size);
1894
1896 "Deferred releasing of preview images should only run on the main thread");
1897 if (preview->runtime->tag & PRV_TAG_DEFFERED_DELETE) {
1898 BLI_assert(preview->runtime->deferred_loading_data);
1900 }
1901}
1902
1903void PreviewLoadJob::update_fn(void *customdata)
1904{
1905 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1906
1907 for (auto request_it = job_data->requested_previews_.begin();
1908 request_it != job_data->requested_previews_.end();)
1909 {
1910 RequestedPreview &requested = *request_it;
1911 /* Skip items that are not done loading yet. */
1912 if (!requested.done) {
1913 ++request_it;
1914 continue;
1915 }
1916 finish_request(requested);
1917
1918 /* Remove properly finished previews from the job data. */
1919 auto next_it = job_data->requested_previews_.erase(request_it);
1920 request_it = next_it;
1921 }
1922}
1923
1924void PreviewLoadJob::end_fn(void *customdata)
1925{
1926 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1927
1928 /* Finish any possibly remaining queued previews. */
1929 for (RequestedPreview &request : job_data->requested_previews_) {
1930 finish_request(request);
1931 }
1932 job_data->requested_previews_.clear();
1933}
1934
1935void PreviewLoadJob::free_fn(void *customdata)
1936{
1937 MEM_delete(static_cast<PreviewLoadJob *>(customdata));
1938}
1939
1940static void icon_preview_free(void *customdata)
1941{
1942 IconPreview *ip = (IconPreview *)customdata;
1943
1944 if (ip->id_copy) {
1946 }
1947
1948 BLI_freelistN(&ip->sizes);
1949 MEM_freeN(ip);
1950}
1951
1953{
1954 return size == ICON_SIZE_PREVIEW && preview->runtime->deferred_loading_data;
1955}
1956
1957bool ED_preview_id_is_supported(const ID *id, const char **r_disabled_hint)
1958{
1959 if (id == nullptr) {
1960 return false;
1961 }
1962
1963 /* Get both the result and the "potential" disabled hint. After that we can decide if the
1964 * disabled hint needs to be returned to the caller. */
1965 const auto [result, disabled_hint] = [id]() -> std::pair<bool, const char *> {
1966 switch (GS(id->name)) {
1967 case ID_NT:
1968 return {false, RPT_("Node groups do not support automatic previews")};
1969 case ID_OB:
1970 return {object_preview_is_type_supported((const Object *)id),
1971 RPT_("Object type does not support automatic previews")};
1972 case ID_GR:
1973 return {
1974 BKE_collection_contains_geometry_recursive(reinterpret_cast<const Collection *>(id)),
1975 RPT_("Collection does not contain object types that can be rendered for the automatic "
1976 "preview")};
1977 case ID_SCE:
1978 return {scene_preview_is_supported((const Scene *)id),
1979 RPT_("Scenes without a camera do not support previews")};
1980 default:
1981 return {BKE_previewimg_id_get_p(id) != nullptr,
1982 RPT_("Data-block type does not support automatic previews")};
1983 }
1984 }();
1985
1986 if (result == false && disabled_hint && r_disabled_hint) {
1987 *r_disabled_hint = disabled_hint;
1988 }
1989
1990 return result;
1991}
1992
1994 const bContext *C, Scene *scene, PreviewImage *prv_img, ID *id, eIconSizes icon_size)
1995{
1996 /* Deferred loading of previews from the file system. */
1997 if (prv_img->runtime->deferred_loading_data) {
1998 if (prv_img->flag[icon_size] & PRV_RENDERING) {
1999 /* Already in the queue, don't add it again. */
2000 return;
2001 }
2002
2003 PreviewLoadJob::load_jobless(prv_img, icon_size);
2004 return;
2005 }
2006
2007 IconPreview ip = {nullptr};
2008
2010
2011 ip.bmain = CTX_data_main(C);
2012 if (GS(id->name) == ID_SCE) {
2013 Scene *icon_scene = reinterpret_cast<Scene *>(id);
2014 ip.scene = icon_scene;
2017 ip.active_object = nullptr;
2018 }
2019 else {
2020 ip.scene = scene;
2022 /* Control isn't given back to the caller until the preview is done. So we don't need to copy
2023 * the ID to avoid thread races. */
2024 ip.id_copy = duplicate_ids(id, true);
2026 }
2028 ip.id = id;
2029
2030 prv_img->flag[icon_size] |= PRV_RENDERING;
2031
2033 &ip, prv_img->rect[icon_size], prv_img->w[icon_size], prv_img->h[icon_size]);
2034
2035 wmJobWorkerStatus worker_status = {};
2036 icon_preview_startjob_all_sizes(&ip, &worker_status);
2037
2039
2040 BLI_freelistN(&ip.sizes);
2041 if (ip.id_copy != nullptr) {
2043 }
2044}
2045
2047 const bContext *C, PreviewImage *prv_img, ID *id, eIconSizes icon_size, const bool delay)
2048{
2049 /* Deferred loading of previews from the file system. */
2050 if (prv_img->runtime->deferred_loading_data) {
2051 if (prv_img->flag[icon_size] & PRV_RENDERING) {
2052 /* Already in the queue, don't add it again. */
2053 return;
2054 }
2056 load_job.push_load_request(prv_img, icon_size);
2057
2058 return;
2059 }
2060
2061 IconPreview *ip, *old_ip;
2062
2064
2065 /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
2066 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
2068 prv_img,
2069 "Generating icon preview...",
2072
2073 ip = MEM_callocN<IconPreview>("icon preview");
2074
2075 /* render all resolutions from suspended job too */
2076 old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job));
2077 if (old_ip) {
2078 BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
2079 }
2080
2081 /* customdata for preview thread */
2082 ip->bmain = CTX_data_main(C);
2083 if (GS(id->name) == ID_SCE) {
2084 Scene *icon_scene = reinterpret_cast<Scene *>(id);
2085 ip->scene = icon_scene;
2088 ip->active_object = nullptr;
2089 }
2090 else {
2093 ip->id_copy = duplicate_ids(id, false);
2095 }
2096 ip->owner = prv_img;
2097 ip->id = id;
2098
2099 prv_img->flag[icon_size] |= PRV_RENDERING;
2100
2102 ip, prv_img->rect[icon_size], prv_img->w[icon_size], prv_img->h[icon_size]);
2103
2104 /* setup job */
2106 WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
2107 /* Wait 2s to start rendering icon previews, to not bog down user interaction.
2108 * Particularly important for heavy scenes and Eevee using OpenGL that blocks
2109 * the user interface drawing. */
2110 WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0);
2112 wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob);
2113
2114 WM_jobs_start(CTX_wm_manager(C), wm_job);
2115}
2116
2118 const void *owner,
2119 ID *id,
2120 ID *parent,
2121 MTex *slot,
2122 int sizex,
2123 int sizey,
2124 ePreviewRenderMethod method)
2125{
2127 wmJob *wm_job;
2128 ShaderPreview *sp;
2129 Scene *scene = CTX_data_scene(C);
2130 const ID_Type id_type = GS(id->name);
2131
2133
2134 /* Use workspace render only for buttons Window,
2135 * since the other previews are related to the datablock. */
2136
2138 return;
2139 }
2140
2142
2143 wm_job = WM_jobs_get(CTX_wm_manager(C),
2145 owner,
2146 "Generating shader preview...",
2149 sp = MEM_callocN<ShaderPreview>("shader preview");
2150
2151 /* customdata for preview thread */
2152 sp->scene = scene;
2153 sp->owner = owner;
2154 sp->sizex = sizex;
2155 sp->sizey = sizey;
2156 sp->pr_method = method;
2157 sp->id = id;
2158 sp->id_copy = duplicate_ids(id, false);
2159 sp->own_id_copy = true;
2160 sp->parent = parent;
2161 sp->slot = slot;
2162 sp->bmain = CTX_data_main(C);
2163 Material *ma = nullptr;
2164
2165 /* hardcoded preview .blend for Eevee + Cycles, this should be solved
2166 * once with custom preview .blend path for external engines */
2167
2168 /* grease pencil use its own preview file */
2169 if (id_type == ID_MA) {
2170 ma = (Material *)id;
2171 }
2172
2173 if ((ma == nullptr) || (ma->gp_style == nullptr)) {
2174 sp->pr_main = G.pr_main;
2175 }
2176 else {
2178 }
2179
2180 if (ob && ob->totcol) {
2181 copy_v4_v4(sp->color, ob->color);
2182 }
2183 else {
2184 ARRAY_SET_ITEMS(sp->color, 0.0f, 0.0f, 0.0f, 1.0f);
2185 }
2186
2187 /* setup job */
2189 WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
2191
2192 WM_jobs_start(CTX_wm_manager(C), wm_job);
2193}
2194
2196{
2197 if (wm) {
2198 /* This is called to stop all preview jobs before scene data changes, to
2199 * avoid invalid memory access. */
2201 }
2202}
2203
2205{
2206 const PreviewImage *preview = BKE_previewimg_id_get(id);
2207 if (wm && preview) {
2209 }
2210}
2211
2218
2219static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
2220
2225
2227{
2229 queue_entry->size = size;
2230 queue_entry->id = id;
2232}
2233
2235{
2237 PreviewImage *preview = BKE_previewimg_id_get(queue_entry->id);
2238 if (!preview) {
2239 continue;
2240 }
2241 if (preview->flag[queue_entry->size] & PRV_USER_EDITED) {
2242 /* Don't touch custom previews. */
2243 continue;
2244 }
2245
2246 BKE_previewimg_clear_single(preview, queue_entry->size);
2247 UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true);
2248
2250 }
2251}
2252
Functions and classes to work with Actions.
Functions to work with animation poses.
void ED_draw_imbuf(ImBuf *ibuf, float x, float y, bool use_filter, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, float zoom_x, float zoom_y)
Definition glutil.cc:559
bool BKE_collection_contains_geometry_recursive(const Collection *collection)
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
void BKE_color_managed_display_settings_copy(ColorManagedDisplaySettings *new_settings, const ColorManagedDisplaySettings *settings)
void BKE_color_managed_view_settings_free(ColorManagedViewSettings *settings)
void BKE_color_managed_view_settings_copy(ColorManagedViewSettings *new_settings, const ColorManagedViewSettings *settings)
SpaceProperties * CTX_wm_space_properties(const bContext *C)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(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)
@ G_FILE_NO_UI
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_pool_free(ImagePool *pool)
ImagePool * BKE_image_pool_new()
void BKE_imageuser_default(ImageUser *iuser)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
ViewLayer * BKE_view_layer_default_render(const Scene *scene)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL()
void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL()
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:777
@ LIB_ID_CREATE_LOCAL
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_NO_ANIMDATA
const char * BKE_id_name(const ID &id)
General operations, lookup, etc. for blender lights.
Main * BKE_main_new()
Definition main.cc:89
void BKE_main_free(Main *bmain)
Definition main.cc:192
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
General operations, lookup, etc. for materials.
Material *** BKE_object_material_array_p(Object *ob)
General operations, lookup, etc. for blender objects.
Object * BKE_object_add(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name) ATTR_NONNULL(1
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
struct PoseBackup * BKE_pose_backup_create_all_bones(blender::Span< Object * > objects, const struct bAction *action) ATTR_WARN_UNUSED_RESULT
void BKE_pose_backup_restore(const struct PoseBackup *pbd)
void BKE_pose_backup_free(struct PoseBackup *pbd)
void BKE_previewimg_deferred_release(PreviewImage *prv)
PreviewImage * BKE_previewimg_id_get(const ID *id)
bool BKE_previewimg_is_finished(const PreviewImage *prv, int size)
std::optional< int > BKE_previewimg_deferred_thumb_source_get(const PreviewImage *prv)
bool BKE_previewimg_id_supports_jobs(const ID *id)
PreviewImage * BKE_previewimg_id_ensure(ID *id)
PreviewImage ** BKE_previewimg_id_get_p(const ID *id)
void BKE_previewimg_clear_single(PreviewImage *prv, enum eIconSizes size)
const char * BKE_previewimg_deferred_filepath_get(const PreviewImage *prv)
void BKE_previewimg_finish(PreviewImage *prv, int size)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3416
Scene * BKE_scene_add(Main *bmain, const char *name)
Definition scene.cc:2001
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2621
void BKE_screen_view3d_shading_init(View3DShading *shading)
Definition screen.cc:1017
void BKE_texture_fetch_images_for_pool(struct Tex *texture, struct ImagePool *pool)
Definition texture.cc:661
void BKE_texture_get_value_ex(struct Tex *texture, const float *tex_co, struct TexResult *texres, struct ImagePool *pool, bool use_color_management)
Definition texture.cc:616
struct World * BKE_world_add(struct Main *bmain, const char *name)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
void void void BLI_movelisttolist(ListBase *dst, ListBase *src) ATTR_NONNULL(1
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
MINLINE int max_ii(int a, int b)
#define M_PI
void mul_m3_m3_post(float R[3][3], const float B[3][3])
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
void eul_to_mat3(float mat[3][3], const float eul[3])
void mat3_to_quat(float q[4], const float mat[3][3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
#define STRNCPY_UTF8(dst, src)
unsigned int uint
@ BLI_THREAD_QUEUE_WORK_PRIORITY_NORMAL
ThreadQueue * BLI_thread_queue_init(void)
Definition threads.cc:624
void BLI_thread_queue_free(ThreadQueue *queue)
Definition threads.cc:635
uint64_t BLI_thread_queue_push(ThreadQueue *queue, void *work, ThreadQueueWorkPriority priority)
Definition threads.cc:645
int BLI_thread_is_main(void)
Definition threads.cc:179
void * BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
Definition threads.cc:782
#define UNUSED_VARS(...)
#define ARRAY_SET_ITEMS(...)
#define ELEM(...)
#define STREQ(a, b)
external readfile function prototypes.
@ BLO_READ_SKIP_NONE
BlendFileData * BLO_read_from_memory(const void *mem, int memsize, eBLOReadSkip skip_flags, ReportList *reports)
#define RPT_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ DAG_EVAL_VIEWPORT
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:278
void DEG_evaluate_on_refresh(Depsgraph *graph, DepsgraphEvaluateSyncWriteback sync_writeback=DEG_EVALUATE_SYNC_WRITEBACK_NO)
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:306
void DEG_graph_build_from_view_layer(Depsgraph *graph)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
Scene * DEG_get_input_scene(const Depsgraph *graph)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ PRV_TAG_DEFFERED_DELETE
Definition DNA_ID.h:630
@ PRV_TAG_DEFFERED_RENDERING
Definition DNA_ID.h:628
@ PRV_TAG_DEFFERED_INVALID
Definition DNA_ID.h:632
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
struct PreviewImage PreviewImage
@ PRV_RENDERING
Definition DNA_ID.h:622
@ PRV_USER_EDITED
Definition DNA_ID.h:620
eIconSizes
@ ICON_SIZE_PREVIEW
@ NUM_ICON_SIZES
ID_Type
@ ID_TE
@ ID_IM
@ ID_NT
@ ID_LA
@ ID_SCE
@ ID_WO
@ ID_MA
@ ID_AC
@ ID_GR
@ ID_OB
@ ROT_MODE_QUAT
Object groups, one object can be in many groups at once.
@ COLLECTION_HIDE_RENDER
@ BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT
@ MA_SPHERE_A
@ MA_SHADERBALL
@ MA_SPHERE
@ MA_PREVIEW_WORLD
@ SOCK_OUT
@ SOCK_IN
@ OB_TEXTURE
@ OB_SOLID
Object is a sort of wrapper for general info.
@ OB_HIDE_RENDER
#define OB_TYPE_IS_GEOMETRY(_type)
@ OB_EMPTY
@ OB_CAMERA
@ OB_LAMP
@ OB_MESH
@ OB_DUPLICOLLECTION
#define OB_TYPE_SUPPORT_MATERIAL(_type)
#define BASE_SELECTED(v3d, base)
@ SCE_DISPLAY_AA_OFF
@ SCE_DISPLAY_AA_SAMPLES_8
@ R_ADDSKY
@ R_ALPHAPREMUL
@ SCE_PASS_COMBINED
@ R_MATNODE_PREVIEW
@ R_NO_IMAGE_LOAD
@ R_TEXNODE_PREVIEW
@ R_BUTS_PREVIEW
@ UI_PREVIEW_TAG_DIRTY
@ V3D_OFSDRAW_NONE
@ V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS
@ V3D_SHADING_SHADOW
const char datatoc_preview_grease_pencil_blend[]
int datatoc_preview_grease_pencil_blend_size
const char datatoc_preview_blend[]
int datatoc_preview_blend_size
ePreviewRenderMethod
Definition ED_render.hh:61
@ PR_ICON_RENDER
Definition ED_render.hh:65
@ PR_ICON_DEFERRED
Definition ED_render.hh:67
@ PR_BUTS_RENDER
Definition ED_render.hh:63
bool ED_view3d_camera_to_view_selected_with_set_clipping(Main *bmain, Depsgraph *depsgraph, const Scene *scene, Object *camera_ob)
ImBuf * ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, Scene *scene, View3DShading *shading_override, eDrawType drawtype, Object *camera, int width, int height, eImBufFlags imbuf_flags, eV3DOffscreenDrawFlag draw_flags, int alpha_mode, const char *viewname, GPUOffScreen *ofs, GPUViewport *viewport, char err_out[256])
static void split(const char *text, const char *seps, char ***str, int *count)
void GPU_texture_free(blender::gpu::Texture *texture)
void IMB_premultiply_alpha(ImBuf *ibuf)
Definition filter.cc:381
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
void IMB_byte_from_float(ImBuf *ibuf)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_scale_into_new(const ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:489
@ IB_TAKE_OWNERSHIP
@ IB_byte_data
@ THB_LARGE
Definition IMB_thumbs.hh:23
void IMB_thumb_path_unlock(const char *path)
Definition thumbs.cc:723
ThumbSource
Definition IMB_thumbs.hh:27
void IMB_thumb_locks_acquire()
Definition thumbs.cc:676
ImBuf * IMB_thumb_manage(const char *file_or_lib_path, ThumbSize size, ThumbSource source)
Definition thumbs.cc:538
void IMB_thumb_path_lock(const char *path)
Definition thumbs.cc:707
void IMB_thumb_locks_release()
Definition thumbs.cc:692
Read Guarded memory(de)allocation.
@ RE_USE_PREVIEW
Definition RE_engine.h:44
#define C
Definition RandGen.cpp:29
void UI_icon_render_id(const bContext *C, Scene *scene, ID *id, enum eIconSizes size, bool use_job)
@ WM_JOB_TYPE_RENDER_PREVIEW
Definition WM_api.hh:1779
@ WM_JOB_TYPE_LOAD_PREVIEW
Definition WM_api.hh:1781
eWM_JobFlag
Definition WM_api.hh:1759
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1765
#define NC_WINDOW
Definition WM_types.hh:375
#define NC_MATERIAL
Definition WM_types.hh:380
#define ND_SHADING_DRAW
Definition WM_types.hh:478
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static void load_jobless(PreviewImage *preview, eIconSizes icon_size)
void push_load_request(PreviewImage *preview, eIconSizes icon_size)
static PreviewLoadJob & ensure_job(wmWindowManager *wm, wmWindow *win)
nullptr float
#define offsetof(t, d)
#define GS(x)
#define printf(...)
#define output
#define abs
uint tex_coord
RenderEngineType * RE_engines_find(const char *idname)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
void pose_apply_action_all_bones(Object *ob, bAction *action, slot_handle_t slot_handle, const AnimationEvalContext *anim_eval_context)
Slot & get_best_pose_slot_for_id(const ID &id, Action &pose_data)
Definition pose.cc:160
bNode * node_find_node_by_name(bNodeTree &ntree, StringRefNull name)
Definition node.cc:3275
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, StringRefNull name, StringRefNull idname)
Definition node.cc:4098
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
bNode * node_add_node(const bContext *C, bNodeTree &ntree, StringRef idname, std::optional< int > unique_identifier=std::nullopt)
Definition node.cc:3477
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:3810
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4724
float wrap(float value, float max, float min)
Definition node_math.h:103
const char * name
static bool preview_method_is_render(const ePreviewRenderMethod pr_method)
static bool scene_preview_is_supported(const Scene *scene)
static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Render *re)
static ID * duplicate_ids(ID *id, const bool allow_failure)
static void icon_preview_endjob(void *customdata)
static bool render_engine_supports_ray_visibility(const Scene *sce)
void ED_preview_free_dbase()
static void icon_preview_startjob_all_sizes(void *customdata, wmJobWorkerStatus *worker_status)
static ListBase G_restart_previews_queue
static void shader_preview_free(void *customdata)
World * ED_preview_prepare_world(Main *pr_main, const Scene *scene, const World *world, const ID_Type id_type, const ePreviewRenderMethod pr_method)
static void preview_sync_exposure(World *dst, const World *src)
static Main * load_main_from_memory(const void *blend, int blend_size)
static void icon_copy_rect(const ImBuf *ibuf, uint w, uint h, uint *rect)
static void shader_preview_update(void *spv, RenderResult *, rcti *)
static void action_preview_render_cleanup(IconPreview *preview, PoseBackup *pose_backup)
const char * ED_preview_collection_name(const ePreviewType pr_type)
static World * preview_get_localized_world(ShaderPreview *sp, World *world)
void ED_preview_world_simple_set_rgb(World *world, const float color[4])
static void icon_preview_free(void *customdata)
void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, uiPreview *ui_preview, rcti *rect)
void ED_preview_kill_jobs(wmWindowManager *wm, Main *)
void ED_preview_icon_render(const bContext *C, Scene *scene, PreviewImage *prv_img, ID *id, eIconSizes icon_size)
static bool ed_preview_draw_rect(Scene *scene, const void *owner, int split, int first, const rcti *rect, rcti *newrect)
static Scene * preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
static World * preview_get_world(Main *pr_main, const Scene *sce, const ID_Type id_type, const ePreviewRenderMethod pr_method)
static void other_id_types_preview_render(IconPreview *ip, IconPreviewSize *cur_size, const ePreviewRenderMethod pr_method, wmJobWorkerStatus *worker_status)
void ED_preview_restart_queue_work(const bContext *C)
void ED_preview_shader_job(const bContext *C, const void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey, ePreviewRenderMethod method)
void ED_preview_restart_queue_add(ID *id, enum eIconSizes size)
static Scene * preview_get_scene(Main *pr_main)
World * ED_preview_prepare_world_simple(Main *pr_main)
static Scene * object_preview_scene_create(const ObjectPreviewData *preview_data, Depsgraph **r_depsgraph)
void ED_preview_kill_jobs_for_id(wmWindowManager *wm, const ID *id)
static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
static int icon_previewimg_size_index_get(const IconPreviewSize *icon_size, const PreviewImage *preview_image)
static void switch_preview_floor_visibility(Main *pr_main, const Scene *scene, ViewLayer *view_layer, const ePreviewRenderMethod pr_method)
static void action_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
void ED_preview_ensure_dbase(const bool with_gpencil)
void ED_preview_set_visibility(Main *pr_main, Scene *scene, ViewLayer *view_layer, const ePreviewType pr_type, const ePreviewRenderMethod pr_method)
static Main * G_pr_main_grease_pencil
static void set_alpha(char *cp, int sizex, int sizey, char alpha)
bool ED_check_engine_supports_preview(const Scene *scene)
static void shader_preview_startjob(void *customdata, bool *stop, bool *do_update)
static const char * preview_world_name(const Scene *sce, const ID_Type id_type, const ePreviewRenderMethod pr_method)
static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int first)
static void preview_id_copy_free(ID *id)
static void switch_preview_collection_visibility(ViewLayer *view_layer, const ePreviewType pr_type)
bool ED_preview_use_image_size(const PreviewImage *preview, eIconSizes size)
static Object * object_preview_camera_create(Main *preview_main, Scene *scene, ViewLayer *view_layer, Object *preview_object)
bool ED_preview_id_is_supported(const ID *id, const char **r_disabled_hint)
static void scene_preview_render(IconPreview *preview, IconPreviewSize *preview_sized, ReportList *reports)
void ED_previews_tag_dirty_by_id(const Main &bmain, const ID &id)
static bool object_preview_is_type_supported(const Object *ob)
static const char * preview_floor_material_name(const Scene *scene, const ePreviewRenderMethod pr_method)
static void common_preview_startjob(void *customdata, wmJobWorkerStatus *worker_status)
void ED_preview_icon_job(const bContext *C, PreviewImage *prv_img, ID *id, eIconSizes icon_size, const bool delay)
static void switch_preview_floor_material(Main *pr_main, Mesh *mesh, const Scene *scene, const ePreviewRenderMethod pr_method)
static void icon_preview_startjob(void *customdata, bool *stop, bool *do_update)
void ED_preview_restart_queue_free()
static bool shader_preview_break(void *spv)
static void shader_preview_updatejob(void *)
static PoseBackup * action_preview_render_prepare(IconPreview *preview)
ImBuf * RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view)
RenderView * RE_RenderViewGetById(RenderResult *rr, const int view_id)
const char * RE_engine_id_BLENDER_EEVEE
Definition scene.cc:1580
void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
void RE_test_break_cb(Render *re, void *handle, bool(*f)(void *handle))
void RE_InitState(Render *re, Render *source, RenderData *rd, ListBase *, ViewLayer *single_layer, int winx, int winy, const rcti *disprect)
void RE_ResultGet32(Render *re, uint *rect)
Render * RE_NewRender(const void *owner)
RenderResult * RE_AcquireResultWrite(Render *re)
void RE_ReleaseResult(Render *re)
void RE_display_update_cb(Render *re, void *handle, void(*f)(void *handle, RenderResult *rr, rcti *rect))
void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
void RE_SetScene(Render *re, Scene *sce)
Render * RE_GetRender(const void *owner)
short flag
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
IconPreviewSize * prev
IconPreviewSize * next
Depsgraph * depsgraph
Object * active_object
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
struct Scene * scene
struct LayerCollection * next
ListBase layer_collections
struct Collection * collection
void * first
ListBase scenes
Definition BKE_main.hh:278
ListBase textures
Definition BKE_main.hh:285
char filepath[1024]
Definition BKE_main.hh:179
ListBase lights
Definition BKE_main.hh:288
ListBase materials
Definition BKE_main.hh:284
ListBase worlds
Definition BKE_main.hh:291
ListBase screens
Definition BKE_main.hh:292
ListBase objects
Definition BKE_main.hh:280
struct PreviewImage * preview
struct MaterialGPencilStyle * gp_style
struct Material ** mat
short totcol
short transflag
struct Collection * instance_collection
float loc[3]
float quat[4]
float color[4]
PreviewImageRuntimeHandle * runtime
Definition DNA_ID.h:648
unsigned int h[2]
Definition DNA_ID.h:643
short flag[2]
Definition DNA_ID.h:644
unsigned int * rect[2]
Definition DNA_ID.h:646
unsigned int w[2]
Definition DNA_ID.h:642
PreviewRestartQueueEntry * prev
PreviewRestartQueueEntry * next
char engine[32]
ListBase views
struct ImBuf * ibuf
Definition RE_pipeline.h:49
struct Collection * master_collection
struct SceneDisplay display
ColorManagedViewSettings view_settings
struct RenderData r
ListBase view_layers
struct Object * camera
struct World * world
ColorManagedDisplaySettings display_settings
ePreviewRenderMethod pr_method
Material * matcopy
const void * owner
float trgba[4]
Definition RE_texture.h:60
char use_nodes
struct bNodeTree * nodetree
struct ViewLayerEEVEE eevee
ListBase layer_collections
struct bNodeTree * nodetree
float range
float exp
void * default_value
int ymin
int ymax
int xmin
int xmax
ReportList * reports
Definition WM_types.hh:1028
i
Definition text_draw.cc:230
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
void WM_global_report(eReportType type, const char *message)
void WM_main_add_notifier(uint type, void *reference)
void WM_global_reportf(eReportType type, const char *format,...)
bool WM_jobs_is_running(const wmJob *wm_job)
Definition wm_jobs.cc:341
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:376
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:479
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:623
void * WM_jobs_customdata_get(wmJob *wm_job)
Definition wm_jobs.cc:352
void WM_jobs_delay_start(wmJob *wm_job, double delay_time)
Definition wm_jobs.cc:383
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:211
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:388
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:247
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:360
void * WM_jobs_customdata_from_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:330