Blender V4.5
source/blender/blenkernel/intern/image.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cctype>
11#include <cmath>
12#include <cstdio>
13#include <cstring>
14#include <ctime>
15#include <fcntl.h>
16#include <optional>
17#ifndef WIN32
18# include <unistd.h>
19#else
20# include <io.h>
21#endif
22
23#include <regex>
24#include <string>
25
26#include "BLI_array.hh"
27#include "BLI_fileops.h"
28#include "BLI_listbase.h"
29#include "BLI_path_utils.hh"
30#include "BLI_rect.h"
31#include "BLI_string.h"
32#include "BLI_string_utils.hh"
33
34#include "CLG_log.h"
35
36#include "MEM_guardedalloc.h"
37
39#include "IMB_imbuf.hh"
40#include "IMB_imbuf_types.hh"
41#include "IMB_metadata.hh"
42#include "IMB_moviecache.hh"
43#include "IMB_openexr.hh"
44
45#include "MOV_read.hh"
46
47/* Allow using deprecated functionality for .blend file I/O. */
48#define DNA_DEPRECATED_ALLOW
49
50#include "DNA_brush_types.h"
51#include "DNA_camera_types.h"
52#include "DNA_defaults.h"
53#include "DNA_image_types.h"
54#include "DNA_light_types.h"
55#include "DNA_material_types.h"
56#include "DNA_object_types.h"
58#include "DNA_scene_types.h"
59#include "DNA_sequence_types.h"
60#include "DNA_userdef_types.h"
61#include "DNA_world_types.h"
62
63#include "BLI_math_vector.h"
64#include "BLI_mempool.h"
65#include "BLI_string_utf8.h"
66#include "BLI_system.h"
67#include "BLI_task.h"
68#include "BLI_threads.h"
69#include "BLI_time.h"
70#include "BLI_timecode.h" /* For stamp time-code format. */
71#include "BLI_utildefines.h"
72
73#include "BLT_translation.hh"
74
75#include "BKE_bpath.hh"
76#include "BKE_colortools.hh"
77#include "BKE_global.hh"
78#include "BKE_icons.h"
79#include "BKE_idtype.hh"
80#include "BKE_image.hh"
81#include "BKE_image_format.hh"
82#include "BKE_lib_id.hh"
83#include "BKE_library.hh"
84#include "BKE_main.hh"
85#include "BKE_node.hh"
87#include "BKE_node_runtime.hh"
89#include "BKE_packedFile.hh"
90#include "BKE_preview_image.hh"
91#include "BKE_report.hh"
92#include "BKE_scene.hh"
93#include "BKE_workspace.hh"
94
95#include "BLF_api.hh"
96
97#include "RE_pipeline.h"
98
99#include "SEQ_utils.hh" /* SEQ_get_topmost_sequence() */
100
101#include "GPU_material.hh"
102#include "GPU_texture.hh"
103
104#include "BLI_sys_types.h" /* for intptr_t support */
105
106#include "DEG_depsgraph.hh"
107#include "DEG_depsgraph_query.hh"
108
109#include "DRW_engine.hh"
110
111#include "BLO_read_write.hh"
112
113/* for image user iteration */
114#include "DNA_node_types.h"
115#include "DNA_screen_types.h"
116#include "DNA_space_types.h"
117
118using blender::Array;
119
120static CLG_LogRef LOG = {"bke.image"};
121
122static void image_init(Image *ima, short source, short type);
123static void image_free_packedfiles(Image *ima);
124static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src);
125
126/* -------------------------------------------------------------------- */
129
131{
132 if (image->runtime->partial_update_user != nullptr) {
133 BKE_image_partial_update_free(image->runtime->partial_update_user);
134 image->runtime->partial_update_user = nullptr;
135 }
137}
138
140{
141 ima->lastused = 0;
142 ima->gpuflag = 0;
147}
148
149static void image_init_data(ID *id)
150{
151 Image *image = (Image *)id;
152
153 if (image != nullptr) {
155 }
156}
157
158static void image_copy_data(Main * /*bmain*/,
159 std::optional<Library *> /*owner_library*/,
160 ID *id_dst,
161 const ID *id_src,
162 const int flag)
163{
164 Image *image_dst = (Image *)id_dst;
165 const Image *image_src = (const Image *)id_src;
166
168 &image_src->colorspace_settings);
169
170 copy_image_packedfiles(&image_dst->packedfiles, &image_src->packedfiles);
171
172 image_dst->stereo3d_format = static_cast<Stereo3dFormat *>(
173 MEM_dupallocN(image_src->stereo3d_format));
174 BLI_duplicatelist(&image_dst->views, &image_src->views);
175
176 /* Cleanup stuff that cannot be copied. */
177 image_dst->cache = nullptr;
178 image_dst->rr = nullptr;
179
180 BLI_duplicatelist(&image_dst->renderslots, &image_src->renderslots);
181 LISTBASE_FOREACH (RenderSlot *, slot, &image_dst->renderslots) {
182 slot->render = nullptr;
183 }
184
185 BLI_listbase_clear(&image_dst->anims);
186
187 BLI_duplicatelist(&image_dst->tiles, &image_src->tiles);
188
189 for (int eye = 0; eye < 2; eye++) {
190 for (int i = 0; i < TEXTARGET_COUNT; i++) {
191 image_dst->gputexture[i][eye] = nullptr;
192 }
193 }
194
195 if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
196 BKE_previewimg_id_copy(&image_dst->id, &image_src->id);
197 }
198 else {
199 image_dst->preview = nullptr;
200 }
201
202 image_dst->runtime = MEM_new<blender::bke::ImageRuntime>(__func__);
203}
204
205static void image_free_data(ID *id)
206{
207 Image *image = (Image *)id;
208
209 /* Also frees animations (#Image.anims list). */
211
213
214 LISTBASE_FOREACH (RenderSlot *, slot, &image->renderslots) {
215 if (slot->render) {
216 RE_FreeRenderResult(slot->render);
217 slot->render = nullptr;
218 }
219 }
220 BLI_freelistN(&image->renderslots);
221
224
225 BKE_icon_id_delete(&image->id);
227
228 BLI_freelistN(&image->tiles);
229
231 MEM_delete(image->runtime);
232}
233
234static void image_foreach_cache(ID *id,
235 IDTypeForeachCacheFunctionCallback function_callback,
236 void *user_data)
237{
238 Image *image = (Image *)id;
239 IDCacheKey key;
240 key.id_session_uid = id->session_uid;
241 key.identifier = offsetof(Image, cache);
242 function_callback(id, &key, (void **)&image->cache, 0, user_data);
243
244 key.identifier = offsetof(Image, anims.first);
245 function_callback(id, &key, &image->anims.first, 0, user_data);
246 key.identifier = offsetof(Image, anims.last);
247 function_callback(id, &key, &image->anims.last, 0, user_data);
248
249 auto gputexture_offset = [image](int target, int eye) {
250 constexpr size_t base_offset = offsetof(Image, gputexture);
251 GPUTexture **first = &image->gputexture[0][0];
252 const size_t array_offset = sizeof(*first) * (&image->gputexture[target][eye] - first);
253 return base_offset + array_offset;
254 };
255
256 for (int eye = 0; eye < 2; eye++) {
257 for (int a = 0; a < TEXTARGET_COUNT; a++) {
258 GPUTexture *texture = image->gputexture[a][eye];
259 if (texture == nullptr) {
260 continue;
261 }
262 key.identifier = gputexture_offset(a, eye);
263 function_callback(id, &key, (void **)&image->gputexture[a][eye], 0, user_data);
264 }
265 }
266
267 key.identifier = offsetof(Image, rr);
268 function_callback(id, &key, (void **)&image->rr, 0, user_data);
269
270 LISTBASE_FOREACH (RenderSlot *, slot, &image->renderslots) {
271 key.identifier = size_t(BLI_ghashutil_strhash_p(slot->name));
272 function_callback(id, &key, (void **)&slot->render, 0, user_data);
273 }
274}
275
276static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
277{
278 Image *ima = (Image *)id;
279 const eBPathForeachFlag flag = bpath_data->flag;
280
282 return;
283 }
284 /* Skip empty file paths, these are typically from generated images and
285 * don't make sense to add directories to until the image has been saved
286 * once to give it a meaningful value. */
287 /* TODO re-assess whether this behavior is desired in the new generic code context. */
289 ima->filepath[0] == '\0')
290 {
291 return;
292 }
293
294 /* If this is a tiled image, and we're asked to resolve the tokens in the virtual
295 * filepath, use the first tile to generate a concrete path for use during processing. */
296 bool result = false;
298 char temp_path[FILE_MAX], orig_file[FILE_MAXFILE];
299 STRNCPY(temp_path, ima->filepath);
300 BLI_path_split_file_part(temp_path, orig_file, sizeof(orig_file));
301
302 eUDIM_TILE_FORMAT tile_format;
303 char *udim_pattern = BKE_image_get_tile_strformat(temp_path, &tile_format);
305 temp_path, udim_pattern, tile_format, ((ImageTile *)ima->tiles.first)->tile_number);
306 MEM_SAFE_FREE(udim_pattern);
307
308 result = BKE_bpath_foreach_path_fixed_process(bpath_data, temp_path, sizeof(temp_path));
309 if (result) {
310 /* Put the filepath back together using the new directory and the original file name. */
311 char new_dir[FILE_MAXDIR];
312 BLI_path_split_dir_part(temp_path, new_dir, sizeof(new_dir));
313 BLI_path_join(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
314 }
315 }
316 else {
318 bpath_data, ima->filepath, sizeof(ima->filepath));
319 }
320
321 if (result) {
323 if (!BKE_image_has_packedfile(ima) &&
324 /* Image may have been painted onto (and not saved, #44543). */
325 !BKE_image_is_dirty(ima))
326 {
327 BKE_image_signal(bpath_data->bmain, ima, nullptr, IMA_SIGNAL_RELOAD);
328 }
329 }
330 }
331}
332
333static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address)
334{
335 Image *ima = (Image *)id;
336 const bool is_undo = BLO_write_is_undo(writer);
337
338 /* Clear all data that isn't read to reduce false detection of changed image during memfile undo.
339 */
340 ima->cache = nullptr;
343 for (int i = 0; i < 3; i++) {
344 for (int j = 0; j < 2; j++) {
345 ima->gputexture[i][j] = nullptr;
346 }
347 }
348
349 ImagePackedFile *imapf;
350
351 BLI_assert(ima->packedfile == nullptr);
352 if (!is_undo) {
353 /* Do not store packed files in case this is a library override ID. */
354 if (ID_IS_OVERRIDE_LIBRARY(ima)) {
356 }
357 else {
358 /* Some trickery to keep forward compatibility of packed images. */
359 if (ima->packedfiles.first != nullptr) {
360 imapf = static_cast<ImagePackedFile *>(ima->packedfiles.first);
361 ima->packedfile = imapf->packedfile;
362 }
363 }
364 }
365
366 /* write LibData */
367 BLO_write_id_struct(writer, Image, id_address, &ima->id);
368 BKE_id_blend_write(writer, &ima->id);
369
371 BLO_write_struct(writer, ImagePackedFile, imapf);
373 }
374
376
377 LISTBASE_FOREACH (ImageView *, iv, &ima->views) {
378 BLO_write_struct(writer, ImageView, iv);
379 }
381
382 BLO_write_struct_list(writer, ImageTile, &ima->tiles);
383
384 ima->packedfile = nullptr;
385
387}
388
389static void image_blend_read_data(BlendDataReader *reader, ID *id)
390{
391 Image *ima = (Image *)id;
392 BLO_read_struct_list(reader, ImageTile, &ima->tiles);
393
395 if (!BLO_read_data_is_undo(reader)) {
396 /* We reset this last render slot index only when actually reading a file, not for undo. */
397 ima->last_render_slot = ima->render_slot;
398 }
399
400 BLO_read_struct_list(reader, ImageView, &(ima->views));
402
403 if (ima->packedfiles.first) {
405 BKE_packedfile_blend_read(reader, &imapf->packedfile, imapf->filepath);
406 if (!imapf->packedfile) {
407 BLI_remlink(&ima->packedfiles, imapf);
408 MEM_freeN(imapf);
409 }
410 }
411 ima->packedfile = nullptr;
412 }
413 else {
414 BKE_packedfile_blend_read(reader, &ima->packedfile, ima->filepath);
415 }
416
418 BLO_read_struct(reader, PreviewImage, &ima->preview);
421
423 ima->runtime = MEM_new<blender::bke::ImageRuntime>(__func__);
424}
425
427{
428 Image *ima = reinterpret_cast<Image *>(id);
429
430 /* Images have some kind of 'main' cache, when null we should also clear all others. */
431 /* Needs to be done *after* cache pointers are restored (call to
432 * `foreach_cache`/`blo_cache_storage_entry_restore_in_new`), easier for now to do it in
433 * lib_link... */
434 if (ima->cache == nullptr) {
436 }
437}
438
440{
441 IDTypeInfo info{};
442 info.id_code = ID_IM;
443 info.id_filter = FILTER_ID_IM;
444 info.dependencies_id_types = 0;
446 info.struct_size = sizeof(Image);
447 info.name = "Image";
448 info.name_plural = "images";
451 info.asset_type_info = nullptr;
452
456 info.make_local = nullptr;
457 info.foreach_id = nullptr;
460 info.owner_pointer_get = nullptr;
461
465
466 info.blend_read_undo_preserve = nullptr;
467
468 info.lib_override_apply_post = nullptr;
469 return info;
470}
472
473/* prototypes */
474static int image_num_viewfiles(Image *ima);
476 Image *ima, ImageUser *iuser, int entry, int cfra, bool is_sequence);
477static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock);
478static void image_update_views_format(Image *ima, ImageUser *iuser);
479static void image_add_view(Image *ima, const char *viewname, const char *filepath);
480
481/* max int, to indicate we don't store sequences in ibuf */
482#define IMA_NO_INDEX 0x7FEFEFEF
483
484/* quick lookup: supports 1 million entries, thousand passes */
485#define IMA_MAKE_INDEX(entry, index) (((entry) << 10) + (index))
486#define IMA_INDEX_ENTRY(index) ((index) >> 10)
487#if 0
488# define IMA_INDEX_PASS(index) (index & ~1023)
489#endif
490
492
493/* -------------------------------------------------------------------- */
496
498 int index;
499};
500
501static uint imagecache_hashhash(const void *key_v)
502{
503 const ImageCacheKey *key = static_cast<const ImageCacheKey *>(key_v);
504 return key->index;
505}
506
507static bool imagecache_hashcmp(const void *a_v, const void *b_v)
508{
509 const ImageCacheKey *a = static_cast<const ImageCacheKey *>(a_v);
510 const ImageCacheKey *b = static_cast<const ImageCacheKey *>(b_v);
511
512 return (a->index != b->index);
513}
514
515static void imagecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags)
516{
517 ImageCacheKey *key = static_cast<ImageCacheKey *>(userkey);
518
519 *framenr = IMA_INDEX_ENTRY(key->index);
520 *proxy = IMB_PROXY_NONE;
521 *render_flags = 0;
522}
523
524static void imagecache_put(Image *image, int index, ImBuf *ibuf)
525{
526 ImageCacheKey key;
527
528 if (image->cache == nullptr) {
529 // char cache_name[64];
530 // SNPRINTF(cache_name, "Image Datablock %s", image->id.name);
531
533 "Image Datablock Cache", sizeof(ImageCacheKey), imagecache_hashhash, imagecache_hashcmp);
535 }
536
537 key.index = index;
538
539 IMB_moviecache_put(image->cache, &key, ibuf);
540}
541
542static void imagecache_remove(Image *image, int index)
543{
544 if (image->cache == nullptr) {
545 return;
546 }
547
548 ImageCacheKey key;
549 key.index = index;
550 IMB_moviecache_remove(image->cache, &key);
551}
552
553static ImBuf *imagecache_get(Image *image, int index, bool *r_is_cached_empty)
554{
555 if (image->cache) {
556 ImageCacheKey key;
557 key.index = index;
558 return IMB_moviecache_get(image->cache, &key, r_is_cached_empty);
559 }
560
561 return nullptr;
562}
563
565
566/* -------------------------------------------------------------------- */
569
571{
572 if (image->cache) {
574 image->cache = nullptr;
575 }
576}
577
579{
580 while (ima->packedfiles.last) {
581 ImagePackedFile *imapf = static_cast<ImagePackedFile *>(ima->packedfiles.last);
582 if (imapf->packedfile) {
584 }
585 BLI_remlink(&ima->packedfiles, imapf);
586 MEM_freeN(imapf);
587 }
588}
589
594
596{
597 BLI_freelistN(&image->views);
598}
599
600static void image_free_anims(Image *ima)
601{
602 while (ima->anims.last) {
603 ImageAnim *ia = static_cast<ImageAnim *>(ima->anims.last);
604 if (ia->anim) {
605 MOV_close(ia->anim);
606 ia->anim = nullptr;
607 }
608 BLI_remlink(&ima->anims, ia);
609 MEM_freeN(ia);
610 }
611}
612
613void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
614{
615 if (do_lock) {
616 ima->runtime->cache_mutex.lock();
617 }
619
620 image_free_anims(ima);
621
622 if (ima->rr) {
624 ima->rr = nullptr;
625 }
626
628
629 if (do_lock) {
630 ima->runtime->cache_mutex.unlock();
631 }
632}
633
635{
636 BKE_image_free_buffers_ex(ima, false);
637}
638
640{
641 image_free_data(&ima->id);
642}
643
644static ImageTile *imagetile_alloc(int tile_number)
645{
646 ImageTile *tile = MEM_callocN<ImageTile>("Image Tile");
647 tile->tile_number = tile_number;
648 tile->gen_x = 1024;
649 tile->gen_y = 1024;
650 tile->gen_type = IMA_GENTYPE_GRID;
651 return tile;
652}
653
654/* only image block itself */
655static void image_init(Image *ima, short source, short type)
656{
658
660
661 ima->source = source;
662 ima->type = type;
663
664 if (source == IMA_SRC_VIEWER) {
665 ima->flag |= IMA_VIEW_AS_RENDER;
666 }
667
669 BLI_addtail(&ima->tiles, tile);
670
671 if (type == IMA_TYPE_R_RESULT) {
672 for (int i = 0; i < 8; i++) {
673 BKE_image_add_renderslot(ima, nullptr);
674 }
675 }
676
677 ima->runtime = MEM_new<blender::bke::ImageRuntime>(__func__);
678
680 ima->stereo3d_format = MEM_callocN<Stereo3dFormat>("Image Stereo Format");
681}
682
683static Image *image_alloc(Main *bmain,
684 std::optional<Library *> owner_library,
685 const char *name,
686 short source,
687 short type)
688{
689 Image *ima;
690
691 ima = static_cast<Image *>(BKE_libblock_alloc_in_lib(bmain, owner_library, ID_IM, name, 0));
692 if (ima) {
693 image_init(ima, source, type);
694 }
695
696 return ima;
697}
698
707 int index,
708 int entry,
709 bool *r_is_cached_empty)
710{
711 if (index != IMA_NO_INDEX) {
712 index = IMA_MAKE_INDEX(entry, index);
713 }
714
715 return imagecache_get(ima, index, r_is_cached_empty);
716}
717
718static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int entry)
719{
720 if (index != IMA_NO_INDEX) {
721 index = IMA_MAKE_INDEX(entry, index);
722 }
723
724 imagecache_put(ima, index, ibuf);
725}
726
727static void image_remove_ibuf(Image *ima, int index, int entry)
728{
729 if (index != IMA_NO_INDEX) {
730 index = IMA_MAKE_INDEX(entry, index);
731 }
732 imagecache_remove(ima, index);
733}
734
735static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
736{
737 const ImagePackedFile *imapf_src;
738
739 BLI_listbase_clear(lb_dst);
740 for (imapf_src = static_cast<const ImagePackedFile *>(lb_src->first); imapf_src;
741 imapf_src = imapf_src->next)
742 {
743 ImagePackedFile *imapf_dst = MEM_mallocN<ImagePackedFile>("Image Packed Files (copy)");
744
745 imapf_dst->view = imapf_src->view;
746 imapf_dst->tile_number = imapf_src->tile_number;
747 STRNCPY(imapf_dst->filepath, imapf_src->filepath);
748
749 if (imapf_src->packedfile) {
750 imapf_dst->packedfile = BKE_packedfile_duplicate(imapf_src->packedfile);
751 }
752
753 BLI_addtail(lb_dst, imapf_dst);
754 }
755}
756
757void BKE_image_merge(Main *bmain, Image *dest, Image *source)
758{
759 /* sanity check */
760 if (dest && source && dest != source) {
761 {
762 std::scoped_lock lock_src(source->runtime->cache_mutex);
763 std::scoped_lock lock_dst(dest->runtime->cache_mutex);
764
765 if (source->cache != nullptr) {
766 MovieCacheIter *iter;
767 iter = IMB_moviecacheIter_new(source->cache);
768 while (!IMB_moviecacheIter_done(iter)) {
770 ImageCacheKey *key = static_cast<ImageCacheKey *>(IMB_moviecacheIter_getUserKey(iter));
771 imagecache_put(dest, key->index, ibuf);
773 }
775 }
776 }
777 BKE_id_free(bmain, source);
778 }
779}
780
781bool BKE_image_scale(Image *image, int width, int height, ImageUser *iuser)
782{
783 /* NOTE: We could be clever and scale all imbuf's
784 * but since some are mipmaps its not so simple. */
785
786 ImBuf *ibuf;
787 void *lock;
788
789 ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
790
791 if (ibuf) {
792 IMB_scale(ibuf, width, height, IMBScaleFilter::Box, false);
793 BKE_image_mark_dirty(image, ibuf);
794 }
795
796 BKE_image_release_ibuf(image, ibuf, lock);
797
798 return (ibuf != nullptr);
799}
800
802{
803 for (int eye = 0; eye < 2; eye++) {
804 for (int i = 0; i < TEXTARGET_COUNT; i++) {
805 if (ima->gputexture[i][eye] != nullptr) {
806 return true;
807 }
808 }
809 }
810 return false;
811}
812
813static int image_get_tile_number_from_iuser(const Image *ima, const ImageUser *iuser)
814{
815 BLI_assert(ima != nullptr && ima->tiles.first);
816 ImageTile *tile = static_cast<ImageTile *>(ima->tiles.first);
817 return (iuser && iuser->tile) ? iuser->tile : tile->tile_number;
818}
819
820ImageTile *BKE_image_get_tile(Image *ima, int tile_number)
821{
822 if (ima == nullptr) {
823 return nullptr;
824 }
825
826 /* Tiles 0 and 1001 are a special case and refer to the first tile, typically
827 * coming from non-UDIM-aware code. */
828 if (ELEM(tile_number, 0, 1001)) {
829 return static_cast<ImageTile *>(ima->tiles.first);
830 }
831
832 /* Must have a tiled image and a valid tile number at this point. */
833 if (ima->source != IMA_SRC_TILED || tile_number < 1001 || tile_number > IMA_UDIM_MAX) {
834 return nullptr;
835 }
836
838 if (tile->tile_number == tile_number) {
839 return tile;
840 }
841 }
842
843 return nullptr;
844}
845
850
851int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
852{
853 float local_ofs[2];
854 if (r_ofs == nullptr) {
855 r_ofs = local_ofs;
856 }
857
858 copy_v2_v2(r_uv, uv);
859 zero_v2(r_ofs);
860
861 if ((ima->source != IMA_SRC_TILED) || uv[0] < 0.0f || uv[1] < 0.0f || uv[0] >= 10.0f) {
862 return 0;
863 }
864
865 int ix = int(uv[0]);
866 int iy = int(uv[1]);
867 int tile_number = 1001 + 10 * iy + ix;
868
869 if (BKE_image_get_tile(ima, tile_number) == nullptr) {
870 return 0;
871 }
872 r_ofs[0] = ix;
873 r_ofs[1] = iy;
874 sub_v2_v2(r_uv, r_ofs);
875
876 return tile_number;
877}
878
879void BKE_image_get_tile_uv(const Image *ima, const int tile_number, float r_uv[2])
880{
881 if (ima->source != IMA_SRC_TILED) {
882 zero_v2(r_uv);
883 }
884 else {
885 const int tile_index = tile_number - 1001;
886 r_uv[0] = float(tile_index % 10);
887 r_uv[1] = float(tile_index / 10);
888 }
889}
890
892static float distance_to_unit_interval(float x)
893{
894 /* The unit interval is between 0 and 1.
895 * Within the interval, return 0.
896 * Outside the interval, return the distance to the nearest boundary.
897 * Intuitively, the function looks like:
898 * \ | | /
899 * __\|___|/__
900 * 0 1
901 */
902
903 if (x <= 0.0f) {
904 return -x; /* Distance to left border. */
905 }
906 if (x <= 1.0f) {
907 return 0.0f; /* Inside unit interval. */
908 }
909 return x - 1.0f; /* Distance to right border. */
910}
911
913static float distance_squared_to_udim(const float co[2], const float udim[2])
914{
915 float delta[2];
916 sub_v2_v2v2(delta, co, udim);
917 delta[0] = distance_to_unit_interval(delta[0]);
918 delta[1] = distance_to_unit_interval(delta[1]);
919 return len_squared_v2(delta);
920}
921
922static bool nearest_udim_tile_tie_break(const float best_dist_sq,
923 const float best_uv[2],
924 const float dist_sq,
925 const float uv[2])
926{
927 if (best_dist_sq == dist_sq) { /* Exact same distance? Tie-break. */
928 if (best_uv[0] == uv[0]) { /* Exact same U? Tie-break. */
929 return (uv[1] > best_uv[1]); /* Higher than previous candidate? */
930 }
931 return (uv[0] > best_uv[0]); /* Further right than previous candidate? */
932 }
933 return (dist_sq < best_dist_sq); /* Closer than previous candidate? */
934}
935
937 const float co[2],
938 float r_uv_offset[2])
939{
940 /* NOTE: If the co-ordinates are integers, take special care to break ties. */
941
942 zero_v2(r_uv_offset);
943 int tile_number_best = -1;
944
945 if (!image || image->source != IMA_SRC_TILED) {
946 return tile_number_best;
947 }
948
949 /* Distance squared to the closest UDIM tile. */
950 float dist_best_sq = FLT_MAX;
951
952 LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
953 float uv_offset[2];
954 BKE_image_get_tile_uv(image, tile->tile_number, uv_offset);
955
956 /* Distance squared between #co and closest point on UDIM tile. */
957 const float dist_sq = distance_squared_to_udim(co, uv_offset);
958
959 if (dist_sq == 0) { /* Either inside in the UDIM, or on its boundary. */
960 if (floorf(co[0]) == uv_offset[0] && floorf(co[1]) == uv_offset[1]) {
961 /* Within the half-open interval of the UDIM. */
962 copy_v2_v2(r_uv_offset, uv_offset);
963 return tile_number_best;
964 }
965 }
966
967 if (nearest_udim_tile_tie_break(dist_best_sq, r_uv_offset, dist_sq, uv_offset)) {
968 /* Tile is better than previous best, update. */
969 dist_best_sq = dist_sq;
970 copy_v2_v2(r_uv_offset, uv_offset);
971 tile_number_best = tile->tile_number;
972 }
973 }
974 return tile_number_best;
975}
976
977int BKE_image_find_nearest_tile(const Image *image, const float co[2])
978{
979 float uv_offset_dummy[2];
980 return BKE_image_find_nearest_tile_with_offset(image, co, uv_offset_dummy);
981}
982
984{
985 ImBuf *ibuf;
986 char filepath[FILE_MAX];
987
988 BKE_image_user_file_path(nullptr, ima, filepath);
989
990 /* Will set input color space to image format default's. */
993
994 if (ibuf) {
995 if (ibuf->flags & IB_alphamode_premul) {
997 }
998 else if (ibuf->flags & IB_alphamode_channel_packed) {
1000 }
1001 else if (ibuf->flags & IB_alphamode_ignore) {
1003 }
1004 else {
1006 }
1007
1008 IMB_freeImBuf(ibuf);
1009 }
1010}
1011
1013{
1014 if (BLI_path_extension_check_n(filepath, ".exr", ".cin", ".dpx", ".hdr", nullptr)) {
1015 return IMA_ALPHA_PREMUL;
1016 }
1017
1018 return IMA_ALPHA_STRAIGHT;
1019}
1020
1025
1026static void image_abs_path(Main *bmain,
1027 Library *owner_library,
1028 const char *filepath,
1029 char *r_filepath_abs)
1030{
1031 BLI_strncpy(r_filepath_abs, filepath, FILE_MAX);
1032 if (owner_library) {
1033 BLI_path_abs(r_filepath_abs, owner_library->runtime->filepath_abs);
1034 }
1035 else {
1036 BLI_path_abs(r_filepath_abs, BKE_main_blendfile_path(bmain));
1037 }
1038}
1039
1040Image *BKE_image_load(Main *bmain, const char *filepath)
1041{
1042 return BKE_image_load_in_lib(bmain, std::nullopt, filepath);
1043}
1044
1046 std::optional<Library *> owner_library,
1047 const char *filepath)
1048{
1049 Image *ima;
1050 int file;
1051 char filepath_abs[FILE_MAX];
1052
1053 /* If no owner library is explicitly given, use the current library from the given #Main. */
1054 Library *owner_lib = owner_library.value_or(bmain->curlib);
1055
1056 image_abs_path(bmain, owner_lib, filepath, filepath_abs);
1057
1058 /* exists? */
1059 file = BLI_open(filepath_abs, O_BINARY | O_RDONLY, 0);
1060 if (file == -1) {
1061 if (!BKE_image_tile_filepath_exists(filepath_abs)) {
1062 return nullptr;
1063 }
1064 }
1065 else {
1066 close(file);
1067 }
1068
1069 ima = image_alloc(
1070 bmain, owner_library, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
1071 STRNCPY(ima->filepath, filepath);
1072
1074 ima->source = IMA_SRC_MOVIE;
1075 }
1076
1078
1079 return ima;
1080}
1081
1082Image *BKE_image_load_exists(Main *bmain, const char *filepath, bool *r_exists)
1083{
1084 return BKE_image_load_exists_in_lib(bmain, std::nullopt, filepath, r_exists);
1085}
1086
1088 std::optional<Library *> owner_library,
1089 const char *filepath,
1090 bool *r_exists)
1091{
1092 Image *ima;
1093 char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
1094
1095 /* If not owner library is explicitly given, use the current library from the given Main. */
1096 Library *owner_lib = owner_library.value_or(bmain->curlib);
1097
1098 image_abs_path(bmain, owner_lib, filepath, filepath_abs);
1099
1100 /* First search an identical filepath. */
1101 for (ima = static_cast<Image *>(bmain->images.first); ima;
1102 ima = static_cast<Image *>(ima->id.next))
1103 {
1105 STRNCPY(filepath_test, ima->filepath);
1106 BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &ima->id));
1107
1108 if (BLI_path_cmp(filepath_test, filepath_abs) != 0) {
1109 continue;
1110 }
1111 if (BKE_image_has_anim(ima) && (ima->id.us != 0)) {
1112 /* TODO explain why animated images with already one or more users are skipped? */
1113 continue;
1114 }
1115 if (ima->id.lib != owner_lib) {
1116 continue;
1117 }
1118 /* FIXME Should not happen here. Only code actually adding an ID usage should increment this
1119 * counter. */
1120 id_us_plus(&ima->id);
1121 if (r_exists) {
1122 *r_exists = true;
1123 }
1124 return ima;
1125 }
1126 }
1127
1128 if (r_exists) {
1129 *r_exists = false;
1130 }
1131 return BKE_image_load_in_lib(bmain, owner_library, filepath);
1132}
1133
1142
1143static void image_buf_fill_isolated(void *usersata_v)
1144{
1145 ImageFillData *usersata = static_cast<ImageFillData *>(usersata_v);
1146
1147 const short gen_type = usersata->gen_type;
1148 const uint width = usersata->width;
1149 const uint height = usersata->height;
1150
1151 uchar *rect = usersata->rect;
1152 float *rect_float = usersata->rect_float;
1153
1154 switch (gen_type) {
1155 case IMA_GENTYPE_GRID:
1156 BKE_image_buf_fill_checker(rect, rect_float, width, height);
1157 break;
1159 BKE_image_buf_fill_checker_color(rect, rect_float, width, height);
1160 break;
1161 default:
1162 BKE_image_buf_fill_color(rect, rect_float, width, height, usersata->fill_color);
1163 break;
1164 }
1165}
1166
1168{
1169 ImBuf *ibuf;
1170 uchar *rect = nullptr;
1171 float *rect_float = nullptr;
1172 float fill_color[4];
1173
1174 const bool floatbuf = (tile->gen_flag & IMA_GEN_FLOAT) != 0;
1175 if (floatbuf) {
1176 ibuf = IMB_allocImBuf(tile->gen_x, tile->gen_y, tile->gen_depth, IB_float_data);
1177
1178 if (ima->colorspace_settings.name[0] == '\0') {
1179 const char *colorspace = IMB_colormanagement_role_colorspace_name_get(
1181
1182 STRNCPY(ima->colorspace_settings.name, colorspace);
1183 }
1184
1185 if (ibuf != nullptr) {
1186 rect_float = ibuf->float_buffer.data;
1188 }
1189
1191 copy_v4_v4(fill_color, tile->gen_color);
1192 }
1193 else {
1194 /* The input color here should ideally be linear already, but for now
1195 * we just convert and postpone breaking the API for later. */
1196 srgb_to_linearrgb_v4(fill_color, tile->gen_color);
1197 }
1198 }
1199 else {
1200 ibuf = IMB_allocImBuf(tile->gen_x, tile->gen_y, tile->gen_depth, IB_byte_data);
1201
1202 if (ima->colorspace_settings.name[0] == '\0') {
1203 const char *colorspace = IMB_colormanagement_role_colorspace_name_get(
1205
1206 STRNCPY(ima->colorspace_settings.name, colorspace);
1207 }
1208
1209 if (ibuf != nullptr) {
1210 rect = ibuf->byte_buffer.data;
1212 }
1213
1214 copy_v4_v4(fill_color, tile->gen_color);
1215 }
1216
1217 if (!ibuf) {
1218 return nullptr;
1219 }
1220
1221 STRNCPY(ibuf->filepath, ima->filepath);
1223
1224 /* Mark the tile itself as having been generated. */
1225 tile->gen_flag |= IMA_GEN_TILE;
1226
1228
1229 data.gen_type = tile->gen_type;
1230 data.width = tile->gen_x;
1231 data.height = tile->gen_y;
1232 data.rect = rect;
1233 data.rect_float = rect_float;
1234 copy_v4_v4(data.fill_color, fill_color);
1235
1237
1238 return ibuf;
1239}
1240
1242 uint width,
1243 uint height,
1244 const char *name,
1245 int depth,
1246 int floatbuf,
1247 short gen_type,
1248 const float color[4],
1249 const bool stereo3d,
1250 const bool is_data,
1251 const bool tiled)
1252{
1253 /* Saving the image changes it's #Image.source to #IMA_SRC_FILE (leave as generated here). */
1254 Image *ima;
1255 if (tiled) {
1256 ima = image_alloc(bmain, std::nullopt, name, IMA_SRC_TILED, IMA_TYPE_IMAGE);
1257 }
1258 else {
1259 ima = image_alloc(bmain, std::nullopt, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
1260 }
1261 if (ima == nullptr) {
1262 return nullptr;
1263 }
1264
1265 int view_id;
1266 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
1267
1268 /* NOTE: leave `ima->filepath` unset,
1269 * setting it to a dummy value may write to an invalid file-path. */
1270
1271 /* The generation info is always stored in the tiles. The first tile
1272 * will be used for non-tiled images. */
1273 ImageTile *tile = static_cast<ImageTile *>(ima->tiles.first);
1274 tile->gen_x = width;
1275 tile->gen_y = height;
1276 tile->gen_type = gen_type;
1277 tile->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0);
1278 tile->gen_depth = depth;
1279 copy_v4_v4(tile->gen_color, color);
1280
1281 if (is_data) {
1284 }
1285
1286 for (view_id = 0; view_id < 2; view_id++) {
1287 ImBuf *ibuf;
1288 ibuf = add_ibuf_for_tile(ima, tile);
1289 int index = tiled ? 0 : IMA_NO_INDEX;
1290 int entry = tiled ? 1001 : 0;
1291 image_assign_ibuf(ima, ibuf, stereo3d ? view_id : index, entry);
1292
1293 /* #image_assign_ibuf puts buffer to the cache, which increments user counter. */
1294 IMB_freeImBuf(ibuf);
1295 if (!stereo3d) {
1296 break;
1297 }
1298
1299 image_add_view(ima, names[view_id], "");
1300 }
1301
1302 return ima;
1303}
1304
1305static void image_colorspace_from_imbuf(Image *image, const ImBuf *ibuf)
1306{
1307 const char *colorspace_name = nullptr;
1308
1309 if (ibuf->float_buffer.data) {
1310 if (ibuf->float_buffer.colorspace) {
1312 }
1313 else {
1315 }
1316 }
1317
1318 if (ibuf->byte_buffer.data && !colorspace_name) {
1319 if (ibuf->byte_buffer.colorspace) {
1321 }
1322 else {
1324 }
1325 }
1326
1327 if (colorspace_name) {
1328 STRNCPY(image->colorspace_settings.name, colorspace_name);
1329 }
1330}
1331
1332Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
1333{
1334 if (name == nullptr) {
1335 name = BLI_path_basename(ibuf->filepath);
1336 }
1337
1338 /* When the image buffer has valid path create a new image with "file" source and copy the path
1339 * from the image buffer.
1340 * Otherwise create "generated" image, avoiding invalid configuration with an empty file path. */
1341 const eImageSource source = ibuf->filepath[0] != '\0' ? IMA_SRC_FILE : IMA_SRC_GENERATED;
1342
1343 Image *ima = image_alloc(bmain, std::nullopt, name, source, IMA_TYPE_IMAGE);
1344
1345 if (!ima) {
1346 return nullptr;
1347 }
1348
1349 BKE_image_replace_imbuf(ima, ibuf);
1350
1351 return ima;
1352}
1353
1355{
1356 BLI_assert(image->type == IMA_TYPE_IMAGE &&
1358
1360
1361 image_assign_ibuf(image, ibuf, IMA_NO_INDEX, 0);
1362 image_colorspace_from_imbuf(image, ibuf);
1363
1364 /* Keep generated image type flags consistent with the image buffer. */
1365 if (image->source == IMA_SRC_GENERATED) {
1366 if (ibuf->float_buffer.data) {
1367 image->gen_flag |= IMA_GEN_FLOAT;
1368 }
1369 else {
1370 image->gen_flag &= ~IMA_GEN_FLOAT;
1371 }
1372
1373 image->gen_x = ibuf->x;
1374 image->gen_y = ibuf->y;
1375 }
1376
1377 /* Consider image dirty since its content can not be re-created unless the image is explicitly
1378 * saved. */
1379 BKE_image_mark_dirty(image, ibuf);
1380}
1381
1384 Image *ima, ImBuf *ibuf, int view, int tile_number, const char *filepath)
1385{
1387
1388 IMB_save_image(ibuf, filepath, IB_byte_data | IB_mem);
1389
1390 if (ibuf->encoded_buffer.data == nullptr) {
1391 CLOG_STR_ERROR(&LOG, "memory save for pack error");
1392 IMB_freeImBuf(ibuf);
1394 return false;
1395 }
1396
1397 ImagePackedFile *imapf;
1398 const int encoded_size = ibuf->encoded_size;
1400
1401 imapf = MEM_mallocN<ImagePackedFile>("Image PackedFile");
1402 STRNCPY(imapf->filepath, filepath);
1403 imapf->packedfile = pf;
1404 imapf->view = view;
1405 imapf->tile_number = tile_number;
1406 BLI_addtail(&ima->packedfiles, imapf);
1407
1408 ibuf->userflags &= ~IB_BITMAPDIRTY;
1409
1410 return true;
1411}
1412
1414{
1415 bool ok = true;
1416
1418
1419 const int tot_viewfiles = image_num_viewfiles(ima);
1420 const bool is_tiled = (ima->source == IMA_SRC_TILED);
1421 const bool is_multiview = BKE_image_is_multiview(ima);
1422
1423 ImageUser iuser{};
1424 BKE_imageuser_default(&iuser);
1425 char tiled_filepath[FILE_MAX];
1426
1427 for (int view = 0; view < tot_viewfiles; view++) {
1428 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
1429 int index = (is_multiview || is_tiled) ? view : IMA_NO_INDEX;
1430 int entry = is_tiled ? tile->tile_number : 0;
1431 ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, nullptr);
1432 if (!ibuf) {
1433 ok = false;
1434 break;
1435 }
1436
1437 const char *filepath = ibuf->filepath;
1438 if (is_tiled) {
1439 iuser.tile = tile->tile_number;
1440 BKE_image_user_file_path(&iuser, ima, tiled_filepath);
1441 filepath = tiled_filepath;
1442 }
1443 else if (is_multiview) {
1444 ImageView *iv = static_cast<ImageView *>(BLI_findlink(&ima->views, view));
1445 /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
1446 if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
1447 const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
1448 BLI_path_suffix(iv->filepath, FILE_MAX, suffix[view], "");
1449 }
1450 filepath = iv->filepath;
1451 }
1452
1453 ok = ok && image_memorypack_imbuf(ima, ibuf, view, tile->tile_number, filepath);
1454 IMB_freeImBuf(ibuf);
1455 }
1456 }
1457
1458 if (is_multiview) {
1460 }
1461
1462 /* Images which were "generated" before packing should now be
1463 * treated as if they were saved as real files. */
1464 if (ok) {
1465 if (ima->source == IMA_SRC_GENERATED) {
1466 ima->source = IMA_SRC_FILE;
1467 ima->type = IMA_TYPE_IMAGE;
1468 }
1469
1470 /* Clear the per-tile generated flag if all tiles were ok.
1471 * Mirrors similar processing inside #BKE_image_save. */
1472 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
1473 tile->gen_flag &= ~IMA_GEN_TILE;
1474 }
1475 }
1476
1477 return ok;
1478}
1479
1480void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
1481{
1482 const int tot_viewfiles = image_num_viewfiles(ima);
1483
1484 ImageUser iuser{};
1485 BKE_imageuser_default(&iuser);
1486 for (int view = 0; view < tot_viewfiles; view++) {
1487 iuser.view = view;
1488 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
1489 iuser.tile = tile->tile_number;
1490 char filepath[FILE_MAX];
1491 BKE_image_user_file_path(&iuser, ima, filepath);
1492
1493 ImagePackedFile *imapf = MEM_mallocN<ImagePackedFile>("Image packed file");
1494 BLI_addtail(&ima->packedfiles, imapf);
1495
1496 imapf->packedfile = BKE_packedfile_new(reports, filepath, basepath);
1497 imapf->view = view;
1498 imapf->tile_number = tile->tile_number;
1499 if (imapf->packedfile) {
1500 STRNCPY(imapf->filepath, filepath);
1501 }
1502 else {
1503 BLI_freelinkN(&ima->packedfiles, imapf);
1504 }
1505 }
1506 }
1507}
1508
1510 Image *ima,
1511 char *data,
1512 const size_t data_len)
1513{
1514 const int tot_viewfiles = image_num_viewfiles(ima);
1515
1516 if (tot_viewfiles != 1) {
1517 BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
1518 }
1519 else if (ima->source == IMA_SRC_TILED) {
1520 BKE_report(reports, RPT_ERROR, "Cannot pack tiled images from raw data currently...");
1521 }
1522 else {
1524 BLI_addtail(&ima->packedfiles, imapf);
1526 imapf->view = 0;
1527 imapf->tile_number = 1001;
1528 STRNCPY(imapf->filepath, ima->filepath);
1529
1530 /* The image should not be marked as "generated" since image data was provided. */
1531 ImageTile *base_tile = BKE_image_get_tile(ima, 0);
1532 base_tile->gen_flag &= ~IMA_GEN_TILE;
1533 }
1534}
1535
1537{
1539}
1540
1541static uintptr_t image_mem_size(Image *image)
1542{
1543 uintptr_t size = 0;
1544
1545 /* viewers have memory depending on other rules, has no valid rect pointer */
1546 if (image->source == IMA_SRC_VIEWER) {
1547 return 0;
1548 }
1549
1550 std::scoped_lock lock(image->runtime->cache_mutex);
1551
1552 if (image->cache != nullptr) {
1553 MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
1554
1555 while (!IMB_moviecacheIter_done(iter)) {
1556 ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
1558 if (ibuf == nullptr) {
1559 continue;
1560 }
1561
1563
1564 for (int level = 0; level < IMB_MIPMAP_LEVELS; level++) {
1565 ImBuf *ibufm = ibuf->mipmap[level];
1566 size += IMB_get_size_in_memory(ibufm);
1567 }
1568 }
1570 }
1571
1572 return size;
1573}
1574
1576{
1577 Image *ima;
1578 uintptr_t size, totsize = 0;
1579
1580 for (ima = static_cast<Image *>(bmain->images.first); ima;
1581 ima = static_cast<Image *>(ima->id.next))
1582 {
1583 totsize += image_mem_size(ima);
1584 }
1585
1586 printf("\ntotal image memory len: %.3f MB\n", double(totsize) / double(1024 * 1024));
1587
1588 for (ima = static_cast<Image *>(bmain->images.first); ima;
1589 ima = static_cast<Image *>(ima->id.next))
1590 {
1591 size = image_mem_size(ima);
1592
1593 if (size) {
1594 printf("%s len: %.3f MB\n", ima->id.name + 2, double(size) / double(1024 * 1024));
1595 }
1596 }
1597}
1598
1599static bool imagecache_check_dirty(ImBuf *ibuf, void * /*userkey*/, void * /*userdata*/)
1600{
1601 if (ibuf == nullptr) {
1602 return false;
1603 }
1604 return (ibuf->userflags & IB_BITMAPDIRTY) == 0;
1605}
1606
1608{
1609#undef CHECK_FREED_SIZE
1610
1611 Tex *tex;
1612 Image *ima;
1613#ifdef CHECK_FREED_SIZE
1614 uintptr_t tot_freed_size = 0;
1615#endif
1616
1617 for (ima = static_cast<Image *>(bmain->images.first); ima;
1618 ima = static_cast<Image *>(ima->id.next))
1619 {
1620 ima->id.tag &= ~ID_TAG_DOIT;
1621 }
1622
1623 for (tex = static_cast<Tex *>(bmain->textures.first); tex;
1624 tex = static_cast<Tex *>(tex->id.next))
1625 {
1626 if (tex->ima) {
1627 tex->ima->id.tag |= ID_TAG_DOIT;
1628 }
1629 }
1630
1631 for (ima = static_cast<Image *>(bmain->images.first); ima;
1632 ima = static_cast<Image *>(ima->id.next))
1633 {
1634 if (ima->cache && (ima->id.tag & ID_TAG_DOIT)) {
1635#ifdef CHECK_FREED_SIZE
1636 uintptr_t old_size = image_mem_size(ima);
1637#endif
1638
1640
1641#ifdef CHECK_FREED_SIZE
1642 tot_freed_size += old_size - image_mem_size(ima);
1643#endif
1644 }
1645 }
1646#ifdef CHECK_FREED_SIZE
1647 printf("%s: freed total %lu MB\n", __func__, tot_freed_size / (1024 * 1024));
1648#endif
1649}
1650
1651static bool imagecache_check_free_anim(ImBuf *ibuf, void * /*userkey*/, void *userdata)
1652{
1653 if (ibuf == nullptr) {
1654 return true;
1655 }
1656 int except_frame = *(int *)userdata;
1657 return (ibuf->userflags & IB_BITMAPDIRTY) == 0 && (ibuf->index != IMA_NO_INDEX) &&
1658 (except_frame != IMA_INDEX_ENTRY(ibuf->index));
1659}
1660
1661void BKE_image_free_anim_ibufs(Image *ima, int except_frame)
1662{
1663 std::scoped_lock lock(ima->runtime->cache_mutex);
1664 if (ima->cache != nullptr) {
1666 }
1667}
1668
1670{
1671 Image *ima;
1672
1673 for (ima = static_cast<Image *>(bmain->images.first); ima;
1674 ima = static_cast<Image *>(ima->id.next))
1675 {
1676 if (BKE_image_is_animated(ima)) {
1677 BKE_image_free_anim_ibufs(ima, cfra);
1678 }
1679 }
1680}
1681
1683
1684/* -------------------------------------------------------------------- */
1687
1688#define STAMP_NAME_SIZE ((MAX_ID_NAME - 2) + 16)
1689/* could allow access externally - 512 is for long names,
1690 * STAMP_NAME_SIZE is for id names, allowing them some room for description */
1693 /* TODO(sergey): Think of better size here, maybe dynamically allocated even. */
1694 char key[512];
1695 char *value;
1696 /* TODO(sergey): Support non-string values. */
1697};
1698
1700 char file[512];
1701 char note[512];
1702 char date[512];
1703 char marker[512];
1704 char time[512];
1705 char frame[512];
1706 char frame_range[512];
1713 char hostname[512];
1714
1715 /* Custom fields are used to put extra meta information header from render
1716 * engine to the result image.
1717 *
1718 * NOTE: This fields are not stamped onto the image. At least for now.
1719 */
1721};
1722#undef STAMP_NAME_SIZE
1723
1728static void stampdata(
1729 const Scene *scene, Object *camera, StampData *stamp_data, int do_prefix, bool use_dynamic)
1730{
1731 char text[256];
1732 tm *tl;
1733 time_t t;
1734
1735 if (scene->r.stamp & R_STAMP_FILENAME) {
1736 const char *blendfile_path = BKE_main_blendfile_path_from_global();
1737 SNPRINTF(stamp_data->file,
1738 do_prefix ? "File %s" : "%s",
1739 (blendfile_path[0] != '\0') ? blendfile_path : "<untitled>");
1740 }
1741 else {
1742 stamp_data->file[0] = '\0';
1743 }
1744
1745 if (scene->r.stamp & R_STAMP_NOTE) {
1746 /* Never do prefix for Note */
1747 SNPRINTF(stamp_data->note, "%s", scene->r.stamp_udata);
1748 }
1749 else {
1750 stamp_data->note[0] = '\0';
1751 }
1752
1753 if (scene->r.stamp & R_STAMP_DATE) {
1754 t = time(nullptr);
1755 tl = localtime(&t);
1756 SNPRINTF(text,
1757 "%04d/%02d/%02d %02d:%02d:%02d",
1758 tl->tm_year + 1900,
1759 tl->tm_mon + 1,
1760 tl->tm_mday,
1761 tl->tm_hour,
1762 tl->tm_min,
1763 tl->tm_sec);
1764 SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", text);
1765 }
1766 else {
1767 stamp_data->date[0] = '\0';
1768 }
1769
1770 if (use_dynamic && scene->r.stamp & R_STAMP_MARKER) {
1771 const char *name = BKE_scene_find_last_marker_name(scene, scene->r.cfra);
1772
1773 if (name) {
1774 STRNCPY(text, name);
1775 }
1776 else {
1777 STRNCPY(text, "<none>");
1778 }
1779
1780 SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", text);
1781 }
1782 else {
1783 stamp_data->marker[0] = '\0';
1784 }
1785
1786 if (use_dynamic && scene->r.stamp & R_STAMP_TIME) {
1787 const short timecode_style = USER_TIMECODE_SMPTE_FULL;
1789 text, sizeof(text), 0, FRA2TIME(scene->r.cfra), FPS, timecode_style);
1790 SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", text);
1791 }
1792 else {
1793 stamp_data->time[0] = '\0';
1794 }
1795
1796 if (use_dynamic && scene->r.stamp & R_STAMP_FRAME) {
1797 char fmtstr[32];
1798 int digits = 1;
1799
1800 if (scene->r.efra > 9) {
1801 digits = integer_digits_i(scene->r.efra);
1802 }
1803
1804 SNPRINTF(fmtstr, do_prefix ? "Frame %%0%di" : "%%0%di", digits);
1805 SNPRINTF(stamp_data->frame, fmtstr, scene->r.cfra);
1806 }
1807 else {
1808 stamp_data->frame[0] = '\0';
1809 }
1810
1811 if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
1812 SNPRINTF(stamp_data->frame_range,
1813 do_prefix ? "Frame Range %d:%d" : "%d:%d",
1814 scene->r.sfra,
1815 scene->r.efra);
1816 }
1817 else {
1818 stamp_data->frame_range[0] = '\0';
1819 }
1820
1821 if (use_dynamic && scene->r.stamp & R_STAMP_CAMERA) {
1822 SNPRINTF(stamp_data->camera,
1823 do_prefix ? "Camera %s" : "%s",
1824 camera ? camera->id.name + 2 : "<none>");
1825 }
1826 else {
1827 stamp_data->camera[0] = '\0';
1828 }
1829
1830 if (use_dynamic && scene->r.stamp & R_STAMP_CAMERALENS) {
1831 if (camera && camera->type == OB_CAMERA) {
1832 SNPRINTF(text, "%.2f", ((Camera *)camera->data)->lens);
1833 }
1834 else {
1835 STRNCPY(text, "<none>");
1836 }
1837
1838 SNPRINTF(stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", text);
1839 }
1840 else {
1841 stamp_data->cameralens[0] = '\0';
1842 }
1843
1844 if (scene->r.stamp & R_STAMP_SCENE) {
1845 SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", scene->id.name + 2);
1846 }
1847 else {
1848 stamp_data->scene[0] = '\0';
1849 }
1850
1851 if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) {
1852 const Strip *strip = blender::seq::strip_topmost_get(scene, scene->r.cfra);
1853
1854 if (strip) {
1855 STRNCPY(text, strip->name + 2);
1856 }
1857 else {
1858 STRNCPY(text, "<none>");
1859 }
1860
1861 SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", text);
1862 }
1863 else {
1864 stamp_data->strip[0] = '\0';
1865 }
1866
1867 {
1868 Render *re = RE_GetSceneRender(scene);
1869 RenderStats *stats = re ? RE_GetStats(re) : nullptr;
1870
1871 if (use_dynamic && stats && (scene->r.stamp & R_STAMP_RENDERTIME)) {
1872 BLI_timecode_string_from_time_simple(text, sizeof(text), stats->lastframetime);
1873
1874 SNPRINTF(stamp_data->rendertime, do_prefix ? "RenderTime %s" : "%s", text);
1875 }
1876 else {
1877 stamp_data->rendertime[0] = '\0';
1878 }
1879
1880 if (use_dynamic && stats && (scene->r.stamp & R_STAMP_MEMORY)) {
1881 SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
1882 }
1883 else {
1884 stamp_data->memory[0] = '\0';
1885 }
1886 }
1887 if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
1888 SNPRINTF(stamp_data->frame_range,
1889 do_prefix ? "Frame Range %d:%d" : "%d:%d",
1890 scene->r.sfra,
1891 scene->r.efra);
1892 }
1893 else {
1894 stamp_data->frame_range[0] = '\0';
1895 }
1896
1897 if (scene->r.stamp & R_STAMP_HOSTNAME) {
1898 char hostname[500]; /* sizeof(stamp_data->hostname) minus some bytes for a label. */
1899 BLI_hostname_get(hostname, sizeof(hostname));
1900 SNPRINTF(stamp_data->hostname, do_prefix ? "Hostname %s" : "%s", hostname);
1901 }
1902 else {
1903 stamp_data->hostname[0] = '\0';
1904 }
1905}
1906
1907static void stampdata_from_template(StampData *stamp_data,
1908 const Scene *scene,
1909 const StampData *stamp_data_template,
1910 bool do_prefix)
1911{
1912 if (scene->r.stamp & R_STAMP_FILENAME) {
1913 SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", stamp_data_template->file);
1914 }
1915 else {
1916 stamp_data->file[0] = '\0';
1917 }
1918 if (scene->r.stamp & R_STAMP_NOTE) {
1919 STRNCPY(stamp_data->note, stamp_data_template->note);
1920 }
1921 else {
1922 stamp_data->note[0] = '\0';
1923 }
1924 if (scene->r.stamp & R_STAMP_DATE) {
1925 SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", stamp_data_template->date);
1926 }
1927 else {
1928 stamp_data->date[0] = '\0';
1929 }
1930 if (scene->r.stamp & R_STAMP_MARKER) {
1931 SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", stamp_data_template->marker);
1932 }
1933 else {
1934 stamp_data->marker[0] = '\0';
1935 }
1936 if (scene->r.stamp & R_STAMP_TIME) {
1937 SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", stamp_data_template->time);
1938 }
1939 else {
1940 stamp_data->time[0] = '\0';
1941 }
1942 if (scene->r.stamp & R_STAMP_FRAME) {
1943 SNPRINTF(stamp_data->frame, do_prefix ? "Frame %s" : "%s", stamp_data_template->frame);
1944 }
1945 else {
1946 stamp_data->frame[0] = '\0';
1947 }
1948 if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
1949 SNPRINTF(stamp_data->frame_range,
1950 do_prefix ? "Frame Range %s" : "%s",
1951 stamp_data_template->frame_range);
1952 }
1953 else {
1954 stamp_data->frame_range[0] = '\0';
1955 }
1956 if (scene->r.stamp & R_STAMP_CAMERA) {
1957 SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", stamp_data_template->camera);
1958 }
1959 else {
1960 stamp_data->camera[0] = '\0';
1961 }
1962 if (scene->r.stamp & R_STAMP_CAMERALENS) {
1963 SNPRINTF(
1964 stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", stamp_data_template->cameralens);
1965 }
1966 else {
1967 stamp_data->cameralens[0] = '\0';
1968 }
1969 if (scene->r.stamp & R_STAMP_SCENE) {
1970 SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", stamp_data_template->scene);
1971 }
1972 else {
1973 stamp_data->scene[0] = '\0';
1974 }
1975 if (scene->r.stamp & R_STAMP_SEQSTRIP) {
1976 SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", stamp_data_template->strip);
1977 }
1978 else {
1979 stamp_data->strip[0] = '\0';
1980 }
1981 if (scene->r.stamp & R_STAMP_RENDERTIME) {
1982 SNPRINTF(stamp_data->rendertime,
1983 do_prefix ? "RenderTime %s" : "%s",
1984 stamp_data_template->rendertime);
1985 }
1986 else {
1987 stamp_data->rendertime[0] = '\0';
1988 }
1989 if (scene->r.stamp & R_STAMP_MEMORY) {
1990 SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %s" : "%s", stamp_data_template->memory);
1991 }
1992 else {
1993 stamp_data->memory[0] = '\0';
1994 }
1995 if (scene->r.stamp & R_STAMP_HOSTNAME) {
1996 SNPRINTF(
1997 stamp_data->hostname, do_prefix ? "Hostname %s" : "%s", stamp_data_template->hostname);
1998 }
1999 else {
2000 stamp_data->hostname[0] = '\0';
2001 }
2002}
2003
2005 Object *camera,
2006 const StampData *stamp_data_template,
2007 uchar *rect,
2008 float *rectf,
2009 int width,
2010 int height)
2011{
2012 StampData stamp_data;
2013 int w, h, pad;
2014 int x, y, y_ofs;
2015 int h_fixed;
2016 const int mono = blf_mono_font_render; /* XXX */
2017 const ColorManagedDisplay *display;
2018 const char *display_device;
2019
2020 /* vars for calculating wordwrap */
2021 struct {
2022 ResultBLF info;
2023 rcti rect;
2024 } wrap;
2025
2026 /* this could be an argument if we want to operate on non linear float imbuf's
2027 * for now though this is only used for renders which use scene settings */
2028
2029#define TEXT_SIZE_CHECK(str, w, h) \
2030 ((str[0]) && ((void)(h = h_fixed), (w = int(BLF_width(mono, str, sizeof(str))))))
2031
2032 /* must enable BLF_WORD_WRAP before using */
2033#define TEXT_SIZE_CHECK_WORD_WRAP(str, w, h) \
2034 ((str[0]) && (BLF_boundbox(mono, str, sizeof(str), &wrap.rect, &wrap.info), \
2035 (void)(h = h_fixed * wrap.info.lines), \
2036 (w = BLI_rcti_size_x(&wrap.rect))))
2037
2038#define BUFF_MARGIN_X 2
2039#define BUFF_MARGIN_Y 1
2040
2041 if (!rect && !rectf) {
2042 return;
2043 }
2044
2045 display_device = scene->display_settings.display_device;
2046 display = IMB_colormanagement_display_get_named(display_device);
2047
2048 bool do_prefix = (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0;
2049 if (stamp_data_template == nullptr) {
2050 stampdata(scene, camera, &stamp_data, do_prefix, true);
2051 }
2052 else {
2053 stampdata_from_template(&stamp_data, scene, stamp_data_template, do_prefix);
2054 }
2055
2056 /* TODO: do_versions. */
2057 if (scene->r.stamp_font_id < 8) {
2058 scene->r.stamp_font_id = 12;
2059 }
2060
2061 /* set before return */
2062 BLF_size(mono, scene->r.stamp_font_id);
2063 BLF_wordwrap(mono, width - (BUFF_MARGIN_X * 2));
2064
2065 BLF_buffer(mono, rectf, rect, width, height, display);
2066 BLF_buffer_col(mono, scene->r.fg_stamp);
2067 pad = BLF_width_max(mono);
2068
2069 /* use 'h_fixed' rather than 'h', aligns better */
2070 h_fixed = BLF_height_max(mono);
2071 y_ofs = -BLF_descender(mono);
2072
2073 x = 0;
2074 y = height;
2075
2076 if (TEXT_SIZE_CHECK(stamp_data.file, w, h)) {
2077 /* Top left corner */
2078 y -= h;
2079
2080 /* also a little of space to the background. */
2081 buf_rectfill_area(rect,
2082 rectf,
2083 width,
2084 height,
2085 scene->r.bg_stamp,
2086 display,
2087 x - BUFF_MARGIN_X,
2088 y - BUFF_MARGIN_Y,
2089 w + BUFF_MARGIN_X,
2090 y + h + BUFF_MARGIN_Y);
2091
2092 /* and draw the text. */
2093 BLF_position(mono, x, y + y_ofs, 0.0);
2094 BLF_draw_buffer(mono, stamp_data.file, sizeof(stamp_data.file));
2095
2096 /* the extra pixel for background. */
2097 y -= BUFF_MARGIN_Y * 2;
2098 }
2099
2100 /* Top left corner, below File */
2101 if (TEXT_SIZE_CHECK(stamp_data.date, w, h)) {
2102 y -= h;
2103
2104 /* and space for background. */
2105 buf_rectfill_area(rect,
2106 rectf,
2107 width,
2108 height,
2109 scene->r.bg_stamp,
2110 display,
2111 0,
2112 y - BUFF_MARGIN_Y,
2113 w + BUFF_MARGIN_X,
2114 y + h + BUFF_MARGIN_Y);
2115
2116 BLF_position(mono, x, y + y_ofs, 0.0);
2117 BLF_draw_buffer(mono, stamp_data.date, sizeof(stamp_data.date));
2118
2119 /* the extra pixel for background. */
2120 y -= BUFF_MARGIN_Y * 2;
2121 }
2122
2123 /* Top left corner, below File, Date */
2124 if (TEXT_SIZE_CHECK(stamp_data.rendertime, w, h)) {
2125 y -= h;
2126
2127 /* and space for background. */
2128 buf_rectfill_area(rect,
2129 rectf,
2130 width,
2131 height,
2132 scene->r.bg_stamp,
2133 display,
2134 0,
2135 y - BUFF_MARGIN_Y,
2136 w + BUFF_MARGIN_X,
2137 y + h + BUFF_MARGIN_Y);
2138
2139 BLF_position(mono, x, y + y_ofs, 0.0);
2140 BLF_draw_buffer(mono, stamp_data.rendertime, sizeof(stamp_data.rendertime));
2141
2142 /* the extra pixel for background. */
2143 y -= BUFF_MARGIN_Y * 2;
2144 }
2145
2146 /* Top left corner, below File, Date, Render-time */
2147 if (TEXT_SIZE_CHECK(stamp_data.memory, w, h)) {
2148 y -= h;
2149
2150 /* and space for background. */
2151 buf_rectfill_area(rect,
2152 rectf,
2153 width,
2154 height,
2155 scene->r.bg_stamp,
2156 display,
2157 0,
2158 y - BUFF_MARGIN_Y,
2159 w + BUFF_MARGIN_X,
2160 y + h + BUFF_MARGIN_Y);
2161
2162 BLF_position(mono, x, y + y_ofs, 0.0);
2163 BLF_draw_buffer(mono, stamp_data.memory, sizeof(stamp_data.memory));
2164
2165 /* the extra pixel for background. */
2166 y -= BUFF_MARGIN_Y * 2;
2167 }
2168
2169 /* Top left corner, below: File, Date, Render-time, Memory. */
2170 if (TEXT_SIZE_CHECK(stamp_data.hostname, w, h)) {
2171 y -= h;
2172
2173 /* and space for background. */
2174 buf_rectfill_area(rect,
2175 rectf,
2176 width,
2177 height,
2178 scene->r.bg_stamp,
2179 display,
2180 0,
2181 y - BUFF_MARGIN_Y,
2182 w + BUFF_MARGIN_X,
2183 y + h + BUFF_MARGIN_Y);
2184
2185 BLF_position(mono, x, y + y_ofs, 0.0);
2186 BLF_draw_buffer(mono, stamp_data.hostname, sizeof(stamp_data.hostname));
2187
2188 /* the extra pixel for background. */
2189 y -= BUFF_MARGIN_Y * 2;
2190 }
2191
2192 /* Top left corner, below: File, Date, Memory, Render-time, Host-name. */
2194 if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) {
2195 y -= h;
2196
2197 /* and space for background. */
2198 buf_rectfill_area(rect,
2199 rectf,
2200 width,
2201 height,
2202 scene->r.bg_stamp,
2203 display,
2204 0,
2205 y - BUFF_MARGIN_Y,
2206 w + BUFF_MARGIN_X,
2207 y + h + BUFF_MARGIN_Y);
2208
2209 BLF_position(mono, x, y + y_ofs + (h - h_fixed), 0.0);
2210 BLF_draw_buffer(mono, stamp_data.note, sizeof(stamp_data.note));
2211 }
2213
2214 x = 0;
2215 y = 0;
2216
2217 /* Bottom left corner, leaving space for timing */
2218 if (TEXT_SIZE_CHECK(stamp_data.marker, w, h)) {
2219
2220 /* extra space for background. */
2221 buf_rectfill_area(rect,
2222 rectf,
2223 width,
2224 height,
2225 scene->r.bg_stamp,
2226 display,
2227 x - BUFF_MARGIN_X,
2228 y - BUFF_MARGIN_Y,
2229 w + BUFF_MARGIN_X,
2230 y + h + BUFF_MARGIN_Y);
2231
2232 /* and pad the text. */
2233 BLF_position(mono, x, y + y_ofs, 0.0);
2234 BLF_draw_buffer(mono, stamp_data.marker, sizeof(stamp_data.marker));
2235
2236 /* space width. */
2237 x += w + pad;
2238 }
2239
2240 /* Left bottom corner */
2241 if (TEXT_SIZE_CHECK(stamp_data.time, w, h)) {
2242
2243 /* extra space for background */
2244 buf_rectfill_area(rect,
2245 rectf,
2246 width,
2247 height,
2248 scene->r.bg_stamp,
2249 display,
2250 x - BUFF_MARGIN_X,
2251 y,
2252 x + w + BUFF_MARGIN_X,
2253 y + h + BUFF_MARGIN_Y);
2254
2255 /* and pad the text. */
2256 BLF_position(mono, x, y + y_ofs, 0.0);
2257 BLF_draw_buffer(mono, stamp_data.time, sizeof(stamp_data.time));
2258
2259 /* space width. */
2260 x += w + pad;
2261 }
2262
2263 if (TEXT_SIZE_CHECK(stamp_data.frame, w, h)) {
2264
2265 /* extra space for background. */
2266 buf_rectfill_area(rect,
2267 rectf,
2268 width,
2269 height,
2270 scene->r.bg_stamp,
2271 display,
2272 x - BUFF_MARGIN_X,
2273 y - BUFF_MARGIN_Y,
2274 x + w + BUFF_MARGIN_X,
2275 y + h + BUFF_MARGIN_Y);
2276
2277 /* and pad the text. */
2278 BLF_position(mono, x, y + y_ofs, 0.0);
2279 BLF_draw_buffer(mono, stamp_data.frame, sizeof(stamp_data.frame));
2280
2281 /* space width. */
2282 x += w + pad;
2283 }
2284
2285 if (TEXT_SIZE_CHECK(stamp_data.frame_range, w, h)) {
2286
2287 /* extra space for background. */
2288 buf_rectfill_area(rect,
2289 rectf,
2290 width,
2291 height,
2292 scene->r.bg_stamp,
2293 display,
2294 x - BUFF_MARGIN_X,
2295 y - BUFF_MARGIN_Y,
2296 x + w + BUFF_MARGIN_X,
2297 y + h + BUFF_MARGIN_Y);
2298
2299 /* and pad the text. */
2300 BLF_position(mono, x, y + y_ofs, 0.0);
2301 BLF_draw_buffer(mono, stamp_data.frame_range, sizeof(stamp_data.frame_range));
2302
2303 /* space width. */
2304 x += w + pad;
2305 }
2306
2307 if (TEXT_SIZE_CHECK(stamp_data.camera, w, h)) {
2308
2309 /* extra space for background. */
2310 buf_rectfill_area(rect,
2311 rectf,
2312 width,
2313 height,
2314 scene->r.bg_stamp,
2315 display,
2316 x - BUFF_MARGIN_X,
2317 y - BUFF_MARGIN_Y,
2318 x + w + BUFF_MARGIN_X,
2319 y + h + BUFF_MARGIN_Y);
2320 BLF_position(mono, x, y + y_ofs, 0.0);
2321 BLF_draw_buffer(mono, stamp_data.camera, sizeof(stamp_data.camera));
2322
2323 /* space width. */
2324 x += w + pad;
2325 }
2326
2327 if (TEXT_SIZE_CHECK(stamp_data.cameralens, w, h)) {
2328
2329 /* extra space for background. */
2330 buf_rectfill_area(rect,
2331 rectf,
2332 width,
2333 height,
2334 scene->r.bg_stamp,
2335 display,
2336 x - BUFF_MARGIN_X,
2337 y - BUFF_MARGIN_Y,
2338 x + w + BUFF_MARGIN_X,
2339 y + h + BUFF_MARGIN_Y);
2340 BLF_position(mono, x, y + y_ofs, 0.0);
2341 BLF_draw_buffer(mono, stamp_data.cameralens, sizeof(stamp_data.cameralens));
2342 }
2343
2344 if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) {
2345
2346 /* Bottom right corner, with an extra space because the BLF API is too strict! */
2347 x = width - w - 2;
2348
2349 /* extra space for background. */
2350 buf_rectfill_area(rect,
2351 rectf,
2352 width,
2353 height,
2354 scene->r.bg_stamp,
2355 display,
2356 x - BUFF_MARGIN_X,
2357 y - BUFF_MARGIN_Y,
2358 x + w + BUFF_MARGIN_X,
2359 y + h + BUFF_MARGIN_Y);
2360
2361 /* and pad the text. */
2362 BLF_position(mono, x, y + y_ofs, 0.0);
2363 BLF_draw_buffer(mono, stamp_data.scene, sizeof(stamp_data.scene));
2364 }
2365
2366 if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) {
2367
2368 /* Top right corner, with an extra space because the BLF API is too strict! */
2369 x = width - w - pad;
2370 y = height - h;
2371
2372 /* extra space for background. */
2373 buf_rectfill_area(rect,
2374 rectf,
2375 width,
2376 height,
2377 scene->r.bg_stamp,
2378 display,
2379 x - BUFF_MARGIN_X,
2380 y - BUFF_MARGIN_Y,
2381 x + w + BUFF_MARGIN_X,
2382 y + h + BUFF_MARGIN_Y);
2383
2384 BLF_position(mono, x, y + y_ofs, 0.0);
2385 BLF_draw_buffer(mono, stamp_data.strip, sizeof(stamp_data.strip));
2386 }
2387
2388 /* cleanup the buffer. */
2389 BLF_buffer(mono, nullptr, nullptr, 0, 0, nullptr);
2390 BLF_wordwrap(mono, 0);
2391
2392#undef TEXT_SIZE_CHECK
2393#undef TEXT_SIZE_CHECK_WORD_WRAP
2394#undef BUFF_MARGIN_X
2395#undef BUFF_MARGIN_Y
2396}
2397
2399 Object *camera,
2400 RenderResult *rr,
2401 bool allocate_only)
2402{
2403 StampData *stamp_data;
2404
2405 if (!(scene && (scene->r.stamp & R_STAMP_ALL)) && !allocate_only) {
2406 return;
2407 }
2408
2409 if (!rr->stamp_data) {
2410 stamp_data = MEM_callocN<StampData>("RenderResult.stamp_data");
2411 }
2412 else {
2413 stamp_data = rr->stamp_data;
2414 }
2415
2416 if (!allocate_only) {
2417 stampdata(scene, camera, stamp_data, 0, true);
2418 }
2419
2420 if (!rr->stamp_data) {
2421 rr->stamp_data = stamp_data;
2422 }
2423}
2424
2426{
2427 StampData *stamp_data;
2428
2429 if (!(scene && (scene->r.stamp & R_STAMP_ALL))) {
2430 return nullptr;
2431 }
2432
2433 /* Memory is allocated here (instead of by the caller) so that the caller
2434 * doesn't have to know the size of the StampData struct. */
2435 stamp_data = MEM_callocN<StampData>(__func__);
2436 stampdata(scene, nullptr, stamp_data, 0, false);
2437
2438 return stamp_data;
2439}
2440
2441static const char *stamp_metadata_fields[] = {
2442 "File",
2443 "Note",
2444 "Date",
2445 "Marker",
2446 "Time",
2447 "Frame",
2448 "FrameRange",
2449 "Camera",
2450 "Lens",
2451 "Scene",
2452 "Strip",
2453 "RenderTime",
2454 "Memory",
2455 "Hostname",
2456 nullptr,
2457};
2458
2459bool BKE_stamp_is_known_field(const char *field_name)
2460{
2461 int i = 0;
2462 while (stamp_metadata_fields[i] != nullptr) {
2463 if (STREQ(field_name, stamp_metadata_fields[i])) {
2464 return true;
2465 }
2466 i++;
2467 }
2468 return false;
2469}
2470
2472 StampData *stamp_data,
2473 StampCallback callback,
2474 bool noskip)
2475{
2476 if ((callback == nullptr) || (stamp_data == nullptr)) {
2477 return;
2478 }
2479
2480#define CALL(member, value_str) \
2481 if (noskip || stamp_data->member[0]) { \
2482 callback(data, value_str, stamp_data->member, sizeof(stamp_data->member)); \
2483 } \
2484 ((void)0)
2485
2486 /* TODO(sergey): Use stamp_metadata_fields somehow, or make it more generic
2487 * meta information to avoid duplication. */
2488 CALL(file, "File");
2489 CALL(note, "Note");
2490 CALL(date, "Date");
2491 CALL(marker, "Marker");
2492 CALL(time, "Time");
2493 CALL(frame, "Frame");
2494 CALL(frame_range, "FrameRange");
2495 CALL(camera, "Camera");
2496 CALL(cameralens, "Lens");
2497 CALL(scene, "Scene");
2498 CALL(strip, "Strip");
2499 CALL(rendertime, "RenderTime");
2500 CALL(memory, "Memory");
2501 CALL(hostname, "Hostname");
2502
2503 LISTBASE_FOREACH (StampDataCustomField *, custom_field, &stamp_data->custom_fields) {
2504 if (noskip || custom_field->value[0]) {
2505 callback(data, custom_field->key, custom_field->value, strlen(custom_field->value) + 1);
2506 }
2507 }
2508
2509#undef CALL
2510}
2511
2513 const Image &image,
2514 StampCallback callback,
2515 bool noskip)
2516{
2517 std::scoped_lock lock(image.runtime->cache_mutex);
2518
2519 if (!image.rr || !image.rr->stamp_data) {
2520 return;
2521 }
2522
2523 BKE_stamp_info_callback(data, image.rr->stamp_data, callback, noskip);
2524}
2525
2526void BKE_render_result_stamp_data(RenderResult *rr, const char *key, const char *value)
2527{
2528 StampData *stamp_data;
2529 if (rr->stamp_data == nullptr) {
2530 rr->stamp_data = MEM_callocN<StampData>("RenderResult.stamp_data");
2531 }
2532 stamp_data = rr->stamp_data;
2533 StampDataCustomField *field = MEM_mallocN<StampDataCustomField>("StampData Custom Field");
2534 STRNCPY(field->key, key);
2535 field->value = BLI_strdup(value);
2536 BLI_addtail(&stamp_data->custom_fields, field);
2537}
2538
2540{
2541 if (stamp_data == nullptr) {
2542 return nullptr;
2543 }
2544
2545 StampData *stamp_datan = static_cast<StampData *>(MEM_dupallocN(stamp_data));
2546 BLI_duplicatelist(&stamp_datan->custom_fields, &stamp_data->custom_fields);
2547
2548 LISTBASE_FOREACH (StampDataCustomField *, custom_fieldn, &stamp_datan->custom_fields) {
2549 custom_fieldn->value = static_cast<char *>(MEM_dupallocN(custom_fieldn->value));
2550 }
2551
2552 return stamp_datan;
2553}
2554
2556{
2557 if (stamp_data == nullptr) {
2558 return;
2559 }
2560 LISTBASE_FOREACH (StampDataCustomField *, custom_field, &stamp_data->custom_fields) {
2561 MEM_freeN(custom_field->value);
2562 }
2563 BLI_freelistN(&stamp_data->custom_fields);
2564 MEM_freeN(stamp_data);
2565}
2566
2567/* wrap for callback only */
2568static void metadata_set_field(void *data,
2569 const char *propname,
2570 char *propvalue,
2571 int /*propvalue_maxncpy*/)
2572{
2573 /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
2574 ImBuf *imbuf = static_cast<ImBuf *>(data);
2575 IMB_metadata_set_field(imbuf->metadata, propname, propvalue);
2576}
2577
2578static void metadata_get_field(void *data,
2579 const char *propname,
2580 char *propvalue,
2581 int propvalue_maxncpy)
2582{
2583 /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
2584 ImBuf *imbuf = static_cast<ImBuf *>(data);
2585 IMB_metadata_get_field(imbuf->metadata, propname, propvalue, propvalue_maxncpy);
2586}
2587
2589{
2590 StampData *stamp_data = const_cast<StampData *>(rr->stamp_data);
2592 BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false);
2593}
2594
2595static void metadata_copy_custom_fields(const char *field, const char *value, void *rr_v)
2596{
2597 if (BKE_stamp_is_known_field(field)) {
2598 return;
2599 }
2600 RenderResult *rr = (RenderResult *)rr_v;
2601 BKE_render_result_stamp_data(rr, field, value);
2602}
2603
2605{
2606 if (rr->stamp_data == nullptr) {
2607 rr->stamp_data = MEM_callocN<StampData>("RenderResult.stamp_data");
2608 }
2609 StampData *stamp_data = rr->stamp_data;
2611 BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true);
2612 /* Copy render engine specific settings. */
2614}
2615
2617{
2618 if (ibuf->float_buffer.data) {
2619 const float *buf = ibuf->float_buffer.data;
2620 for (size_t tot = IMB_get_pixel_count(ibuf); tot--; buf += 4) {
2621 if (buf[3] < 1.0f) {
2622 return true;
2623 }
2624 }
2625 }
2626 else if (ibuf->byte_buffer.data) {
2627 uchar *buf = ibuf->byte_buffer.data;
2628 for (size_t tot = IMB_get_pixel_count(ibuf); tot--; buf += 4) {
2629 if (buf[3] != 255) {
2630 return true;
2631 }
2632 }
2633 }
2634
2635 return false;
2636}
2637
2638bool BKE_imbuf_write(ImBuf *ibuf, const char *filepath, const ImageFormatData *imf)
2639{
2640 BKE_image_format_to_imbuf(ibuf, imf);
2641
2643
2644 const bool ok = IMB_save_image(ibuf, filepath, IB_byte_data);
2645 if (ok == 0) {
2646 perror(filepath);
2647 }
2648
2649 return ok;
2650}
2651
2653 const char *filepath,
2654 const ImageFormatData *imf,
2655 const bool save_copy)
2656{
2657 ImBuf ibuf_back = *ibuf;
2658 bool ok;
2659
2660 /* All data is RGBA anyway, this just controls how to save for some formats. */
2661 ibuf->planes = imf->planes;
2662
2663 ok = BKE_imbuf_write(ibuf, filepath, imf);
2664
2665 if (save_copy) {
2666 /* note that we are not restoring _all_ settings */
2667 ibuf->planes = ibuf_back.planes;
2668 ibuf->ftype = ibuf_back.ftype;
2669 ibuf->foptions = ibuf_back.foptions;
2670 }
2671
2672 return ok;
2673}
2674
2676 const RenderResult *rr,
2677 ImBuf *ibuf,
2678 const char *filepath,
2679 const ImageFormatData *imf)
2680{
2681 if (scene && scene->r.stamp & R_STAMP_ALL) {
2682 BKE_imbuf_stamp_info(rr, ibuf);
2683 }
2684
2685 return BKE_imbuf_write(ibuf, filepath, imf);
2686}
2687
2688MovieReader *openanim_noload(const char *filepath,
2689 int flags,
2690 int streamindex,
2691 char colorspace[IMA_MAX_SPACE])
2692{
2693 MovieReader *anim;
2694
2695 anim = MOV_open_file(filepath, flags, streamindex, colorspace);
2696 return anim;
2697}
2698
2699MovieReader *openanim(const char *filepath,
2700 int flags,
2701 int streamindex,
2702 char colorspace[IMA_MAX_SPACE])
2703{
2704 MovieReader *anim;
2705 ImBuf *ibuf;
2706
2707 anim = MOV_open_file(filepath, flags, streamindex, colorspace);
2708 if (anim == nullptr) {
2709 return nullptr;
2710 }
2711
2713 if (ibuf == nullptr) {
2714 const char *reason;
2715 if (!BLI_exists(filepath)) {
2716 reason = "file doesn't exist";
2717 }
2718 else {
2719 reason = "not an anim";
2720 }
2721 CLOG_INFO(&LOG, 1, "unable to load anim, %s: %s", reason, filepath);
2722
2723 MOV_close(anim);
2724 return nullptr;
2725 }
2726 IMB_freeImBuf(ibuf);
2727
2728 return anim;
2729}
2730
2732
2733/* -------------------------------------------------------------------- */
2736
2737/* Notes about Image storage
2738 * - packedfile
2739 * -> written in .blend
2740 * - filename
2741 * -> written in .blend
2742 * - movie
2743 * -> comes from packedfile or filename
2744 * - renderresult
2745 * -> comes from packedfile or filename
2746 * - listbase
2747 * -> ibufs from EXR-handle.
2748 * - flip-book array
2749 * -> ibufs come from movie, temporary renderresult or sequence
2750 * - ibuf
2751 * -> comes from packedfile or filename or generated
2752 */
2753
2754Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
2755{
2756 Image *ima;
2757
2758 for (ima = static_cast<Image *>(bmain->images.first); ima;
2759 ima = static_cast<Image *>(ima->id.next))
2760 {
2761 if (ima->source == IMA_SRC_VIEWER) {
2762 if (ima->type == type) {
2763 break;
2764 }
2765 }
2766 }
2767
2768 if (ima == nullptr) {
2769 ima = image_alloc(bmain, std::nullopt, name, IMA_SRC_VIEWER, type);
2770 }
2771
2772 /* Happens on reload, image-window cannot be image user when hidden. */
2773 if (ima->id.us == 0) {
2774 id_us_ensure_real(&ima->id);
2775 }
2776
2777 return ima;
2778}
2779
2780static void image_viewer_create_views(const RenderData *rd, Image *ima)
2781{
2782 if ((rd->scemode & R_MULTIVIEW) == 0) {
2783 image_add_view(ima, "", "");
2784 }
2785 else {
2786 LISTBASE_FOREACH (SceneRenderView *, srv, &rd->views) {
2787 if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
2788 continue;
2789 }
2790 image_add_view(ima, srv->name, "");
2791 }
2792 }
2793}
2794
2795/* Returns true if the views of the given image match the actives views in the given render data.
2796 * Returns false otherwise to indicate that the image views should be recreated to make them match
2797 * the render data. */
2798static bool image_views_match_render_views(const Image *image, const RenderData *render_data)
2799{
2800 /* The number of views in the image do not match the number of active views in the render
2801 * data. */
2802 const int number_of_active_views = BKE_scene_multiview_num_views_get(render_data);
2803 if (BLI_listbase_count(&image->views) != number_of_active_views) {
2804 return false;
2805 }
2806
2807 /* If the render data is not multi-view, then a single unnamed view should exist in the image,
2808 * otherwise, the views don't match. We don't have to check that a single view exist, since this
2809 * is handled by the check above for the number of views. */
2810 if (!(render_data->scemode & R_MULTIVIEW)) {
2811 const ImageView *image_view = static_cast<ImageView *>(image->views.first);
2812 /* If the view is unnamed, the views match, otherwise, they don't. */
2813 return image_view->name[0] == '\0';
2814 }
2815
2816 /* The render data is multi-view, so we need to check that for every view in the image, a
2817 * corresponding active render view with the same name exists, noting that they may not
2818 * necessarily be in the same order. */
2819 LISTBASE_FOREACH (ImageView *, image_view, &image->views) {
2820 SceneRenderView *scene_render_view = static_cast<SceneRenderView *>(
2821 BLI_findstring(&render_data->views, image_view->name, offsetof(SceneRenderView, name)));
2822 /* A render view doesn't exist for that image view with the same name, so the views don't
2823 * match. */
2824 if (!scene_render_view) {
2825 return false;
2826 }
2827
2828 /* A render view exists for that image view with the same name, but it is disabled, so the
2829 * views don't match. */
2830 if (!BKE_scene_multiview_is_render_view_active(render_data, scene_render_view)) {
2831 return false;
2832 }
2833 }
2834
2835 return true;
2836}
2837
2839{
2841
2843 iuser->flag &= ~IMA_SHOW_STEREO;
2844 }
2845
2846 if (!image_views_match_render_views(ima, rd)) {
2847 std::scoped_lock lock(ima->runtime->cache_mutex);
2848
2851
2852 /* add new views */
2854 }
2855
2857}
2858
2860 bNodeTree *ntree,
2861 ID *id,
2862 void *customdata,
2863 void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
2864{
2865 switch (ntree->type) {
2866 case NTREE_SHADER:
2867 for (bNode *node : ntree->all_nodes()) {
2868 if (node->id) {
2869 if (node->type_legacy == SH_NODE_TEX_IMAGE) {
2870 NodeTexImage *tex = static_cast<NodeTexImage *>(node->storage);
2871 Image *ima = (Image *)node->id;
2872 callback(ima, id, &tex->iuser, customdata);
2873 }
2874 if (node->type_legacy == SH_NODE_TEX_ENVIRONMENT) {
2875 NodeTexImage *tex = static_cast<NodeTexImage *>(node->storage);
2876 Image *ima = (Image *)node->id;
2877 callback(ima, id, &tex->iuser, customdata);
2878 }
2879 }
2880 }
2881 break;
2882 case NTREE_TEXTURE:
2883 for (bNode *node : ntree->all_nodes()) {
2884 if (node->id && node->type_legacy == TEX_NODE_IMAGE) {
2885 Image *ima = (Image *)node->id;
2886 ImageUser *iuser = static_cast<ImageUser *>(node->storage);
2887 callback(ima, id, iuser, customdata);
2888 }
2889 }
2890 break;
2891 case NTREE_COMPOSIT:
2892 for (bNode *node : ntree->all_nodes()) {
2893 if (node->id && node->type_legacy == CMP_NODE_IMAGE) {
2894 Image *ima = (Image *)node->id;
2895 ImageUser *iuser = static_cast<ImageUser *>(node->storage);
2896 callback(ima, id, iuser, customdata);
2897 }
2898 if (node->type_legacy == CMP_NODE_CRYPTOMATTE) {
2899 CMPNodeCryptomatteSource source = static_cast<CMPNodeCryptomatteSource>(node->custom1);
2900 if (source == CMP_NODE_CRYPTOMATTE_SOURCE_IMAGE) {
2901 Image *image = (Image *)node->id;
2902 ImageUser *image_user = &static_cast<NodeCryptomatte *>(node->storage)->iuser;
2903 callback(image, id, image_user, customdata);
2904 }
2905 }
2906 }
2907 break;
2908 }
2909}
2910
2912 ID *id,
2913 ListBase *gpu_materials,
2914 void *customdata,
2915 void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
2916{
2917 LISTBASE_FOREACH (LinkData *, link, gpu_materials) {
2918 GPUMaterial *gpu_material = (GPUMaterial *)link->data;
2919 ListBase textures = GPU_material_textures(gpu_material);
2920 LISTBASE_FOREACH (GPUMaterialTexture *, gpu_material_texture, &textures) {
2921 if (gpu_material_texture->iuser_available) {
2922 callback(gpu_material_texture->ima, id, &gpu_material_texture->iuser, customdata);
2923 }
2924 }
2925 }
2926}
2927
2929 ID *id,
2930 bool skip_nested_nodes,
2931 void *customdata,
2932 void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
2933{
2934 switch (GS(id->name)) {
2935 case ID_OB: {
2936 Object *ob = (Object *)id;
2937 if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) {
2938 callback(static_cast<Image *>(ob->data), &ob->id, ob->iuser, customdata);
2939 }
2940 break;
2941 }
2942 case ID_MA: {
2943 Material *ma = (Material *)id;
2944 if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) {
2945 image_walk_ntree_all_users(ma->nodetree, &ma->id, customdata, callback);
2946 }
2947 image_walk_gpu_materials(id, &ma->gpumaterial, customdata, callback);
2948 break;
2949 }
2950 case ID_LA: {
2951 Light *light = (Light *)id;
2952 if (light->nodetree && light->use_nodes && !skip_nested_nodes) {
2953 image_walk_ntree_all_users(light->nodetree, &light->id, customdata, callback);
2954 }
2955 break;
2956 }
2957 case ID_WO: {
2958 World *world = (World *)id;
2959 if (world->nodetree && world->use_nodes && !skip_nested_nodes) {
2960 image_walk_ntree_all_users(world->nodetree, &world->id, customdata, callback);
2961 }
2962 image_walk_gpu_materials(id, &world->gpumaterial, customdata, callback);
2963 break;
2964 }
2965 case ID_TE: {
2966 Tex *tex = (Tex *)id;
2967 if (tex->type == TEX_IMAGE && tex->ima) {
2968 callback(tex->ima, &tex->id, &tex->iuser, customdata);
2969 }
2970 if (tex->nodetree && tex->use_nodes && !skip_nested_nodes) {
2971 image_walk_ntree_all_users(tex->nodetree, &tex->id, customdata, callback);
2972 }
2973 break;
2974 }
2975 case ID_NT: {
2976 bNodeTree *ntree = (bNodeTree *)id;
2977 image_walk_ntree_all_users(ntree, &ntree->id, customdata, callback);
2978 break;
2979 }
2980 case ID_CA: {
2981 Camera *cam = (Camera *)id;
2982 LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
2983 callback(bgpic->ima, nullptr, &bgpic->iuser, customdata);
2984 }
2985 break;
2986 }
2987 case ID_WM: {
2988 wmWindowManager *wm = (wmWindowManager *)id;
2989 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2990 const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
2991
2992 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
2993 if (area->spacetype == SPACE_IMAGE) {
2994 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
2995 callback(sima->image, nullptr, &sima->iuser, customdata);
2996 }
2997 }
2998 }
2999 break;
3000 }
3001 case ID_SCE: {
3002 Scene *scene = (Scene *)id;
3003 if (scene->nodetree && scene->use_nodes && !skip_nested_nodes) {
3004 image_walk_ntree_all_users(scene->nodetree, &scene->id, customdata, callback);
3005 }
3006 break;
3007 }
3008 default:
3009 break;
3010 }
3011}
3012
3014 const Main *mainp,
3015 void *customdata,
3016 void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
3017{
3018 for (Scene *scene = static_cast<Scene *>(mainp->scenes.first); scene;
3019 scene = static_cast<Scene *>(scene->id.next))
3020 {
3021 image_walk_id_all_users(&scene->id, false, customdata, callback);
3022 }
3023
3024 for (Object *ob = static_cast<Object *>(mainp->objects.first); ob;
3025 ob = static_cast<Object *>(ob->id.next))
3026 {
3027 image_walk_id_all_users(&ob->id, false, customdata, callback);
3028 }
3029
3030 for (bNodeTree *ntree = static_cast<bNodeTree *>(mainp->nodetrees.first); ntree;
3031 ntree = static_cast<bNodeTree *>(ntree->id.next))
3032 {
3033 image_walk_id_all_users(&ntree->id, false, customdata, callback);
3034 }
3035
3036 for (Material *ma = static_cast<Material *>(mainp->materials.first); ma;
3037 ma = static_cast<Material *>(ma->id.next))
3038 {
3039 image_walk_id_all_users(&ma->id, false, customdata, callback);
3040 }
3041
3042 for (Light *light = static_cast<Light *>(mainp->materials.first); light;
3043 light = static_cast<Light *>(light->id.next))
3044 {
3045 image_walk_id_all_users(&light->id, false, customdata, callback);
3046 }
3047
3048 for (World *world = static_cast<World *>(mainp->materials.first); world;
3049 world = static_cast<World *>(world->id.next))
3050 {
3051 image_walk_id_all_users(&world->id, false, customdata, callback);
3052 }
3053
3054 for (Tex *tex = static_cast<Tex *>(mainp->textures.first); tex;
3055 tex = static_cast<Tex *>(tex->id.next))
3056 {
3057 image_walk_id_all_users(&tex->id, false, customdata, callback);
3058 }
3059
3060 for (Camera *cam = static_cast<Camera *>(mainp->cameras.first); cam;
3061 cam = static_cast<Camera *>(cam->id.next))
3062 {
3063 image_walk_id_all_users(&cam->id, false, customdata, callback);
3064 }
3065 /* Only ever 1 `wm`. */
3066 for (wmWindowManager *wm = static_cast<wmWindowManager *>(mainp->wm.first); wm;
3067 wm = static_cast<wmWindowManager *>(wm->id.next))
3068 {
3069 image_walk_id_all_users(&wm->id, false, customdata, callback);
3070 }
3071}
3072
3073static void image_tag_frame_recalc(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata)
3074{
3075 Image *changed_image = static_cast<Image *>(customdata);
3076
3077 if (ima == changed_image && BKE_image_is_animated(ima)) {
3078 iuser->flag |= IMA_NEED_FRAME_RECALC;
3079
3080 if (iuser_id) {
3081 /* Must copy image user changes to evaluated data-block. */
3083 }
3084 }
3085}
3086
3087static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata)
3088{
3089 Image *changed_image = static_cast<Image *>(customdata);
3090
3091 if (ima == changed_image) {
3092 if (iuser->scene) {
3093 image_update_views_format(ima, iuser);
3094 }
3095 if (iuser_id) {
3096 /* Must copy image user changes to evaluated data-block. */
3098 }
3100 }
3101}
3102
3104{
3105 *iuser = ImageUser{};
3106 iuser->frames = 100;
3107 iuser->sfra = 1;
3108}
3109
3111{
3112 RenderResult *rr = ima->rr;
3113
3114 iuser->multi_index = 0;
3115 iuser->layer = iuser->pass = iuser->view = 0;
3116
3117 if (rr) {
3118 BKE_image_multilayer_index(rr, iuser);
3119 }
3120}
3121
3123{
3124 for (int i = 0; i < TEXTARGET_COUNT; i++) {
3125 /* Only two textures depends on all tiles, so if this is a secondary tile we can keep the other
3126 * two. */
3128 continue;
3129 }
3130
3131 for (int eye = 0; eye < 2; eye++) {
3132 if (ima->gputexture[i][eye] != nullptr) {
3133 GPU_texture_free(ima->gputexture[i][eye]);
3134 ima->gputexture[i][eye] = nullptr;
3135 }
3136 }
3137 }
3139
3140 if (BKE_image_is_multiview(ima)) {
3141 const int totviews = BLI_listbase_count(&ima->views);
3142 for (int i = 0; i < totviews; i++) {
3143 image_remove_ibuf(ima, i, tile->tile_number);
3144 }
3145 }
3146 else {
3147 image_remove_ibuf(ima, 0, tile->tile_number);
3148 }
3149}
3150
3152{
3153 if (BLI_listbase_is_single(&ima->tiles)) {
3154 /* Can't remove the last remaining tile. */
3155 return false;
3156 }
3157
3158 image_free_tile(ima, tile);
3159 BLI_remlink(&ima->tiles, tile);
3160 MEM_freeN(tile);
3161
3162 return true;
3163}
3164
3166{
3167 /* Remove all but the final tile. */
3168 while (image_remove_tile(ima, static_cast<ImageTile *>(ima->tiles.last))) {
3169 ;
3170 }
3171}
3172
3173void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
3174{
3175 if (ima == nullptr) {
3176 return;
3177 }
3178
3179 ima->runtime->cache_mutex.lock();
3180
3181 switch (signal) {
3182 case IMA_SIGNAL_FREE:
3184
3185 if (iuser) {
3186 if (iuser->scene) {
3187 image_update_views_format(ima, iuser);
3188 }
3189 }
3190 break;
3192 if (ima->type == IMA_TYPE_UV_TEST) {
3193 if (ima->source != IMA_SRC_GENERATED) {
3194 ima->type = IMA_TYPE_IMAGE;
3195 }
3196 }
3197
3198 if (ima->source == IMA_SRC_GENERATED) {
3199 ImageTile *base_tile = BKE_image_get_tile(ima, 0);
3200 if (base_tile->gen_x == 0 || base_tile->gen_y == 0) {
3202 if (ibuf) {
3203 base_tile->gen_x = ibuf->x;
3204 base_tile->gen_y = ibuf->y;
3205 IMB_freeImBuf(ibuf);
3206 }
3207 }
3208
3209 /* Changing source type to generated will likely change file format
3210 * used by generated image buffer. Saving different file format to
3211 * the old name might confuse other applications.
3212 *
3213 * Here we ensure original image path wouldn't be used when saving
3214 * generated image.
3215 */
3216 ima->filepath[0] = '\0';
3217 }
3218
3219 if (ima->source != IMA_SRC_TILED) {
3220 /* Free all but the first tile. */
3222
3223 /* If this used to be a UDIM image, get the concrete filepath associated
3224 * with the remaining tile and use that as the new filepath. */
3225 ImageTile *base_tile = BKE_image_get_tile(ima, 0);
3227 const bool was_relative = BLI_path_is_rel(ima->filepath);
3228
3229 eUDIM_TILE_FORMAT tile_format;
3230 char *udim_pattern = BKE_image_get_tile_strformat(ima->filepath, &tile_format);
3232 ima->filepath, udim_pattern, tile_format, base_tile->tile_number);
3233 MEM_freeN(udim_pattern);
3234
3235 if (was_relative) {
3236 const char *relbase = ID_BLEND_PATH(bmain, &ima->id);
3237 BLI_path_rel(ima->filepath, relbase);
3238 }
3239 }
3240
3241 /* If the remaining tile was not number 1001, we need to reassign it so that
3242 * ibuf lookups from the cache still succeed. */
3243 base_tile->tile_number = 1001;
3244 }
3245 else {
3246 /* When changing to UDIM, attempt to tokenize the filepath. */
3247 BKE_image_ensure_tile_token(ima->filepath, sizeof(ima->filepath));
3248 }
3249
3250 /* image buffers for non-sequence multilayer will share buffers with RenderResult,
3251 * however sequence multilayer will own buffers. Such logic makes switching from
3252 * single multilayer file to sequence completely unstable
3253 * since changes in nodes seems this workaround isn't needed anymore, all sockets
3254 * are nicely detecting anyway, but freeing buffers always here makes multilayer
3255 * sequences behave stable
3256 */
3258
3259 if (iuser) {
3260 image_tag_frame_recalc(ima, nullptr, iuser, ima);
3261 }
3264
3265 break;
3266
3267 case IMA_SIGNAL_RELOAD:
3268 /* try to repack file */
3269 if (BKE_image_has_packedfile(ima)) {
3270 const int tot_viewfiles = image_num_viewfiles(ima);
3271 const int tot_files = tot_viewfiles * BLI_listbase_count(&ima->tiles);
3272
3273 if (!BLI_listbase_count_is_equal_to(&ima->packedfiles, tot_files)) {
3274 /* in case there are new available files to be loaded */
3276 BKE_image_packfiles(nullptr, ima, ID_BLEND_PATH(bmain, &ima->id));
3277 }
3278 else {
3279 LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) {
3280 PackedFile *pf;
3281 pf = BKE_packedfile_new(nullptr, imapf->filepath, ID_BLEND_PATH(bmain, &ima->id));
3282 if (pf) {
3283 BKE_packedfile_free(imapf->packedfile);
3284 imapf->packedfile = pf;
3285 }
3286 else {
3287 printf("ERROR: Image \"%s\" not available. Keeping packed image\n", imapf->filepath);
3288 }
3289 }
3290 }
3291
3292 if (BKE_image_has_packedfile(ima)) {
3294 }
3295 }
3296 else {
3298 }
3299
3300 if (ima->source == IMA_SRC_TILED) {
3301 ListBase new_tiles = {nullptr, nullptr};
3302 int new_start, new_range;
3303
3304 char filepath[FILE_MAX];
3305 STRNCPY(filepath, ima->filepath);
3306 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
3307 bool result = BKE_image_get_tile_info(filepath, &new_tiles, &new_start, &new_range);
3308 if (result) {
3309 /* Because the prior and new list of tiles are both sparse sequences, we need to be sure
3310 * to account for how the two sets might or might not overlap. To be complete, we start
3311 * the refresh process by clearing all existing tiles, stopping when there's only 1 tile
3312 * left. */
3314
3315 ImageTile *base_tile = BKE_image_get_tile(ima, 0);
3316 int remaining_tile_number = base_tile->tile_number;
3317 bool needs_final_cleanup = true;
3318
3319 /* Add in all the new tiles. As the image is proven to be on disk at this point, remove
3320 * the generation flag from the remaining tile in case this was previously a generated
3321 * image. */
3322 base_tile->gen_flag &= ~IMA_GEN_TILE;
3323 LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) {
3324 int new_tile_number = POINTER_AS_INT(new_tile->data);
3325 BKE_image_add_tile(ima, new_tile_number, nullptr);
3326 if (new_tile_number == remaining_tile_number) {
3327 needs_final_cleanup = false;
3328 }
3329 }
3330
3331 /* Final cleanup if the prior remaining tile was never encountered in the new list. */
3332 if (needs_final_cleanup) {
3333 BKE_image_remove_tile(ima, BKE_image_get_tile(ima, remaining_tile_number));
3334 }
3335 }
3336 BLI_freelistN(&new_tiles);
3337 }
3338 else if (ima->filepath[0] != '\0') {
3339 /* If the filepath is set at this point remove the generation flag. */
3340 ImageTile *base_tile = BKE_image_get_tile(ima, 0);
3341 base_tile->gen_flag &= ~IMA_GEN_TILE;
3342 }
3343
3344 if (iuser) {
3345 image_tag_reload(ima, nullptr, iuser, ima);
3346 }
3348 break;
3350 if (iuser) {
3352 if (ima->type == IMA_TYPE_MULTILAYER) {
3353 BKE_image_init_imageuser(ima, iuser);
3354 }
3355 }
3356 }
3357 break;
3360 break;
3361 }
3362
3363 /* NOTE: It is important that the image is unlocked before calling the node tree updates since
3364 * its update functions might need to acquire image buffers from this image. */
3365 ima->runtime->cache_mutex.unlock();
3366
3367 BKE_ntree_update_tag_id_changed(bmain, &ima->id);
3368 BKE_ntree_update(*bmain);
3369}
3370
3376 const int pass,
3377 const int view,
3378 int *r_passindex)
3379{
3380 RenderPass *rpass_ret = nullptr;
3381 RenderPass *rpass;
3382
3383 int rp_index = 0;
3384 const char *rp_name = "";
3385
3386 for (rpass = static_cast<RenderPass *>(rl->passes.first); rpass; rpass = rpass->next, rp_index++)
3387 {
3388 if (rp_index == pass) {
3389 rpass_ret = rpass;
3390 if (view == 0) {
3391 /* no multiview or left eye */
3392 break;
3393 }
3394
3395 rp_name = rpass->name;
3396 }
3397 /* multiview */
3398 else if (rp_name[0] && STREQ(rpass->name, rp_name) && (rpass->view_id == view)) {
3399 rpass_ret = rpass;
3400 break;
3401 }
3402 }
3403
3404 /* fall back to the first pass in the layer */
3405 if (rpass_ret == nullptr) {
3406 rp_index = 0;
3407 rpass_ret = static_cast<RenderPass *>(rl->passes.first);
3408 }
3409
3410 if (r_passindex) {
3411 *r_passindex = (rpass == rpass_ret ? rp_index : pass);
3412 }
3413
3414 return rpass_ret;
3415}
3416
3418 const ImageTile *tile,
3419 char *label,
3420 const int label_maxncpy)
3421{
3422 label[0] = '\0';
3423 if (ima == nullptr || tile == nullptr) {
3424 return 0;
3425 }
3426
3427 if (tile->label[0]) {
3428 return BLI_strncpy_rlen(label, tile->label, label_maxncpy);
3429 }
3430 return BLI_snprintf_rlen(label, label_maxncpy, "%d", tile->tile_number);
3431}
3432
3433bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start, int *r_tile_range)
3434{
3435 char filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
3436 BLI_path_split_dir_file(filepath, dirname, sizeof(dirname), filename, sizeof(filename));
3437
3438 if (!BKE_image_is_filename_tokenized(filename)) {
3439 BKE_image_ensure_tile_token_filename_only(filename, sizeof(filename));
3440 }
3441
3442 eUDIM_TILE_FORMAT tile_format;
3443 char *udim_pattern = BKE_image_get_tile_strformat(filename, &tile_format);
3444
3445 bool all_valid_udim = true;
3446 int min_udim = IMA_UDIM_MAX + 1;
3447 int max_udim = 0;
3448 int id;
3449
3450 direntry *dirs;
3451 const uint dirs_num = BLI_filelist_dir_contents(dirname, &dirs);
3452 for (int i = 0; i < dirs_num; i++) {
3453 if (!(dirs[i].type & S_IFREG)) {
3454 continue;
3455 }
3456
3457 if (!BKE_image_get_tile_number_from_filepath(dirs[i].relname, udim_pattern, tile_format, &id))
3458 {
3459 continue;
3460 }
3461
3462 if (id < 1001 || id > IMA_UDIM_MAX) {
3463 all_valid_udim = false;
3464 break;
3465 }
3466
3468 min_udim = min_ii(min_udim, id);
3469 max_udim = max_ii(max_udim, id);
3470 }
3471 BLI_filelist_free(dirs, dirs_num);
3472 MEM_SAFE_FREE(udim_pattern);
3473
3474 if (all_valid_udim && min_udim <= IMA_UDIM_MAX) {
3475 BLI_path_join(filepath, FILE_MAX, dirname, filename);
3476
3477 *r_tile_start = min_udim;
3478 *r_tile_range = max_udim - min_udim + 1;
3479 return true;
3480 }
3481 return false;
3482}
3483
3484ImageTile *BKE_image_add_tile(Image *ima, int tile_number, const char *label)
3485{
3486 if (ima->source != IMA_SRC_TILED) {
3487 return nullptr;
3488 }
3489
3490 if (tile_number < 1001 || tile_number > IMA_UDIM_MAX) {
3491 return nullptr;
3492 }
3493
3494 /* Search the first tile that has a higher number.
3495 * We then insert before that to keep the list sorted. */
3496 ImageTile *next_tile;
3497 for (next_tile = static_cast<ImageTile *>(ima->tiles.first); next_tile;
3498 next_tile = next_tile->next)
3499 {
3500 if (next_tile->tile_number == tile_number) {
3501 /* Tile already exists. */
3502 return nullptr;
3503 }
3504 if (next_tile->tile_number > tile_number) {
3505 break;
3506 }
3507 }
3508
3509 ImageTile *tile = imagetile_alloc(tile_number);
3510
3511 if (next_tile) {
3512 BLI_insertlinkbefore(&ima->tiles, next_tile, tile);
3513 }
3514 else {
3515 BLI_addtail(&ima->tiles, tile);
3516 }
3517
3518 if (label) {
3519 STRNCPY(tile->label, label);
3520 }
3521
3522 for (int eye = 0; eye < 2; eye++) {
3523 /* Reallocate GPU tile array. */
3524 if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != nullptr) {
3526 ima->gputexture[TEXTARGET_2D_ARRAY][eye] = nullptr;
3527 }
3528 if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != nullptr) {
3530 ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = nullptr;
3531 }
3532 }
3534
3535 return tile;
3536}
3537
3539{
3540 if (ima == nullptr || tile == nullptr || ima->source != IMA_SRC_TILED) {
3541 return false;
3542 }
3543
3544 return image_remove_tile(ima, tile);
3545}
3546
3547void BKE_image_reassign_tile(Image *ima, ImageTile *tile, int new_tile_number)
3548{
3549 if (ima == nullptr || tile == nullptr || ima->source != IMA_SRC_TILED) {
3550 return;
3551 }
3552
3553 if (new_tile_number < 1001 || new_tile_number > IMA_UDIM_MAX) {
3554 return;
3555 }
3556
3557 const int old_tile_number = tile->tile_number;
3558 tile->tile_number = new_tile_number;
3559
3560 if (BKE_image_is_multiview(ima)) {
3561 const int totviews = BLI_listbase_count(&ima->views);
3562 for (int i = 0; i < totviews; i++) {
3563 ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, old_tile_number, nullptr);
3564 image_remove_ibuf(ima, i, old_tile_number);
3565 image_assign_ibuf(ima, ibuf, i, new_tile_number);
3566 IMB_freeImBuf(ibuf);
3567 }
3568 }
3569 else {
3570 ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, 0, old_tile_number, nullptr);
3571 image_remove_ibuf(ima, 0, old_tile_number);
3572 image_assign_ibuf(ima, ibuf, 0, new_tile_number);
3573 IMB_freeImBuf(ibuf);
3574 }
3575
3576 for (int eye = 0; eye < 2; eye++) {
3577 /* Reallocate GPU tile array. */
3578 if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != nullptr) {
3580 ima->gputexture[TEXTARGET_2D_ARRAY][eye] = nullptr;
3581 }
3582 if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != nullptr) {
3584 ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = nullptr;
3585 }
3586 }
3588}
3589
3590static int tile_sort_cb(const void *a, const void *b)
3591{
3592 const ImageTile *tile_a = static_cast<const ImageTile *>(a);
3593 const ImageTile *tile_b = static_cast<const ImageTile *>(b);
3594 return (tile_a->tile_number > tile_b->tile_number) ? 1 : 0;
3595}
3596
3598{
3599 if (ima == nullptr || ima->source != IMA_SRC_TILED) {
3600 return;
3601 }
3602
3604}
3605
3607{
3608 if (ima == nullptr || tile == nullptr || ima->source != IMA_SRC_TILED) {
3609 return false;
3610 }
3611
3612 image_free_tile(ima, tile);
3613
3614 ImBuf *tile_ibuf = add_ibuf_for_tile(ima, tile);
3615
3616 if (tile_ibuf != nullptr) {
3617 image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number);
3618 BKE_image_release_ibuf(ima, tile_ibuf, nullptr);
3619 return true;
3620 }
3621 return false;
3622}
3623
3625{
3626 const char *filename = BLI_path_basename(filepath);
3627 return strstr(filename, "<UDIM>") != nullptr || strstr(filename, "<UVTILE>") != nullptr;
3628}
3629
3630void BKE_image_ensure_tile_token_filename_only(char *filename, size_t filename_maxncpy)
3631{
3632 BLI_assert_msg(BLI_path_slash_find(filename) == nullptr,
3633 "Only the file-name component should be used!");
3634
3635 if (BKE_image_is_filename_tokenized(filename)) {
3636 return;
3637 }
3638
3639 std::string path(filename);
3640 std::smatch match;
3641
3642 /* General 4-digit "udim" pattern. As this format is susceptible to ambiguity
3643 * with other digit sequences, we can leverage the supported range of roughly
3644 * 1000 through 2000 to provide better detection. */
3645 std::regex pattern(R"((.*[._-])([12]\d{3})([._-].*))");
3646 if (std::regex_search(path, match, pattern)) {
3647 BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), filename_maxncpy);
3648 return;
3649 }
3650
3651 /* General `u##_v###` `uvtile` pattern. */
3652 pattern = std::regex(R"((.*)(u\d{1,2}_v\d{1,3})(\D.*))");
3653 if (std::regex_search(path, match, pattern)) {
3654 BLI_strncpy(filename, match.format("$1<UVTILE>$3").c_str(), filename_maxncpy);
3655 return;
3656 }
3657}
3658
3659void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy)
3660{
3661 char *filename = (char *)BLI_path_basename(filepath);
3662 BKE_image_ensure_tile_token_filename_only(filename, filepath_maxncpy - (filename - filepath));
3663}
3664
3665bool BKE_image_tile_filepath_exists(const char *filepath)
3666{
3667 BLI_assert(!BLI_path_is_rel(filepath));
3668
3669 char dirname[FILE_MAXDIR];
3670 BLI_path_split_dir_part(filepath, dirname, sizeof(dirname));
3671
3672 eUDIM_TILE_FORMAT tile_format;
3673 char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
3674
3675 bool found = false;
3676 direntry *dirs;
3677 const uint dirs_num = BLI_filelist_dir_contents(dirname, &dirs);
3678 for (int i = 0; i < dirs_num; i++) {
3679 if (!(dirs[i].type & S_IFREG)) {
3680 continue;
3681 }
3682
3683 int id;
3684 if (!BKE_image_get_tile_number_from_filepath(dirs[i].path, udim_pattern, tile_format, &id)) {
3685 continue;
3686 }
3687
3688 if (id < 1001 || id > IMA_UDIM_MAX) {
3689 continue;
3690 }
3691
3692 found = true;
3693 break;
3694 }
3695 BLI_filelist_free(dirs, dirs_num);
3696 MEM_SAFE_FREE(udim_pattern);
3697
3698 return found;
3699}
3700
3701char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format)
3702{
3703 if (filepath == nullptr || r_tile_format == nullptr) {
3704 return nullptr;
3705 }
3706
3707 if (strstr(filepath, "<UDIM>") != nullptr) {
3708 *r_tile_format = UDIM_TILE_FORMAT_UDIM;
3709 return BLI_string_replaceN(filepath, "<UDIM>", "%d");
3710 }
3711 if (strstr(filepath, "<UVTILE>") != nullptr) {
3712 *r_tile_format = UDIM_TILE_FORMAT_UVTILE;
3713 return BLI_string_replaceN(filepath, "<UVTILE>", "u%d_v%d");
3714 }
3715
3716 *r_tile_format = UDIM_TILE_FORMAT_NONE;
3717 return nullptr;
3718}
3719
3721 const char *pattern,
3722 eUDIM_TILE_FORMAT tile_format,
3723 int *r_tile_number)
3724{
3725 if (filepath == nullptr || pattern == nullptr || r_tile_number == nullptr) {
3726 return false;
3727 }
3728
3729 int u, v;
3730 bool result = false;
3731
3732 if (tile_format == UDIM_TILE_FORMAT_UDIM) {
3733 if (sscanf(filepath, pattern, &u) == 1) {
3734 *r_tile_number = u;
3735 result = true;
3736 }
3737 }
3738 else if (tile_format == UDIM_TILE_FORMAT_UVTILE) {
3739 if (sscanf(filepath, pattern, &u, &v) == 2) {
3740 *r_tile_number = 1001 + (u - 1) + ((v - 1) * 10);
3741 result = true;
3742 }
3743 }
3744
3745 return result;
3746}
3747
3749 const char *pattern,
3750 eUDIM_TILE_FORMAT tile_format,
3751 int tile_number)
3752{
3753 if (filepath == nullptr || pattern == nullptr) {
3754 return;
3755 }
3756
3757 if (tile_format == UDIM_TILE_FORMAT_UDIM) {
3758 BLI_snprintf(filepath, FILE_MAX, pattern, tile_number);
3759 }
3760 else if (tile_format == UDIM_TILE_FORMAT_UVTILE) {
3761 int u = ((tile_number - 1001) % 10);
3762 int v = ((tile_number - 1001) / 10);
3763 BLI_snprintf(filepath, FILE_MAX, pattern, u + 1, v + 1);
3764 }
3765}
3766
3768{
3769 /* If layer or pass changes, we need an index for the imbufs list. */
3770 /* NOTE: it is called for rendered results, but it doesn't use the index! */
3771
3772 RenderLayer *rl;
3773 RenderPass *rpass = nullptr;
3774
3775 if (rr == nullptr) {
3776 return nullptr;
3777 }
3778
3779 if (iuser) {
3780 short index = 0, rv_index, rl_index = 0;
3781 bool is_stereo = (iuser->flag & IMA_SHOW_STEREO) && RE_RenderResult_is_stereo(rr);
3782
3783 rv_index = is_stereo ? iuser->multiview_eye : iuser->view;
3784 if (RE_HasCombinedLayer(rr)) {
3785 rl_index += 1;
3786 }
3787
3788 for (rl = static_cast<RenderLayer *>(rr->layers.first); rl; rl = rl->next, rl_index++) {
3789 if (iuser->layer == rl_index) {
3790 int rp_index;
3791 rpass = image_render_pass_get(rl, iuser->pass, rv_index, &rp_index);
3792 iuser->multi_index = index + rp_index;
3793 break;
3794 }
3795
3796 index += BLI_listbase_count(&rl->passes);
3797 }
3798 }
3799
3800 return rpass;
3801}
3802
3804{
3805 if (iuser) {
3806 bool is_stereo = BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO);
3807 if (is_stereo) {
3808 iuser->multi_index = iuser->multiview_eye;
3809 }
3810 else {
3811 if ((iuser->view < 0) ||
3812 (iuser->view >= BLI_listbase_count_at_most(&ima->views, iuser->view + 1)))
3813 {
3814 iuser->multi_index = iuser->view = 0;
3815 }
3816 else {
3817 iuser->multi_index = iuser->view;
3818 }
3819 }
3820 }
3821}
3822
3824{
3825 /* If layer or pass changes, we need an index for the imbufs list. */
3826 /* NOTE: it is called for rendered results, but it doesn't use the index! */
3827
3829 if (ima->type == IMA_TYPE_MULTILAYER) {
3830 return true;
3831 }
3832 }
3833 else if (ima->source == IMA_SRC_VIEWER) {
3834 if (ima->type == IMA_TYPE_R_RESULT) {
3835 return true;
3836 }
3837 }
3838 return false;
3839}
3840
3842{
3843 ImageView *view = static_cast<ImageView *>(ima->views.first);
3844 return (view && (view->next || view->name[0]));
3845}
3846
3848{
3849 return BKE_image_is_multiview(ima) &&
3852}
3853
3855{
3856 /* update image views from render views, but only if they actually changed,
3857 * to avoid invalid memory access during render. ideally these should always
3858 * be acquired with a mutex along with the render result, but there are still
3859 * some places with just an image pointer that need to access views */
3860 if (rr && BLI_listbase_count(&ima->views) == BLI_listbase_count(&rr->views)) {
3861 ImageView *iv = static_cast<ImageView *>(ima->views.first);
3862 RenderView *rv = static_cast<RenderView *>(rr->views.first);
3863 bool modified = false;
3864 for (; rv; rv = rv->next, iv = iv->next) {
3865 modified |= !STREQ(rv->name, iv->name);
3866 }
3867 if (!modified) {
3868 return;
3869 }
3870 }
3871
3873
3874 if (rr) {
3875 LISTBASE_FOREACH (RenderView *, rv, &rr->views) {
3876 ImageView *iv = MEM_callocN<ImageView>("Viewer Image View");
3877 STRNCPY(iv->name, rv->name);
3878 BLI_addtail(&ima->views, iv);
3879 }
3880 }
3881}
3882
3884{
3885 std::scoped_lock lock(ima->runtime->cache_mutex);
3886
3887 RenderResult *rr = nullptr;
3888
3889 if (ima->rr) {
3890 rr = ima->rr;
3891 }
3892 else if (scene && ima->type == IMA_TYPE_R_RESULT) {
3893 if (ima->render_slot == ima->last_render_slot) {
3895 }
3896 else {
3899 }
3900
3901 /* set proper views */
3903 }
3904
3905 if (rr) {
3907 }
3908
3909 return rr;
3910}
3911
3912void BKE_image_release_renderresult(Scene *scene, Image *ima, RenderResult *render_result)
3913{
3914 if (render_result) {
3915 /* Decrement user counter, and free if nobody else holds a reference to the result. */
3916 std::scoped_lock lock(ima->runtime->cache_mutex);
3917 RE_FreeRenderResult(render_result);
3918 }
3919
3920 if (ima->rr) {
3921 /* pass */
3922 }
3923 else if (scene && ima->type == IMA_TYPE_R_RESULT) {
3924 if (ima->render_slot == ima->last_render_slot) {
3926 }
3927 }
3928}
3929
3931{
3932#ifdef WITH_IMAGE_OPENEXR
3934 return BLI_path_extension_check(ima->filepath, ".exr");
3935 }
3936#else
3937 UNUSED_VARS(ima);
3938#endif
3939 return false;
3940}
3941
3942void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
3943{
3944 /* called right before rendering, ima->renderslots contains render
3945 * result pointers for everything but the current render */
3946 Render *re = RE_GetSceneRender(scene);
3947
3948 /* Ensure we always have a valid render slot. */
3949 if (!ima->renderslots.first) {
3950 BKE_image_add_renderslot(ima, nullptr);
3951 ima->render_slot = 0;
3952 ima->last_render_slot = 0;
3953 }
3954 else if (ima->render_slot >= BLI_listbase_count(&ima->renderslots)) {
3955 ima->render_slot = 0;
3956 ima->last_render_slot = 0;
3957 }
3958
3960 RenderSlot *cur_slot = BKE_image_get_renderslot(ima, ima->render_slot);
3961
3962 if (last_slot && ima->render_slot != ima->last_render_slot) {
3963 last_slot->render = nullptr;
3964 RE_SwapResult(re, &last_slot->render);
3965
3966 if (cur_slot->render) {
3967 if (free_current_slot) {
3968 BKE_image_clear_renderslot(ima, nullptr, ima->render_slot);
3969 }
3970 else {
3971 RE_SwapResult(re, &cur_slot->render);
3972 }
3973 }
3974 }
3975
3976 ima->last_render_slot = ima->render_slot;
3977}
3978
3980
3981/* -------------------------------------------------------------------- */
3984
3985static void image_add_view(Image *ima, const char *viewname, const char *filepath)
3986{
3987 ImageView *iv;
3988
3989 iv = MEM_mallocN<ImageView>("Viewer Image View");
3990 STRNCPY(iv->name, viewname);
3991 STRNCPY(iv->filepath, filepath);
3992
3993 /* For stereo drawing we need to ensure:
3994 * STEREO_LEFT_NAME == STEREO_LEFT_ID and
3995 * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
3996
3997 if (STREQ(viewname, STEREO_LEFT_NAME)) {
3998 BLI_addhead(&ima->views, iv);
3999 }
4000 else if (STREQ(viewname, STEREO_RIGHT_NAME)) {
4001 ImageView *left_iv = static_cast<ImageView *>(
4003
4004 if (left_iv == nullptr) {
4005 BLI_addhead(&ima->views, iv);
4006 }
4007 else {
4008 BLI_insertlinkafter(&ima->views, left_iv, iv);
4009 }
4010 }
4011 else {
4012 BLI_addtail(&ima->views, iv);
4013 }
4014}
4015
4016/* After imbuf load, OpenEXR type can return with a EXR-handle open
4017 * in that case we have to build a render-result. */
4018#ifdef WITH_IMAGE_OPENEXR
4019static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
4020{
4021 const char *colorspace = ima->colorspace_settings.name;
4022 bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
4023
4024 /* only load rr once for multiview */
4025 if (!ima->rr) {
4026 ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
4027 }
4028
4029 IMB_exr_close(ibuf->userdata);
4030
4031 ibuf->userdata = nullptr;
4032 if (ima->rr != nullptr) {
4033 ima->rr->framenr = framenr;
4034 BKE_stamp_info_from_imbuf(ima->rr, ibuf);
4035 }
4036
4037 /* set proper views */
4039}
4040#endif /* WITH_IMAGE_OPENEXR */
4041
4043static void image_init_after_load(Image *ima, ImageUser *iuser, ImBuf * /*ibuf*/)
4044{
4045 /* Preview is null when it has never been used as an icon before.
4046 * Never handle previews/icons outside of main thread. */
4047 if (G.background == 0 && ima->preview == nullptr && BLI_thread_is_main()) {
4049 }
4050
4051 /* timer */
4052 BKE_image_tag_time(ima);
4053
4055 /* Images should never get loaded if the corresponding tile does not exist,
4056 * but we should at least not crash if it happens due to a bug elsewhere. */
4057 BLI_assert(tile != nullptr);
4059}
4060
4062{
4063 switch (ima->alpha_mode) {
4064 case IMA_ALPHA_STRAIGHT:
4065 return 0;
4066 case IMA_ALPHA_PREMUL:
4067 return IB_alphamode_premul;
4070 case IMA_ALPHA_IGNORE:
4071 return IB_alphamode_ignore;
4072 }
4073
4074 return 0;
4075}
4076
4081{
4082 const bool is_multiview = BKE_image_is_multiview(ima);
4083
4084 if (!is_multiview) {
4085 return 1;
4086 }
4087 if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
4088 return 1;
4089 }
4090 /* R_IMF_VIEWS_INDIVIDUAL */
4091
4092 return BLI_listbase_count(&ima->views);
4093}
4094
4095static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int entry, int frame)
4096{
4097 ImBuf *ibuf = nullptr;
4098
4099 /* either we load from RenderResult, or we have to load a new one */
4100
4101 /* check for new RenderResult */
4102 if (ima->rr == nullptr || frame != ima->rr->framenr) {
4103 if (ima->rr) {
4104 /* Cached image buffers shares pointers with render result,
4105 * need to ensure there's no image buffers are hanging around
4106 * with dead links after freeing the render result.
4107 */
4109 RE_FreeRenderResult(ima->rr);
4110 ima->rr = nullptr;
4111 }
4112
4113 ibuf = image_load_image_file(ima, iuser, entry, frame, true);
4114
4115 if (ibuf) { /* actually an error */
4116 ima->type = IMA_TYPE_IMAGE;
4117 printf("error, multi is normal image\n");
4118 }
4119 }
4120 if (ima->rr) {
4121 RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
4122
4123 if (rpass && rpass->ibuf) {
4124 ibuf = rpass->ibuf;
4125 IMB_refImBuf(ibuf);
4126
4127 BKE_imbuf_stamp_info(ima->rr, ibuf);
4128 copy_v2_v2_db(ibuf->ppm, ima->rr->ppm);
4129
4130 image_init_after_load(ima, iuser, ibuf);
4131 image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : 0, entry);
4132 }
4133 // else printf("pass not found\n");
4134 }
4135
4136 return ibuf;
4137}
4138
4139static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const int view_id)
4140{
4141 ImBuf *ibuf = nullptr;
4142 ImageAnim *ia;
4143
4144 ia = static_cast<ImageAnim *>(BLI_findlink(&ima->anims, view_id));
4145
4146 if (ia->anim == nullptr) {
4147 char filepath[FILE_MAX];
4148 int flags = IB_byte_data;
4149 ImageUser iuser_t{};
4150
4151 if (ima->flag & IMA_DEINTERLACE) {
4152 flags |= IB_animdeinterlace;
4153 }
4154
4155 if (iuser) {
4156 iuser_t = *iuser;
4157 }
4158
4159 iuser_t.view = view_id;
4160
4161 BKE_image_user_file_path(&iuser_t, ima, filepath);
4162
4163 /* FIXME: make several stream accessible in image editor, too. */
4164 ia->anim = openanim(filepath, flags, 0, ima->colorspace_settings.name);
4165
4166 /* let's initialize this user */
4167 if (ia->anim && iuser && iuser->frames == 0) {
4169 }
4170 }
4171
4172 if (ia->anim) {
4174 int fra = frame - 1;
4175
4176 fra = std::max(fra, 0);
4177 fra = std::min(fra, dur - 1);
4179
4180 if (ibuf) {
4182 image_init_after_load(ima, iuser, ibuf);
4183 }
4184 }
4185
4186 return ibuf;
4187}
4188
4189static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
4190{
4191 ImBuf *ibuf = nullptr;
4192 const bool is_multiview = BKE_image_is_multiview(ima);
4193 const int tot_viewfiles = image_num_viewfiles(ima);
4194
4195 if (!BLI_listbase_count_is_equal_to(&ima->anims, tot_viewfiles)) {
4196 image_free_anims(ima);
4197
4198 for (int i = 0; i < tot_viewfiles; i++) {
4199 /* allocate the ImageAnim */
4200 ImageAnim *ia = MEM_callocN<ImageAnim>("Image Anim");
4201 BLI_addtail(&ima->anims, ia);
4202 }
4203 }
4204
4205 if (!is_multiview) {
4206 ibuf = load_movie_single(ima, iuser, frame, 0);
4207 image_assign_ibuf(ima, ibuf, 0, frame);
4208 }
4209 else {
4210 const int totviews = BLI_listbase_count(&ima->views);
4211 Array<ImBuf *> ibuf_arr(totviews);
4212
4213 for (int i = 0; i < tot_viewfiles; i++) {
4214 ibuf_arr[i] = load_movie_single(ima, iuser, frame, i);
4215 }
4216
4218 IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]);
4219 }
4220
4221 for (int i = 0; i < totviews; i++) {
4222 image_assign_ibuf(ima, ibuf_arr[i], i, frame);
4223 }
4224
4225 /* return the original requested ImBuf */
4226 ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
4227
4228 /* "remove" the others (decrease their refcount) */
4229 for (int i = 0; i < totviews; i++) {
4230 if (ibuf_arr[i] != ibuf) {
4231 IMB_freeImBuf(ibuf_arr[i]);
4232 }
4233 }
4234 }
4235
4236 return ibuf;
4237}
4238
4240 ImageUser *iuser,
4241 int cfra,
4242 const int view_id,
4243 const bool has_packed,
4244 const bool is_sequence,
4245 bool *r_cache_ibuf)
4246{
4247 char filepath[FILE_MAX];
4248 ImBuf *ibuf = nullptr;
4250
4251 *r_cache_ibuf = true;
4252 const int tile_number = image_get_tile_number_from_iuser(ima, iuser);
4253
4254 /* is there a PackedFile with this image ? */
4255 if (has_packed && !is_sequence) {
4256 LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) {
4257 if (imapf->view == view_id && imapf->tile_number == tile_number) {
4258 if (imapf->packedfile) {
4259 ibuf = IMB_load_image_from_memory((uchar *)imapf->packedfile->data,
4260 imapf->packedfile->size,
4261 flag,
4262 "<packed data>",
4263 nullptr,
4265 }
4266 break;
4267 }
4268 }
4269 }
4270 else {
4271 if (is_sequence) {
4272 ima->lastframe = cfra;
4273 }
4274
4275 /* get the correct filepath */
4276 const bool is_tiled = (ima->source == IMA_SRC_TILED);
4277 if (!(is_sequence || is_tiled)) {
4278 BKE_image_user_frame_calc(ima, iuser, cfra);
4279 }
4280
4281 ImageUser iuser_t{};
4282 if (iuser) {
4283 iuser_t = *iuser;
4284 }
4285 else {
4286 iuser_t.framenr = ima->lastframe;
4287 }
4288
4289 iuser_t.view = view_id;
4290
4291 BKE_image_user_file_path(&iuser_t, ima, filepath);
4292
4293 /* read ibuf */
4295 }
4296
4297 if (ibuf) {
4298#ifdef WITH_IMAGE_OPENEXR
4299 if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
4300 /* Handle multilayer and multiview cases, don't assign ibuf here.
4301 * will be set layer in BKE_image_acquire_ibuf from ima->rr. */
4302 if (IMB_exr_has_multilayer(ibuf->userdata)) {
4303 image_create_multilayer(ima, ibuf, cfra);
4305 IMB_freeImBuf(ibuf);
4306 ibuf = nullptr;
4307 /* Null ibuf in the cache means the image failed to load. However for multilayer we load
4308 * pixels into RenderResult instead and intentionally leave ibuf null. */
4309 *r_cache_ibuf = false;
4310 }
4311 }
4312 else
4313#endif
4314 {
4315 image_init_after_load(ima, iuser, ibuf);
4316
4317 /* Make packed file for auto-pack. */
4318 if (!is_sequence && (has_packed == false) && (G.fileflags & G_FILE_AUTOPACK)) {
4319 ImagePackedFile *imapf = MEM_mallocN<ImagePackedFile>("Image Pack-file");
4320 BLI_addtail(&ima->packedfiles, imapf);
4321
4322 STRNCPY(imapf->filepath, filepath);
4323 imapf->view = view_id;
4324 imapf->tile_number = tile_number;
4326 nullptr, filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
4327 }
4328 }
4329 }
4330
4331 return ibuf;
4332}
4333
4334/* warning, 'iuser' can be null
4335 * NOTE: Image->views was already populated (in image_update_views_format)
4336 */
4338 Image *ima, ImageUser *iuser, int entry, int cfra, bool is_sequence)
4339{
4340 ImBuf *ibuf = nullptr;
4341 const bool is_multiview = BKE_image_is_multiview(ima);
4342 const bool is_tiled = (ima->source == IMA_SRC_TILED);
4343 const int tot_viewfiles = image_num_viewfiles(ima);
4344 bool has_packed = BKE_image_has_packedfile(ima);
4345
4346 if (!(is_sequence || is_tiled)) {
4347 /* ensure clean ima */
4349 }
4350
4351 /* this should never happen, but just playing safe */
4352 if (!is_sequence && has_packed) {
4353 const int totfiles = tot_viewfiles * BLI_listbase_count(&ima->tiles);
4354 if (!BLI_listbase_count_is_equal_to(&ima->packedfiles, totfiles)) {
4356 has_packed = false;
4357 }
4358 }
4359
4360 if (!is_multiview) {
4361 bool put_in_cache;
4362 ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, is_sequence, &put_in_cache);
4363 if (put_in_cache) {
4364 const int index = (is_sequence || is_tiled) ? 0 : IMA_NO_INDEX;
4365 image_assign_ibuf(ima, ibuf, index, entry);
4366 }
4367 }
4368 else {
4369 const int totviews = BLI_listbase_count(&ima->views);
4370 BLI_assert(totviews > 0);
4371
4372 Array<ImBuf *> ibuf_arr(totviews);
4373 Array<bool> cache_ibuf_arr(totviews);
4374
4375 for (int i = 0; i < tot_viewfiles; i++) {
4376 ibuf_arr[i] = load_image_single(
4377 ima, iuser, cfra, i, has_packed, is_sequence, &cache_ibuf_arr[i]);
4378 }
4379
4380 /* multi-views/multi-layers OpenEXR files directly populate ima, and return null ibuf... */
4381 if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D && ibuf_arr[0] &&
4382 tot_viewfiles == 1 && totviews >= 2)
4383 {
4384 IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]);
4385 }
4386
4387 /* return the original requested ImBuf */
4388 const int ibuf_index = (iuser && iuser->multi_index < totviews) ? iuser->multi_index : 0;
4389 ibuf = ibuf_arr[ibuf_index];
4390
4391 for (int i = 0; i < totviews; i++) {
4392 if (cache_ibuf_arr[i]) {
4393 image_assign_ibuf(ima, ibuf_arr[i], i, entry);
4394 }
4395 }
4396
4397 /* "remove" the others (decrease their refcount) */
4398 for (int i = 0; i < totviews; i++) {
4399 if (ibuf_arr[i] != ibuf) {
4400 IMB_freeImBuf(ibuf_arr[i]);
4401 }
4402 }
4403 }
4404
4405 return ibuf;
4406}
4407
4409{
4410 ImBuf *ibuf = nullptr;
4411
4412 if (ima->rr == nullptr) {
4413 ibuf = image_load_image_file(ima, iuser, 0, 0, false);
4414 if (ibuf) { /* actually an error */
4415 ima->type = IMA_TYPE_IMAGE;
4416 return ibuf;
4417 }
4418 }
4419 if (ima->rr) {
4420 RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
4421
4422 if (rpass && rpass->ibuf) {
4423 ibuf = rpass->ibuf;
4424 IMB_refImBuf(ibuf);
4425
4426 image_init_after_load(ima, iuser, ibuf);
4427
4428 BKE_imbuf_stamp_info(ima->rr, ibuf);
4429 copy_v2_v2_db(ibuf->ppm, ima->rr->ppm);
4430
4431 image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : IMA_NO_INDEX, 0);
4432 }
4433 }
4434
4435 return ibuf;
4436}
4437
4438/* showing RGBA result itself (from compo/sequence) or
4439 * like exr, using layers etc */
4440/* always returns a single ibuf, also during render progress */
4441static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock)
4442{
4443 RenderView *rv;
4444 ImBuf *pass_ibuf = nullptr;
4445 float dither;
4446 const int from_render = (ima->render_slot == ima->last_render_slot);
4447
4448 if (!(iuser && iuser->scene)) {
4449 return nullptr;
4450 }
4451
4452 /* if we the caller is not going to release the lock, don't give the image */
4453 if (!r_lock) {
4454 return nullptr;
4455 }
4456
4457 Render *re = RE_GetSceneRender(iuser->scene);
4458
4459 const int layer = iuser->layer;
4460 const int pass = iuser->pass;
4461 int actview = iuser->view;
4462
4463 if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO)) {
4464 actview = iuser->multiview_eye;
4465 }
4466
4467 RenderResult rres{};
4468 RenderSlot *slot;
4469 if (from_render) {
4470 RE_AcquireResultImage(re, &rres, actview);
4471 }
4472 else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
4473 rres = *(slot->render);
4474 rres.have_combined = ((RenderView *)rres.views.first)->ibuf != nullptr;
4475 }
4476
4477 if (!(rres.rectx > 0 && rres.recty > 0)) {
4478 if (from_render) {
4480 }
4481 return nullptr;
4482 }
4483
4484 /* release is done in BKE_image_release_ibuf using r_lock */
4485 if (from_render) {
4487 *r_lock = re;
4488 rv = nullptr;
4489 }
4490 else {
4491 rv = static_cast<RenderView *>(BLI_findlink(&rres.views, actview));
4492 if (rv == nullptr) {
4493 rv = static_cast<RenderView *>(rres.views.first);
4494 }
4495 }
4496
4497 /* this gives active layer, composite or sequence result */
4498 if (rv == nullptr) {
4499 pass_ibuf = rres.ibuf;
4500 }
4501 else {
4502 pass_ibuf = rv->ibuf;
4503 }
4504
4505 dither = iuser->scene->r.dither_intensity;
4506
4507 /* combined layer gets added as first layer */
4508 if (rres.have_combined && layer == 0) {
4509 /* pass */
4510 }
4511 else if (pass_ibuf && pass_ibuf->byte_buffer.data && layer == 0) {
4512 /* pass */
4513 }
4514 else if (rres.layers.first) {
4515 RenderLayer *rl = static_cast<RenderLayer *>(
4516 BLI_findlink(&rres.layers, layer - (rres.have_combined ? 1 : 0)));
4517 if (rl) {
4518 RenderPass *rpass = image_render_pass_get(rl, pass, actview, nullptr);
4519 if (rpass) {
4520 pass_ibuf = rpass->ibuf;
4521 if (pass != 0) {
4522 dither = 0.0f; /* don't dither passes */
4523 }
4524 }
4525 }
4526 }
4527
4528 /* Put an empty image buffer to the cache. This allows to achieve the following:
4529 *
4530 * 1. It makes it so the generic logic in the #BKE_image_has_loaded_ibuf properly detects that
4531 * an Image used to display render result has loaded image buffer.
4532 *
4533 * Surely there are all the design questions about scene-dependent Render Result image
4534 * data-block, and the behavior of the flag dependent on whether the Render Result image was ever
4535 * shown on screen. The purpose of this code is to preserve the Python API behavior to the level
4536 * prior to the #RenderResult refactor to use #ImBuf which happened for Blender 4.0.
4537 *
4538 * 2. Provides an image buffer which can be used to communicate the render resolution (with
4539 * possible border render applied to it) prior to the actual pixels storage is allocated. */
4540 if (ima->cache == nullptr) {
4541 ImBuf *empty_ibuf = IMB_allocImBuf(0, 0, 0, 0);
4542 image_assign_ibuf(ima, empty_ibuf, IMA_NO_INDEX, 0);
4543
4544 /* The cache references the image buffer, and the freeing only happens if the buffer has 0
4545 * references at the time when the #IMB_freeImBuf() is called. This particular image buffer is
4546 * to be freed together with the cache, without any extra reference counting done by any image
4547 * pixel accessor. */
4548 IMB_freeImBuf(empty_ibuf);
4549 }
4550
4551 if (pass_ibuf) {
4552 /* TODO(@sergey): Perhaps its better to assign dither when #ImBuf is allocated for the render
4553 * result. It will avoid modification here, and allow comparing render results with different
4554 * dither applied to them. */
4555 pass_ibuf->dither = dither;
4556
4557 IMB_refImBuf(pass_ibuf);
4558 }
4559 else {
4560 pass_ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, nullptr);
4561
4562 /* Assign the current render resolution to the image buffer.
4563 * The actual storage is still empty. The intended use is to merely communicate the actual
4564 * render resolution prior to render border is "un-cropped". */
4565 pass_ibuf->x = rres.rectx;
4566 pass_ibuf->y = rres.recty;
4567 }
4568
4569 return pass_ibuf;
4570}
4571
4573{
4574 const bool is_multilayer = BKE_image_is_multilayer(ima);
4575 const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) &&
4576 (iuser == nullptr);
4577 int index = BKE_image_has_multiple_ibufs(ima) ? 0 : IMA_NO_INDEX;
4578
4579 if (is_multilayer) {
4580 return iuser ? iuser->multi_index : index;
4581 }
4582 if (is_backdrop) {
4583 if (BKE_image_is_stereo(ima)) {
4584 /* Backdrop hack / workaround (since there is no `iuser`). */
4585 return ima->eye;
4586 }
4587 }
4588 else if (BKE_image_is_multiview(ima)) {
4589 return iuser ? iuser->multi_index : index;
4590 }
4591
4592 return index;
4593}
4594
4595static void image_get_entry_and_index(Image *ima, ImageUser *iuser, int *r_entry, int *r_index)
4596{
4597 int frame = 0, index = image_get_multiview_index(ima, iuser);
4598
4599 /* see if we already have an appropriate ibuf, with image source and type */
4600 if (ima->source == IMA_SRC_MOVIE) {
4601 frame = iuser ? iuser->framenr : ima->lastframe;
4602 }
4603 else if (ima->source == IMA_SRC_SEQUENCE) {
4604 if (ima->type == IMA_TYPE_IMAGE) {
4605 frame = iuser ? iuser->framenr : ima->lastframe;
4606 }
4607 else if (ima->type == IMA_TYPE_MULTILAYER) {
4608 frame = iuser ? iuser->framenr : ima->lastframe;
4609 }
4610 }
4611 else if (ima->source == IMA_SRC_TILED) {
4612 frame = image_get_tile_number_from_iuser(ima, iuser);
4613 }
4614
4615 *r_entry = frame;
4616 *r_index = index;
4617}
4618
4619/* Get the ibuf from an image cache for a given image user.
4620 *
4621 * Returns referenced image buffer if it exists, callee is to
4622 * call IMB_freeImBuf to de-reference the image buffer after
4623 * it's done handling it.
4624 */
4626 Image *ima, ImageUser *iuser, int *r_entry, int *r_index, bool *r_is_cached_empty)
4627{
4628 ImBuf *ibuf = nullptr;
4629 int entry = 0, index = image_get_multiview_index(ima, iuser);
4630
4631 /* see if we already have an appropriate ibuf, with image source and type */
4632 if (ima->source == IMA_SRC_MOVIE) {
4633 entry = iuser ? iuser->framenr : ima->lastframe;
4634 ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, r_is_cached_empty);
4635 ima->lastframe = entry;
4636 }
4637 else if (ima->source == IMA_SRC_SEQUENCE) {
4638 if (ima->type == IMA_TYPE_IMAGE) {
4639 entry = iuser ? iuser->framenr : ima->lastframe;
4640 ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, r_is_cached_empty);
4641 ima->lastframe = entry;
4642 }
4643 else if (ima->type == IMA_TYPE_MULTILAYER) {
4644 entry = iuser ? iuser->framenr : ima->lastframe;
4645 ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, r_is_cached_empty);
4646 }
4647 }
4648 else if (ima->source == IMA_SRC_FILE) {
4649 if (ima->type == IMA_TYPE_IMAGE) {
4650 ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0, r_is_cached_empty);
4651 }
4652 else if (ima->type == IMA_TYPE_MULTILAYER) {
4653 ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0, r_is_cached_empty);
4654 }
4655 }
4656 else if (ima->source == IMA_SRC_GENERATED) {
4657 ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0, r_is_cached_empty);
4658 }
4659 else if (ima->source == IMA_SRC_VIEWER) {
4660 /* always verify entirely, not that this shouldn't happen
4661 * as part of texture sampling in rendering anyway, so not
4662 * a big bottleneck */
4663 }
4664 else if (ima->source == IMA_SRC_TILED) {
4666 entry = image_get_tile_number_from_iuser(ima, iuser);
4667 ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, r_is_cached_empty);
4668 }
4669 }
4670
4671 if (r_entry) {
4672 *r_entry = entry;
4673 }
4674
4675 if (r_index) {
4676 *r_index = index;
4677 }
4678
4679 return ibuf;
4680}
4681
4683{
4684 if (ima == nullptr) {
4685 return false;
4686 }
4687
4689 if (tile == nullptr) {
4690 return false;
4691 }
4692
4693 return true;
4694}
4695
4701static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
4702{
4703 ImBuf *ibuf = nullptr;
4704 int entry = 0, index = 0;
4705
4706 if (r_lock) {
4707 *r_lock = nullptr;
4708 }
4709
4710 /* quick reject tests */
4711 if (!image_quick_test(ima, iuser)) {
4712 return nullptr;
4713 }
4714
4715 bool is_cached_empty = false;
4716 ibuf = image_get_cached_ibuf(ima, iuser, &entry, &index, &is_cached_empty);
4717 if (is_cached_empty) {
4718 return nullptr;
4719 }
4720
4721 if (ibuf == nullptr) {
4722 /* We are sure we have to load the ibuf, using source and type. */
4723 if (ima->source == IMA_SRC_MOVIE) {
4724 /* Source is from single file, use flip-book to store ibuf. */
4725 ibuf = image_load_movie_file(ima, iuser, entry);
4726 }
4727 else if (ima->source == IMA_SRC_SEQUENCE) {
4728 if (ima->type == IMA_TYPE_IMAGE) {
4729 /* Regular files, ibufs in flip-book, allows saving. */
4730 ibuf = image_load_image_file(ima, iuser, entry, entry, true);
4731 }
4732 /* no else; on load the ima type can change */
4733 if (ima->type == IMA_TYPE_MULTILAYER) {
4734 /* Only 1 layer/pass stored in imbufs, no EXR-handle anim storage, no saving. */
4735 ibuf = image_load_sequence_multilayer(ima, iuser, entry, entry);
4736 }
4737 }
4738 else if (ima->source == IMA_SRC_TILED) {
4739 /* Nothing was cached. Check to see if the tile should be generated. */
4740 ImageTile *tile = BKE_image_get_tile(ima, entry);
4741 if ((tile->gen_flag & IMA_GEN_TILE) != 0) {
4742 ibuf = add_ibuf_for_tile(ima, tile);
4743 image_assign_ibuf(ima, ibuf, 0, entry);
4744 }
4745 else {
4746 if (ima->type == IMA_TYPE_IMAGE) {
4747 /* Regular files, ibufs in flip-book, allows saving */
4748 ibuf = image_load_image_file(ima, iuser, entry, 0, false);
4749 }
4750 /* no else; on load the ima type can change */
4751 if (ima->type == IMA_TYPE_MULTILAYER) {
4752 /* Only 1 layer/pass stored in imbufs, no EXR-handle anim storage, no saving. */
4753 ibuf = image_load_sequence_multilayer(ima, iuser, entry, 0);
4754 }
4755 }
4756 }
4757 else if (ima->source == IMA_SRC_FILE) {
4758
4759 if (ima->type == IMA_TYPE_IMAGE) {
4760 ibuf = image_load_image_file(
4761 ima, iuser, 0, entry, false); /* cfra only for '#', this global is OK */
4762 }
4763 /* no else; on load the ima type can change */
4764 if (ima->type == IMA_TYPE_MULTILAYER) {
4765 /* keeps render result, stores ibufs in listbase, allows saving */
4766 ibuf = image_get_ibuf_multilayer(ima, iuser);
4767 }
4768 }
4769 else if (ima->source == IMA_SRC_GENERATED) {
4770 /* Generated is: `ibuf` is allocated dynamically. */
4771 /* UV test-grid or black or solid etc. */
4772 ImageTile *base_tile = BKE_image_get_tile(ima, 0);
4773 if (base_tile->gen_x == 0) {
4774 base_tile->gen_x = 1024;
4775 }
4776 if (base_tile->gen_y == 0) {
4777 base_tile->gen_y = 1024;
4778 }
4779 if (base_tile->gen_depth == 0) {
4780 base_tile->gen_depth = 24;
4781 }
4782 ibuf = add_ibuf_for_tile(ima, base_tile);
4783 image_assign_ibuf(ima, ibuf, index, 0);
4784 }
4785 else if (ima->source == IMA_SRC_VIEWER) {
4786 if (ima->type == IMA_TYPE_R_RESULT) {
4787 /* always verify entirely, and potentially
4788 * returns pointer to release later */
4789 ibuf = image_get_render_result(ima, iuser, r_lock);
4790 }
4791 else if (ima->type == IMA_TYPE_COMPOSITE) {
4792 /* requires lock/unlock, otherwise don't return image */
4793 if (r_lock) {
4794 /* unlock in BKE_image_release_ibuf */
4796 *r_lock = ima;
4797
4798 /* XXX anim play for viewer nodes not yet supported */
4799 entry = 0; // XXX iuser ? iuser->framenr : 0;
4800 ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, nullptr);
4801
4802 if (!ibuf) {
4803 /* Composite Viewer, all handled in compositor */
4804 /* fake ibuf, will be filled in compositor */
4805 ibuf = IMB_allocImBuf(256, 256, 32, IB_byte_data | IB_float_data);
4806 image_assign_ibuf(ima, ibuf, index, entry);
4807 }
4808 }
4809 }
4810 }
4811
4812 /* We only want movies and sequences to be memory limited. */
4813 if (ibuf != nullptr && !ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
4814 ibuf->userflags |= IB_PERSISTENT;
4815 }
4816 }
4817
4818 BKE_image_tag_time(ima);
4819
4820 return ibuf;
4821}
4822
4823ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
4824{
4825 /* NOTE: same as #image_acquire_ibuf, but can be used to retrieve images being rendered in
4826 * a thread safe way, always call both acquire and release. */
4827
4828 if (ima == nullptr) {
4829 return nullptr;
4830 }
4831
4832 std::scoped_lock lock(ima->runtime->cache_mutex);
4833 return image_acquire_ibuf(ima, iuser, r_lock);
4834}
4835
4836static int get_multilayer_view_index(const Image &image,
4837 const ImageUser &image_user,
4838 const char *view_name)
4839{
4840 if (BLI_listbase_count_at_most(&image.rr->views, 2) <= 1) {
4841 return 0;
4842 }
4843
4844 const int view_image = image_user.view;
4845 const bool is_allview = (view_image == 0); /* if view selected == All (0) */
4846
4847 if (is_allview) {
4848 /* Heuristic to match image name with scene names check if the view name exists in the image.
4849 */
4850 const int view = BLI_findstringindex(&image.rr->views, view_name, offsetof(RenderView, name));
4851 if (view == -1) {
4852 return 0;
4853 }
4854 return view;
4855 }
4856
4857 return view_image - 1;
4858}
4859
4861 Image &image,
4862 const ImageUser &image_user,
4863 const char *pass_name,
4864 const char *view_name)
4865{
4866 std::scoped_lock lock(image.runtime->cache_mutex);
4867
4868 /* Local changes to the original ImageUser. */
4869 ImageUser local_user = image_user;
4870
4871 /* Force load the image once, possibly with a different user from what it will need to be in the
4872 * end. This ensures proper image type, and initializes multi-layer state when needed. */
4873 ImBuf *tmp_ibuf = image_acquire_ibuf(&image, &local_user, nullptr);
4874 IMB_freeImBuf(tmp_ibuf);
4875
4876 if (BKE_image_is_multilayer(&image)) {
4877 BLI_assert(pass_name);
4878
4879 if (!image.rr) {
4880 return nullptr;
4881 }
4882
4883 const RenderLayer *render_layer = static_cast<const RenderLayer *>(
4884 BLI_findlink(&image.rr->layers, local_user.layer));
4885
4886 local_user.view = get_multilayer_view_index(image, local_user, view_name);
4887 local_user.pass = BLI_findstringindex(
4888 &render_layer->passes, pass_name, offsetof(RenderPass, name));
4889
4890 if (!BKE_image_multilayer_index(image.rr, &local_user)) {
4891 return nullptr;
4892 }
4893 }
4894 else {
4895 local_user.multi_index = BKE_scene_multiview_view_id_get(&render_data, view_name);
4896 }
4897
4898 return image_acquire_ibuf(&image, &local_user, nullptr);
4899}
4900
4901void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
4902{
4903 if (lock != nullptr) {
4904 /* for getting image during threaded render / compositing, need to release */
4905 if (lock == ima) {
4906 BLI_thread_unlock(LOCK_VIEWER); /* viewer image */
4907 }
4908 else {
4909 RE_ReleaseResultImage(static_cast<Render *>(lock)); /* render result */
4910 BLI_thread_unlock(LOCK_VIEWER); /* view image imbuf */
4911 }
4912 }
4913
4914 if (ibuf) {
4915 std::scoped_lock lock(ima->runtime->cache_mutex);
4916 IMB_freeImBuf(ibuf);
4917 }
4918}
4919
4921{
4922 ImBuf *ibuf;
4923
4924 /* quick reject tests */
4925 if (!image_quick_test(ima, iuser)) {
4926 return false;
4927 }
4928
4929 std::scoped_lock lock(ima->runtime->cache_mutex);
4930
4931 ibuf = image_get_cached_ibuf(ima, iuser, nullptr, nullptr, nullptr);
4932
4933 if (!ibuf) {
4934 ibuf = image_acquire_ibuf(ima, iuser, nullptr);
4935 }
4936
4937 IMB_freeImBuf(ibuf);
4938
4939 return ibuf != nullptr;
4940}
4941
4942ImBuf *BKE_image_preview(Image *ima, const short max_size, short *r_width, short *r_height)
4943{
4944 void *lock;
4945 ImBuf *image_ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
4946 if (image_ibuf == nullptr) {
4947 return nullptr;
4948 }
4949
4950 ImBuf *preview = IMB_dupImBuf(image_ibuf);
4951 float scale = float(max_size) / float(std::max(image_ibuf->x, image_ibuf->y));
4952 if (r_width) {
4953 *r_width = image_ibuf->x;
4954 }
4955 if (r_height) {
4956 *r_height = image_ibuf->y;
4957 }
4958 BKE_image_release_ibuf(ima, image_ibuf, lock);
4959
4960 /* Resize. */
4961 IMB_scale(preview, scale * image_ibuf->x, scale * image_ibuf->y, IMBScaleFilter::Box, false);
4962 IMB_byte_from_float(preview);
4963
4964 return preview;
4965}
4966
4968
4969/* -------------------------------------------------------------------- */
4972
4980
4986
4988{
4989 ImagePool *pool = MEM_new<ImagePool>(__func__);
4991 return pool;
4992}
4993
4995{
4996 /* Use single lock to dereference all the image buffers. */
4997 {
4998 std::scoped_lock lock(pool->mutex);
4999 for (ImagePoolItem *item = static_cast<ImagePoolItem *>(pool->image_buffers.first);
5000 item != nullptr;
5001 item = item->next)
5002 {
5003 if (item->ibuf != nullptr) {
5004 std::scoped_lock lock(item->image->runtime->cache_mutex);
5005 IMB_freeImBuf(item->ibuf);
5006 }
5007 }
5008
5010 }
5011 MEM_delete(pool);
5012}
5013
5015 ImagePool *pool, Image *image, int entry, int index, bool *r_found)
5016{
5017 LISTBASE_FOREACH (ImagePoolItem *, item, &pool->image_buffers) {
5018 if (item->image == image && item->entry == entry && item->index == index) {
5019 *r_found = true;
5020 return item->ibuf;
5021 }
5022 }
5023
5024 *r_found = false;
5025 return nullptr;
5026}
5027
5029{
5030 ImBuf *ibuf;
5031 int index, entry;
5032 bool found;
5033
5034 if (!image_quick_test(ima, iuser)) {
5035 return nullptr;
5036 }
5037
5038 if (pool == nullptr) {
5039 /* Pool could be null, in this case use general acquire function. */
5040 return BKE_image_acquire_ibuf(ima, iuser, nullptr);
5041 }
5042
5043 image_get_entry_and_index(ima, iuser, &entry, &index);
5044
5045 /* Use double-checked locking, to avoid locking when the requested image buffer is already in the
5046 * pool. */
5047
5048 ibuf = image_pool_find_item(pool, ima, entry, index, &found);
5049 if (found) {
5050 return ibuf;
5051 }
5052
5053 /* Lock the pool, to allow thread-safe modification of the content of the pool. */
5054 std::scoped_lock lock(pool->mutex);
5055
5056 ibuf = image_pool_find_item(pool, ima, entry, index, &found);
5057
5058 /* Will also create item even in cases image buffer failed to load,
5059 * prevents trying to load the same buggy file multiple times. */
5060 if (!found) {
5061 ImagePoolItem *item;
5062
5063 /* Thread-safe acquisition of an image buffer from the image.
5064 * The acquisition does not use image pools, so there is no risk of recursive or out-of-order
5065 * mutex locking. */
5066 ibuf = BKE_image_acquire_ibuf(ima, iuser, nullptr);
5067
5068 item = static_cast<ImagePoolItem *>(BLI_mempool_alloc(pool->memory_pool));
5069 item->image = ima;
5070 item->entry = entry;
5071 item->index = index;
5072 item->ibuf = ibuf;
5073
5074 BLI_addtail(&pool->image_buffers, item);
5075 }
5076
5077 return ibuf;
5078}
5079
5081{
5082 /* if pool wasn't actually used, use general release stuff,
5083 * for pools image buffers will be dereferenced on pool free
5084 */
5085 if (pool == nullptr) {
5086 BKE_image_release_ibuf(ima, ibuf, nullptr);
5087 }
5088}
5089
5090int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, bool *r_is_in_range)
5091{
5092 const int len = iuser->frames;
5093
5094 if (r_is_in_range) {
5095 *r_is_in_range = false;
5096 }
5097
5098 if (len == 0) {
5099 return 0;
5100 }
5101
5102 int framenr;
5103 cfra = cfra - iuser->sfra + 1;
5104
5105 /* cyclic */
5106 if (iuser->cycl) {
5107 cfra = ((cfra) % len);
5108 if (cfra < 0) {
5109 cfra += len;
5110 }
5111 if (cfra == 0) {
5112 cfra = len;
5113 }
5114
5115 if (r_is_in_range) {
5116 *r_is_in_range = true;
5117 }
5118 }
5119
5120 if (cfra < 0) {
5121 cfra = 0;
5122 }
5123 else if (cfra > len) {
5124 cfra = len;
5125 }
5126 else {
5127 if (r_is_in_range) {
5128 *r_is_in_range = true;
5129 }
5130 }
5131
5132 /* transform to images space */
5133 framenr = cfra;
5134 framenr = std::min(framenr, iuser->frames);
5135
5136 if (iuser->cycl) {
5137 framenr = ((framenr) % len);
5138 while (framenr < 0) {
5139 framenr += len;
5140 }
5141 if (framenr == 0) {
5142 framenr = len;
5143 }
5144 }
5145
5146 /* important to apply after else we can't loop on frames 100 - 110 for eg. */
5147 framenr += iuser->offset;
5148
5149 return framenr;
5150}
5151
5152void BKE_image_user_frame_calc(Image *ima, ImageUser *iuser, int cfra)
5153{
5154 if (iuser) {
5155 if (ima && BKE_image_is_animated(ima)) {
5156 /* Compute current frame for animated image. */
5157 bool is_in_range;
5158 const int framenr = BKE_image_user_frame_get(iuser, cfra, &is_in_range);
5159
5160 if (is_in_range) {
5161 iuser->flag |= IMA_USER_FRAME_IN_RANGE;
5162 }
5163 else {
5165 }
5166
5167 iuser->framenr = framenr;
5168 }
5169 else {
5170 /* Set fixed frame number for still image. */
5171 iuser->framenr = 0;
5172 iuser->flag |= IMA_USER_FRAME_IN_RANGE;
5173 }
5174
5175 if (ima && ima->gpuframenr != iuser->framenr) {
5176 /* NOTE: a single texture and refresh doesn't really work when
5177 * multiple image users may use different frames, this is to
5178 * be improved with perhaps a GPU texture cache. */
5179 if (ima->gpuframenr != IMAGE_GPU_FRAME_NONE) {
5181 }
5182 ima->gpuframenr = iuser->framenr;
5183 }
5184
5185 iuser->flag &= ~IMA_NEED_FRAME_RECALC;
5186 }
5187}
5188
5189/* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
5191 ID * /*iuser_id*/,
5192 ImageUser *iuser,
5193 void *customdata)
5194{
5195 if (ima && BKE_image_is_animated(ima)) {
5196 if ((iuser->flag & IMA_ANIM_ALWAYS) || (iuser->flag & IMA_NEED_FRAME_RECALC)) {
5197 int cfra = *(int *)customdata;
5198
5199 BKE_image_user_frame_calc(ima, iuser, cfra);
5200 }
5201 }
5202}
5203
5204void BKE_image_editors_update_frame(const Main *bmain, int cfra)
5205{
5206 /* This only updates images used by the user interface. For others the
5207 * dependency graph will call BKE_image_user_id_eval_animation. */
5208 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
5210}
5211
5213 ID * /*iuser_id*/,
5214 ImageUser * /*iuser*/,
5215 void *customdata)
5216{
5217 if (ima && BKE_image_is_animated(ima)) {
5218 *(bool *)customdata = true;
5219 }
5220}
5221
5223{
5224 /* For the dependency graph, this does not consider nested node
5225 * trees as these are handled as their own data-block. */
5226 bool has_animation = false;
5227 bool skip_nested_nodes = true;
5228 image_walk_id_all_users(id, skip_nested_nodes, &has_animation, image_user_id_has_animation);
5229 return has_animation;
5230}
5231
5233 ID * /*iduser_id*/,
5234 ImageUser *iuser,
5235 void *customdata)
5236{
5237 if (ima && BKE_image_is_animated(ima)) {
5238 Depsgraph *depsgraph = (Depsgraph *)customdata;
5239
5240 if ((iuser->flag & IMA_ANIM_ALWAYS) || (iuser->flag & IMA_NEED_FRAME_RECALC) ||
5242 {
5243 float cfra = DEG_get_ctime(depsgraph);
5244
5245 BKE_image_user_frame_calc(ima, iuser, cfra);
5246 }
5247 }
5248}
5249
5251{
5252 /* This is called from the dependency graph to update the image
5253 * users in data-blocks. It computes the current frame number
5254 * and tags the image to be refreshed.
5255 * This does not consider nested node trees as these are handled
5256 * as their own data-block. */
5257 bool skip_nested_nodes = true;
5259}
5260
5261void BKE_image_user_file_path(const ImageUser *iuser, const Image *ima, char *filepath)
5262{
5263 BKE_image_user_file_path_ex(G_MAIN, iuser, ima, filepath, true, true);
5264}
5265
5267 const ImageUser *iuser,
5268 const Image *ima,
5269 char *filepath,
5270 const bool resolve_udim,
5271 const bool resolve_multiview)
5272{
5273 if (resolve_multiview && BKE_image_is_multiview(ima)) {
5274 ImageView *iv = static_cast<ImageView *>(BLI_findlink(&ima->views, iuser->view));
5275 if (iv->filepath[0]) {
5276 BLI_strncpy(filepath, iv->filepath, FILE_MAX);
5277 }
5278 else {
5279 BLI_strncpy(filepath, ima->filepath, FILE_MAX);
5280 }
5281 }
5282 else {
5283 BLI_strncpy(filepath, ima->filepath, FILE_MAX);
5284 }
5285
5287 char head[FILE_MAX], tail[FILE_MAX];
5288 ushort numlen;
5289
5290 int index;
5291 if (ima->source == IMA_SRC_SEQUENCE) {
5292 index = iuser ? iuser->framenr : ima->lastframe;
5293 BLI_path_sequence_decode(filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
5294 BLI_path_sequence_encode(filepath, FILE_MAX, head, tail, numlen, index);
5295 }
5296 else if (resolve_udim) {
5297 index = image_get_tile_number_from_iuser(ima, iuser);
5298
5299 eUDIM_TILE_FORMAT tile_format;
5300 char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
5301 BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, index);
5302 MEM_SAFE_FREE(udim_pattern);
5303 }
5304 }
5305
5306 BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &ima->id));
5307}
5308
5310{
5311 void *lock;
5312 ImBuf *ibuf = BKE_image_acquire_ibuf(image, nullptr, &lock);
5313 const int planes = (ibuf ? ibuf->planes : 0);
5314 BKE_image_release_ibuf(image, ibuf, lock);
5315
5316 if (ELEM(planes, 32, 16)) {
5317 return true;
5318 }
5319
5320 return false;
5321}
5322
5323void BKE_image_get_size(Image *image, ImageUser *iuser, int *r_width, int *r_height)
5324{
5325 ImBuf *ibuf = nullptr;
5326 void *lock;
5327
5328 if (image != nullptr) {
5329 ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
5330 }
5331
5332 if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
5333 *r_width = ibuf->x;
5334 *r_height = ibuf->y;
5335 }
5336 else if (image != nullptr && image->type == IMA_TYPE_R_RESULT && iuser != nullptr &&
5337 iuser->scene != nullptr)
5338 {
5339 BKE_render_resolution(&iuser->scene->r, true, r_width, r_height);
5340 }
5341 else {
5342 *r_width = IMG_SIZE_FALLBACK;
5343 *r_height = IMG_SIZE_FALLBACK;
5344 }
5345
5346 if (image != nullptr) {
5347 BKE_image_release_ibuf(image, ibuf, lock);
5348 }
5349}
5350
5351void BKE_image_get_size_fl(Image *image, ImageUser *iuser, float r_size[2])
5352{
5353 int width, height;
5354 BKE_image_get_size(image, iuser, &width, &height);
5355
5356 r_size[0] = float(width);
5357 r_size[1] = float(height);
5358}
5359
5360void BKE_image_get_aspect(Image *image, float *r_aspx, float *r_aspy)
5361{
5362 *r_aspx = 1.0;
5363
5364 /* x is always 1 */
5365 if (image) {
5366 *r_aspy = image->aspy / image->aspx;
5367 }
5368 else {
5369 *r_aspy = 1.0f;
5370 }
5371}
5372
5374{
5375 ImageUser iuser;
5376 BKE_imageuser_default(&iuser);
5377 void *lock;
5378 ImBuf *ibuf;
5379 uchar *pixels = nullptr;
5380
5381 iuser.framenr = frame;
5382 iuser.tile = tile;
5383
5384 ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
5385
5386 if (ibuf) {
5387 pixels = ibuf->byte_buffer.data;
5388
5389 if (pixels) {
5390 pixels = static_cast<uchar *>(MEM_dupallocN(pixels));
5391 }
5392
5393 BKE_image_release_ibuf(image, ibuf, lock);
5394 }
5395
5396 if (!pixels) {
5397 return nullptr;
5398 }
5399
5400 return pixels;
5401}
5402
5404{
5405 ImageUser iuser;
5406 BKE_imageuser_default(&iuser);
5407 void *lock;
5408 ImBuf *ibuf;
5409 float *pixels = nullptr;
5410
5411 iuser.framenr = frame;
5412 iuser.tile = tile;
5413
5414 ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
5415
5416 if (ibuf) {
5417 pixels = ibuf->float_buffer.data;
5418
5419 if (pixels) {
5420 pixels = static_cast<float *>(MEM_dupallocN(pixels));
5421 }
5422
5423 BKE_image_release_ibuf(image, ibuf, lock);
5424 }
5425
5426 if (!pixels) {
5427 return nullptr;
5428 }
5429
5430 return pixels;
5431}
5432
5434{
5435 return BLI_path_sequence_decode(image->filepath, nullptr, 0, nullptr, 0, nullptr);
5436}
5437
5439{
5440 return (BLI_listbase_is_empty(&ima->anims) == false);
5441}
5442
5444{
5445 return (BLI_listbase_is_empty(&ima->packedfiles) == false);
5446}
5447
5449{
5450 /* This could be improved to detect cases like //../../, currently path
5451 * remapping empty file paths empty. */
5452 return ima->filepath[0] != '\0';
5453}
5454
5456{
5457 return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
5458}
5459
5464
5465bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
5466{
5467 bool is_dirty = false;
5468 bool is_writable = false;
5469
5470 std::scoped_lock lock(image->runtime->cache_mutex);
5471 if (image->cache != nullptr) {
5472 MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
5473
5474 while (!IMB_moviecacheIter_done(iter)) {
5475 ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
5476 if (ibuf != nullptr && ibuf->userflags & IB_BITMAPDIRTY) {
5477 is_writable = BKE_image_buffer_format_writable(ibuf);
5478 is_dirty = true;
5479 break;
5480 }
5482 }
5484 }
5485
5486 if (r_is_writable) {
5487 *r_is_writable = is_writable;
5488 }
5489
5490 return is_dirty;
5491}
5492
5494{
5495 return BKE_image_is_dirty_writable(image, nullptr);
5496}
5497
5498void BKE_image_mark_dirty(Image * /*image*/, ImBuf *ibuf)
5499{
5500 ibuf->userflags |= IB_BITMAPDIRTY;
5501}
5502
5504{
5505 ImageFormatData im_format;
5506 ImbFormatOptions options_dummy;
5507 BKE_image_format_from_imbuf(&im_format, ibuf);
5508 return (BKE_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype);
5509}
5510
5512{
5513 std::scoped_lock lock(image->runtime->cache_mutex);
5514 if (image->cache != nullptr) {
5515 MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
5516
5517 while (!IMB_moviecacheIter_done(iter)) {
5518 ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
5519 if (ibuf != nullptr) {
5520 ibuf->ftype = static_cast<eImbFileType>(ftype);
5521 ibuf->foptions = *options;
5522 }
5524 }
5526 }
5527}
5528
5530{
5531 bool has_loaded_ibuf = false;
5532
5533 std::scoped_lock lock(image->runtime->cache_mutex);
5534 if (image->cache != nullptr) {
5535 MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
5536
5537 while (!IMB_moviecacheIter_done(iter)) {
5538 ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
5539 if (ibuf != nullptr) {
5540 has_loaded_ibuf = true;
5541 break;
5542 }
5544 }
5546 }
5547
5548 return has_loaded_ibuf;
5549}
5550
5551ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *filepath)
5552{
5553 BLI_assert(!BLI_path_is_rel(filepath));
5554 ImBuf *ibuf = nullptr;
5555
5556 std::scoped_lock lock(image->runtime->cache_mutex);
5557 if (image->cache != nullptr) {
5558 MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
5559
5560 while (!IMB_moviecacheIter_done(iter)) {
5561 ImBuf *current_ibuf = IMB_moviecacheIter_getImBuf(iter);
5562 if (current_ibuf != nullptr && STREQ(current_ibuf->filepath, filepath)) {
5563 ibuf = current_ibuf;
5564 IMB_refImBuf(ibuf);
5565 break;
5566 }
5568 }
5570 }
5571
5572 return ibuf;
5573}
5574
5576{
5577 ImBuf *ibuf = nullptr;
5578
5579 std::scoped_lock lock(image->runtime->cache_mutex);
5580 if (image->cache != nullptr) {
5581 MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
5582
5583 while (!IMB_moviecacheIter_done(iter)) {
5584 ibuf = IMB_moviecacheIter_getImBuf(iter);
5585 if (ibuf != nullptr) {
5586 IMB_refImBuf(ibuf);
5587 }
5588 break;
5589 }
5591 }
5592
5593 return ibuf;
5594}
5595
5597{
5598 ImageView *iv;
5599 Scene *scene = iuser->scene;
5600 const bool is_multiview = ((scene->r.scemode & R_MULTIVIEW) != 0) &&
5601 ((ima->flag & IMA_USE_VIEWS) != 0);
5602
5603 /* reset the image views */
5605
5606 if (!is_multiview) {
5607 /* nothing to do */
5608 }
5609 else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
5610 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
5611
5612 for (int i = 0; i < 2; i++) {
5613 image_add_view(ima, names[i], ima->filepath);
5614 }
5615 return;
5616 }
5617 else {
5618 /* R_IMF_VIEWS_INDIVIDUAL */
5619 char prefix[FILE_MAX] = {'\0'};
5620 char *filepath = ima->filepath;
5621 const char *ext = nullptr;
5622
5623 BKE_scene_multiview_view_prefix_get(scene, filepath, prefix, &ext);
5624
5625 if (prefix[0] == '\0') {
5627 return;
5628 }
5629
5630 /* create all the image views */
5631 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
5632 if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
5633 char filepath_view[FILE_MAX];
5634 SNPRINTF(filepath_view, "%s%s%s", prefix, srv->suffix, ext);
5635 image_add_view(ima, srv->name, filepath_view);
5636 }
5637 }
5638
5639 /* check if the files are all available */
5640 iv = static_cast<ImageView *>(ima->views.last);
5641 while (iv) {
5642 int file;
5643 char filepath[FILE_MAX];
5644
5645 STRNCPY(filepath, iv->filepath);
5646 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
5647
5648 /* exists? */
5649 file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
5650 if (file == -1) {
5651 ImageView *iv_del = iv;
5652 iv = iv->prev;
5653 BLI_remlink(&ima->views, iv_del);
5654 MEM_freeN(iv_del);
5655 }
5656 else {
5657 iv = iv->prev;
5658 close(file);
5659 }
5660 }
5661
5662 /* all good */
5663 if (!BKE_image_is_multiview(ima)) {
5665 }
5666 }
5667}
5668
5670
5671/* -------------------------------------------------------------------- */
5674
5676{
5677 RenderSlot *slot = MEM_callocN<RenderSlot>("Image new Render Slot");
5678 if (name && name[0]) {
5679 STRNCPY_UTF8(slot->name, name);
5680 }
5681 else {
5682 int n = BLI_listbase_count(&ima->renderslots) + 1;
5683 SNPRINTF(slot->name, DATA_("Slot %d"), n);
5684 }
5685 BLI_addtail(&ima->renderslots, slot);
5686 return slot;
5687}
5688
5689bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int slot)
5690{
5691 if (slot == ima->last_render_slot) {
5692 /* Don't remove render slot while rendering to it. */
5693 if (G.is_rendering) {
5694 return false;
5695 }
5696 }
5697
5698 int num_slots = BLI_listbase_count(&ima->renderslots);
5699 if (slot >= num_slots || num_slots == 1) {
5700 return false;
5701 }
5702
5703 RenderSlot *remove_slot = static_cast<RenderSlot *>(BLI_findlink(&ima->renderslots, slot));
5704 RenderSlot *current_slot = static_cast<RenderSlot *>(
5705 BLI_findlink(&ima->renderslots, ima->render_slot));
5706 RenderSlot *current_last_slot = static_cast<RenderSlot *>(
5708
5709 RenderSlot *next_slot;
5710 if (current_slot == remove_slot) {
5711 next_slot = static_cast<RenderSlot *>(
5712 BLI_findlink(&ima->renderslots, (slot == num_slots - 1) ? slot - 1 : slot + 1));
5713 }
5714 else {
5715 next_slot = current_slot;
5716 }
5717
5718 /* If the slot to be removed is the slot with the last render,
5719 * make another slot the last render slot. */
5720 if (remove_slot == current_last_slot) {
5721 /* Choose the currently selected slot unless that one is being removed,
5722 * in that case take the next one. */
5723 RenderSlot *next_last_slot;
5724 if (current_slot == remove_slot) {
5725 next_last_slot = next_slot;
5726 }
5727 else {
5728 next_last_slot = current_slot;
5729 }
5730
5731 if (iuser == nullptr || iuser->scene == nullptr) {
5732 return false;
5733 }
5734 Render *re = RE_GetSceneRender(iuser->scene);
5735 if (re != nullptr) {
5736 RE_SwapResult(re, &current_last_slot->render);
5737 RE_SwapResult(re, &next_last_slot->render);
5738 }
5739 current_last_slot = next_last_slot;
5740 }
5741
5742 current_slot = next_slot;
5743
5744 BLI_remlink(&ima->renderslots, remove_slot);
5745
5746 ima->render_slot = BLI_findindex(&ima->renderslots, current_slot);
5747 ima->last_render_slot = BLI_findindex(&ima->renderslots, current_last_slot);
5748
5749 if (remove_slot->render) {
5750 RE_FreeRenderResult(remove_slot->render);
5751 }
5752 MEM_freeN(remove_slot);
5753
5754 return true;
5755}
5756
5757bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int slot)
5758{
5759 if (slot == ima->last_render_slot) {
5760 if (!iuser) {
5761 return false;
5762 }
5763 if (G.is_rendering) {
5764 return false;
5765 }
5766 Render *re = RE_GetSceneRender(iuser->scene);
5767 if (!re) {
5768 return false;
5769 }
5770 RE_ClearResult(re);
5771 return true;
5772 }
5773
5774 RenderSlot *render_slot = static_cast<RenderSlot *>(BLI_findlink(&ima->renderslots, slot));
5775 if (!render_slot) {
5776 return false;
5777 }
5778 if (render_slot->render) {
5779 RE_FreeRenderResult(render_slot->render);
5780 render_slot->render = nullptr;
5781 }
5782 return true;
5783}
5784
5786{
5787 /* Can be null for images without render slots. */
5788 return static_cast<RenderSlot *>(BLI_findlink(&ima->renderslots, index));
5789}
5790
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:125
eBPathForeachFlag
Definition BKE_bpath.hh:27
@ BKE_BPATH_FOREACH_PATH_SKIP_PACKED
Definition BKE_bpath.hh:37
@ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN
Definition BKE_bpath.hh:39
@ BKE_BPATH_FOREACH_PATH_RELOAD_EDITED
Definition BKE_bpath.hh:66
void BKE_color_managed_colorspace_settings_init(ColorManagedColorspaceSettings *colorspace_settings)
void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings *colorspace_settings, const ColorManagedColorspaceSettings *settings)
@ G_FILE_AUTOPACK
#define G_MAIN
void BKE_icon_id_delete(struct ID *id)
Definition icons.cc:437
void BKE_icon_changed(int icon_id)
Definition icons.cc:204
int BKE_icon_id_ensure(struct ID *id)
Definition icons.cc:267
void(*)(ID *id, const IDCacheKey *cache_key, void **cache_p, uint flags, void *user_data) IDTypeForeachCacheFunctionCallback
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:44
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:46
eUDIM_TILE_FORMAT
Definition BKE_image.hh:446
@ UDIM_TILE_FORMAT_UVTILE
Definition BKE_image.hh:449
@ UDIM_TILE_FORMAT_NONE
Definition BKE_image.hh:447
@ UDIM_TILE_FORMAT_UDIM
Definition BKE_image.hh:448
void StampCallback(void *data, const char *propname, char *propvalue, int propvalue_maxncpy)
Definition BKE_image.hh:79
#define IMA_MAX_SPACE
Definition BKE_image.hh:39
void BKE_image_partial_update_free(PartialUpdateUser *user)
free a partial update user.
#define IMA_UDIM_MAX
Definition BKE_image.hh:40
void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int width, int height)
Definition image_gen.cc:375
void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
Definition image_gen.cc:150
#define IMA_SIGNAL_COLORMANAGE
Definition BKE_image.hh:167
#define IMA_SIGNAL_FREE
Definition BKE_image.hh:162
void BKE_image_free_gputextures(Image *ima)
Definition image_gpu.cc:570
#define IMA_SIGNAL_SRC_CHANGE
Definition BKE_image.hh:164
#define IMA_SIGNAL_USER_NEW_IMAGE
Definition BKE_image.hh:166
#define IMA_SIGNAL_RELOAD
Definition BKE_image.hh:161
void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width, int height, const float color[4])
Definition image_gen.cc:25
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
void BKE_image_partial_update_register_free(Image *image)
void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
int BKE_imtype_to_ftype(char imtype, ImbFormatOptions *r_options)
@ LIB_ID_COPY_NO_PREVIEW
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:353
void id_us_ensure_real(ID *id)
Definition lib_id.cc:308
void * BKE_libblock_alloc_in_lib(Main *bmain, std::optional< Library * > owner_library, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1334
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2611
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:882
#define SH_NODE_TEX_IMAGE
#define CMP_NODE_CRYPTOMATTE
#define SH_NODE_TEX_ENVIRONMENT
#define TEX_NODE_IMAGE
#define CMP_NODE_IMAGE
void BKE_ntree_update(Main &bmain, std::optional< blender::Span< bNodeTree * > > modified_trees=std::nullopt, const NodeTreeUpdateExtraParams &params={})
void BKE_ntree_update_tag_id_changed(Main *bmain, ID *id)
PackedFile * BKE_packedfile_duplicate(const PackedFile *pf_src)
void BKE_packedfile_free(PackedFile *pf)
PackedFile * BKE_packedfile_new_from_memory(const void *mem, int memlen, const blender::ImplicitSharingInfo *sharing_info=nullptr)
void BKE_packedfile_blend_write(BlendWriter *writer, const PackedFile *pf)
void BKE_packedfile_blend_read(BlendDataReader *reader, PackedFile **pf_p, blender::StringRefNull filepath)
PackedFile * BKE_packedfile_new(ReportList *reports, const char *filepath_rel, const char *basepath)
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
void BKE_previewimg_free(PreviewImage **prv)
void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2927
int BKE_scene_multiview_num_views_get(const RenderData *rd)
Definition scene.cc:2952
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:3000
void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *filepath, char *r_prefix, const char **r_ext)
Definition scene.cc:3176
bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
Definition scene.cc:2983
const char * BKE_scene_find_last_marker_name(const Scene *scene, int frame)
Definition scene.cc:2305
int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
Definition scene.cc:3094
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:612
void BLF_size(int fontid, float size)
Definition blf.cc:440
int BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:875
int BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:864
void BLF_draw_buffer(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:1035
void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, const ColorManagedDisplay *display)
Definition blf.cc:950
int blf_mono_font_render
Definition blf.cc:49
@ BLF_WORD_WRAP
Definition BLF_api.hh:439
void BLF_disable(int fontid, int option)
Definition blf.cc:329
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2)
Definition blf.cc:1010
void BLF_wordwrap(int fontid, int wrap_width, BLFWrapMode mode=BLFWrapMode::Minimal)
Definition blf.cc:918
blender::ocio::Display ColorManagedDisplay
Definition BLF_api.hh:35
void BLF_enable(int fontid, int option)
Definition blf.cc:320
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:853
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:385
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define BLI_INLINE
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:373
#define O_BINARY
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
LinkData * BLI_genericNodeN(void *data)
Definition listbase.cc:922
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
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_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:332
int BLI_listbase_count_at_most(const ListBase *listbase, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:511
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
int BLI_findstringindex(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:780
void void BLI_listbase_sort(ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
BLI_INLINE bool BLI_listbase_count_is_equal_to(const ListBase *listbase, const int count_cmp)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void void void void void BLI_duplicatelist(ListBase *dst, const ListBase *src) ATTR_NONNULL(1
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:371
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE int integer_digits_i(int i)
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2_db(double r[2], const double a[2])
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
@ BLI_MEMPOOL_NOP
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool bool BLI_path_suffix(char *path, size_t path_maxncpy, const char *suffix, const char *sep) ATTR_NONNULL(1
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAXFILE
bool BLI_path_extension_check_array(const char *path, const char **ext_array) ATTR_NONNULL(1
#define FILE_MAX
#define BLI_path_join(...)
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_extension_check(const char *path, const char *ext) ATTR_NONNULL(1
const char * BLI_path_slash_find(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
int BLI_path_sequence_decode(const char *path, char *head, size_t head_maxncpy, char *tail, size_t tail_maxncpy, unsigned short *r_digits_len)
Definition path_utils.cc:57
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
bool BLI_path_extension_check_n(const char *path,...) ATTR_NONNULL(1) ATTR_SENTINEL(0)
#define FILE_MAXDIR
#define BLI_path_cmp
void BLI_path_sequence_encode(char *path, size_t path_maxncpy, const char *head, const char *tail, unsigned short numlen, int pic)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
size_t BLI_snprintf_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char char size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
char * BLI_string_replaceN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
unsigned short ushort
void BLI_hostname_get(char *buffer, size_t bufsize)
Definition system.cc:180
void BLI_task_isolate(void(*func)(void *userdata), void *userdata)
void BLI_thread_unlock(int type)
Definition threads.cc:333
void BLI_thread_lock(int type)
Definition threads.cc:328
int BLI_thread_is_main(void)
Definition threads.cc:179
@ LOCK_DRAW_IMAGE
Definition BLI_threads.h:64
@ LOCK_VIEWER
Definition BLI_threads.h:65
Platform independent time functions.
long int BLI_time_now_seconds_i(void)
Definition time.cc:75
size_t BLI_timecode_string_from_time_simple(char *str, size_t maxncpy, double time_seconds) ATTR_NONNULL()
Definition timecode.cc:170
size_t BLI_timecode_string_from_time(char *str, size_t maxncpy, int brevity_level, float time_seconds, double fps, short timecode_style) ATTR_NONNULL()
Definition timecode.cc:22
#define UNUSED_VARS(...)
#define POINTER_FROM_INT(i)
#define UNUSED_VARS_NDEBUG(...)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
const char * dirname(char *path)
bool BLO_read_data_is_undo(BlendDataReader *reader)
Definition readfile.cc:5485
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_write_struct_list(writer, struct_name, list_ptr)
#define BLO_read_struct(reader, struct_name, ptr_p)
bool BLO_write_is_undo(BlendWriter *writer)
#define BLT_I18NCONTEXT_ID_IMAGE
#define DATA_(msgid)
#define CLOG_STR_ERROR(clg_ref, str)
Definition CLG_log.h:188
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
void DEG_id_tag_update(ID *id, unsigned int flags)
@ DAG_EVAL_RENDER
float DEG_get_ctime(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_TAG_DOIT
Definition DNA_ID.h:944
@ INDEX_ID_IM
Definition DNA_ID.h:1216
@ ID_WM
@ ID_CA
@ ID_TE
@ ID_IM
@ ID_NT
@ ID_LA
@ ID_SCE
@ ID_WO
@ ID_MA
@ ID_OB
#define DNA_struct_default_get(struct_name)
@ IMA_GEN_TILE
@ IMA_GEN_FLOAT
@ IMA_ANIM_ALWAYS
@ IMA_NEED_FRAME_RECALC
@ IMA_SHOW_STEREO
eImageSource
@ IMA_SRC_FILE
@ IMA_SRC_MOVIE
@ IMA_SRC_GENERATED
@ IMA_SRC_VIEWER
@ IMA_SRC_TILED
@ IMA_SRC_SEQUENCE
@ IMA_ALPHA_IGNORE
@ IMA_ALPHA_STRAIGHT
@ IMA_ALPHA_PREMUL
@ IMA_ALPHA_CHANNEL_PACKED
@ IMA_DEINTERLACE
@ IMA_USER_FRAME_IN_RANGE
@ IMA_USE_VIEWS
@ IMA_VIEW_AS_RENDER
@ IMA_TYPE_MULTILAYER
@ IMA_TYPE_UV_TEST
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ IMA_TYPE_IMAGE
@ IMA_GENTYPE_GRID_COLOR
@ IMA_GENTYPE_GRID
@ TEXTARGET_2D_ARRAY
@ TEXTARGET_COUNT
@ TEXTARGET_TILE_MAPPING
CMPNodeCryptomatteSource
@ CMP_NODE_CRYPTOMATTE_SOURCE_IMAGE
@ NTREE_TEXTURE
@ NTREE_SHADER
@ NTREE_COMPOSIT
Object is a sort of wrapper for general info.
@ OB_CAMERA
@ OB_EMPTY_IMAGE
#define R_STAMP_ALL
#define STEREO_LEFT_NAME
@ R_STAMP_MEMORY
@ R_STAMP_SEQSTRIP
@ R_STAMP_RENDERTIME
@ R_STAMP_HIDE_LABELS
@ R_STAMP_MARKER
@ R_STAMP_CAMERA
@ R_STAMP_FRAME_RANGE
@ R_STAMP_SCENE
@ R_STAMP_CAMERALENS
@ R_STAMP_NOTE
@ R_STAMP_FRAME
@ R_STAMP_TIME
@ R_STAMP_FILENAME
@ R_STAMP_HOSTNAME
@ R_STAMP_DATE
@ R_IMF_VIEWS_STEREO_3D
@ R_IMF_VIEWS_INDIVIDUAL
@ R_MULTIVIEW
#define STEREO_LEFT_SUFFIX
#define STEREO_RIGHT_NAME
#define STEREO_RIGHT_SUFFIX
#define FPS
#define FRA2TIME(a)
@ SPACE_IMAGE
#define IMG_SIZE_FALLBACK
@ TEX_IMAGE
@ USER_TIMECODE_SMPTE_FULL
static AppView * view
ListBase GPU_material_textures(GPUMaterial *material)
void GPU_texture_free(GPUTexture *texture)
void IMB_colormanagement_assign_byte_colorspace(ImBuf *ibuf, const char *name)
void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
bool IMB_colormanagement_space_name_is_data(const char *name)
const char * IMB_colormanagement_colorspace_get_name(const ColorSpace *colorspace)
@ COLOR_ROLE_DEFAULT_FLOAT
@ COLOR_ROLE_DATA
@ COLOR_ROLE_DEFAULT_BYTE
const char * IMB_colormanagement_role_colorspace_name_get(int role)
const ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
ImBuf * IMB_load_image_from_filepath(const char *filepath, const int flags, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:204
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
ImBuf * IMB_load_image_from_memory(const unsigned char *mem, const size_t size, const int flags, const char *descr, const char *filepath=nullptr, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:116
ImBuf * IMB_makeSingleUser(ImBuf *ibuf)
void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, const float col[4], const ColorManagedDisplay *display, int x1, int y1, int x2, int y2)
Definition rectop.cc:1058
void IMB_ImBufFromStereo3d(const Stereo3dFormat *s3d, ImBuf *ibuf_stereo3d, ImBuf **r_ibuf_left, ImBuf **r_ibuf_right)
void IMB_byte_from_float(ImBuf *ibuf)
void IMB_freeImBuf(ImBuf *ibuf)
size_t IMB_get_pixel_count(const ImBuf *ibuf)
Get the length of the data of the given image buffer in pixels.
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_refImBuf(ImBuf *ibuf)
uint8_t * IMB_steal_encoded_buffer(ImBuf *ibuf)
bool IMB_save_image(ImBuf *ibuf, const char *filepath, const int flags)
Definition writeimage.cc:20
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:777
size_t IMB_get_size_in_memory(const ImBuf *ibuf)
eImbFileType
@ IMB_FTYPE_OPENEXR
@ IMB_FTYPE_PNG
@ IMB_PROXY_NONE
const char * imb_ext_movie[]
@ IB_PERSISTENT
@ IB_BITMAPDIRTY
#define IMB_MIPMAP_LEVELS
@ IB_animdeinterlace
@ IB_float_data
@ IB_alphamode_channel_packed
@ IB_alphamode_premul
@ IB_byte_data
@ IB_alphamode_ignore
@ IB_metadata
@ IB_multilayer
@ IB_alphamode_detect
@ IB_mem
@ IB_test
void IMB_metadata_set_field(IDProperty *metadata, const char *key, const char *value)
Definition metadata.cc:68
bool IMB_metadata_get_field(const IDProperty *metadata, const char *key, char *value, size_t value_maxncpy)
Definition metadata.cc:41
void IMB_metadata_ensure(IDProperty **metadata)
Definition metadata.cc:23
void IMB_metadata_foreach(const ImBuf *ibuf, IMBMetadataForeachCb callback, void *userdata)
Definition metadata.cc:87
MovieCacheIter * IMB_moviecacheIter_new(MovieCache *cache)
void * IMB_moviecacheIter_getUserKey(MovieCacheIter *iter)
void IMB_moviecache_free(MovieCache *cache)
void IMB_moviecache_cleanup(MovieCache *cache, bool(cleanup_check_cb)(ImBuf *ibuf, void *userkey, void *userdata), void *userdata)
ImBuf * IMB_moviecache_get(MovieCache *cache, void *userkey, bool *r_is_cached_empty)
void IMB_moviecacheIter_free(MovieCacheIter *iter)
bool IMB_moviecacheIter_done(MovieCacheIter *iter)
void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
void IMB_moviecache_set_getdata_callback(MovieCache *cache, MovieCacheGetKeyDataFP getdatafp)
void IMB_moviecacheIter_step(MovieCacheIter *iter)
ImBuf * IMB_moviecacheIter_getImBuf(MovieCacheIter *iter)
MovieCache * IMB_moviecache_create(const char *name, int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp)
void IMB_moviecache_remove(MovieCache *cache, void *userkey)
bool IMB_exr_has_multilayer(void *handle)
void IMB_exr_close(void *handle)
Read Guarded memory(de)allocation.
@ IMB_TC_NONE
Definition MOV_enums.hh:46
@ IMB_TC_RECORD_RUN
Definition MOV_enums.hh:54
ReportList * reports
Definition WM_types.hh:1025
int pad[32 - sizeof(int)]
volatile int lock
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
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
const T * data() const
Definition BLI_array.hh:301
void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
CCL_NAMESPACE_BEGIN struct Options options
#define floorf(x)
#define offsetof(t, d)
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
#define printf(...)
#define IMAGE_GPU_PASS_NONE
#define IMAGE_GPU_LAYER_NONE
#define MEM_SAFE_FREE(v)
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
#define ID_BLEND_PATH(_bmain, _id)
#define IMAGE_GPU_FRAME_NONE
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define IMAGE_GPU_VIEW_NONE
#define FILTER_ID_IM
#define GS(a)
ccl_gpu_kernel_postfix ccl_global KernelWorkTile * tiles
const ccl_global KernelWorkTile * tile
const int tile_index
#define LOG(severity)
Definition log.h:32
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
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 MOV_close(MovieReader *anim)
Definition movie_read.cc:58
MovieReader * MOV_open_file(const char *filepath, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE])
int MOV_get_duration_frames(MovieReader *anim, IMB_Timecode_Type tc)
ImBuf * MOV_decode_frame(MovieReader *anim, int position, IMB_Timecode_Type tc, IMB_Proxy_Size preview_size)
const Strip * strip_topmost_get(const Scene *scene, int frame)
std::mutex Mutex
Definition BLI_mutex.hh:47
float wrap(float value, float max, float min)
Definition node_math.h:71
bool RE_HasCombinedLayer(const RenderResult *result)
bool RE_RenderResult_is_stereo(const RenderResult *result)
void BKE_imbuf_stamp_info(const RenderResult *rr, ImBuf *ibuf)
Image * BKE_image_load_exists_in_lib(Main *bmain, std::optional< Library * > owner_library, const char *filepath, bool *r_exists)
static bool nearest_udim_tile_tie_break(const float best_dist_sq, const float best_uv[2], const float dist_sq, const float uv[2])
int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
RenderSlot * BKE_image_get_renderslot(Image *ima, int index)
static void image_init_color_management(Image *ima)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
static void image_free_tile(Image *ima, ImageTile *tile)
static void image_abs_path(Main *bmain, Library *owner_library, const char *filepath, char *r_filepath_abs)
bool BKE_image_is_multilayer(const Image *ima)
bool BKE_image_has_alpha(Image *image)
static void image_init_after_load(Image *ima, ImageUser *iuser, ImBuf *)
void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
static void image_walk_ntree_all_users(bNodeTree *ntree, ID *id, void *customdata, void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
static void image_gpu_runtime_reset(Image *ima)
void BKE_image_user_frame_calc(Image *ima, ImageUser *iuser, int cfra)
char * BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format)
Image * BKE_image_load(Main *bmain, const char *filepath)
static int image_num_viewfiles(Image *ima)
BLI_INLINE bool image_quick_test(Image *ima, const ImageUser *iuser)
void BKE_stamp_info_from_imbuf(RenderResult *rr, ImBuf *ibuf)
void BKE_image_alpha_mode_from_extension(Image *image)
Image * BKE_image_load_exists(Main *bmain, const char *filepath, bool *r_exists)
bool BKE_image_scale(Image *image, int width, int height, ImageUser *iuser)
static void image_viewer_create_views(const RenderData *rd, Image *ima)
BLI_INLINE ImBuf * image_pool_find_item(ImagePool *pool, Image *image, int entry, int index, bool *r_found)
static ImBuf * image_get_cached_ibuf_for_index_entry(Image *ima, int index, int entry, bool *r_is_cached_empty)
void BKE_image_get_size_fl(Image *image, ImageUser *iuser, float r_size[2])
void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
static void stampdata(const Scene *scene, Object *camera, StampData *stamp_data, int do_prefix, bool use_dynamic)
bool BKE_image_user_id_has_animation(ID *id)
bool BKE_image_has_filepath(const Image *ima)
void BKE_image_mark_dirty(Image *, ImBuf *ibuf)
void BKE_image_set_filepath_from_tile_number(char *filepath, const char *pattern, eUDIM_TILE_FORMAT tile_format, int tile_number)
void BKE_image_multilayer_stamp_info_callback(void *data, const Image &image, StampCallback callback, bool noskip)
void BKE_image_get_aspect(Image *image, float *r_aspx, float *r_aspy)
StampData * BKE_stamp_data_copy(const StampData *stamp_data)
static ImBuf * add_ibuf_for_tile(Image *ima, ImageTile *tile)
ImBuf * BKE_image_acquire_multilayer_view_ibuf(const RenderData &render_data, Image &image, const ImageUser &image_user, const char *pass_name, const char *view_name)
static void imagecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags)
static void metadata_copy_custom_fields(const char *field, const char *value, void *rr_v)
#define BUFF_MARGIN_X
bool BKE_image_is_openexr(Image *ima)
bool BKE_image_has_multiple_ibufs(Image *image)
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
static int tile_sort_cb(const void *a, const void *b)
static void image_remove_ibuf(Image *ima, int index, int entry)
RenderPass * BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
static void image_get_entry_and_index(Image *ima, ImageUser *iuser, int *r_entry, int *r_index)
static void image_init_data(ID *id)
bool BKE_image_fill_tile(Image *ima, ImageTile *tile)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_free_data(Image *ima)
Image * BKE_image_add_generated(Main *bmain, uint width, uint height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d, const bool is_data, const bool tiled)
RenderSlot * BKE_image_add_renderslot(Image *ima, const char *name)
StampData * BKE_stamp_info_from_scene_static(const Scene *scene)
static uintptr_t image_mem_size(Image *image)
static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata)
static float distance_squared_to_udim(const float co[2], const float udim[2])
void BKE_image_user_file_path(const ImageUser *iuser, const Image *ima, char *filepath)
void BKE_image_tag_time(Image *ima)
static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
void BKE_image_merge(Main *bmain, Image *dest, Image *source)
MovieReader * openanim_noload(const char *filepath, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
bool BKE_image_memorypack(Image *ima)
void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
static int get_multilayer_view_index(const Image &image, const ImageUser &image_user, const char *view_name)
#define IMA_MAKE_INDEX(entry, index)
void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, const size_t data_len)
static ImBuf * image_load_image_file(Image *ima, ImageUser *iuser, int entry, int cfra, bool is_sequence)
static ImBuf * image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
bool BKE_image_is_dirty(Image *image)
static const char * stamp_metadata_fields[]
void BKE_stamp_data_free(StampData *stamp_data)
void BKE_image_free_anim_ibufs(Image *ima, int except_frame)
static ImBuf * imagecache_get(Image *image, int index, bool *r_is_cached_empty)
void BKE_image_release_renderresult(Scene *scene, Image *ima, RenderResult *render_result)
void BKE_image_pool_free(ImagePool *pool)
int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, bool *r_is_in_range)
static void image_tag_frame_recalc(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata)
static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
static void stampdata_from_template(StampData *stamp_data, const Scene *scene, const StampData *stamp_data_template, bool do_prefix)
#define CALL(member, value_str)
void BKE_image_free_packedfiles(Image *ima)
static void image_runtime_free_data(Image *image)
ImBuf * BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool)
Image * BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
static void image_walk_id_all_users(ID *id, bool skip_nested_nodes, void *customdata, void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
static void image_user_id_has_animation(Image *ima, ID *, ImageUser *, void *customdata)
static bool image_views_match_render_views(const Image *image, const RenderData *render_data)
static void image_foreach_cache(ID *id, IDTypeForeachCacheFunctionCallback function_callback, void *user_data)
void BKE_image_sort_tiles(Image *ima)
uchar * BKE_image_get_pixels_for_frame(Image *image, int frame, int tile)
static ImBuf * load_movie_single(Image *ima, ImageUser *iuser, int frame, const int view_id)
void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
static uint imagecache_hashhash(const void *key_v)
static ImBuf * load_image_single(Image *ima, ImageUser *iuser, int cfra, const int view_id, const bool has_packed, const bool is_sequence, bool *r_cache_ibuf)
#define BUFF_MARGIN_Y
static Image * image_alloc(Main *bmain, std::optional< Library * > owner_library, const char *name, short source, short type)
void BKE_image_user_file_path_ex(const Main *bmain, const ImageUser *iuser, const Image *ima, char *filepath, const bool resolve_udim, const bool resolve_multiview)
bool BKE_image_get_tile_number_from_filepath(const char *filepath, const char *pattern, eUDIM_TILE_FORMAT tile_format, int *r_tile_number)
bool BKE_image_has_opengl_texture(Image *ima)
static void image_free_anims(Image *ima)
void BKE_image_ensure_tile_token_filename_only(char *filename, size_t filename_maxncpy)
static void image_remove_all_tiles(Image *ima)
void BKE_image_get_tile_uv(const Image *ima, const int tile_number, float r_uv[2])
static ImBuf * image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry, int *r_index, bool *r_is_cached_empty)
static ImBuf * image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
ImagePool * BKE_image_pool_new()
bool BKE_imbuf_alpha_test(ImBuf *ibuf)
static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int entry)
static void image_walk_gpu_materials(ID *id, ListBase *gpu_materials, void *customdata, void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
static int image_get_tile_number_from_iuser(const Image *ima, const ImageUser *iuser)
void BKE_imageuser_default(ImageUser *iuser)
bool BKE_image_has_anim(Image *ima)
#define TEXT_SIZE_CHECK(str, w, h)
MovieReader * openanim(const char *filepath, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
Image * BKE_image_load_in_lib(Main *bmain, std::optional< Library * > owner_library, const char *filepath)
int BKE_image_get_tile_label(const Image *ima, const ImageTile *tile, char *label, const int label_maxncpy)
void BKE_render_result_stamp_info(Scene *scene, Object *camera, RenderResult *rr, bool allocate_only)
static void image_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int flag)
static ImBuf * image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_free_all_textures(Main *bmain)
static ImBuf * image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int entry, int frame)
void BKE_stamp_info_callback(void *data, StampData *stamp_data, StampCallback callback, bool noskip)
static int imbuf_alpha_flags_for_image(Image *ima)
static bool image_remove_tile(Image *ima, ImageTile *tile)
int BKE_image_sequence_guess_offset(Image *image)
static void metadata_get_field(void *data, const char *propname, char *propvalue, int propvalue_maxncpy)
bool BKE_image_is_stereo(const Image *ima)
bool BKE_image_is_multiview(const Image *ima)
bool BKE_imbuf_write(ImBuf *ibuf, const char *filepath, const ImageFormatData *imf)
void BKE_image_get_size(Image *image, ImageUser *iuser, int *r_width, int *r_height)
static void imagecache_put(Image *image, int index, ImBuf *ibuf)
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy)
static void image_free_data(ID *id)
ImBuf * BKE_image_get_ibuf_with_name(Image *image, const char *filepath)
static bool imagecache_check_dirty(ImBuf *ibuf, void *, void *)
static bool image_memorypack_imbuf(Image *ima, ImBuf *ibuf, int view, int tile_number, const char *filepath)
static void image_update_views_format(Image *ima, ImageUser *iuser)
bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start, int *r_tile_range)
static float distance_to_unit_interval(float x)
static void image_free_packedfiles(Image *ima)
char BKE_image_alpha_mode_from_extension_ex(const char *filepath)
void BKE_image_free_views(Image *image)
static void image_editors_update_frame(Image *ima, ID *, ImageUser *iuser, void *customdata)
void BKE_image_all_free_anim_ibufs(Main *bmain, int cfra)
void BKE_image_walk_all_users(const Main *mainp, void *customdata, void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int slot)
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
void BKE_image_reassign_tile(Image *ima, ImageTile *tile, int new_tile_number)
static void image_colorspace_from_imbuf(Image *image, const ImBuf *ibuf)
void BKE_render_result_stamp_data(RenderResult *rr, const char *key, const char *value)
static void image_blend_read_data(BlendDataReader *reader, ID *id)
bool BKE_image_is_animated(Image *image)
bool BKE_stamp_is_known_field(const char *field_name)
bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int slot)
bool BKE_image_is_filename_tokenized(char *filepath)
int BKE_image_find_nearest_tile_with_offset(const Image *image, const float co[2], float r_uv_offset[2])
static bool imagecache_hashcmp(const void *a_v, const void *b_v)
static void imagecache_remove(Image *image, int index)
void BKE_image_user_id_eval_animation(Depsgraph *depsgraph, ID *id)
int BKE_image_find_nearest_tile(const Image *image, const float co[2])
bool BKE_imbuf_write_stamp(const Scene *scene, const RenderResult *rr, ImBuf *ibuf, const char *filepath, const ImageFormatData *imf)
void BKE_image_editors_update_frame(const Main *bmain, int cfra)
void BKE_image_replace_imbuf(Image *image, ImBuf *ibuf)
void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
#define IMA_INDEX_ENTRY(index)
#define TEXT_SIZE_CHECK_WORD_WRAP(str, w, h)
static void image_buf_fill_isolated(void *usersata_v)
ImBuf * BKE_image_preview(Image *ima, const short max_size, short *r_width, short *r_height)
constexpr IDTypeInfo get_type_info()
RenderResult * BKE_image_acquire_renderresult(Scene *scene, Image *ima)
ImageTile * BKE_image_add_tile(Image *ima, int tile_number, const char *label)
static ImageTile * imagetile_alloc(int tile_number)
static RenderPass * image_render_pass_get(RenderLayer *rl, const int pass, const int view, int *r_passindex)
ImBuf * BKE_image_get_first_ibuf(Image *image)
static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address)
static void image_free_cached_frames(Image *image)
static void metadata_set_field(void *data, const char *propname, char *propvalue, int)
static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options)
static bool imagecache_check_free_anim(ImBuf *ibuf, void *, void *userdata)
static ImBuf * image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock)
bool BKE_image_remove_tile(Image *ima, ImageTile *tile)
static int image_get_multiview_index(Image *ima, ImageUser *iuser)
static void image_add_view(Image *ima, const char *viewname, const char *filepath)
static void image_user_id_eval_animation(Image *ima, ID *, ImageUser *iuser, void *customdata)
bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
float * BKE_image_get_float_pixels_for_frame(Image *image, int frame, int tile)
bool BKE_image_has_packedfile(const Image *ima)
void BKE_image_stamp_buf(Scene *scene, Object *camera, const StampData *stamp_data_template, uchar *rect, float *rectf, int width, int height)
bool BKE_imbuf_write_as(ImBuf *ibuf, const char *filepath, const ImageFormatData *imf, const bool save_copy)
void BKE_image_multiview_index(const Image *ima, ImageUser *iuser)
bool BKE_image_has_loaded_ibuf(Image *image)
bool BKE_image_tile_filepath_exists(const char *filepath)
void BKE_image_print_memlist(Main *bmain)
bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
static void image_init(Image *ima, short source, short type)
static void image_blend_read_after_liblink(BlendLibReader *, ID *id)
bool BKE_image_buffer_format_writable(ImBuf *ibuf)
RenderResult * RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
void RE_ReleaseResultImage(Render *re)
void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
void RE_ClearResult(Render *re)
void RE_SwapResult(Render *re, RenderResult **rr)
void RE_FreeRenderResult(RenderResult *rr)
void RE_ReferenceRenderResult(RenderResult *rr)
RenderResult * RE_AcquireResultRead(Render *re)
void RE_ReleaseResult(Render *re)
Render * RE_GetSceneRender(const Scene *scene)
RenderStats * RE_GetStats(Render *re)
#define FLT_MAX
Definition stdcycles.h:14
eBPathForeachFlag flag
Definition BKE_bpath.hh:94
struct ListBase bg_images
unsigned int id_session_uid
Definition BKE_idtype.hh:74
size_t identifier
Definition BKE_idtype.hh:79
IDTypeBlendReadUndoPreserve blend_read_undo_preserve
int main_listbase_index
short id_code
const char * name
uint64_t dependencies_id_types
IDTypeForeachIDFunction foreach_id
const char * name_plural
IDTypeCopyDataFunction copy_data
IDTypeInitDataFunction init_data
IDTypeForeachCacheFunction foreach_cache
uint64_t id_filter
IDTypeBlendWriteFunction blend_write
IDTypeBlendReadDataFunction blend_read_data
IDTypeFreeDataFunction free_data
uint32_t flags
size_t struct_size
IDTypeMakeLocalFunction make_local
AssetTypeInfo * asset_type_info
IDTypeLibOverrideApplyPost lib_override_apply_post
IDTypeForeachPathFunction foreach_path
const char * translation_context
IDTypeBlendReadAfterLiblinkFunction blend_read_after_liblink
IDTypeEmbeddedOwnerPointerGetFunction owner_pointer_get
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
struct Library * lib
Definition DNA_ID.h:410
int us
Definition DNA_ID.h:425
void * next
Definition DNA_ID.h:407
char name[66]
Definition DNA_ID.h:415
const ColorSpace * colorspace
const ColorSpace * colorspace
void * userdata
char filepath[IMB_FILEPATH_SIZE]
ImBufFloatBuffer float_buffer
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
unsigned char planes
enum eImbFileType ftype
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
IDProperty * metadata
ImBufByteBuffer encoded_buffer
double ppm[2]
unsigned int encoded_size
struct MovieReader * anim
struct PackedFile * packedfile
struct ImagePackedFile * next
char filepath[1024]
struct ImageTile * next
short multi_index
struct Scene * scene
char name[64]
char filepath[1024]
struct ImageView * next
struct ImageView * prev
short gpuflag
struct MovieCache * cache
struct ListBase packedfiles
struct PreviewImage * preview
short last_render_slot
ListBase anims
ColorManagedColorspaceSettings colorspace_settings
short gpu_pass
ListBase renderslots
short gpu_layer
char views_format
short gpu_view
char filepath[1024]
ListBase tiles
struct GPUTexture * gputexture[3][2]
short source
short render_slot
struct RenderResult * rr
ListBase views
char alpha_mode
struct Stereo3dFormat * stereo3d_format
ImageRuntimeHandle * runtime
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:516
short use_nodes
struct bNodeTree * nodetree
void * last
void * first
ListBase scenes
Definition BKE_main.hh:245
ListBase wm
Definition BKE_main.hh:276
ListBase textures
Definition BKE_main.hh:252
ListBase nodetrees
Definition BKE_main.hh:270
ListBase materials
Definition BKE_main.hh:251
ListBase cameras
Definition BKE_main.hh:256
Library * curlib
Definition BKE_main.hh:241
ListBase images
Definition BKE_main.hh:253
ListBase objects
Definition BKE_main.hh:247
struct bNodeTree * nodetree
ListBase gpumaterial
char empty_drawtype
ImageUser * iuser
char stamp_udata[768]
float fg_stamp[4]
float bg_stamp[4]
float dither_intensity
ListBase passes
Definition RE_pipeline.h:89
struct RenderLayer * next
Definition RE_pipeline.h:78
struct ImBuf * ibuf
Definition RE_pipeline.h:60
char name[64]
Definition RE_pipeline.h:50
struct RenderPass * next
Definition RE_pipeline.h:48
ListBase views
ListBase layers
struct StampData * stamp_data
double ppm[2]
struct ImBuf * ibuf
struct RenderResult * render
char name[64]
double lastframetime
struct ImBuf * ibuf
Definition RE_pipeline.h:44
struct RenderView * next
Definition RE_pipeline.h:38
char name[64]
Definition RE_pipeline.h:39
struct bNodeTree * nodetree
struct RenderData r
ColorManagedDisplaySettings display_settings
struct ImageUser iuser
struct Image * image
char name[64]
char use_nodes
struct ImageUser iuser
struct bNodeTree * nodetree
struct Image * ima
struct bNodeTree * nodetree
ListBase gpumaterial
short use_nodes
ListBase areabase
void * BKE_image_free_buffers
Definition stubs.c:35
void * BKE_image_get_tile_from_iuser
Definition stubs.c:37
void * BKE_image_get_tile
Definition stubs.c:36
i
Definition text_draw.cc:230
uint len
uint8_t flag
Definition wm_window.cc:139