Blender V4.5
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_utildefines.h"
31
32#include "BLT_translation.hh"
33
34#include "BLO_readfile.hh"
35
36#include "DNA_brush_types.h"
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_colortools.hh"
53#include "BKE_context.hh"
54#include "BKE_global.hh"
55#include "BKE_icons.h"
56#include "BKE_idprop.hh"
57#include "BKE_image.hh"
58#include "BKE_layer.hh"
59#include "BKE_lib_id.hh"
60#include "BKE_library.hh"
61#include "BKE_light.h"
62#include "BKE_main.hh"
63#include "BKE_material.hh"
64#include "BKE_node.hh"
65#include "BKE_object.hh"
66#include "BKE_pose_backup.h"
67#include "BKE_preview_image.hh"
68#include "BKE_scene.hh"
69#include "BKE_screen.hh"
70#include "BKE_texture.h"
71#include "BKE_world.h"
72
73#include "BLI_math_vector.h"
74
75#include "DEG_depsgraph.hh"
78
79#include "IMB_imbuf.hh"
80#include "IMB_imbuf_types.hh"
81#include "IMB_thumbs.hh"
82
83#include "BIF_glutil.hh"
84
85#include "RE_engine.h"
86#include "RE_pipeline.h"
87#include "RE_texture.h"
88
89#include "WM_api.hh"
90#include "WM_types.hh"
91
92#include "ED_datafiles.h"
93#include "ED_render.hh"
94#include "ED_screen.hh"
95#include "ED_view3d.hh"
97
98#include "UI_interface_icons.hh"
99
100#include "ANIM_action.hh"
101#include "ANIM_pose.hh"
102
103#ifndef NDEBUG
104/* Used for database init assert(). */
105# include "BLI_threads.h"
106#endif
107
108static void icon_copy_rect(const ImBuf *ibuf, uint w, uint h, uint *rect);
109
110/* -------------------------------------------------------------------- */
113
115 /* from wmJob */
116 void *owner;
118
123
124 /* Data-blocks with nodes need full copy during preview render, GLSL uses it too. */
129
131 float color[4];
132
137
140};
141
147
150 Depsgraph *depsgraph; /* May be nullptr (see #WM_OT_previews_ensure). */
152 void *owner;
157
158 /* May be nullptr, is used for rendering IDs that require some other object for it to be applied
159 * on before the ID can be represented as an image, for example when rendering an Action. */
161};
162
164
165/* -------------------------------------------------------------------- */
168
170
171#ifndef WITH_HEADLESS
172static Main *load_main_from_memory(const void *blend, int blend_size)
173{
174 const int fileflags = G.fileflags;
175 Main *bmain = nullptr;
176 BlendFileData *bfd;
177
178 G.fileflags |= G_FILE_NO_UI;
179 bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr);
180 if (bfd) {
181 bmain = bfd->main;
182 MEM_delete(bfd);
183 }
184 G.fileflags = fileflags;
185
186 return bmain;
187}
188#endif
189
190void ED_preview_ensure_dbase(const bool with_gpencil)
191{
192#ifndef WITH_HEADLESS
193 static bool base_initialized = false;
194 static bool base_initialized_gpencil = false;
196 if (!base_initialized) {
198 base_initialized = true;
199 }
200 if (!base_initialized_gpencil && with_gpencil) {
203 base_initialized_gpencil = true;
204 }
205#else
206 UNUSED_VARS(with_gpencil);
207#endif
208}
209
211{
213 return (type->flag & RE_USE_PREVIEW) != 0;
214}
215
217{
218 return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
219}
220
222{
223 if (G.pr_main) {
224 BKE_main_free(G.pr_main);
225 }
226
229 }
230}
231
232static Scene *preview_get_scene(Main *pr_main)
233{
234 if (pr_main == nullptr) {
235 return nullptr;
236 }
237
238 return static_cast<Scene *>(pr_main->scenes.first);
239}
240
241const char *ED_preview_collection_name(const ePreviewType pr_type)
242{
243 switch (pr_type) {
244 case MA_FLAT:
245 return "Flat";
246 case MA_SPHERE:
247 return "Sphere";
248 case MA_CUBE:
249 return "Cube";
250 case MA_SHADERBALL:
251 return "Shader Ball";
252 case MA_CLOTH:
253 return "Cloth";
254 case MA_FLUID:
255 return "Fluid";
256 case MA_SPHERE_A:
257 return "World Sphere";
258 case MA_LAMP:
259 return "Lamp";
260 case MA_SKY:
261 return "Sky";
262 case MA_HAIR:
263 return "Hair";
264 case MA_ATMOS:
265 return "Atmosphere";
266 default:
267 BLI_assert_msg(0, "Unknown preview type");
268 return "";
269 }
270}
271
273{
275}
276
277static void switch_preview_collection_visibility(ViewLayer *view_layer, const ePreviewType pr_type)
278{
279 /* Set appropriate layer as visible. */
280 LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first);
281 const char *collection_name = ED_preview_collection_name(pr_type);
282
283 for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) {
284 if (STREQ(lc->collection->id.name + 2, collection_name)) {
286 }
287 else {
289 }
290 }
291}
292
293static const char *preview_floor_material_name(const Scene *scene,
294 const ePreviewRenderMethod pr_method)
295{
296 if (pr_method == PR_ICON_RENDER && render_engine_supports_ray_visibility(scene)) {
297 return "FloorHidden";
298 }
299 return "Floor";
300}
301
303 Mesh *mesh,
304 const Scene *scene,
305 const ePreviewRenderMethod pr_method)
306{
307 if (mesh->totcol == 0) {
308 return;
309 }
310
311 const char *material_name = preview_floor_material_name(scene, pr_method);
312 Material *mat = static_cast<Material *>(
313 BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2));
314 if (mat) {
315 mesh->mat[0] = mat;
316 }
317}
318
320 const Scene *scene,
321 ViewLayer *view_layer,
322 const ePreviewRenderMethod pr_method)
323{
324 /* Hide floor for icon renders. */
325 BKE_view_layer_synced_ensure(scene, view_layer);
327 if (STREQ(base->object->id.name + 2, "Floor")) {
328 base->object->visibility_flag &= ~OB_HIDE_RENDER;
329 if (pr_method == PR_ICON_RENDER) {
331 base->object->visibility_flag |= OB_HIDE_RENDER;
332 }
333 }
334 if (base->object->type == OB_MESH) {
336 pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method);
337 }
338 }
339 }
340}
341
343 Scene *scene,
344 ViewLayer *view_layer,
345 const ePreviewType pr_type,
346 const ePreviewRenderMethod pr_method)
347{
348 switch_preview_collection_visibility(view_layer, pr_type);
349 switch_preview_floor_visibility(pr_main, scene, view_layer, pr_method);
350 BKE_layer_collection_sync(scene, view_layer);
351}
352
354{
355 if (world == nullptr) {
356 return nullptr;
357 }
358 if (sp->worldcopy != nullptr) {
359 return sp->worldcopy;
360 }
361
362 ID *id_copy = BKE_id_copy_ex(nullptr,
363 &world->id,
364 nullptr,
367 sp->worldcopy = (World *)id_copy;
369 return sp->worldcopy;
370}
371
372static ID *duplicate_ids(ID *id, const bool allow_failure)
373{
374 if (id == nullptr) {
375 /* Non-ID preview render. */
376 return nullptr;
377 }
378
379 switch (GS(id->name)) {
380 case ID_OB:
381 case ID_MA:
382 case ID_TE:
383 case ID_LA:
384 case ID_WO: {
386 ID *id_copy = BKE_id_copy_ex(nullptr,
387 id,
388 nullptr,
391 return id_copy;
392 }
393 case ID_GR: {
394 /* Doesn't really duplicate the collection. Just creates a collection instance empty. */
396 Object *instance_empty = BKE_object_add_only_object(nullptr, OB_EMPTY, nullptr);
397 instance_empty->instance_collection = (Collection *)id;
398 instance_empty->transflag |= OB_DUPLICOLLECTION;
399 return &instance_empty->id;
400 }
401 /* These support threading, but don't need duplicating. */
402 case ID_IM:
403 case ID_BR:
405 return nullptr;
406 default:
407 if (!allow_failure) {
408 BLI_assert_msg(0, "ID type preview not supported.");
409 }
410 return nullptr;
411 }
412}
413
414static const char *preview_world_name(const Scene *sce,
415 const ID_Type id_type,
416 const ePreviewRenderMethod pr_method)
417{
418 /* When rendering material icons the floor will not be shown in the output. Cycles will use a
419 * material trick to show the floor in the reflections, but hide the floor for camera rays. For
420 * Eevee we use a transparent world that has a projected grid.
421 *
422 * In the future when Eevee supports VULKAN ray-tracing we can re-evaluate and perhaps remove
423 * this approximation.
424 */
425 if (id_type == ID_MA && pr_method == PR_ICON_RENDER &&
427 {
428 return "WorldFloor";
429 }
430 return "World";
431}
432
433static World *preview_get_world(Main *pr_main,
434 const Scene *sce,
435 const ID_Type id_type,
436 const ePreviewRenderMethod pr_method)
437{
438 World *result = nullptr;
439 const char *world_name = preview_world_name(sce, id_type, pr_method);
440 result = static_cast<World *>(
441 BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2));
442
443 /* No world found return first world. */
444 if (result == nullptr) {
445 result = static_cast<World *>(pr_main->worlds.first);
446 }
447
448 BLI_assert_msg(result, "Preview file has no world.");
449 return result;
450}
451
452static void preview_sync_exposure(World *dst, const World *src)
453{
454 BLI_assert(dst);
455 BLI_assert(src);
456 dst->exp = src->exp;
457 dst->range = src->range;
458}
459
461 const Scene *scene,
462 const World *world,
463 const ID_Type id_type,
464 const ePreviewRenderMethod pr_method)
465{
466 World *result = preview_get_world(pr_main, scene, id_type, pr_method);
467 if (world) {
469 }
470 return result;
471}
472
473/* call this with a pointer to initialize preview scene */
474/* call this with nullptr to restore assigned ID pointers in preview scene */
476 Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
477{
478 Scene *sce;
479 Main *pr_main = sp->pr_main;
480
481 memcpy(pr_main->filepath, BKE_main_blendfile_path(bmain), sizeof(pr_main->filepath));
482
483 sce = preview_get_scene(pr_main);
484 if (sce) {
485 ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first);
486
487 /* Only enable the combined render-pass. */
488 view_layer->passflag = SCE_PASS_COMBINED;
489 view_layer->eevee.render_passes = 0;
490
491 /* This flag tells render to not execute depsgraph or F-Curves etc. */
492 sce->r.scemode |= R_BUTS_PREVIEW;
493 STRNCPY(sce->r.engine, scene->r.engine);
494
495 sce->r.color_mgt_flag = scene->r.color_mgt_flag;
497
500
501 if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO) {
503 }
504 else {
505 sce->r.alphamode = R_ADDSKY;
506 }
507
508 sce->r.cfra = scene->r.cfra;
509
510 /* Setup the world. */
512 pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method);
513
514 if (id_type == ID_TE) {
515 /* Texture is not actually rendered with engine, just set dummy value. */
517 }
518
519 if (id_type == ID_MA) {
520 Material *mat = nullptr, *origmat = (Material *)id;
521
522 if (origmat) {
523 /* work on a copy */
524 BLI_assert(sp->id_copy != nullptr);
525 mat = sp->matcopy = (Material *)sp->id_copy;
526 sp->id_copy = nullptr;
527 BLI_addtail(&pr_main->materials, mat);
528
529 /* Use current scene world for lighting. */
530 if (mat->pr_flag == MA_PREVIEW_WORLD && sp->pr_method == PR_BUTS_RENDER) {
531 /* Use current scene world to light sphere. */
532 sce->world = preview_get_localized_world(sp, scene->world);
533 }
534 else if (sce->world && sp->pr_method != PR_ICON_RENDER) {
535 /* Use a default world color. Using the current
536 * scene world can be slow if it has big textures. */
537 sce->world->use_nodes = false;
538 /* Use brighter world color for grease pencil. */
539 if (sp->pr_main == G_pr_main_grease_pencil) {
540 sce->world->horr = 1.0f;
541 sce->world->horg = 1.0f;
542 sce->world->horb = 1.0f;
543 }
544 else {
545 sce->world->horr = 0.05f;
546 sce->world->horg = 0.05f;
547 sce->world->horb = 0.05f;
548 }
549 }
550
551 const ePreviewType preview_type = static_cast<ePreviewType>(mat->pr_type);
552 ED_preview_set_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
553 }
554 else {
556 }
557 BKE_view_layer_synced_ensure(sce, view_layer);
559 if (base->object->id.name[2] == 'p') {
560 /* copy over object color, in case material uses it */
561 copy_v4_v4(base->object->color, sp->color);
562
563 if (OB_TYPE_SUPPORT_MATERIAL(base->object->type)) {
564 /* don't use BKE_object_material_assign, it changed mat->id.us, which shows in the UI
565 */
566 Material ***matar = BKE_object_material_array_p(base->object);
567 int actcol = max_ii(base->object->actcol - 1, 0);
568
569 if (matar && actcol < base->object->totcol) {
570 (*matar)[actcol] = mat;
571 }
572 }
573 else if (base->object->type == OB_LAMP) {
575 }
576 }
577 }
578 }
579 else if (id_type == ID_TE) {
580 Tex *tex = nullptr, *origtex = (Tex *)id;
581
582 if (origtex) {
583 BLI_assert(sp->id_copy != nullptr);
584 tex = sp->texcopy = (Tex *)sp->id_copy;
585 sp->id_copy = nullptr;
586 BLI_addtail(&pr_main->textures, tex);
587 }
588 }
589 else if (id_type == ID_LA) {
590 Light *la = nullptr, *origla = (Light *)id;
591
592 /* work on a copy */
593 if (origla) {
594 BLI_assert(sp->id_copy != nullptr);
595 la = sp->lampcopy = (Light *)sp->id_copy;
596 sp->id_copy = nullptr;
597 BLI_addtail(&pr_main->lights, la);
598 }
599
600 ED_preview_set_visibility(pr_main, sce, view_layer, MA_LAMP, sp->pr_method);
601
602 if (sce->world) {
603 /* Only use lighting from the light. */
604 sce->world->use_nodes = false;
605 sce->world->horr = 0.0f;
606 sce->world->horg = 0.0f;
607 sce->world->horb = 0.0f;
608 }
609
610 BKE_view_layer_synced_ensure(sce, view_layer);
612 if (base->object->id.name[2] == 'p') {
613 if (base->object->type == OB_LAMP) {
614 base->object->data = la;
615 }
616 }
617 }
618 }
619 else if (id_type == ID_WO) {
620 World *wrld = nullptr, *origwrld = (World *)id;
621
622 if (origwrld) {
623 BLI_assert(sp->id_copy != nullptr);
624 wrld = sp->worldcopy = (World *)sp->id_copy;
625 sp->id_copy = nullptr;
626 BLI_addtail(&pr_main->worlds, wrld);
627 }
628
629 ED_preview_set_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method);
630 sce->world = wrld;
631 }
632
633 return sce;
634 }
635
636 return nullptr;
637}
638
639/* new UI convention: draw is in pixel space already. */
640/* uses UI_BTYPE_ROUNDBOX button in block to get the rect */
642 Scene *scene, ScrArea *area, int split, int first, const rcti *rect, rcti *newrect)
643{
644 Render *re;
645 RenderView *rv;
646 RenderResult rres;
647 char name[32];
648 int offx = 0;
649 int newx = BLI_rcti_size_x(rect);
650 int newy = BLI_rcti_size_y(rect);
651 bool ok = false;
652
653 if (!split || first) {
654 SNPRINTF(name, "Preview %p", (void *)area);
655 }
656 else {
657 SNPRINTF(name, "SecondPreview %p", (void *)area);
658 }
659
660 if (split) {
661 if (first) {
662 offx = 0;
663 newx = newx / 2;
664 }
665 else {
666 offx = newx / 2;
667 newx = newx - newx / 2;
668 }
669 }
670
671 /* test if something rendered ok */
672 re = RE_GetRender(name);
673
674 if (re == nullptr) {
675 return false;
676 }
677
679
680 if (!BLI_listbase_is_empty(&rres.views)) {
681 /* material preview only needs monoscopy (view 0) */
682 rv = RE_RenderViewGetById(&rres, 0);
683 }
684 else {
685 /* possible the job clears the views but we're still drawing #45496 */
686 rv = nullptr;
687 }
688
689 if (rv && rv->ibuf) {
690 if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) {
691 newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx);
692 newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
693
694 if (rres.rectx && rres.recty) {
695 float fx = rect->xmin + offx;
696 float fy = rect->ymin;
697
699 rv->ibuf, fx, fy, false, &scene->view_settings, &scene->display_settings, 1.0f, 1.0f);
700
701 ok = true;
702 }
703 }
704 }
705
707
708 return ok;
709}
710
712 const bContext *C, void *idp, void *parentp, void *slotp, uiPreview *ui_preview, rcti *rect)
713{
714 if (idp) {
715 Scene *scene = CTX_data_scene(C);
717 ScrArea *area = CTX_wm_area(C);
718 ID *id = (ID *)idp;
719 ID *parent = (ID *)parentp;
720 MTex *slot = (MTex *)slotp;
722 ShaderPreview *sp = static_cast<ShaderPreview *>(
724 rcti newrect;
725 bool ok;
726 int newx = BLI_rcti_size_x(rect);
727 int newy = BLI_rcti_size_y(rect);
728
729 newrect.xmin = rect->xmin;
730 newrect.xmax = rect->xmin;
731 newrect.ymin = rect->ymin;
732 newrect.ymax = rect->ymin;
733
734 if (parent) {
735 ok = ed_preview_draw_rect(scene, area, 1, 1, rect, &newrect);
736 ok &= ed_preview_draw_rect(scene, area, 1, 0, rect, &newrect);
737 }
738 else {
739 ok = ed_preview_draw_rect(scene, area, 0, 0, rect, &newrect);
740 }
741
742 if (ok) {
743 *rect = newrect;
744 }
745
746 /* start a new preview render job if signaled through sbuts->preview,
747 * if no render result was found and no preview render job is running,
748 * or if the job is running and the size of preview changed */
749 if ((sbuts != nullptr && sbuts->preview) || (ui_preview->tag & UI_PREVIEW_TAG_DIRTY) ||
750 (!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
751 (sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2)))
752 {
753 if (sbuts != nullptr) {
754 sbuts->preview = 0;
755 }
756 ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
757 ui_preview->tag &= ~UI_PREVIEW_TAG_DIRTY;
758 }
759 }
760}
761
762void ED_previews_tag_dirty_by_id(const Main &bmain, const ID &id)
763{
764 LISTBASE_FOREACH (const bScreen *, screen, &bmain.screens) {
765 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
766 LISTBASE_FOREACH (const ARegion *, region, &area->regionbase) {
767 LISTBASE_FOREACH (uiPreview *, preview, &region->ui_previews) {
768 if (preview->id_session_uid == id.session_uid) {
769 preview->tag |= UI_PREVIEW_TAG_DIRTY;
770 }
771 }
772 }
773 }
774 }
775}
776
778
779/* -------------------------------------------------------------------- */
782
784 /* The main for the preview, not of the current file. */
786 /* Copy of the object to create the preview for. The copy is for thread safety (and to insert
787 * it into its own main). */
789 /* Current frame. */
790 int cfra;
791 int sizex;
792 int sizey;
793};
794
796{
797 return OB_TYPE_IS_GEOMETRY(ob->type);
798}
799
801 Scene *scene,
802 ViewLayer *view_layer,
803 Object *preview_object)
804{
805 Object *camera = BKE_object_add(preview_main, scene, view_layer, OB_CAMERA, "Preview Camera");
806
807 float rotmat[3][3];
808 float dummy_scale[3];
809 mat4_to_loc_rot_size(camera->loc, rotmat, dummy_scale, preview_object->object_to_world().ptr());
810
811 /* Camera is Y up, so needs additional rotations to obliquely face the front. */
812 float drotmat[3][3];
813 const float eul[3] = {M_PI * 0.4f, 0.0f, M_PI * 0.1f};
814 eul_to_mat3(drotmat, eul);
815 mul_m3_m3_post(rotmat, drotmat);
816
817 camera->rotmode = ROT_MODE_QUAT;
818 mat3_to_quat(camera->quat, rotmat);
819
820 /* Nice focal length for close portraiture. */
821 ((Camera *)camera->data)->lens = 85;
822
823 return camera;
824}
825
827 Depsgraph **r_depsgraph)
828{
829 Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene");
830 /* Preview need to be in the current frame to get a thumbnail similar of what
831 * viewport displays. */
832 scene->r.cfra = preview_data->cfra;
833
834 ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
835 Depsgraph *depsgraph = DEG_graph_new(
836 preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
837
838 BLI_assert(preview_data->object != nullptr);
839 BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
840
841 BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
842
843 Object *camera_object = object_preview_camera_create(
844 preview_data->pr_main, scene, view_layer, preview_data->object);
845
846 scene->camera = camera_object;
847 scene->r.xsch = preview_data->sizex;
848 scene->r.ysch = preview_data->sizey;
849 scene->r.size = 100;
850
851 BKE_view_layer_synced_ensure(scene, view_layer);
852 Base *preview_base = BKE_view_layer_base_find(view_layer, preview_data->object);
853 /* For 'view selected' below. */
854 preview_base->flag |= BASE_SELECTED;
855
858
860 preview_data->pr_main, depsgraph, scene, camera_object);
861
863
864 *r_depsgraph = depsgraph;
865 return scene;
866}
867
868static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
869{
870 Main *preview_main = BKE_main_new();
871 char err_out[256] = "unknown";
872
873 BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
874
875 ObjectPreviewData preview_data = {};
876 preview_data.pr_main = preview_main;
877 /* Act on a copy. */
878 preview_data.object = (Object *)preview->id_copy;
879 preview_data.cfra = preview->scene->r.cfra;
880 preview_data.sizex = preview_sized->sizex;
881 preview_data.sizey = preview_sized->sizey;
882
883 Depsgraph *depsgraph;
884 Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
885
886 /* Ownership is now ours. */
887 preview->id_copy = nullptr;
888
889 View3DShading shading;
891 /* Enable shadows, makes it a bit easier to see the shape. */
892 shading.flag |= V3D_SHADING_SHADOW;
893
896 &shading,
899 preview_sized->sizex,
900 preview_sized->sizey,
904 nullptr,
905 nullptr,
906 nullptr,
907 err_out);
908 /* TODO: color-management? */
909
910 if (ibuf) {
911 icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
912 IMB_freeImBuf(ibuf);
913 }
914
916 BKE_main_free(preview_main);
917}
918
920
921/* -------------------------------------------------------------------- */
928
935{
936 LISTBASE_FOREACH (CollectionObject *, col_ob, &collection->gobject) {
937 if (col_ob->ob->visibility_flag & OB_HIDE_RENDER) {
938 continue;
939 }
940 if (OB_TYPE_IS_GEOMETRY(col_ob->ob->type)) {
941 return true;
942 }
943 }
944
945 LISTBASE_FOREACH (CollectionChild *, child_col, &collection->children) {
946 if (child_col->collection->flag & COLLECTION_HIDE_RENDER) {
947 continue;
948 }
949 if (collection_preview_contains_geometry_recursive(child_col->collection)) {
950 return true;
951 }
952 }
953
954 return false;
955}
956
958
959/* -------------------------------------------------------------------- */
962
964{
965 Object *object = preview->active_object;
966 if (object == nullptr) {
967 WM_global_report(RPT_WARNING, "No active object, unable to apply the Action before rendering");
968 return nullptr;
969 }
970 if (object->pose == nullptr) {
972 "Object %s has no pose, unable to apply the Action before rendering",
973 object->id.name + 2);
974 return nullptr;
975 }
976
977 /* Create a backup of the current pose. */
978 blender::animrig::Action &pose_action = reinterpret_cast<bAction *>(preview->id)->wrap();
979
980 if (pose_action.slot_array_num == 0) {
981 WM_global_report(RPT_WARNING, "Action has no data, cannot render preview");
982 return nullptr;
983 }
984
986 pose_action);
987 PoseBackup *pose_backup = BKE_pose_backup_create_all_bones({object}, &pose_action);
988
989 /* Apply the Action as pose, so that it can be rendered. This assumes the Action represents a
990 * single pose, and that thus the evaluation time doesn't matter. */
991 AnimationEvalContext anim_eval_context = {preview->depsgraph, 0.0f};
993 object, &pose_action, slot.handle, &anim_eval_context);
994
995 /* Force evaluation of the new pose, before the preview is rendered. */
998
999 return pose_backup;
1000}
1001
1002static void action_preview_render_cleanup(IconPreview *preview, PoseBackup *pose_backup)
1003{
1004 if (pose_backup == nullptr) {
1005 return;
1006 }
1007 BKE_pose_backup_restore(pose_backup);
1008 BKE_pose_backup_free(pose_backup);
1009
1011}
1012
1013/* Render a pose from the scene camera. It is assumed that the scene camera is
1014 * capturing the pose. The pose is applied temporarily to the current object
1015 * before rendering. */
1016static void action_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
1017{
1018 char err_out[256] = "";
1019
1020 Depsgraph *depsgraph = preview->depsgraph;
1021 /* Not all code paths that lead to this function actually provide a depsgraph.
1022 * The "Refresh Asset Preview" button (#ED_OT_lib_id_generate_preview) does,
1023 * but #WM_OT_previews_ensure does not. */
1024 BLI_assert(depsgraph != nullptr);
1026
1027 /* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */
1028 PoseBackup *pose_backup = action_preview_render_prepare(preview);
1029
1031 Object *camera_eval = scene_eval->camera;
1032 if (camera_eval == nullptr) {
1033 printf("Scene has no camera, unable to render preview of %s without it.\n",
1034 preview->id->name + 2);
1035 action_preview_render_cleanup(preview, pose_backup);
1036 return;
1037 }
1038
1039 /* This renders with the Workbench engine settings stored on the Scene. */
1041 scene_eval,
1042 nullptr,
1043 OB_SOLID,
1044 camera_eval,
1045 preview_sized->sizex,
1046 preview_sized->sizey,
1049 R_ADDSKY,
1050 nullptr,
1051 nullptr,
1052 nullptr,
1053 err_out);
1054
1055 action_preview_render_cleanup(preview, pose_backup);
1056
1057 if (err_out[0] != '\0') {
1058 printf("Error rendering Action %s preview: %s\n", preview->id->name + 2, err_out);
1059 }
1060
1061 if (ibuf) {
1062 icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
1063 IMB_freeImBuf(ibuf);
1064 }
1065}
1066
1068
1069/* -------------------------------------------------------------------- */
1072
1073/* inside thread, called by renderer, sets job update value */
1074static void shader_preview_update(void *spv, RenderResult * /*rr*/, rcti * /*rect*/)
1075{
1076 ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
1077
1078 *(sp->do_update) = true;
1079}
1080
1081/* called by renderer, checks job value */
1082static bool shader_preview_break(void *spv)
1083{
1084 ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
1085
1086 return *(sp->stop);
1087}
1088
1089static void shader_preview_updatejob(void * /*spv*/) {}
1090
1091/* Renders texture directly to render buffer. */
1092static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Render *re)
1093{
1094 /* Setup output buffer. */
1095 int width = sp->sizex;
1096 int height = sp->sizey;
1097
1098 /* This is needed otherwise no RenderResult is created. */
1099 sce->r.scemode &= ~R_BUTS_PREVIEW;
1100 RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr);
1101 RE_SetScene(re, sce);
1102
1103 /* Create buffer in empty RenderView created in the init step. */
1105 RenderView *rv = (RenderView *)rr->views.first;
1106 ImBuf *rv_ibuf = RE_RenderViewEnsureImBuf(rr, rv);
1108 MEM_calloc_arrayN<float>(4 * width * height, "texture render result"),
1110 RE_ReleaseResult(re);
1111
1112 /* Get texture image pool (if any) */
1113 ImagePool *img_pool = BKE_image_pool_new();
1114 BKE_texture_fetch_images_for_pool(tex, img_pool);
1115
1116 /* Fill in image buffer. */
1117 float *rect_float = rv_ibuf->float_buffer.data;
1118 float tex_coord[3] = {0.0f, 0.0f, 0.0f};
1119
1120 for (int y = 0; y < height; y++) {
1121 /* Tex coords between -1.0f and 1.0f. */
1122 tex_coord[1] = (float(y) / float(height)) * 2.0f - 1.0f;
1123
1124 for (int x = 0; x < width; x++) {
1125 tex_coord[0] = (float(x) / float(height)) * 2.0f - 1.0f;
1126
1127 /* Evaluate texture at tex_coord. */
1128 TexResult texres = {0};
1129 BKE_texture_get_value_ex(tex, tex_coord, &texres, img_pool, true);
1130 copy_v4_fl4(rect_float,
1131 texres.trgba[0],
1132 texres.trgba[1],
1133 texres.trgba[2],
1134 texres.talpha ? texres.trgba[3] : 1.0f);
1135
1136 rect_float += 4;
1137 }
1138
1139 /* Check if we should cancel texture preview. */
1140 if (shader_preview_break(sp)) {
1141 break;
1142 }
1143 }
1144
1145 BKE_image_pool_free(img_pool);
1146}
1147
1148static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int first)
1149{
1150 Render *re;
1151 Scene *sce;
1152 float oldlens;
1153 short idtype = GS(id->name);
1154 char name[32];
1155 int sizex;
1156 Main *pr_main = sp->pr_main;
1157
1158 /* in case of split preview, use border render */
1159 if (split) {
1160 if (first) {
1161 sizex = sp->sizex / 2;
1162 }
1163 else {
1164 sizex = sp->sizex - sp->sizex / 2;
1165 }
1166 }
1167 else {
1168 sizex = sp->sizex;
1169 }
1170
1171 /* we have to set preview variables first */
1172 sce = preview_get_scene(pr_main);
1173 if (sce) {
1174 sce->r.xsch = sizex;
1175 sce->r.ysch = sp->sizey;
1176 sce->r.size = 100;
1177 }
1178
1179 /* get the stuff from the builtin preview dbase */
1180 sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
1181 if (sce == nullptr) {
1182 return;
1183 }
1184
1185 if (!split || first) {
1186 SNPRINTF(name, "Preview %p", sp->owner);
1187 }
1188 else {
1189 SNPRINTF(name, "SecondPreview %p", sp->owner);
1190 }
1191 re = RE_GetRender(name);
1192
1193 /* full refreshed render from first tile */
1194 if (re == nullptr) {
1195 re = RE_NewRender(name);
1196 }
1197
1198 /* sce->r gets copied in RE_InitState! */
1200 sce->r.scemode &= ~R_NO_IMAGE_LOAD;
1201
1202 if (sp->pr_method == PR_ICON_RENDER) {
1203 sce->r.scemode |= R_NO_IMAGE_LOAD;
1205 }
1206 else { /* PR_BUTS_RENDER */
1208 }
1209
1210 /* Callbacks are cleared on GetRender(). */
1211 if (sp->pr_method == PR_BUTS_RENDER) {
1213 }
1214 /* set this for all previews, default is react to G.is_break still */
1216
1217 /* lens adjust */
1218 oldlens = ((Camera *)sce->camera->data)->lens;
1219 if (sizex > sp->sizey) {
1220 ((Camera *)sce->camera->data)->lens *= float(sp->sizey) / float(sizex);
1221 }
1222
1223 /* entire cycle for render engine */
1224 if (idtype == ID_TE) {
1225 shader_preview_texture(sp, (Tex *)id, sce, re);
1226 }
1227 else {
1228 /* Render preview scene */
1229 RE_PreviewRender(re, pr_main, sce);
1230 }
1231
1232 ((Camera *)sce->camera->data)->lens = oldlens;
1233
1234 /* handle results */
1235 if (sp->pr_method == PR_ICON_RENDER) {
1236 // char *rct = (char *)(sp->pr_rect + 32 * 16 + 16);
1237
1238 if (sp->pr_rect) {
1239 RE_ResultGet32(re, sp->pr_rect);
1240 }
1241 }
1242
1243 /* unassign the pointers, reset vars */
1244 preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp);
1245
1246 /* XXX bad exception, end-exec is not being called in render, because it uses local main. */
1247#if 0
1248 if (idtype == ID_TE) {
1249 Tex *tex = (Tex *)id;
1250 if (tex->use_nodes && tex->nodetree)
1251 ntreeEndExecTree(tex->nodetree);
1252 }
1253#endif
1254}
1255
1256/* runs inside thread for material and icons */
1257static void shader_preview_startjob(void *customdata, bool *stop, bool *do_update)
1258{
1259 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1260
1261 sp->stop = stop;
1262 sp->do_update = do_update;
1263
1264 if (sp->parent) {
1265 shader_preview_render(sp, sp->id, 1, 1);
1266 shader_preview_render(sp, sp->parent, 1, 0);
1267 }
1268 else {
1269 shader_preview_render(sp, sp->id, 0, 0);
1270 }
1271
1272 *do_update = true;
1273}
1274
1275static void preview_id_copy_free(ID *id)
1276{
1277 IDProperty *properties;
1278 /* get rid of copied ID */
1279 properties = IDP_GetProperties(id);
1280 if (properties) {
1281 IDP_FreePropertyContent_ex(properties, false);
1282 MEM_freeN(properties);
1283 }
1285 MEM_freeN(id);
1286}
1287
1288static void shader_preview_free(void *customdata)
1289{
1290 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1291 Main *pr_main = sp->pr_main;
1292 ID *main_id_copy = nullptr;
1293 ID *sub_id_copy = nullptr;
1294
1295 if (sp->matcopy) {
1296 main_id_copy = (ID *)sp->matcopy;
1297 BLI_remlink(&pr_main->materials, sp->matcopy);
1298 }
1299 if (sp->texcopy) {
1300 BLI_assert(main_id_copy == nullptr);
1301 main_id_copy = (ID *)sp->texcopy;
1302 BLI_remlink(&pr_main->textures, sp->texcopy);
1303 }
1304 if (sp->worldcopy) {
1305 /* worldcopy is also created for material with `Preview World` enabled */
1306 if (main_id_copy) {
1307 sub_id_copy = (ID *)sp->worldcopy;
1308 }
1309 else {
1310 main_id_copy = (ID *)sp->worldcopy;
1311 }
1312 BLI_remlink(&pr_main->worlds, sp->worldcopy);
1313 }
1314 if (sp->lampcopy) {
1315 BLI_assert(main_id_copy == nullptr);
1316 main_id_copy = (ID *)sp->lampcopy;
1317 BLI_remlink(&pr_main->lights, sp->lampcopy);
1318 }
1319 if (sp->own_id_copy) {
1320 if (sp->id_copy) {
1322 }
1323 if (main_id_copy) {
1324 preview_id_copy_free(main_id_copy);
1325 }
1326 if (sub_id_copy) {
1327 preview_id_copy_free(sub_id_copy);
1328 }
1329 }
1330
1331 MEM_freeN(sp);
1332}
1333
1335
1336/* -------------------------------------------------------------------- */
1339
1341{
1342 if (!brush->icon_imbuf && (brush->flag & BRUSH_CUSTOM_ICON) && brush->icon_filepath[0]) {
1343 const int flags = IB_byte_data | IB_multilayer | IB_metadata;
1344
1345 /* First use the path directly to try and load the file. */
1346 char filepath[FILE_MAX];
1347
1348 STRNCPY(filepath, brush->icon_filepath);
1349 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
1350
1351 /* Use default color-spaces for brushes. */
1352 brush->icon_imbuf = IMB_load_image_from_filepath(filepath, flags);
1353
1354 if (brush->icon_imbuf) {
1356 }
1357 }
1358
1359 if (!(brush->icon_imbuf)) {
1360 brush->id.icon_id = 0;
1361 }
1362
1363 return brush->icon_imbuf;
1364}
1365
1366static void icon_copy_rect(const ImBuf *ibuf, uint w, uint h, uint *rect)
1367{
1368 if (ibuf == nullptr ||
1369 (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr) || rect == nullptr)
1370 {
1371 return;
1372 }
1373
1374 float scaledx, scaledy;
1375 if (ibuf->x > ibuf->y) {
1376 scaledx = float(w);
1377 scaledy = (float(ibuf->y) / float(ibuf->x)) * float(w);
1378 }
1379 else {
1380 scaledx = (float(ibuf->x) / float(ibuf->y)) * float(h);
1381 scaledy = float(h);
1382 }
1383
1384 /* Scaling down must never assign zero width/height, see: #89868. */
1385 int ex = std::max<int>(1, scaledx);
1386 int ey = std::max<int>(1, scaledy);
1387
1388 int dx = (w - ex) / 2;
1389 int dy = (h - ey) / 2;
1390
1391 ImBuf *ima = IMB_scale_into_new(ibuf, ex, ey, IMBScaleFilter::Nearest, false);
1392 if (ima == nullptr) {
1393 return;
1394 }
1395
1396 /* if needed, convert to 32 bits */
1397 if (ima->byte_buffer.data == nullptr) {
1399 }
1400
1401 const uint *srect = reinterpret_cast<const uint *>(ima->byte_buffer.data);
1402 uint *drect = rect;
1403
1404 drect += dy * w + dx;
1405 for (; ey > 0; ey--) {
1406 memcpy(drect, srect, ex * sizeof(int));
1407 drect += w;
1408 srect += ima->x;
1409 }
1410
1411 IMB_freeImBuf(ima);
1412}
1413
1414static void set_alpha(char *cp, int sizex, int sizey, char alpha)
1415{
1416 int a, size = sizex * sizey;
1417
1418 for (a = 0; a < size; a++, cp += 4) {
1419 cp[3] = alpha;
1420 }
1421}
1422
1423static void icon_preview_startjob(void *customdata, bool *stop, bool *do_update)
1424{
1425 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1426
1427 if (sp->pr_method == PR_ICON_DEFERRED) {
1429 return;
1430 }
1431
1432 ID *id = sp->id;
1433 short idtype = GS(id->name);
1434
1435 BLI_assert(id != nullptr);
1436
1437 if (idtype == ID_IM) {
1438 Image *ima = (Image *)id;
1439 ImBuf *ibuf = nullptr;
1440 ImageUser iuser;
1441 BKE_imageuser_default(&iuser);
1442
1443 if (ima == nullptr) {
1444 return;
1445 }
1446
1447 /* setup dummy image user */
1448 iuser.framenr = 1;
1449 iuser.scene = sp->scene;
1450
1451 /* NOTE(@elubie): this needs to be changed: here image is always loaded if not
1452 * already there. Very expensive for large images. Need to find a way to
1453 * only get existing `ibuf`. */
1454 ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
1455 if (ibuf == nullptr ||
1456 (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr))
1457 {
1458 BKE_image_release_ibuf(ima, ibuf, nullptr);
1459 return;
1460 }
1461
1462 icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
1463
1464 *do_update = true;
1465
1466 BKE_image_release_ibuf(ima, ibuf, nullptr);
1467 }
1468 else if (idtype == ID_BR) {
1469 Brush *br = reinterpret_cast<Brush *>(id);
1470
1472
1473 memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(uint));
1474
1475 if (!(br->icon_imbuf) || !(br->icon_imbuf->byte_buffer.data)) {
1476 return;
1477 }
1478
1479 icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
1480
1481 *do_update = true;
1482 }
1483 else {
1484 /* re-use shader job */
1486
1487 /* world is rendered with alpha=0, so it wasn't displayed
1488 * this could be render option for sky to, for later */
1489 if (idtype == ID_WO) {
1490 set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
1491 }
1492 }
1493}
1494
1495/* use same function for icon & shader, so the job manager
1496 * does not run two of them at the same time. */
1497
1498static void common_preview_startjob(void *customdata, wmJobWorkerStatus *worker_status)
1499{
1500 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1501
1503 icon_preview_startjob(customdata, &worker_status->stop, &worker_status->do_update);
1504 }
1505 else {
1506 shader_preview_startjob(customdata, &worker_status->stop, &worker_status->do_update);
1507 }
1508}
1509
1515 IconPreviewSize *cur_size,
1516 const ePreviewRenderMethod pr_method,
1517 wmJobWorkerStatus *worker_status)
1518{
1519 ShaderPreview *sp = MEM_callocN<ShaderPreview>("Icon ShaderPreview");
1520
1521 /* These types don't use the ShaderPreview mess, they have their own types and functions. */
1522 BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
1523
1524 /* Construct shader preview from image size and preview custom-data. */
1525 sp->scene = ip->scene;
1526 sp->owner = ip->owner;
1527 sp->sizex = cur_size->sizex;
1528 sp->sizey = cur_size->sizey;
1529 sp->pr_method = pr_method;
1530 sp->pr_rect = cur_size->rect;
1531 sp->id = ip->id;
1532 sp->id_copy = ip->id_copy;
1533 sp->bmain = ip->bmain;
1534 sp->own_id_copy = false;
1535 Material *ma = nullptr;
1536
1537 if (sp->pr_method == PR_ICON_RENDER) {
1538 BLI_assert(ip->id);
1539
1540 /* grease pencil use its own preview file */
1541 if (GS(ip->id->name) == ID_MA) {
1542 ma = (Material *)ip->id;
1543 }
1544
1545 if ((ma == nullptr) || (ma->gp_style == nullptr)) {
1546 sp->pr_main = G.pr_main;
1547 }
1548 else {
1550 }
1551 }
1552
1553 common_preview_startjob(sp, worker_status);
1555}
1556
1557/* exported functions */
1558
1563 const PreviewImage *preview_image)
1564{
1565 for (int i = 0; i < NUM_ICON_SIZES; i++) {
1566 if ((preview_image->w[i] == icon_size->sizex) && (preview_image->h[i] == icon_size->sizey)) {
1567 return i;
1568 }
1569 }
1570
1571 BLI_assert_msg(0, "The searched icon size does not match any in the preview image");
1572 return -1;
1573}
1574
1575static void icon_preview_startjob_all_sizes(void *customdata, wmJobWorkerStatus *worker_status)
1576{
1577 IconPreview *ip = (IconPreview *)customdata;
1578
1579 LISTBASE_FOREACH (IconPreviewSize *, cur_size, &ip->sizes) {
1580 PreviewImage *prv = static_cast<PreviewImage *>(ip->owner);
1581 /* Is this a render job or a deferred loading job? */
1582 const ePreviewRenderMethod pr_method = (prv->runtime->deferred_loading_data) ?
1585
1586 if (worker_status->stop) {
1587 break;
1588 }
1589
1590 if (prv->runtime->tag & PRV_TAG_DEFFERED_DELETE) {
1591 /* Non-thread-protected reading is not an issue here. */
1592 continue;
1593 }
1594
1595 /* check_engine_supports_preview() checks whether the engine supports "preview mode" (think:
1596 * Material Preview). This check is only relevant when the render function called below is
1597 * going to use such a mode. Group, Object and Action render functions use Solid mode, though,
1598 * so they can skip this test. Same is true for Images and Brushes, they can also skip this
1599 * test since their preview is just pulled from ImBuf which is not dependent on the render
1600 * engine. */
1601 /* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
1602 * necessary to know here what happens inside lower-level functions. */
1603 const bool use_solid_render_mode = (ip->id != nullptr) &&
1604 ELEM(GS(ip->id->name), ID_OB, ID_AC, ID_IM, ID_GR, ID_BR);
1605 if (!use_solid_render_mode && preview_method_is_render(pr_method) &&
1607 {
1608 continue;
1609 }
1610
1611 /* Workaround: Skip preview renders for linked IDs. Preview rendering can be slow and even
1612 * freeze the UI (e.g. on Eevee shader compilation). And since the result will never be stored
1613 * in a file, it's done every time the file is reloaded, so this becomes a frequent annoyance.
1614 */
1615 if (!use_solid_render_mode && ip->id && !ID_IS_EDITABLE(ip->id)) {
1616 continue;
1617 }
1618
1619#ifndef NDEBUG
1620 {
1621 int size_index = icon_previewimg_size_index_get(cur_size, prv);
1622 BLI_assert(!BKE_previewimg_is_finished(prv, size_index));
1623 }
1624#endif
1625
1626 if (ip->id != nullptr) {
1627 switch (GS(ip->id->name)) {
1628 case ID_OB:
1630 /* Much simpler than the ShaderPreview mess used for other ID types. */
1631 object_preview_render(ip, cur_size);
1632 }
1633 continue;
1634 case ID_GR:
1636 /* A collection instance empty was created, so this can just reuse the object preview
1637 * rendering. */
1638 object_preview_render(ip, cur_size);
1639 continue;
1640 case ID_AC:
1641 action_preview_render(ip, cur_size);
1642 continue;
1643 default:
1644 /* Fall through to the same code as the `ip->id == nullptr` case. */
1645 break;
1646 }
1647 }
1648 other_id_types_preview_render(ip, cur_size, pr_method, worker_status);
1649 }
1650}
1651
1652static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
1653{
1654 IconPreviewSize *cur_size = static_cast<IconPreviewSize *>(ip->sizes.first);
1655
1656 while (cur_size) {
1657 if (cur_size->sizex == sizex && cur_size->sizey == sizey) {
1658 /* requested size is already in list, no need to add it again */
1659 return;
1660 }
1661
1662 cur_size = cur_size->next;
1663 }
1664
1665 IconPreviewSize *new_size = MEM_callocN<IconPreviewSize>("IconPreviewSize");
1666 new_size->sizex = sizex;
1667 new_size->sizey = sizey;
1668 new_size->rect = rect;
1669
1670 BLI_addtail(&ip->sizes, new_size);
1671}
1672
1673static void icon_preview_endjob(void *customdata)
1674{
1675 IconPreview *ip = static_cast<IconPreview *>(customdata);
1676
1677 if (ip->id) {
1678
1679 if (GS(ip->id->name) == ID_BR) {
1681 }
1682#if 0
1683 if (GS(ip->id->name) == ID_MA) {
1684 Material *ma = (Material *)ip->id;
1685 PreviewImage *prv_img = ma->preview;
1686 int i;
1687
1688 /* signal to gpu texture */
1689 for (i = 0; i < NUM_ICON_SIZES; i++) {
1690 if (prv_img->gputexture[i]) {
1691 GPU_texture_free(prv_img->gputexture[i]);
1692 prv_img->gputexture[i] = nullptr;
1694 }
1695 }
1696 }
1697#endif
1698 }
1699
1700 if (ip->owner) {
1701 PreviewImage *prv_img = static_cast<PreviewImage *>(ip->owner);
1702 prv_img->runtime->tag &= ~PRV_TAG_DEFFERED_RENDERING;
1703
1704 LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) {
1705 int size_index = icon_previewimg_size_index_get(icon_size, prv_img);
1706 BKE_previewimg_finish(prv_img, size_index);
1707 }
1708
1709 if (prv_img->runtime->tag & PRV_TAG_DEFFERED_DELETE) {
1710 BLI_assert(prv_img->runtime->deferred_loading_data);
1712 }
1713 }
1714}
1715
1726 struct RequestedPreview {
1727 PreviewImage *preview;
1729 eIconSizes icon_size;
1731 std::atomic<bool> done = false;
1734 std::atomic<bool> failure = false;
1735
1736 RequestedPreview(PreviewImage *preview, eIconSizes icon_size)
1737 : preview(preview), icon_size(icon_size)
1738 {
1739 }
1740 };
1741
1743 ThreadQueue *todo_queue_; /* RequestedPreview * */
1746 std::list<RequestedPreview> requested_previews_;
1747
1748 public:
1751
1753 static void load_jobless(PreviewImage *preview, eIconSizes icon_size);
1754
1755 void push_load_request(PreviewImage *preview, eIconSizes icon_size);
1756
1757 private:
1758 static void run_fn(void *customdata, wmJobWorkerStatus *worker_status);
1759 static void update_fn(void *customdata);
1760 static void end_fn(void *customdata);
1761 static void free_fn(void *customdata);
1762
1764 static void finish_request(RequestedPreview &request);
1765};
1766
1768
1773
1775{
1776 wmJob *wm_job = WM_jobs_get(
1777 wm, win, nullptr, "Load Previews", eWM_JobFlag(0), WM_JOB_TYPE_LOAD_PREVIEW);
1778
1779 if (!WM_jobs_is_running(wm_job)) {
1780 PreviewLoadJob *job_data = MEM_new<PreviewLoadJob>("PreviewLoadJobData");
1781
1782 WM_jobs_customdata_set(wm_job, job_data, free_fn);
1783 WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
1784 WM_jobs_callbacks(wm_job, run_fn, nullptr, update_fn, end_fn);
1785
1786 WM_jobs_start(wm, wm_job);
1787 }
1788
1789 return *static_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job));
1790}
1791
1793{
1794 PreviewLoadJob job_data{};
1795
1796 job_data.push_load_request(preview, icon_size);
1797
1798 wmJobWorkerStatus worker_status = {};
1799 run_fn(&job_data, &worker_status);
1800 update_fn(&job_data);
1801 end_fn(&job_data);
1802}
1803
1805{
1806 BLI_assert(preview->runtime->deferred_loading_data);
1807
1808 preview->flag[icon_size] |= PRV_RENDERING;
1809 /* Warn main thread code that this preview is being rendered and cannot be freed. */
1810 preview->runtime->tag |= PRV_TAG_DEFFERED_RENDERING;
1811
1812 requested_previews_.emplace_back(preview, icon_size);
1813 BLI_thread_queue_push(todo_queue_, &requested_previews_.back());
1814}
1815
1816void PreviewLoadJob::run_fn(void *customdata, wmJobWorkerStatus *worker_status)
1817{
1818 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1819
1821
1822 while (RequestedPreview *request = static_cast<RequestedPreview *>(
1823 BLI_thread_queue_pop_timeout(job_data->todo_queue_, 100)))
1824 {
1825 if (worker_status->stop) {
1826 break;
1827 }
1828
1829 PreviewImage *preview = request->preview;
1830
1831 const std::optional<int> source = BKE_previewimg_deferred_thumb_source_get(preview);
1832 const char *filepath = BKE_previewimg_deferred_filepath_get(preview);
1833
1834 if (!source || !filepath) {
1835 continue;
1836 }
1837
1838 // printf("loading deferred %dx%d preview for %s\n", request->sizex, request->sizey, filepath);
1839
1840 IMB_thumb_path_lock(filepath);
1841 ImBuf *thumb = IMB_thumb_manage(filepath, THB_LARGE, ThumbSource(*source));
1842 IMB_thumb_path_unlock(filepath);
1843
1844 if (thumb) {
1845 /* PreviewImage assumes premultiplied alpha. */
1846 IMB_premultiply_alpha(thumb);
1847
1848 if (ED_preview_use_image_size(preview, request->icon_size)) {
1849 preview->w[request->icon_size] = thumb->x;
1850 preview->h[request->icon_size] = thumb->y;
1851 BLI_assert(preview->rect[request->icon_size] == nullptr);
1852 preview->rect[request->icon_size] = (uint *)MEM_dupallocN(thumb->byte_buffer.data);
1853 }
1854 else {
1855 icon_copy_rect(thumb,
1856 preview->w[request->icon_size],
1857 preview->h[request->icon_size],
1858 preview->rect[request->icon_size]);
1859 }
1860 IMB_freeImBuf(thumb);
1861 }
1862 else {
1863 request->failure = true;
1864 }
1865
1866 request->done = true;
1867 worker_status->do_update = true;
1868 }
1869
1871}
1872
1873/* Only execute on the main thread! */
1874void PreviewLoadJob::finish_request(RequestedPreview &request)
1875{
1876 PreviewImage *preview = request.preview;
1877
1878 preview->runtime->tag &= ~PRV_TAG_DEFFERED_RENDERING;
1879 if (request.failure) {
1880 preview->runtime->tag |= PRV_TAG_DEFFERED_INVALID;
1881 }
1882 BKE_previewimg_finish(preview, request.icon_size);
1883
1885 "Deferred releasing of preview images should only run on the main thread");
1886 if (preview->runtime->tag & PRV_TAG_DEFFERED_DELETE) {
1887 BLI_assert(preview->runtime->deferred_loading_data);
1889 }
1890}
1891
1892void PreviewLoadJob::update_fn(void *customdata)
1893{
1894 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1895
1896 for (auto request_it = job_data->requested_previews_.begin();
1897 request_it != job_data->requested_previews_.end();)
1898 {
1899 RequestedPreview &requested = *request_it;
1900 /* Skip items that are not done loading yet. */
1901 if (!requested.done) {
1902 ++request_it;
1903 continue;
1904 }
1905 finish_request(requested);
1906
1907 /* Remove properly finished previews from the job data. */
1908 auto next_it = job_data->requested_previews_.erase(request_it);
1909 request_it = next_it;
1910 }
1911}
1912
1913void PreviewLoadJob::end_fn(void *customdata)
1914{
1915 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1916
1917 /* Finish any possibly remaining queued previews. */
1918 for (RequestedPreview &request : job_data->requested_previews_) {
1919 finish_request(request);
1920 }
1921 job_data->requested_previews_.clear();
1922}
1923
1924void PreviewLoadJob::free_fn(void *customdata)
1925{
1926 MEM_delete(static_cast<PreviewLoadJob *>(customdata));
1927}
1928
1929static void icon_preview_free(void *customdata)
1930{
1931 IconPreview *ip = (IconPreview *)customdata;
1932
1933 if (ip->id_copy) {
1935 }
1936
1937 BLI_freelistN(&ip->sizes);
1938 MEM_freeN(ip);
1939}
1940
1942{
1943 return size == ICON_SIZE_PREVIEW && preview->runtime->deferred_loading_data;
1944}
1945
1946bool ED_preview_id_is_supported(const ID *id, const char **r_disabled_hint)
1947{
1948 if (id == nullptr) {
1949 return false;
1950 }
1951
1952 /* Get both the result and the "potential" disabled hint. After that we can decide if the
1953 * disabled hint needs to be returned to the caller. */
1954 const auto [result, disabled_hint] = [id]() -> std::pair<bool, const char *> {
1955 switch (GS(id->name)) {
1956 case ID_NT:
1957 return {false, RPT_("Node groups do not support automatic previews")};
1958 case ID_OB:
1959 return {object_preview_is_type_supported((const Object *)id),
1960 RPT_("Object type does not support automatic previews")};
1961 case ID_GR:
1962 return {
1964 RPT_("Collection does not contain object types that can be rendered for the automatic "
1965 "preview")};
1966 default:
1967 return {BKE_previewimg_id_get_p(id) != nullptr,
1968 RPT_("Data-block type does not support automatic previews")};
1969 }
1970 }();
1971
1972 if (result == false && disabled_hint && r_disabled_hint) {
1973 *r_disabled_hint = disabled_hint;
1974 }
1975
1976 return result;
1977}
1978
1980 const bContext *C, Scene *scene, PreviewImage *prv_img, ID *id, eIconSizes icon_size)
1981{
1982 /* Deferred loading of previews from the file system. */
1983 if (prv_img->runtime->deferred_loading_data) {
1984 if (prv_img->flag[icon_size] & PRV_RENDERING) {
1985 /* Already in the queue, don't add it again. */
1986 return;
1987 }
1988
1989 PreviewLoadJob::load_jobless(prv_img, icon_size);
1990 return;
1991 }
1992
1993 IconPreview ip = {nullptr};
1994
1996
1997 ip.bmain = CTX_data_main(C);
1998 ip.scene = scene;
2001 ip.id = id;
2002 /* Control isn't given back to the caller until the preview is done. So we don't need to copy
2003 * the ID to avoid thread races. */
2004 ip.id_copy = duplicate_ids(id, true);
2006
2007 prv_img->flag[icon_size] |= PRV_RENDERING;
2008
2010 &ip, prv_img->rect[icon_size], prv_img->w[icon_size], prv_img->h[icon_size]);
2011
2012 wmJobWorkerStatus worker_status = {};
2013 icon_preview_startjob_all_sizes(&ip, &worker_status);
2014
2016
2017 BLI_freelistN(&ip.sizes);
2018 if (ip.id_copy != nullptr) {
2020 }
2021}
2022
2024 const bContext *C, PreviewImage *prv_img, ID *id, eIconSizes icon_size, const bool delay)
2025{
2026 /* Deferred loading of previews from the file system. */
2027 if (prv_img->runtime->deferred_loading_data) {
2028 if (prv_img->flag[icon_size] & PRV_RENDERING) {
2029 /* Already in the queue, don't add it again. */
2030 return;
2031 }
2033 load_job.push_load_request(prv_img, icon_size);
2034
2035 return;
2036 }
2037
2038 IconPreview *ip, *old_ip;
2039
2041
2042 /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
2043 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
2045 prv_img,
2046 "Icon Preview",
2049
2050 ip = MEM_callocN<IconPreview>("icon preview");
2051
2052 /* render all resolutions from suspended job too */
2053 old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job));
2054 if (old_ip) {
2055 BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
2056 }
2057
2058 /* customdata for preview thread */
2059 ip->bmain = CTX_data_main(C);
2063 ip->owner = prv_img;
2064 ip->id = id;
2065 ip->id_copy = duplicate_ids(id, false);
2066
2067 prv_img->flag[icon_size] |= PRV_RENDERING;
2068
2070 ip, prv_img->rect[icon_size], prv_img->w[icon_size], prv_img->h[icon_size]);
2071
2072 /* setup job */
2074 WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
2075 /* Wait 2s to start rendering icon previews, to not bog down user interaction.
2076 * Particularly important for heavy scenes and Eevee using OpenGL that blocks
2077 * the user interface drawing. */
2078 WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0);
2080 wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob);
2081
2082 WM_jobs_start(CTX_wm_manager(C), wm_job);
2083}
2084
2086 void *owner,
2087 ID *id,
2088 ID *parent,
2089 MTex *slot,
2090 int sizex,
2091 int sizey,
2092 ePreviewRenderMethod method)
2093{
2095 wmJob *wm_job;
2096 ShaderPreview *sp;
2097 Scene *scene = CTX_data_scene(C);
2098 const ID_Type id_type = GS(id->name);
2099
2101
2102 /* Use workspace render only for buttons Window,
2103 * since the other previews are related to the datablock. */
2104
2106 return;
2107 }
2108
2110
2111 wm_job = WM_jobs_get(CTX_wm_manager(C),
2113 owner,
2114 "Shader Preview",
2117 sp = MEM_callocN<ShaderPreview>("shader preview");
2118
2119 /* customdata for preview thread */
2120 sp->scene = scene;
2121 sp->owner = owner;
2122 sp->sizex = sizex;
2123 sp->sizey = sizey;
2124 sp->pr_method = method;
2125 sp->id = id;
2126 sp->id_copy = duplicate_ids(id, false);
2127 sp->own_id_copy = true;
2128 sp->parent = parent;
2129 sp->slot = slot;
2130 sp->bmain = CTX_data_main(C);
2131 Material *ma = nullptr;
2132
2133 /* hardcoded preview .blend for Eevee + Cycles, this should be solved
2134 * once with custom preview .blend path for external engines */
2135
2136 /* grease pencil use its own preview file */
2137 if (id_type == ID_MA) {
2138 ma = (Material *)id;
2139 }
2140
2141 if ((ma == nullptr) || (ma->gp_style == nullptr)) {
2142 sp->pr_main = G.pr_main;
2143 }
2144 else {
2146 }
2147
2148 if (ob && ob->totcol) {
2149 copy_v4_v4(sp->color, ob->color);
2150 }
2151 else {
2152 ARRAY_SET_ITEMS(sp->color, 0.0f, 0.0f, 0.0f, 1.0f);
2153 }
2154
2155 /* setup job */
2157 WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
2159
2160 WM_jobs_start(CTX_wm_manager(C), wm_job);
2161}
2162
2164{
2165 if (wm) {
2166 /* This is called to stop all preview jobs before scene data changes, to
2167 * avoid invalid memory access. */
2169 }
2170}
2171
2173{
2174 const PreviewImage *preview = BKE_previewimg_id_get(id);
2175 if (wm && preview) {
2177 }
2178}
2179
2186
2187static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
2188
2193
2195{
2197 queue_entry->size = size;
2198 queue_entry->id = id;
2200}
2201
2203{
2205 PreviewImage *preview = BKE_previewimg_id_get(queue_entry->id);
2206 if (!preview) {
2207 continue;
2208 }
2209 if (preview->flag[queue_entry->size] & PRV_USER_EDITED) {
2210 /* Don't touch custom previews. */
2211 continue;
2212 }
2213
2214 BKE_previewimg_clear_single(preview, queue_entry->size);
2215 UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true);
2216
2218 }
2219}
2220
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:544
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
void BKE_icon_changed(int icon_id)
Definition icons.cc:204
int BKE_icon_id_ensure(struct ID *id)
Definition icons.cc:267
void IDP_FreePropertyContent_ex(IDProperty *prop, bool do_id_user)
Definition idprop.cc:1205
IDProperty * IDP_GetProperties(ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition idprop.cc:887
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)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
@ LIB_ID_CREATE_LOCAL
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_NO_ANIMDATA
void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL()
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:767
General operations, lookup, etc. for blender lights.
Main * BKE_main_new()
Definition main.cc:48
void BKE_main_free(Main *bmain)
Definition main.cc:175
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
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)
Scene * BKE_scene_add(Main *bmain, const char *name)
Definition scene.cc:2010
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2618
void BKE_screen_view3d_shading_init(View3DShading *shading)
Definition screen.cc:1011
void BKE_texture_fetch_images_for_pool(struct Tex *texture, struct ImagePool *pool)
Definition texture.cc:735
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:690
#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)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
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 SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
unsigned int uint
void BLI_thread_queue_push(ThreadQueue *queue, void *work)
Definition threads.cc:642
ThreadQueue * BLI_thread_queue_init(void)
Definition threads.cc:616
void BLI_thread_queue_free(ThreadQueue *queue)
Definition threads.cc:630
int BLI_thread_is_main(void)
Definition threads.cc:179
void * BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
Definition threads.cc:712
#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)
@ PRV_TAG_DEFFERED_DELETE
Definition DNA_ID.h:553
@ PRV_TAG_DEFFERED_RENDERING
Definition DNA_ID.h:551
@ PRV_TAG_DEFFERED_INVALID
Definition DNA_ID.h:555
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
struct PreviewImage PreviewImage
@ PRV_RENDERING
Definition DNA_ID.h:545
@ PRV_USER_EDITED
Definition DNA_ID.h:543
eIconSizes
@ ICON_SIZE_PREVIEW
@ NUM_ICON_SIZES
ID_Type
@ ID_TE
@ ID_IM
@ ID_NT
@ ID_LA
@ ID_BR
@ ID_WO
@ ID_MA
@ ID_AC
@ ID_GR
@ ID_OB
@ ROT_MODE_QUAT
@ BRUSH_CUSTOM_ICON
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
@ OB_TEXTURE
@ OB_SOLID
Object is a sort of wrapper for general info.
#define OB_TYPE_IS_GEOMETRY(_type)
@ OB_HIDE_RENDER
@ OB_EMPTY
@ OB_CAMERA
@ OB_LAMP
@ OB_MESH
#define OB_TYPE_SUPPORT_MATERIAL(_type)
@ OB_DUPLICOLLECTION
#define BASE_SELECTED(v3d, base)
@ R_ADDSKY
@ R_ALPHAPREMUL
@ SCE_DISPLAY_AA_OFF
@ SCE_DISPLAY_AA_SAMPLES_8
@ R_MATNODE_PREVIEW
@ R_NO_IMAGE_LOAD
@ R_TEXNODE_PREVIEW
@ R_BUTS_PREVIEW
@ SCE_PASS_COMBINED
@ 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(GPUTexture *texture)
void IMB_premultiply_alpha(ImBuf *ibuf)
Definition filter.cc:577
ImBuf * IMB_load_image_from_filepath(const char *filepath, const int flags, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:204
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:801
@ IB_TAKE_OWNERSHIP
@ IB_byte_data
@ IB_metadata
@ IB_multilayer
@ THB_LARGE
Definition IMB_thumbs.hh:23
void IMB_thumb_path_unlock(const char *path)
Definition thumbs.cc:719
ThumbSource
Definition IMB_thumbs.hh:27
void IMB_thumb_locks_acquire()
Definition thumbs.cc:672
ImBuf * IMB_thumb_manage(const char *file_or_lib_path, ThumbSize size, ThumbSource source)
Definition thumbs.cc:534
void IMB_thumb_path_lock(const char *path)
Definition thumbs.cc:703
void IMB_thumb_locks_release()
Definition thumbs.cc:688
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:1729
@ WM_JOB_TYPE_LOAD_PREVIEW
Definition WM_api.hh:1731
eWM_JobFlag
Definition WM_api.hh:1709
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1715
#define NC_WINDOW
Definition WM_types.hh:372
#define NC_BRUSH
Definition WM_types.hh:382
bool stop
Definition WM_types.hh:1016
#define NA_EDITED
Definition WM_types.hh:581
bool do_update
Definition WM_types.hh:1008
#define NC_MATERIAL
Definition WM_types.hh:377
#define ND_SHADING_DRAW
Definition WM_types.hh:475
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)
#define offsetof(t, d)
#define abs
#define printf(...)
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
#define ID_IS_EDITABLE(_id)
#define GS(a)
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:161
float wrap(float value, float max, float min)
Definition node_math.h:71
static bool preview_method_is_render(const ePreviewRenderMethod pr_method)
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)
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, ScrArea *area, 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_restart_queue_add(ID *id, enum eIconSizes size)
static bool collection_preview_contains_geometry_recursive(const Collection *collection)
static Scene * preview_get_scene(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)
static ImBuf * icon_preview_imbuf_from_brush(Brush *brush)
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)
void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey, ePreviewRenderMethod method)
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)
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_NEXT
Definition scene.cc:1626
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 char *name)
RenderResult * RE_AcquireResultWrite(Render *re)
Render * RE_GetRender(const char *name)
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)
short flag
struct ImBuf * icon_imbuf
char icon_filepath[1024]
Definition DNA_ID.h:404
int icon_id
Definition DNA_ID.h:426
char name[66]
Definition DNA_ID.h:415
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:245
ListBase textures
Definition BKE_main.hh:252
char filepath[1024]
Definition BKE_main.hh:155
ListBase lights
Definition BKE_main.hh:255
ListBase materials
Definition BKE_main.hh:251
ListBase worlds
Definition BKE_main.hh:260
ListBase screens
Definition BKE_main.hh:261
ListBase objects
Definition BKE_main.hh:247
struct PreviewImage * preview
struct MaterialGPencilStyle * gp_style
struct Material ** mat
short totcol
short transflag
struct Collection * instance_collection
struct bPose * pose
float loc[3]
float quat[4]
float color[4]
PreviewImageRuntimeHandle * runtime
Definition DNA_ID.h:571
unsigned int h[2]
Definition DNA_ID.h:566
short flag[2]
Definition DNA_ID.h:567
unsigned int * rect[2]
Definition DNA_ID.h:569
unsigned int w[2]
Definition DNA_ID.h:565
PreviewRestartQueueEntry * prev
PreviewRestartQueueEntry * next
char engine[32]
ListBase views
struct ImBuf * ibuf
Definition RE_pipeline.h:44
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
float trgba[4]
Definition RE_texture.h:84
char use_nodes
struct bNodeTree * nodetree
struct ViewLayerEEVEE eevee
ListBase layer_collections
float horg
float range
short use_nodes
float exp
float horb
float horr
int ymin
int ymax
int xmin
int xmax
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:318
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:353
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:456
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:598
void * WM_jobs_customdata_get(wmJob *wm_job)
Definition wm_jobs.cc:329
void WM_jobs_delay_start(wmJob *wm_job, double delay_time)
Definition wm_jobs.cc:360
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:190
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:365
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:224
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:337
void * WM_jobs_customdata_from_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:307