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