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