Blender V4.3
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
9/* global includes */
10
11#include <algorithm>
12#include <cmath>
13#include <cstdlib>
14#include <cstring>
15#include <list>
16
17#ifndef WIN32
18# include <unistd.h>
19#else
20# include <io.h>
21#endif
22#include "MEM_guardedalloc.h"
23
24#include "BLI_blenlib.h"
25#include "BLI_math_matrix.h"
26#include "BLI_math_rotation.h"
27#include "BLI_time.h"
28#include "BLI_utildefines.h"
29
30#include "BLT_translation.hh"
31
32#include "BLO_readfile.hh"
33
34#include "DNA_brush_types.h"
35#include "DNA_camera_types.h"
37#include "DNA_light_types.h"
38#include "DNA_material_types.h"
39#include "DNA_mesh_types.h"
40#include "DNA_node_types.h"
41#include "DNA_object_types.h"
42#include "DNA_scene_types.h"
43#include "DNA_screen_types.h"
44#include "DNA_space_types.h"
45#include "DNA_world_types.h"
46
47#include "BKE_animsys.h"
48#include "BKE_appdir.hh"
49#include "BKE_armature.hh"
50#include "BKE_brush.hh"
51#include "BKE_colortools.hh"
52#include "BKE_context.hh"
53#include "BKE_global.hh"
54#include "BKE_icons.h"
55#include "BKE_idprop.hh"
56#include "BKE_image.hh"
57#include "BKE_layer.hh"
58#include "BKE_lib_id.hh"
59#include "BKE_light.h"
60#include "BKE_main.hh"
61#include "BKE_material.h"
62#include "BKE_node.hh"
63#include "BKE_object.hh"
64#include "BKE_pose_backup.h"
65#include "BKE_preview_image.hh"
66#include "BKE_scene.hh"
67#include "BKE_screen.hh"
68#include "BKE_texture.h"
69#include "BKE_world.h"
70
71#include "BLI_math_vector.h"
72
73#include "DEG_depsgraph.hh"
76
77#include "IMB_imbuf.hh"
78#include "IMB_imbuf_types.hh"
79#include "IMB_thumbs.hh"
80
81#include "BIF_glutil.hh"
82
83#include "GPU_shader.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(ImBuf *ibuf, uint w, uint h, uint *rect);
109
110/* -------------------------------------------------------------------- */
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
165/* -------------------------------------------------------------------- */
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
179 bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr);
180 if (bfd) {
181 bmain = bfd->main;
182
183 MEM_freeN(bfd);
184 }
185 G.fileflags = fileflags;
186
187 return bmain;
188}
189#endif
190
191void ED_preview_ensure_dbase(const bool with_gpencil)
192{
193#ifndef WITH_HEADLESS
194 static bool base_initialized = false;
195 static bool base_initialized_gpencil = false;
197 if (!base_initialized) {
199 base_initialized = true;
200 }
201 if (!base_initialized_gpencil && with_gpencil) {
204 base_initialized_gpencil = true;
205 }
206#else
207 UNUSED_VARS(with_gpencil);
208#endif
209}
210
212{
213 RenderEngineType *type = RE_engines_find(scene->r.engine);
214 return (type->flag & RE_USE_PREVIEW) != 0;
215}
216
218{
219 return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
220}
221
223{
224 if (G.pr_main) {
225 BKE_main_free(G.pr_main);
226 }
227
230 }
231}
232
233static Scene *preview_get_scene(Main *pr_main)
234{
235 if (pr_main == nullptr) {
236 return nullptr;
237 }
238
239 return static_cast<Scene *>(pr_main->scenes.first);
240}
241
242const char *ED_preview_collection_name(const ePreviewType pr_type)
243{
244 switch (pr_type) {
245 case MA_FLAT:
246 return "Flat";
247 case MA_SPHERE:
248 return "Sphere";
249 case MA_CUBE:
250 return "Cube";
251 case MA_SHADERBALL:
252 return "Shader Ball";
253 case MA_CLOTH:
254 return "Cloth";
255 case MA_FLUID:
256 return "Fluid";
257 case MA_SPHERE_A:
258 return "World Sphere";
259 case MA_LAMP:
260 return "Lamp";
261 case MA_SKY:
262 return "Sky";
263 case MA_HAIR:
264 return "Hair";
265 case MA_ATMOS:
266 return "Atmosphere";
267 default:
268 BLI_assert_msg(0, "Unknown preview type");
269 return "";
270 }
271}
272
274{
276}
277
278static void switch_preview_collection_visibility(ViewLayer *view_layer, const ePreviewType pr_type)
279{
280 /* Set appropriate layer as visible. */
281 LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first);
282 const char *collection_name = ED_preview_collection_name(pr_type);
283
284 for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) {
285 if (STREQ(lc->collection->id.name + 2, collection_name)) {
286 lc->collection->flag &= ~COLLECTION_HIDE_RENDER;
287 }
288 else {
290 }
291 }
292}
293
294static const char *preview_floor_material_name(const Scene *scene,
295 const ePreviewRenderMethod pr_method)
296{
297 if (pr_method == PR_ICON_RENDER && render_engine_supports_ray_visibility(scene)) {
298 return "FloorHidden";
299 }
300 return "Floor";
301}
302
304 Mesh *mesh,
305 const Scene *scene,
306 const ePreviewRenderMethod pr_method)
307{
308 if (mesh->totcol == 0) {
309 return;
310 }
311
312 const char *material_name = preview_floor_material_name(scene, pr_method);
313 Material *mat = static_cast<Material *>(
314 BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2));
315 if (mat) {
316 mesh->mat[0] = mat;
317 }
318}
319
321 const Scene *scene,
322 ViewLayer *view_layer,
323 const ePreviewRenderMethod pr_method)
324{
325 /* Hide floor for icon renders. */
326 BKE_view_layer_synced_ensure(scene, view_layer);
328 if (STREQ(base->object->id.name + 2, "Floor")) {
329 base->object->visibility_flag &= ~OB_HIDE_RENDER;
330 if (pr_method == PR_ICON_RENDER) {
332 base->object->visibility_flag |= OB_HIDE_RENDER;
333 }
334 }
335 if (base->object->type == OB_MESH) {
337 pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method);
338 }
339 }
340 }
341}
342
344 Scene *scene,
345 ViewLayer *view_layer,
346 const ePreviewType pr_type,
347 const ePreviewRenderMethod pr_method)
348{
349 switch_preview_collection_visibility(view_layer, pr_type);
350 switch_preview_floor_visibility(pr_main, scene, view_layer, pr_method);
351 BKE_layer_collection_sync(scene, view_layer);
352}
353
355{
356 if (world == nullptr) {
357 return nullptr;
358 }
359 if (sp->worldcopy != nullptr) {
360 return sp->worldcopy;
361 }
362
363 ID *id_copy = BKE_id_copy_ex(nullptr,
364 &world->id,
365 nullptr,
368 sp->worldcopy = (World *)id_copy;
370 return sp->worldcopy;
371}
372
373static ID *duplicate_ids(ID *id, const bool allow_failure)
374{
375 if (id == nullptr) {
376 /* Non-ID preview render. */
377 return nullptr;
378 }
379
380 switch (GS(id->name)) {
381 case ID_OB:
382 case ID_MA:
383 case ID_TE:
384 case ID_LA:
385 case ID_WO: {
387 ID *id_copy = BKE_id_copy_ex(nullptr,
388 id,
389 nullptr,
392 return id_copy;
393 }
394 case ID_GR: {
395 /* Doesn't really duplicate the collection. Just creates a collection instance empty. */
397 Object *instance_empty = BKE_object_add_only_object(nullptr, OB_EMPTY, nullptr);
398 instance_empty->instance_collection = (Collection *)id;
399 instance_empty->transflag |= OB_DUPLICOLLECTION;
400 return &instance_empty->id;
401 }
402 /* These support threading, but don't need duplicating. */
403 case ID_IM:
404 case ID_BR:
406 return nullptr;
407 default:
408 if (!allow_failure) {
409 BLI_assert_msg(0, "ID type preview not supported.");
410 }
411 return nullptr;
412 }
413}
414
415static const char *preview_world_name(const Scene *sce,
416 const ID_Type id_type,
417 const ePreviewRenderMethod pr_method)
418{
419 /* When rendering material icons the floor will not be shown in the output. Cycles will use a
420 * material trick to show the floor in the reflections, but hide the floor for camera rays. For
421 * Eevee we use a transparent world that has a projected grid.
422 *
423 * In the future when Eevee supports VULKAN ray-tracing we can re-evaluate and perhaps remove
424 * this approximation.
425 */
426 if (id_type == ID_MA && pr_method == PR_ICON_RENDER &&
428 {
429 return "WorldFloor";
430 }
431 return "World";
432}
433
434static World *preview_get_world(Main *pr_main,
435 const Scene *sce,
436 const ID_Type id_type,
437 const ePreviewRenderMethod pr_method)
438{
439 World *result = nullptr;
440 const char *world_name = preview_world_name(sce, id_type, pr_method);
441 result = static_cast<World *>(
442 BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2));
443
444 /* No world found return first world. */
445 if (result == nullptr) {
446 result = static_cast<World *>(pr_main->worlds.first);
447 }
448
449 BLI_assert_msg(result, "Preview file has no world.");
450 return result;
451}
452
453static void preview_sync_exposure(World *dst, const World *src)
454{
455 BLI_assert(dst);
456 BLI_assert(src);
457 dst->exp = src->exp;
458 dst->range = src->range;
459}
460
462 const Scene *scene,
463 const World *world,
464 const ID_Type id_type,
465 const ePreviewRenderMethod pr_method)
466{
467 World *result = preview_get_world(pr_main, scene, id_type, pr_method);
468 if (world) {
469 preview_sync_exposure(result, world);
470 }
471 return result;
472}
473
474/* call this with a pointer to initialize preview scene */
475/* call this with nullptr to restore assigned ID pointers in preview scene */
477 Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
478{
479 Scene *sce;
480 Main *pr_main = sp->pr_main;
481
482 memcpy(pr_main->filepath, BKE_main_blendfile_path(bmain), sizeof(pr_main->filepath));
483
484 sce = preview_get_scene(pr_main);
485 if (sce) {
486 ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first);
487
488 /* Only enable the combined render-pass. */
489 view_layer->passflag = SCE_PASS_COMBINED;
490 view_layer->eevee.render_passes = 0;
491
492 /* This flag tells render to not execute depsgraph or F-Curves etc. */
493 sce->r.scemode |= R_BUTS_PREVIEW;
494 STRNCPY(sce->r.engine, scene->r.engine);
495
496 sce->r.color_mgt_flag = scene->r.color_mgt_flag;
497 BKE_color_managed_display_settings_copy(&sce->display_settings, &scene->display_settings);
498
500 BKE_color_managed_view_settings_copy(&sce->view_settings, &scene->view_settings);
501
502 if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO) {
504 }
505 else {
506 sce->r.alphamode = R_ADDSKY;
507 }
508
509 sce->r.cfra = scene->r.cfra;
510
511 /* Setup the world. */
513 pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method);
514
515 if (id_type == ID_TE) {
516 /* Texture is not actually rendered with engine, just set dummy value. */
518 }
519
520 if (id_type == ID_MA) {
521 Material *mat = nullptr, *origmat = (Material *)id;
522
523 if (origmat) {
524 /* work on a copy */
525 BLI_assert(sp->id_copy != nullptr);
526 mat = sp->matcopy = (Material *)sp->id_copy;
527 sp->id_copy = nullptr;
528 BLI_addtail(&pr_main->materials, mat);
529
530 /* Use current scene world for lighting. */
531 if (mat->pr_flag == MA_PREVIEW_WORLD && sp->pr_method == PR_BUTS_RENDER) {
532 /* Use current scene world to light sphere. */
533 sce->world = preview_get_localized_world(sp, scene->world);
534 }
535 else if (sce->world && sp->pr_method != PR_ICON_RENDER) {
536 /* Use a default world color. Using the current
537 * scene world can be slow if it has big textures. */
538 sce->world->use_nodes = false;
539 /* Use brighter world color for grease pencil. */
540 if (sp->pr_main == G_pr_main_grease_pencil) {
541 sce->world->horr = 1.0f;
542 sce->world->horg = 1.0f;
543 sce->world->horb = 1.0f;
544 }
545 else {
546 sce->world->horr = 0.05f;
547 sce->world->horg = 0.05f;
548 sce->world->horb = 0.05f;
549 }
550 }
551
552 const ePreviewType preview_type = static_cast<ePreviewType>(mat->pr_type);
553 ED_preview_set_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
554 }
555 else {
557 }
558 BKE_view_layer_synced_ensure(sce, view_layer);
560 if (base->object->id.name[2] == 'p') {
561 /* copy over object color, in case material uses it */
562 copy_v4_v4(base->object->color, sp->color);
563
564 if (OB_TYPE_SUPPORT_MATERIAL(base->object->type)) {
565 /* don't use BKE_object_material_assign, it changed mat->id.us, which shows in the UI
566 */
567 Material ***matar = BKE_object_material_array_p(base->object);
568 int actcol = max_ii(base->object->actcol - 1, 0);
569
570 if (matar && actcol < base->object->totcol) {
571 (*matar)[actcol] = mat;
572 }
573 }
574 else if (base->object->type == OB_LAMP) {
576 }
577 }
578 }
579 }
580 else if (id_type == ID_TE) {
581 Tex *tex = nullptr, *origtex = (Tex *)id;
582
583 if (origtex) {
584 BLI_assert(sp->id_copy != nullptr);
585 tex = sp->texcopy = (Tex *)sp->id_copy;
586 sp->id_copy = nullptr;
587 BLI_addtail(&pr_main->textures, tex);
588 }
589 }
590 else if (id_type == ID_LA) {
591 Light *la = nullptr, *origla = (Light *)id;
592
593 /* work on a copy */
594 if (origla) {
595 BLI_assert(sp->id_copy != nullptr);
596 la = sp->lampcopy = (Light *)sp->id_copy;
597 sp->id_copy = nullptr;
598 BLI_addtail(&pr_main->lights, la);
599 }
600
601 ED_preview_set_visibility(pr_main, sce, view_layer, MA_LAMP, sp->pr_method);
602
603 if (sce->world) {
604 /* Only use lighting from the light. */
605 sce->world->use_nodes = false;
606 sce->world->horr = 0.0f;
607 sce->world->horg = 0.0f;
608 sce->world->horb = 0.0f;
609 }
610
611 BKE_view_layer_synced_ensure(sce, view_layer);
613 if (base->object->id.name[2] == 'p') {
614 if (base->object->type == OB_LAMP) {
615 base->object->data = la;
616 }
617 }
618 }
619 }
620 else if (id_type == ID_WO) {
621 World *wrld = nullptr, *origwrld = (World *)id;
622
623 if (origwrld) {
624 BLI_assert(sp->id_copy != nullptr);
625 wrld = sp->worldcopy = (World *)sp->id_copy;
626 sp->id_copy = nullptr;
627 BLI_addtail(&pr_main->worlds, wrld);
628 }
629
630 ED_preview_set_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method);
631 sce->world = wrld;
632 }
633
634 return sce;
635 }
636
637 return nullptr;
638}
639
640/* new UI convention: draw is in pixel space already. */
641/* uses UI_BTYPE_ROUNDBOX button in block to get the rect */
643 Scene *scene, ScrArea *area, int split, int first, const rcti *rect, rcti *newrect)
644{
645 Render *re;
646 RenderView *rv;
647 RenderResult rres;
648 char name[32];
649 int offx = 0;
650 int newx = BLI_rcti_size_x(rect);
651 int newy = BLI_rcti_size_y(rect);
652 bool ok = false;
653
654 if (!split || first) {
655 SNPRINTF(name, "Preview %p", (void *)area);
656 }
657 else {
658 SNPRINTF(name, "SecondPreview %p", (void *)area);
659 }
660
661 if (split) {
662 if (first) {
663 offx = 0;
664 newx = newx / 2;
665 }
666 else {
667 offx = newx / 2;
668 newx = newx - newx / 2;
669 }
670 }
671
672 /* test if something rendered ok */
673 re = RE_GetRender(name);
674
675 if (re == nullptr) {
676 return false;
677 }
678
680
681 if (!BLI_listbase_is_empty(&rres.views)) {
682 /* material preview only needs monoscopy (view 0) */
683 rv = RE_RenderViewGetById(&rres, 0);
684 }
685 else {
686 /* possible the job clears the views but we're still drawing #45496 */
687 rv = nullptr;
688 }
689
690 if (rv && rv->ibuf) {
691 if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) {
692 newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx);
693 newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
694
695 if (rres.rectx && rres.recty) {
696 float fx = rect->xmin + offx;
697 float fy = rect->ymin;
698
700 rv->ibuf, fx, fy, false, &scene->view_settings, &scene->display_settings, 1.0f, 1.0f);
701
702 ok = true;
703 }
704 }
705 }
706
708
709 return ok;
710}
711
713 const bContext *C, void *idp, void *parentp, void *slotp, uiPreview *ui_preview, rcti *rect)
714{
715 if (idp) {
716 Scene *scene = CTX_data_scene(C);
718 ScrArea *area = CTX_wm_area(C);
719 ID *id = (ID *)idp;
720 ID *parent = (ID *)parentp;
721 MTex *slot = (MTex *)slotp;
723 ShaderPreview *sp = static_cast<ShaderPreview *>(
725 rcti newrect;
726 bool ok;
727 int newx = BLI_rcti_size_x(rect);
728 int newy = BLI_rcti_size_y(rect);
729
730 newrect.xmin = rect->xmin;
731 newrect.xmax = rect->xmin;
732 newrect.ymin = rect->ymin;
733 newrect.ymax = rect->ymin;
734
735 if (parent) {
736 ok = ed_preview_draw_rect(scene, area, 1, 1, rect, &newrect);
737 ok &= ed_preview_draw_rect(scene, area, 1, 0, rect, &newrect);
738 }
739 else {
740 ok = ed_preview_draw_rect(scene, area, 0, 0, rect, &newrect);
741 }
742
743 if (ok) {
744 *rect = newrect;
745 }
746
747 /* start a new preview render job if signaled through sbuts->preview,
748 * if no render result was found and no preview render job is running,
749 * or if the job is running and the size of preview changed */
750 if ((sbuts != nullptr && sbuts->preview) || (ui_preview->tag & UI_PREVIEW_TAG_DIRTY) ||
751 (!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
752 (sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2)))
753 {
754 if (sbuts != nullptr) {
755 sbuts->preview = 0;
756 }
757 ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
758 ui_preview->tag &= ~UI_PREVIEW_TAG_DIRTY;
759 }
760 }
761}
762
763void ED_previews_tag_dirty_by_id(const Main &bmain, const ID &id)
764{
765 LISTBASE_FOREACH (const bScreen *, screen, &bmain.screens) {
766 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
767 LISTBASE_FOREACH (const ARegion *, region, &area->regionbase) {
768 LISTBASE_FOREACH (uiPreview *, preview, &region->ui_previews) {
769 if (preview->id_session_uid == id.session_uid) {
770 preview->tag |= UI_PREVIEW_TAG_DIRTY;
771 }
772 }
773 }
774 }
775 }
776}
777
780/* -------------------------------------------------------------------- */
785 /* The main for the preview, not of the current file. */
787 /* Copy of the object to create the preview for. The copy is for thread safety (and to insert
788 * it into its own main). */
790 /* Current frame. */
791 int cfra;
792 int sizex;
793 int sizey;
794};
795
797{
798 return OB_TYPE_IS_GEOMETRY(ob->type);
799}
800
802 Scene *scene,
803 ViewLayer *view_layer,
804 Object *preview_object)
805{
806 Object *camera = BKE_object_add(preview_main, scene, view_layer, OB_CAMERA, "Preview Camera");
807
808 float rotmat[3][3];
809 float dummy_scale[3];
810 mat4_to_loc_rot_size(camera->loc, rotmat, dummy_scale, preview_object->object_to_world().ptr());
811
812 /* Camera is Y up, so needs additional rotations to obliquely face the front. */
813 float drotmat[3][3];
814 const float eul[3] = {M_PI * 0.4f, 0.0f, M_PI * 0.1f};
815 eul_to_mat3(drotmat, eul);
816 mul_m3_m3_post(rotmat, drotmat);
817
818 camera->rotmode = ROT_MODE_QUAT;
819 mat3_to_quat(camera->quat, rotmat);
820
821 /* Nice focal length for close portraiture. */
822 ((Camera *)camera->data)->lens = 85;
823
824 return camera;
825}
826
828 Depsgraph **r_depsgraph)
829{
830 Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene");
831 /* Preview need to be in the current frame to get a thumbnail similar of what
832 * viewport displays. */
833 scene->r.cfra = preview_data->cfra;
834
835 ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
836 Depsgraph *depsgraph = DEG_graph_new(
837 preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
838
839 BLI_assert(preview_data->object != nullptr);
840 BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
841
842 BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
843
844 Object *camera_object = object_preview_camera_create(
845 preview_data->pr_main, scene, view_layer, preview_data->object);
846
847 scene->camera = camera_object;
848 scene->r.xsch = preview_data->sizex;
849 scene->r.ysch = preview_data->sizey;
850 scene->r.size = 100;
851
852 BKE_view_layer_synced_ensure(scene, view_layer);
853 Base *preview_base = BKE_view_layer_base_find(view_layer, preview_data->object);
854 /* For 'view selected' below. */
855 preview_base->flag |= BASE_SELECTED;
856
859
861 preview_data->pr_main, depsgraph, scene, camera_object);
862
864
865 *r_depsgraph = depsgraph;
866 return scene;
867}
868
869static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
870{
871 Main *preview_main = BKE_main_new();
872 char err_out[256] = "unknown";
873
874 BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
875
876 ObjectPreviewData preview_data = {};
877 preview_data.pr_main = preview_main;
878 /* Act on a copy. */
879 preview_data.object = (Object *)preview->id_copy;
880 preview_data.cfra = preview->scene->r.cfra;
881 preview_data.sizex = preview_sized->sizex;
882 preview_data.sizey = preview_sized->sizey;
883
884 Depsgraph *depsgraph;
885 Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
886
887 /* Ownership is now ours. */
888 preview->id_copy = nullptr;
889
890 View3DShading shading;
892 /* Enable shadows, makes it a bit easier to see the shape. */
893 shading.flag |= V3D_SHADING_SHADOW;
894
896 depsgraph,
898 &shading,
900 DEG_get_evaluated_object(depsgraph, scene->camera),
901 preview_sized->sizex,
902 preview_sized->sizey,
903 IB_rect,
906 nullptr,
907 nullptr,
908 nullptr,
909 err_out);
910 /* TODO: color-management? */
911
912 if (ibuf) {
913 icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
914 IMB_freeImBuf(ibuf);
915 }
916
918 BKE_main_free(preview_main);
919}
920
923/* -------------------------------------------------------------------- */
937{
938 LISTBASE_FOREACH (CollectionObject *, col_ob, &collection->gobject) {
939 if (col_ob->ob->visibility_flag & OB_HIDE_RENDER) {
940 continue;
941 }
942 if (OB_TYPE_IS_GEOMETRY(col_ob->ob->type)) {
943 return true;
944 }
945 }
946
947 LISTBASE_FOREACH (CollectionChild *, child_col, &collection->children) {
948 if (child_col->collection->flag & COLLECTION_HIDE_RENDER) {
949 continue;
950 }
951 if (collection_preview_contains_geometry_recursive(child_col->collection)) {
952 return true;
953 }
954 }
955
956 return false;
957}
958
961/* -------------------------------------------------------------------- */
966{
967 Object *object = preview->active_object;
968 if (object == nullptr) {
969 WM_report(RPT_WARNING, "No active object, unable to apply the Action before rendering");
970 return nullptr;
971 }
972 if (object->pose == nullptr) {
974 "Object %s has no pose, unable to apply the Action before rendering",
975 object->id.name + 2);
976 return nullptr;
977 }
978
979 /* Create a backup of the current pose. */
980 bAction *action = (bAction *)preview->id;
981 PoseBackup *pose_backup = BKE_pose_backup_create_all_bones(object, action);
982
983 /* Apply the Action as pose, so that it can be rendered. This assumes the Action represents a
984 * single pose, and that thus the evaluation time doesn't matter. */
985 AnimationEvalContext anim_eval_context = {preview->depsgraph, 0.0f};
987 blender::animrig::pose_apply_action_all_bones(object, action, slot_handle, &anim_eval_context);
988
989 /* Force evaluation of the new pose, before the preview is rendered. */
992
993 return pose_backup;
994}
995
996static void action_preview_render_cleanup(IconPreview *preview, PoseBackup *pose_backup)
997{
998 if (pose_backup == nullptr) {
999 return;
1000 }
1001 BKE_pose_backup_restore(pose_backup);
1002 BKE_pose_backup_free(pose_backup);
1003
1005}
1006
1007/* Render a pose from the scene camera. It is assumed that the scene camera is
1008 * capturing the pose. The pose is applied temporarily to the current object
1009 * before rendering. */
1010static void action_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
1011{
1012 char err_out[256] = "";
1013
1014 Depsgraph *depsgraph = preview->depsgraph;
1015 /* Not all code paths that lead to this function actually provide a depsgraph.
1016 * The "Refresh Asset Preview" button (ED_OT_lib_id_generate_preview) does,
1017 * but WM_OT_previews_ensure does not. */
1018 BLI_assert(depsgraph != nullptr);
1020
1021 /* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */
1022 PoseBackup *pose_backup = action_preview_render_prepare(preview);
1023
1025 Object *camera_eval = scene_eval->camera;
1026 if (camera_eval == nullptr) {
1027 printf("Scene has no camera, unable to render preview of %s without it.\n",
1028 preview->id->name + 2);
1029 action_preview_render_cleanup(preview, pose_backup);
1030 return;
1031 }
1032
1033 /* This renders with the Workbench engine settings stored on the Scene. */
1035 scene_eval,
1036 nullptr,
1037 OB_SOLID,
1038 camera_eval,
1039 preview_sized->sizex,
1040 preview_sized->sizey,
1041 IB_rect,
1043 R_ADDSKY,
1044 nullptr,
1045 nullptr,
1046 nullptr,
1047 err_out);
1048
1049 action_preview_render_cleanup(preview, pose_backup);
1050
1051 if (err_out[0] != '\0') {
1052 printf("Error rendering Action %s preview: %s\n", preview->id->name + 2, err_out);
1053 }
1054
1055 if (ibuf) {
1056 icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
1057 IMB_freeImBuf(ibuf);
1058 }
1059}
1060
1063/* -------------------------------------------------------------------- */
1067/* inside thread, called by renderer, sets job update value */
1068static void shader_preview_update(void *spv, RenderResult * /*rr*/, rcti * /*rect*/)
1069{
1070 ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
1071
1072 *(sp->do_update) = true;
1073}
1074
1075/* called by renderer, checks job value */
1076static bool shader_preview_break(void *spv)
1077{
1078 ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
1079
1080 return *(sp->stop);
1081}
1082
1083static void shader_preview_updatejob(void * /*spv*/) {}
1084
1085/* Renders texture directly to render buffer. */
1087{
1088 /* Setup output buffer. */
1089 int width = sp->sizex;
1090 int height = sp->sizey;
1091
1092 /* This is needed otherwise no RenderResult is created. */
1093 sce->r.scemode &= ~R_BUTS_PREVIEW;
1094 RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr);
1095 RE_SetScene(re, sce);
1096
1097 /* Create buffer in empty RenderView created in the init step. */
1099 RenderView *rv = (RenderView *)rr->views.first;
1100 ImBuf *rv_ibuf = RE_RenderViewEnsureImBuf(rr, rv);
1102 static_cast<float *>(MEM_callocN(sizeof(float[4]) * width * height,
1103 "texture render result")),
1105 RE_ReleaseResult(re);
1106
1107 /* Get texture image pool (if any) */
1108 ImagePool *img_pool = BKE_image_pool_new();
1110
1111 /* Fill in image buffer. */
1112 float *rect_float = rv_ibuf->float_buffer.data;
1113 float tex_coord[3] = {0.0f, 0.0f, 0.0f};
1114
1115 for (int y = 0; y < height; y++) {
1116 /* Tex coords between -1.0f and 1.0f. */
1117 tex_coord[1] = (float(y) / float(height)) * 2.0f - 1.0f;
1118
1119 for (int x = 0; x < width; x++) {
1120 tex_coord[0] = (float(x) / float(height)) * 2.0f - 1.0f;
1121
1122 /* Evaluate texture at tex_coord. */
1123 TexResult texres = {0};
1124 BKE_texture_get_value_ex(tex, tex_coord, &texres, img_pool, true);
1125 copy_v4_fl4(rect_float,
1126 texres.trgba[0],
1127 texres.trgba[1],
1128 texres.trgba[2],
1129 texres.talpha ? texres.trgba[3] : 1.0f);
1130
1131 rect_float += 4;
1132 }
1133
1134 /* Check if we should cancel texture preview. */
1135 if (shader_preview_break(sp)) {
1136 break;
1137 }
1138 }
1139
1140 BKE_image_pool_free(img_pool);
1141}
1142
1143static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int first)
1144{
1145 Render *re;
1146 Scene *sce;
1147 float oldlens;
1148 short idtype = GS(id->name);
1149 char name[32];
1150 int sizex;
1151 Main *pr_main = sp->pr_main;
1152
1153 /* in case of split preview, use border render */
1154 if (split) {
1155 if (first) {
1156 sizex = sp->sizex / 2;
1157 }
1158 else {
1159 sizex = sp->sizex - sp->sizex / 2;
1160 }
1161 }
1162 else {
1163 sizex = sp->sizex;
1164 }
1165
1166 /* we have to set preview variables first */
1167 sce = preview_get_scene(pr_main);
1168 if (sce) {
1169 sce->r.xsch = sizex;
1170 sce->r.ysch = sp->sizey;
1171 sce->r.size = 100;
1172 }
1173
1174 /* get the stuff from the builtin preview dbase */
1175 sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
1176 if (sce == nullptr) {
1177 return;
1178 }
1179
1180 if (!split || first) {
1181 SNPRINTF(name, "Preview %p", sp->owner);
1182 }
1183 else {
1184 SNPRINTF(name, "SecondPreview %p", sp->owner);
1185 }
1186 re = RE_GetRender(name);
1187
1188 /* full refreshed render from first tile */
1189 if (re == nullptr) {
1190 re = RE_NewRender(name);
1191 }
1192
1193 /* sce->r gets copied in RE_InitState! */
1195 sce->r.scemode &= ~R_NO_IMAGE_LOAD;
1196
1197 if (sp->pr_method == PR_ICON_RENDER) {
1198 sce->r.scemode |= R_NO_IMAGE_LOAD;
1200 }
1201 else { /* PR_BUTS_RENDER */
1203 }
1204
1205 /* Callbacks are cleared on GetRender(). */
1206 if (sp->pr_method == PR_BUTS_RENDER) {
1208 }
1209 /* set this for all previews, default is react to G.is_break still */
1211
1212 /* lens adjust */
1213 oldlens = ((Camera *)sce->camera->data)->lens;
1214 if (sizex > sp->sizey) {
1215 ((Camera *)sce->camera->data)->lens *= float(sp->sizey) / float(sizex);
1216 }
1217
1218 /* entire cycle for render engine */
1219 if (idtype == ID_TE) {
1220 shader_preview_texture(sp, (Tex *)id, sce, re);
1221 }
1222 else {
1223 /* Render preview scene */
1224 RE_PreviewRender(re, pr_main, sce);
1225 }
1226
1227 ((Camera *)sce->camera->data)->lens = oldlens;
1228
1229 /* handle results */
1230 if (sp->pr_method == PR_ICON_RENDER) {
1231 // char *rct = (char *)(sp->pr_rect + 32 * 16 + 16);
1232
1233 if (sp->pr_rect) {
1234 RE_ResultGet32(re, sp->pr_rect);
1235 }
1236 }
1237
1238 /* unassign the pointers, reset vars */
1239 preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp);
1240
1241 /* XXX bad exception, end-exec is not being called in render, because it uses local main. */
1242#if 0
1243 if (idtype == ID_TE) {
1244 Tex *tex = (Tex *)id;
1245 if (tex->use_nodes && tex->nodetree)
1246 ntreeEndExecTree(tex->nodetree);
1247 }
1248#endif
1249}
1250
1251/* runs inside thread for material and icons */
1252static void shader_preview_startjob(void *customdata, bool *stop, bool *do_update)
1253{
1254 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1255
1256 sp->stop = stop;
1257 sp->do_update = do_update;
1258
1259 if (sp->parent) {
1260 shader_preview_render(sp, sp->id, 1, 1);
1261 shader_preview_render(sp, sp->parent, 1, 0);
1262 }
1263 else {
1264 shader_preview_render(sp, sp->id, 0, 0);
1265 }
1266
1267 *do_update = true;
1268}
1269
1270static void preview_id_copy_free(ID *id)
1271{
1272 IDProperty *properties;
1273 /* get rid of copied ID */
1274 properties = IDP_GetProperties(id);
1275 if (properties) {
1276 IDP_FreePropertyContent_ex(properties, false);
1277 MEM_freeN(properties);
1278 }
1280 MEM_freeN(id);
1281}
1282
1283static void shader_preview_free(void *customdata)
1284{
1285 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1286 Main *pr_main = sp->pr_main;
1287 ID *main_id_copy = nullptr;
1288 ID *sub_id_copy = nullptr;
1289
1290 if (sp->matcopy) {
1291 main_id_copy = (ID *)sp->matcopy;
1292 BLI_remlink(&pr_main->materials, sp->matcopy);
1293 }
1294 if (sp->texcopy) {
1295 BLI_assert(main_id_copy == nullptr);
1296 main_id_copy = (ID *)sp->texcopy;
1297 BLI_remlink(&pr_main->textures, sp->texcopy);
1298 }
1299 if (sp->worldcopy) {
1300 /* worldcopy is also created for material with `Preview World` enabled */
1301 if (main_id_copy) {
1302 sub_id_copy = (ID *)sp->worldcopy;
1303 }
1304 else {
1305 main_id_copy = (ID *)sp->worldcopy;
1306 }
1307 BLI_remlink(&pr_main->worlds, sp->worldcopy);
1308 }
1309 if (sp->lampcopy) {
1310 BLI_assert(main_id_copy == nullptr);
1311 main_id_copy = (ID *)sp->lampcopy;
1312 BLI_remlink(&pr_main->lights, sp->lampcopy);
1313 }
1314 if (sp->own_id_copy) {
1315 if (sp->id_copy) {
1317 }
1318 if (main_id_copy) {
1319 preview_id_copy_free(main_id_copy);
1320 }
1321 if (sub_id_copy) {
1322 preview_id_copy_free(sub_id_copy);
1323 }
1324 }
1325
1326 MEM_freeN(sp);
1327}
1328
1331/* -------------------------------------------------------------------- */
1336{
1337 if (!brush->icon_imbuf && (brush->flag & BRUSH_CUSTOM_ICON) && brush->icon_filepath[0]) {
1338 const int flags = IB_rect | IB_multilayer | IB_metadata;
1339
1340 /* First use the path directly to try and load the file. */
1341 char filepath[FILE_MAX];
1342
1343 STRNCPY(filepath, brush->icon_filepath);
1344 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
1345
1346 /* Use default color-spaces for brushes. */
1347 brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);
1348
1349 if (brush->icon_imbuf) {
1351 }
1352 }
1353
1354 if (!(brush->icon_imbuf)) {
1355 brush->id.icon_id = 0;
1356 }
1357
1358 return brush->icon_imbuf;
1359}
1360
1361static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
1362{
1363 ImBuf *ima;
1364 uint *drect, *srect;
1365 float scaledx, scaledy;
1366 short ex, ey, dx, dy;
1367
1368 /* paranoia test */
1369 if (ibuf == nullptr || (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr))
1370 {
1371 return;
1372 }
1373
1374 /* Waste of cpu cycles... but the imbuf API has no other way to scale fast (ton). */
1375 ima = IMB_dupImBuf(ibuf);
1376
1377 if (!ima) {
1378 return;
1379 }
1380
1381 if (ima->x > ima->y) {
1382 scaledx = float(w);
1383 scaledy = (float(ima->y) / float(ima->x)) * float(w);
1384 }
1385 else {
1386 scaledx = (float(ima->x) / float(ima->y)) * float(h);
1387 scaledy = float(h);
1388 }
1389
1390 /* Scaling down must never assign zero width/height, see: #89868. */
1391 ex = std::max(short(1), short(scaledx));
1392 ey = std::max(short(1), short(scaledy));
1393
1394 dx = (w - ex) / 2;
1395 dy = (h - ey) / 2;
1396
1397 IMB_scale(ima, ex, ey, IMBScaleFilter::Nearest, false);
1398
1399 /* if needed, convert to 32 bits */
1400 if (ima->byte_buffer.data == nullptr) {
1402 }
1403
1404 srect = reinterpret_cast<uint *>(ima->byte_buffer.data);
1405 drect = rect;
1406
1407 drect += dy * w + dx;
1408 for (; ey > 0; ey--) {
1409 memcpy(drect, srect, ex * sizeof(int));
1410 drect += w;
1411 srect += ima->x;
1412 }
1413
1414 IMB_freeImBuf(ima);
1415}
1416
1417static void set_alpha(char *cp, int sizex, int sizey, char alpha)
1418{
1419 int a, size = sizex * sizey;
1420
1421 for (a = 0; a < size; a++, cp += 4) {
1422 cp[3] = alpha;
1423 }
1424}
1425
1426static void icon_preview_startjob(void *customdata, bool *stop, bool *do_update)
1427{
1428 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1429
1430 if (sp->pr_method == PR_ICON_DEFERRED) {
1432 return;
1433 }
1434
1435 ID *id = sp->id;
1436 short idtype = GS(id->name);
1437
1438 BLI_assert(id != nullptr);
1439
1440 if (idtype == ID_IM) {
1441 Image *ima = (Image *)id;
1442 ImBuf *ibuf = nullptr;
1443 ImageUser iuser;
1444 BKE_imageuser_default(&iuser);
1445
1446 if (ima == nullptr) {
1447 return;
1448 }
1449
1450 /* setup dummy image user */
1451 iuser.framenr = 1;
1452 iuser.scene = sp->scene;
1453
1454 /* NOTE(@elubie): this needs to be changed: here image is always loaded if not
1455 * already there. Very expensive for large images. Need to find a way to
1456 * only get existing `ibuf`. */
1457 ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
1458 if (ibuf == nullptr ||
1459 (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr))
1460 {
1461 BKE_image_release_ibuf(ima, ibuf, nullptr);
1462 return;
1463 }
1464
1465 icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
1466
1467 *do_update = true;
1468
1469 BKE_image_release_ibuf(ima, ibuf, nullptr);
1470 }
1471 else if (idtype == ID_BR) {
1472 Brush *br = (Brush *)id;
1473
1475
1476 memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(uint));
1477
1478 if (!(br->icon_imbuf) || !(br->icon_imbuf->byte_buffer.data)) {
1479 return;
1480 }
1481
1482 icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
1483
1484 *do_update = true;
1485 }
1486 else {
1487 /* re-use shader job */
1488 shader_preview_startjob(customdata, stop, do_update);
1489
1490 /* world is rendered with alpha=0, so it wasn't displayed
1491 * this could be render option for sky to, for later */
1492 if (idtype == ID_WO) {
1493 set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
1494 }
1495 }
1496}
1497
1498/* use same function for icon & shader, so the job manager
1499 * does not run two of them at the same time. */
1500
1501static void common_preview_startjob(void *customdata, wmJobWorkerStatus *worker_status)
1502{
1503 ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
1504
1506 icon_preview_startjob(customdata, &worker_status->stop, &worker_status->do_update);
1507 }
1508 else {
1509 shader_preview_startjob(customdata, &worker_status->stop, &worker_status->do_update);
1510 }
1511}
1512
1518 IconPreviewSize *cur_size,
1519 const ePreviewRenderMethod pr_method,
1520 wmJobWorkerStatus *worker_status)
1521{
1522 ShaderPreview *sp = MEM_cnew<ShaderPreview>("Icon ShaderPreview");
1523
1524 /* These types don't use the ShaderPreview mess, they have their own types and functions. */
1525 BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
1526
1527 /* Construct shader preview from image size and preview custom-data. */
1528 sp->scene = ip->scene;
1529 sp->owner = ip->owner;
1530 sp->sizex = cur_size->sizex;
1531 sp->sizey = cur_size->sizey;
1532 sp->pr_method = pr_method;
1533 sp->pr_rect = cur_size->rect;
1534 sp->id = ip->id;
1535 sp->id_copy = ip->id_copy;
1536 sp->bmain = ip->bmain;
1537 sp->own_id_copy = false;
1538 Material *ma = nullptr;
1539
1540 if (sp->pr_method == PR_ICON_RENDER) {
1541 BLI_assert(ip->id);
1542
1543 /* grease pencil use its own preview file */
1544 if (GS(ip->id->name) == ID_MA) {
1545 ma = (Material *)ip->id;
1546 }
1547
1548 if ((ma == nullptr) || (ma->gp_style == nullptr)) {
1549 sp->pr_main = G.pr_main;
1550 }
1551 else {
1553 }
1554 }
1555
1556 common_preview_startjob(sp, worker_status);
1558}
1559
1560/* exported functions */
1561
1566 const PreviewImage *preview_image)
1567{
1568 for (int i = 0; i < NUM_ICON_SIZES; i++) {
1569 if ((preview_image->w[i] == icon_size->sizex) && (preview_image->h[i] == icon_size->sizey)) {
1570 return i;
1571 }
1572 }
1573
1574 BLI_assert_msg(0, "The searched icon size does not match any in the preview image");
1575 return -1;
1576}
1577
1578static void icon_preview_startjob_all_sizes(void *customdata, wmJobWorkerStatus *worker_status)
1579{
1580 IconPreview *ip = (IconPreview *)customdata;
1581
1582 LISTBASE_FOREACH (IconPreviewSize *, cur_size, &ip->sizes) {
1583 PreviewImage *prv = static_cast<PreviewImage *>(ip->owner);
1584 /* Is this a render job or a deferred loading job? */
1585 const ePreviewRenderMethod pr_method = (prv->runtime->deferred_loading_data) ?
1588
1589 if (worker_status->stop) {
1590 break;
1591 }
1592
1593 if (prv->runtime->tag & PRV_TAG_DEFFERED_DELETE) {
1594 /* Non-thread-protected reading is not an issue here. */
1595 continue;
1596 }
1597
1598 /* check_engine_supports_preview() checks whether the engine supports "preview mode" (think:
1599 * Material Preview). This check is only relevant when the render function called below is
1600 * going to use such a mode. Object and Action render functions use Solid mode, though, so
1601 * they can skip this test. */
1602 /* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
1603 * necessary to know here what happens inside lower-level functions. */
1604 const bool use_solid_render_mode = (ip->id != nullptr) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
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_cnew<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;
1730 };
1731
1733 ThreadQueue *todo_queue_; /* RequestedPreview * */
1736 std::list<RequestedPreview> requested_previews_;
1737
1738 public:
1741
1743 static void load_jobless(PreviewImage *preview, eIconSizes icon_size);
1744
1745 void push_load_request(PreviewImage *preview, eIconSizes icon_size);
1746
1747 private:
1748 static void run_fn(void *customdata, wmJobWorkerStatus *worker_status);
1749 static void update_fn(void *customdata);
1750 static void end_fn(void *customdata);
1751 static void free_fn(void *customdata);
1752
1754 static void finish_request(RequestedPreview &request);
1755};
1756
1758
1763
1765{
1766 wmJob *wm_job = WM_jobs_get(
1767 wm, win, nullptr, "Load Previews", eWM_JobFlag(0), WM_JOB_TYPE_LOAD_PREVIEW);
1768
1769 if (!WM_jobs_is_running(wm_job)) {
1770 PreviewLoadJob *job_data = MEM_new<PreviewLoadJob>("PreviewLoadJobData");
1771
1772 WM_jobs_customdata_set(wm_job, job_data, free_fn);
1773 WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
1774 WM_jobs_callbacks(wm_job, run_fn, nullptr, update_fn, end_fn);
1775
1776 WM_jobs_start(wm, wm_job);
1777 }
1778
1779 return *static_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job));
1780}
1781
1783{
1784 PreviewLoadJob job_data{};
1785
1786 job_data.push_load_request(preview, icon_size);
1787
1788 wmJobWorkerStatus worker_status = {};
1789 run_fn(&job_data, &worker_status);
1790 update_fn(&job_data);
1791 end_fn(&job_data);
1792}
1793
1795{
1796 BLI_assert(preview->runtime->deferred_loading_data);
1797 RequestedPreview requested_preview{};
1798 requested_preview.preview = preview;
1799 requested_preview.icon_size = icon_size;
1800
1801 preview->flag[icon_size] |= PRV_RENDERING;
1802 /* Warn main thread code that this preview is being rendered and cannot be freed. */
1803 preview->runtime->tag |= PRV_TAG_DEFFERED_RENDERING;
1804
1805 requested_previews_.push_back(requested_preview);
1806 BLI_thread_queue_push(todo_queue_, &requested_previews_.back());
1807}
1808
1809void PreviewLoadJob::run_fn(void *customdata, wmJobWorkerStatus *worker_status)
1810{
1811 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1812
1814
1815 while (RequestedPreview *request = static_cast<RequestedPreview *>(
1816 BLI_thread_queue_pop_timeout(job_data->todo_queue_, 100)))
1817 {
1818 if (worker_status->stop) {
1819 break;
1820 }
1821
1822 PreviewImage *preview = request->preview;
1823
1824 const std::optional<int> source = BKE_previewimg_deferred_thumb_source_get(preview);
1825 const char *filepath = BKE_previewimg_deferred_filepath_get(preview);
1826
1827 if (!source || !filepath) {
1828 continue;
1829 }
1830
1831 // printf("loading deferred %dx%d preview for %s\n", request->sizex, request->sizey, filepath);
1832
1833 IMB_thumb_path_lock(filepath);
1834 ImBuf *thumb = IMB_thumb_manage(filepath, THB_LARGE, ThumbSource(*source));
1835 IMB_thumb_path_unlock(filepath);
1836
1837 if (thumb) {
1838 /* PreviewImage assumes premultiplied alpha... */
1839 IMB_premultiply_alpha(thumb);
1840
1841 icon_copy_rect(thumb,
1842 preview->w[request->icon_size],
1843 preview->h[request->icon_size],
1844 preview->rect[request->icon_size]);
1845 IMB_freeImBuf(thumb);
1846 }
1847
1848 worker_status->do_update = true;
1849 }
1850
1852}
1853
1854/* Only execute on the main thread! */
1855void PreviewLoadJob::finish_request(RequestedPreview &request)
1856{
1857 PreviewImage *preview = request.preview;
1858
1859 preview->runtime->tag &= ~PRV_TAG_DEFFERED_RENDERING;
1860 BKE_previewimg_finish(preview, request.icon_size);
1861
1863 "Deferred releasing of preview images should only run on the main thread");
1864 if (preview->runtime->tag & PRV_TAG_DEFFERED_DELETE) {
1865 BLI_assert(preview->runtime->deferred_loading_data);
1867 }
1868}
1869
1870void PreviewLoadJob::update_fn(void *customdata)
1871{
1872 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1873
1874 for (auto request_it = job_data->requested_previews_.begin();
1875 request_it != job_data->requested_previews_.end();)
1876 {
1877 RequestedPreview &requested = *request_it;
1878 /* Skip items that are not done loading yet. */
1879 if (requested.preview->runtime->tag & PRV_TAG_DEFFERED_RENDERING) {
1880 ++request_it;
1881 continue;
1882 }
1883 finish_request(requested);
1884
1885 /* Remove properly finished previews from the job data. */
1886 auto next_it = job_data->requested_previews_.erase(request_it);
1887 request_it = next_it;
1888 }
1889}
1890
1891void PreviewLoadJob::end_fn(void *customdata)
1892{
1893 PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
1894
1895 /* Finish any possibly remaining queued previews. */
1896 for (RequestedPreview &request : job_data->requested_previews_) {
1897 finish_request(request);
1898 }
1899 job_data->requested_previews_.clear();
1900}
1901
1902void PreviewLoadJob::free_fn(void *customdata)
1903{
1904 MEM_delete(static_cast<PreviewLoadJob *>(customdata));
1905}
1906
1907static void icon_preview_free(void *customdata)
1908{
1909 IconPreview *ip = (IconPreview *)customdata;
1910
1911 if (ip->id_copy) {
1913 }
1914
1915 BLI_freelistN(&ip->sizes);
1916 MEM_freeN(ip);
1917}
1918
1919bool ED_preview_id_is_supported(const ID *id, const char **r_disabled_hint)
1920{
1921 if (id == nullptr) {
1922 return false;
1923 }
1924
1925 /* Get both the result and the "potential" disabled hint. After that we can decide if the
1926 * disabled hint needs to be returned to the caller. */
1927 const auto [result, disabled_hint] = [id]() -> std::pair<bool, const char *> {
1928 switch (GS(id->name)) {
1929 case ID_NT:
1930 return {false, RPT_("Node groups do not support automatic previews")};
1931 case ID_OB:
1932 return {object_preview_is_type_supported((const Object *)id),
1933 RPT_("Object type does not support automatic previews")};
1934 case ID_GR:
1935 return {
1937 RPT_("Collection does not contain object types that can be rendered for the automatic "
1938 "preview")};
1939 default:
1940 return {BKE_previewimg_id_get_p(id) != nullptr,
1941 RPT_("Data-block type does not support automatic previews")};
1942 }
1943 }();
1944
1945 if (result == false && disabled_hint && r_disabled_hint) {
1946 *r_disabled_hint = disabled_hint;
1947 }
1948
1949 return result;
1950}
1951
1953 const bContext *C, Scene *scene, PreviewImage *prv_img, ID *id, eIconSizes icon_size)
1954{
1955 /* Deferred loading of previews from the file system. */
1956 if (prv_img->runtime->deferred_loading_data) {
1957 if (prv_img->flag[icon_size] & PRV_RENDERING) {
1958 /* Already in the queue, don't add it again. */
1959 return;
1960 }
1961
1962 PreviewLoadJob::load_jobless(prv_img, icon_size);
1963 return;
1964 }
1965
1966 IconPreview ip = {nullptr};
1967
1969
1970 ip.bmain = CTX_data_main(C);
1971 ip.scene = scene;
1974 ip.id = id;
1975 /* Control isn't given back to the caller until the preview is done. So we don't need to copy
1976 * the ID to avoid thread races. */
1977 ip.id_copy = duplicate_ids(id, true);
1979
1980 prv_img->flag[icon_size] |= PRV_RENDERING;
1981
1983 &ip, prv_img->rect[icon_size], prv_img->w[icon_size], prv_img->h[icon_size]);
1984
1985 wmJobWorkerStatus worker_status = {};
1986 icon_preview_startjob_all_sizes(&ip, &worker_status);
1987
1989
1990 BLI_freelistN(&ip.sizes);
1991 if (ip.id_copy != nullptr) {
1993 }
1994}
1995
1997 const bContext *C, PreviewImage *prv_img, ID *id, eIconSizes icon_size, const bool delay)
1998{
1999 /* Deferred loading of previews from the file system. */
2000 if (prv_img->runtime->deferred_loading_data) {
2001 if (prv_img->flag[icon_size] & PRV_RENDERING) {
2002 /* Already in the queue, don't add it again. */
2003 return;
2004 }
2006 load_job.push_load_request(prv_img, icon_size);
2007
2008 return;
2009 }
2010
2011 IconPreview *ip, *old_ip;
2012
2014
2015 /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
2016 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
2017 CTX_wm_window(C),
2018 prv_img,
2019 "Icon Preview",
2022
2023 ip = MEM_cnew<IconPreview>("icon preview");
2024
2025 /* render all resolutions from suspended job too */
2026 old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job));
2027 if (old_ip) {
2028 BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
2029 }
2030
2031 /* customdata for preview thread */
2032 ip->bmain = CTX_data_main(C);
2036 ip->owner = prv_img;
2037 ip->id = id;
2038 ip->id_copy = duplicate_ids(id, false);
2039
2040 prv_img->flag[icon_size] |= PRV_RENDERING;
2041
2043 ip, prv_img->rect[icon_size], prv_img->w[icon_size], prv_img->h[icon_size]);
2044
2045 /* setup job */
2047 WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
2048 /* Wait 2s to start rendering icon previews, to not bog down user interaction.
2049 * Particularly important for heavy scenes and Eevee using OpenGL that blocks
2050 * the user interface drawing. */
2051 WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0);
2053 wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob);
2054
2055 WM_jobs_start(CTX_wm_manager(C), wm_job);
2056}
2057
2059 void *owner,
2060 ID *id,
2061 ID *parent,
2062 MTex *slot,
2063 int sizex,
2064 int sizey,
2065 ePreviewRenderMethod method)
2066{
2068 wmJob *wm_job;
2069 ShaderPreview *sp;
2070 Scene *scene = CTX_data_scene(C);
2071 const ID_Type id_type = GS(id->name);
2072
2074
2075 /* Use workspace render only for buttons Window,
2076 * since the other previews are related to the datablock. */
2077
2079 return;
2080 }
2081
2083
2084 wm_job = WM_jobs_get(CTX_wm_manager(C),
2085 CTX_wm_window(C),
2086 owner,
2087 "Shader Preview",
2090 sp = MEM_cnew<ShaderPreview>("shader preview");
2091
2092 /* customdata for preview thread */
2093 sp->scene = scene;
2094 sp->owner = owner;
2095 sp->sizex = sizex;
2096 sp->sizey = sizey;
2097 sp->pr_method = method;
2098 sp->id = id;
2099 sp->id_copy = duplicate_ids(id, false);
2100 sp->own_id_copy = true;
2101 sp->parent = parent;
2102 sp->slot = slot;
2103 sp->bmain = CTX_data_main(C);
2104 Material *ma = nullptr;
2105
2106 /* hardcoded preview .blend for Eevee + Cycles, this should be solved
2107 * once with custom preview .blend path for external engines */
2108
2109 /* grease pencil use its own preview file */
2110 if (id_type == ID_MA) {
2111 ma = (Material *)id;
2112 }
2113
2114 if ((ma == nullptr) || (ma->gp_style == nullptr)) {
2115 sp->pr_main = G.pr_main;
2116 }
2117 else {
2119 }
2120
2121 if (ob && ob->totcol) {
2122 copy_v4_v4(sp->color, ob->color);
2123 }
2124 else {
2125 ARRAY_SET_ITEMS(sp->color, 0.0f, 0.0f, 0.0f, 1.0f);
2126 }
2127
2128 /* setup job */
2130 WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
2132
2133 WM_jobs_start(CTX_wm_manager(C), wm_job);
2134}
2135
2137{
2138 if (wm) {
2139 /* This is called to stop all preview jobs before scene data changes, to
2140 * avoid invalid memory access. */
2142 }
2143}
2144
2151
2152static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
2153
2158
2160{
2161 PreviewRestartQueueEntry *queue_entry = MEM_cnew<PreviewRestartQueueEntry>(__func__);
2162 queue_entry->size = size;
2163 queue_entry->id = id;
2165}
2166
2168{
2170 PreviewImage *preview = BKE_previewimg_id_get(queue_entry->id);
2171 if (!preview) {
2172 continue;
2173 }
2174 if (preview->flag[queue_entry->size] & PRV_USER_EDITED) {
2175 /* Don't touch custom previews. */
2176 continue;
2177 }
2178
2179 BKE_previewimg_clear_single(preview, queue_entry->size);
2180 UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true);
2181
2183 }
2184}
2185
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:549
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:205
int BKE_icon_id_ensure(struct ID *id)
Definition icons.cc:268
void IDP_FreePropertyContent_ex(IDProperty *prop, bool do_id_user)
Definition idprop.cc:1189
IDProperty * IDP_GetProperties(ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition idprop.cc:875
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)
void BKE_imageuser_default(ImageUser *iuser)
ImagePool * BKE_image_pool_new(void)
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)
void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL()
@ LIB_ID_CREATE_LOCAL
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_NO_ANIMDATA
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
General operations, lookup, etc. for blender lights.
Main * BKE_main_new(void)
Definition main.cc:45
void BKE_main_free(Main *bmain)
Definition main.cc:175
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
General operations, lookup, etc. for materials.
struct Material *** BKE_object_material_array_p(struct 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(const struct Object *ob, 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:1954
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2568
void BKE_screen_view3d_shading_init(View3DShading *shading)
Definition screen.cc:976
void BKE_texture_fetch_images_for_pool(struct Tex *texture, struct ImagePool *pool)
Definition texture.cc:745
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:700
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
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:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
void BLI_thread_queue_push(ThreadQueue *queue, void *work)
Definition threads.cc:644
ThreadQueue * BLI_thread_queue_init(void)
Definition threads.cc:618
void BLI_thread_queue_free(ThreadQueue *queue)
Definition threads.cc:632
int BLI_thread_is_main(void)
Definition threads.cc:179
void * BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
Definition threads.cc:714
Platform independent time functions.
#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:273
void DEG_evaluate_on_refresh(Depsgraph *graph, DepsgraphEvaluateSyncWriteback sync_writeback=DEG_EVALUATE_SYNC_WRITEBACK_NO)
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:301
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)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ PRV_TAG_DEFFERED_DELETE
Definition DNA_ID.h:593
@ PRV_TAG_DEFFERED_RENDERING
Definition DNA_ID.h:591
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition DNA_ID.h:649
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ PRV_RENDERING
Definition DNA_ID.h:585
@ PRV_USER_EDITED
Definition DNA_ID.h:583
eIconSizes
@ 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.
@ 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)
@ R_MATNODE_PREVIEW
@ R_NO_IMAGE_LOAD
@ R_TEXNODE_PREVIEW
@ R_BUTS_PREVIEW
@ R_ADDSKY
@ R_ALPHAPREMUL
@ SCE_DISPLAY_AA_OFF
@ SCE_DISPLAY_AA_SAMPLES_8
@ 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])
void GPU_texture_free(GPUTexture *texture)
void IMB_premultiply_alpha(ImBuf *ibuf)
Definition filter.cc:579
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
ImBuf * IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
Definition readimage.cc:146
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:779
Contains defines and structs used throughout the imbuf module.
@ IB_TAKE_OWNERSHIP
@ IB_metadata
@ IB_multilayer
@ IB_rect
@ THB_LARGE
Definition IMB_thumbs.hh:21
void IMB_thumb_path_unlock(const char *path)
Definition thumbs.cc:718
ThumbSource
Definition IMB_thumbs.hh:25
void IMB_thumb_locks_acquire()
Definition thumbs.cc:671
ImBuf * IMB_thumb_manage(const char *file_or_lib_path, ThumbSize size, ThumbSource source)
Definition thumbs.cc:533
void IMB_thumb_path_lock(const char *path)
Definition thumbs.cc:702
void IMB_thumb_locks_release()
Definition thumbs.cc:687
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
@ RE_USE_PREVIEW
Definition RE_engine.h:48
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:1579
@ WM_JOB_TYPE_LOAD_PREVIEW
Definition WM_api.hh:1581
eWM_JobFlag
Definition WM_api.hh:1559
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1565
#define NC_WINDOW
Definition WM_types.hh:342
#define NC_BRUSH
Definition WM_types.hh:352
#define NA_EDITED
Definition WM_types.hh:550
#define NC_MATERIAL
Definition WM_types.hh:347
#define ND_SHADING_DRAW
Definition WM_types.hh:445
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 printf
const Depsgraph * depsgraph
#define offsetof(t, d)
draw_view in_light_buf[] float
void IMB_freeImBuf(ImBuf *)
uint tex_coord
RenderEngineType * RE_engines_find(const char *idname)
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#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_handle_t first_slot_handle(const ::bAction &dna_action)
decltype(::ActionSlot::handle) slot_handle_t
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 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)
static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
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)
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)
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:1610
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:413
int icon_id
Definition DNA_ID.h:436
char name[66]
Definition DNA_ID.h:425
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:210
ListBase textures
Definition BKE_main.hh:217
char filepath[1024]
Definition BKE_main.hh:136
ListBase lights
Definition BKE_main.hh:220
ListBase materials
Definition BKE_main.hh:216
ListBase worlds
Definition BKE_main.hh:224
ListBase screens
Definition BKE_main.hh:225
ListBase objects
Definition BKE_main.hh:212
struct PreviewImage * preview
struct MaterialGPencilStyle * gp_style
short transflag
struct Collection * instance_collection
float color[4]
PreviewImageRuntimeHandle * runtime
Definition DNA_ID.h:609
unsigned int h[2]
Definition DNA_ID.h:604
short flag[2]
Definition DNA_ID.h:605
unsigned int * rect[2]
Definition DNA_ID.h:607
unsigned int w[2]
Definition DNA_ID.h:603
PreviewRestartQueueEntry * prev
PreviewRestartQueueEntry * next
char engine[32]
ListBase views
struct ImBuf * ibuf
Definition RE_pipeline.h:52
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:88
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
ccl_device_inline int abs(int x)
Definition util/math.h:120
void WM_report(eReportType type, const char *message)
void WM_main_add_notifier(uint type, void *reference)
void WM_reportf(eReportType type, const char *format,...)
bool WM_jobs_is_running(const wmJob *wm_job)
Definition wm_jobs.cc:317
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:352
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:455
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:597
void * WM_jobs_customdata_get(wmJob *wm_job)
Definition wm_jobs.cc:328
void WM_jobs_delay_start(wmJob *wm_job, double delay_time)
Definition wm_jobs.cc:359
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:189
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:364
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336
void * WM_jobs_customdata_from_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:306