Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Stockner <lukas.stockner@freenet.de>2019-12-12 18:06:08 +0300
committerLukas Stockner <lukas.stockner@freenet.de>2019-12-12 20:40:37 +0300
commitc30d6571bb47734e0bcb2fced5cf11cb6d8b1169 (patch)
treef92f065147296e6c72e6cd85f26711157d81e09c /source/blender/blenkernel/intern/image.c
parentd7a8a606889fed58775c88bfdc079bee3c9333e2 (diff)
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender. With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser. Therefore, code that is not yet aware of tiles will just access the default tile as usual. The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9. Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator. The following features are supported so far: - Automatic detection and loading of all tiles when opening the first tile (1001) - Saving all tiles - Adding and removing tiles - Filling tiles with generated images - Drawing all tiles in the Image Editor - Viewing a tiled grid even if no image is selected - Rendering tiled images in Eevee - Rendering tiled images in Cycles (in SVM mode) - Automatically skipping loading of unused tiles in Cycles - 2D texture painting (also across tiles) - 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders) - Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID) - Different resolutions between tiles There still are some missing features that will be added later (see T72390): - Workbench engine support - Packing/Unpacking support - Baking support - Cycles OSL support - many other Blender features that rely on images Thanks to Brecht for the review and to all who tested the intermediate versions! Differential Revision: https://developer.blender.org/D3509
Diffstat (limited to 'source/blender/blenkernel/intern/image.c')
-rw-r--r--source/blender/blenkernel/intern/image.c566
1 files changed, 439 insertions, 127 deletions
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 4c81bd4b019..fca81acf038 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -87,6 +87,7 @@
#include "RE_pipeline.h"
#include "GPU_draw.h"
+#include "GPU_texture.h"
#include "BLI_sys_types.h" // for intptr_t support
@@ -111,9 +112,9 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
/* max int, to indicate we don't store sequences in ibuf */
#define IMA_NO_INDEX 0x7FEFEFEF
-/* quick lookup: supports 1 million frames, thousand passes */
-#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index))
-#define IMA_INDEX_FRAME(index) ((index) >> 10)
+/* quick lookup: supports 1 million entries, thousand passes */
+#define IMA_MAKE_INDEX(entry, index) (((entry) << 10) + (index))
+#define IMA_INDEX_ENTRY(index) ((index) >> 10)
#if 0
# define IMA_INDEX_PASS(index) (index & ~1023)
#endif
@@ -142,7 +143,7 @@ static void imagecache_keydata(void *userkey, int *framenr, int *proxy, int *ren
{
ImageCacheKey *key = userkey;
- *framenr = IMA_INDEX_FRAME(key->index);
+ *framenr = IMA_INDEX_ENTRY(key->index);
*proxy = IMB_PROXY_NONE;
*render_flags = 0;
}
@@ -165,6 +166,17 @@ static void imagecache_put(Image *image, int index, ImBuf *ibuf)
IMB_moviecache_put(image->cache, &key, ibuf);
}
+static void imagecache_remove(Image *image, int index)
+{
+ if (image->cache == NULL) {
+ return;
+ }
+
+ ImageCacheKey key;
+ key.index = index;
+ IMB_moviecache_remove(image->cache, &key);
+}
+
static struct ImBuf *imagecache_get(Image *image, int index)
{
if (image->cache) {
@@ -257,7 +269,9 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
GPU_free_image(ima);
}
- ima->ok = IMA_OK;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ tile->ok = IMA_OK;
+ }
if (do_lock) {
BLI_mutex_unlock(image_mutex);
@@ -290,6 +304,8 @@ void BKE_image_free(Image *ima)
BKE_icon_id_delete(&ima->id);
BKE_previewimg_free(&ima->preview);
+
+ BLI_freelistN(&ima->tiles);
}
/* only image block itself */
@@ -299,8 +315,6 @@ static void image_init(Image *ima, short source, short type)
MEMCPY_STRUCT_AFTER(ima, DNA_struct_default_get(Image), id);
- ima->ok = IMA_OK;
-
ima->source = source;
ima->type = type;
@@ -308,6 +322,11 @@ static void image_init(Image *ima, short source, short type)
ima->flag |= IMA_VIEW_AS_RENDER;
}
+ ImageTile *tile = MEM_callocN(sizeof(ImageTile), "Image Tiles");
+ tile->ok = IMA_OK;
+ tile->tile_number = 1001;
+ BLI_addtail(&ima->tiles, tile);
+
if (type == IMA_TYPE_R_RESULT) {
for (int i = 0; i < 8; i++) {
BKE_image_add_renderslot(ima, NULL);
@@ -337,34 +356,42 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ
return ima;
}
-/* Get the ibuf from an image cache by it's index and frame.
+/* Get the ibuf from an image cache by it's index and entry.
* Local use here only.
*
* Returns referenced image buffer if it exists, callee is to
* call IMB_freeImBuf to de-reference the image buffer after
* it's done handling it.
*/
-static ImBuf *image_get_cached_ibuf_for_index_frame(Image *ima, int index, int frame)
+static ImBuf *image_get_cached_ibuf_for_index_entry(Image *ima, int index, int entry)
{
if (index != IMA_NO_INDEX) {
- index = IMA_MAKE_INDEX(frame, index);
+ index = IMA_MAKE_INDEX(entry, index);
}
return imagecache_get(ima, index);
}
/* no ima->ibuf anymore, but listbase */
-static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
+static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int entry)
{
if (ibuf) {
if (index != IMA_NO_INDEX) {
- index = IMA_MAKE_INDEX(frame, index);
+ index = IMA_MAKE_INDEX(entry, index);
}
imagecache_put(ima, index, ibuf);
}
}
+static void image_remove_ibuf(Image *ima, int index, int entry)
+{
+ if (index != IMA_NO_INDEX) {
+ index = IMA_MAKE_INDEX(entry, index);
+ }
+ imagecache_remove(ima, index);
+}
+
static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
{
const ImagePackedFile *imapf_src;
@@ -413,8 +440,11 @@ void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_s
BLI_listbase_clear(&ima_dst->anims);
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima_dst->gputexture[i] = NULL;
+ BLI_duplicatelist(&ima_dst->tiles, &ima_src->tiles);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima_dst->tiles) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ tile->gputexture[i] = NULL;
+ }
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
@@ -480,14 +510,82 @@ bool BKE_image_scale(Image *image, int width, int height)
bool BKE_image_has_opengl_texture(Image *ima)
{
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i]) {
- return true;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (tile->gputexture[i] != NULL) {
+ return true;
+ }
}
}
return false;
}
+ImageTile *BKE_image_get_tile(Image *ima, int tile_number)
+{
+ if (ima == NULL) {
+ return NULL;
+ }
+
+ /* Verify valid tile range. */
+ if ((tile_number != 0) && (tile_number < 1001 || tile_number > IMA_UDIM_MAX)) {
+ return NULL;
+ }
+
+ /* Tile number 0 is a special case and refers to the first tile, typically
+ * coming from non-UDIM-aware code. */
+ if (tile_number == 0 || tile_number == 1001) {
+ return ima->tiles.first;
+ }
+
+ if (ima->source != IMA_SRC_TILED) {
+ return NULL;
+ }
+
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ if (tile->tile_number == tile_number) {
+ return tile;
+ }
+ }
+
+ return NULL;
+}
+
+ImageTile *BKE_image_get_tile_from_iuser(Image *ima, ImageUser *iuser)
+{
+ return BKE_image_get_tile(ima, (iuser && iuser->tile) ? iuser->tile : 1001);
+}
+
+int BKE_image_get_tile_from_pos(struct Image *ima,
+ const float uv[2],
+ float new_uv[2],
+ float ofs[2])
+{
+ float local_ofs[2];
+ if (ofs == NULL) {
+ ofs = local_ofs;
+ }
+
+ copy_v2_v2(new_uv, uv);
+ zero_v2(ofs);
+
+ if ((ima->source != IMA_SRC_TILED) || uv[0] < 0.0f || uv[1] < 0.0f || uv[0] >= 10.0f) {
+ return 0;
+ }
+
+ int ix = (int)uv[0];
+ int iy = (int)uv[1];
+ int tile_number = 1001 + 10 * iy + ix;
+
+ if (BKE_image_get_tile(ima, tile_number) == NULL) {
+ return 0;
+ }
+ ofs[0] = ix;
+ ofs[1] = iy;
+ sub_v2_v2(new_uv, ofs);
+
+ return tile_number;
+}
+
static void image_init_color_management(Image *ima)
{
ImBuf *ibuf;
@@ -580,8 +678,10 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist
if (BLI_path_cmp(strtest, str) == 0) {
if ((BKE_image_has_anim(ima) == false) || (ima->id.us == 0)) {
id_us_plus(&ima->id); /* officially should not, it doesn't link here! */
- if (ima->ok == 0) {
- ima->ok = IMA_OK;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ if (tile->ok == 0) {
+ tile->ok = IMA_OK;
+ }
}
if (r_exists) {
*r_exists = true;
@@ -690,10 +790,17 @@ Image *BKE_image_add_generated(Main *bmain,
short gen_type,
const float color[4],
const bool stereo3d,
- const bool is_data)
+ const bool is_data,
+ const bool tiled)
{
/* on save, type is changed to FILE in editsima.c */
- Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+ Image *ima;
+ if (tiled) {
+ ima = image_alloc(bmain, name, IMA_SRC_TILED, IMA_TYPE_IMAGE);
+ }
+ else {
+ ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+ }
if (ima == NULL) {
return NULL;
}
@@ -718,7 +825,9 @@ Image *BKE_image_add_generated(Main *bmain,
ImBuf *ibuf;
ibuf = add_ibuf_size(
width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, stereo3d ? view_id : IMA_NO_INDEX, 0);
+ int index = tiled ? 0 : IMA_NO_INDEX;
+ int entry = tiled ? 1001 : 0;
+ image_assign_ibuf(ima, ibuf, stereo3d ? view_id : index, entry);
/* image_assign_ibuf puts buffer to the cache, which increments user counter. */
IMB_freeImBuf(ibuf);
@@ -729,7 +838,8 @@ Image *BKE_image_add_generated(Main *bmain,
image_add_view(ima, names[view_id], "");
}
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
return ima;
}
@@ -751,7 +861,8 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
if (ima) {
STRNCPY(ima->name, ibuf->name);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
}
return ima;
@@ -802,7 +913,7 @@ bool BKE_image_memorypack(Image *ima)
int i;
for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, i, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, 0);
if (!ibuf) {
ok = false;
@@ -822,7 +933,7 @@ bool BKE_image_memorypack(Image *ima)
ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
}
else {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
if (ibuf) {
ok = ok && image_memorypack_imbuf(ima, ibuf, ibuf->name);
@@ -1009,7 +1120,7 @@ static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void
{
int except_frame = *(int *)userdata;
return (ibuf->userflags & IB_BITMAPDIRTY) == 0 && (ibuf->index != IMA_NO_INDEX) &&
- (except_frame != IMA_INDEX_FRAME(ibuf->index));
+ (except_frame != IMA_INDEX_ENTRY(ibuf->index));
}
/* except_frame is weak, only works for seqs without offset... */
@@ -3162,7 +3273,7 @@ static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *c
void BKE_imageuser_default(ImageUser *iuser)
{
memset(iuser, 0, sizeof(ImageUser));
- iuser->ok = true;
+ iuser->ok = 1;
iuser->frames = 100;
iuser->sfra = 1;
}
@@ -3179,6 +3290,26 @@ void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
}
}
+static void image_free_tile(Image *ima, ImageTile *tile)
+{
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (tile->gputexture[i] != NULL) {
+ GPU_texture_free(tile->gputexture[i]);
+ tile->gputexture[i] = NULL;
+ }
+ }
+
+ if (BKE_image_is_multiview(ima)) {
+ const int totviews = BLI_listbase_count(&ima->views);
+ for (int i = 0; i < totviews; i++) {
+ image_remove_ibuf(ima, i, tile->tile_number);
+ }
+ }
+ else {
+ image_remove_ibuf(ima, 0, tile->tile_number);
+ }
+}
+
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
{
if (ima == NULL) {
@@ -3207,7 +3338,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
if (ima->source == IMA_SRC_GENERATED) {
if (ima->gen_x == 0 || ima->gen_y == 0) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
if (ibuf) {
ima->gen_x = ibuf->x;
ima->gen_y = ibuf->y;
@@ -3225,6 +3356,17 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
ima->name[0] = '\0';
}
+ if (ima->source != IMA_SRC_TILED) {
+ /* Free all but the first tile. */
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ for (ImageTile *tile = base_tile->next; tile; tile = tile->next) {
+ image_free_tile(ima, tile);
+ MEM_freeN(tile);
+ }
+ base_tile->next = NULL;
+ ima->tiles.last = base_tile;
+ }
+
/* image buffers for non-sequence multilayer will share buffers with RenderResult,
* however sequence multilayer will own buffers. Such logic makes switching from
* single multilayer file to sequence completely unstable
@@ -3234,7 +3376,10 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
*/
BKE_image_free_buffers(ima);
- ima->ok = 1;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ tile->ok = 1;
+ }
+
if (iuser) {
image_tag_frame_recalc(ima, NULL, iuser, ima);
}
@@ -3283,7 +3428,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
case IMA_SIGNAL_USER_NEW_IMAGE:
if (iuser) {
iuser->ok = 1;
- if (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_SEQUENCE) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
if (ima->type == IMA_TYPE_MULTILAYER) {
BKE_image_init_imageuser(ima, iuser);
}
@@ -3293,7 +3438,9 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
case IMA_SIGNAL_COLORMANAGE:
BKE_image_free_buffers(ima);
- ima->ok = 1;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ tile->ok = 1;
+ }
if (iuser) {
iuser->ok = 1;
@@ -3360,6 +3507,107 @@ static RenderPass *image_render_pass_get(RenderLayer *rl,
return rpass_ret;
}
+void BKE_image_get_tile_label(Image *ima, ImageTile *tile, char *label, int len_label)
+{
+ label[0] = '\0';
+ if (ima == NULL || tile == NULL) {
+ return;
+ }
+
+ if (tile->label[0]) {
+ BLI_strncpy(label, tile->label, len_label);
+ }
+ else {
+ BLI_snprintf(label, len_label, "%d", tile->tile_number);
+ }
+}
+
+ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label)
+{
+ if (ima->source != IMA_SRC_TILED) {
+ return NULL;
+ }
+
+ if (tile_number < 1001 || tile_number > IMA_UDIM_MAX) {
+ return NULL;
+ }
+
+ /* Search the first tile that has a higher number.
+ * We then insert before that to keep the list sorted. */
+ ImageTile *next_tile;
+ for (next_tile = ima->tiles.first; next_tile; next_tile = next_tile->next) {
+ if (next_tile->tile_number == tile_number) {
+ /* Tile already exists. */
+ return NULL;
+ }
+ if (next_tile->tile_number > tile_number) {
+ break;
+ }
+ }
+
+ ImageTile *tile = MEM_callocN(sizeof(ImageTile), "image new tile");
+ tile->ok = 1;
+ tile->tile_number = tile_number;
+
+ if (next_tile) {
+ BLI_insertlinkbefore(&ima->tiles, next_tile, tile);
+ }
+ else {
+ BLI_addtail(&ima->tiles, tile);
+ }
+
+ if (label) {
+ BLI_strncpy(tile->label, label, sizeof(tile->label));
+ }
+
+ return tile;
+}
+
+bool BKE_image_remove_tile(struct Image *ima, ImageTile *tile)
+{
+ if (ima == NULL || tile == NULL || ima->source != IMA_SRC_TILED) {
+ return false;
+ }
+
+ if (tile == ima->tiles.first) {
+ /* Can't remove first tile. */
+ return false;
+ }
+
+ image_free_tile(ima, tile);
+ BLI_remlink(&ima->tiles, tile);
+ MEM_freeN(tile);
+
+ return true;
+}
+
+bool BKE_image_fill_tile(struct Image *ima,
+ ImageTile *tile,
+ int width,
+ int height,
+ const float color[4],
+ int gen_type,
+ int planes,
+ bool is_float)
+{
+ if (ima == NULL || tile == NULL || ima->source != IMA_SRC_TILED) {
+ return false;
+ }
+
+ image_free_tile(ima, tile);
+
+ ImBuf *tile_ibuf = add_ibuf_size(
+ width, height, ima->name, planes, is_float, gen_type, color, &ima->colorspace_settings);
+
+ if (tile_ibuf != NULL) {
+ image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number);
+ BKE_image_release_ibuf(ima, tile_ibuf, NULL);
+ tile->ok = 1;
+ return true;
+ }
+ return false;
+}
+
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
@@ -3421,7 +3669,7 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
bool BKE_image_is_multilayer(Image *ima)
{
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
if (ima->type == IMA_TYPE_MULTILAYER) {
return true;
}
@@ -3512,7 +3760,7 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima)
bool BKE_image_is_openexr(struct Image *ima)
{
#ifdef WITH_OPENEXR
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
return BLI_path_extension_check(ima->name, ".exr");
}
#else
@@ -3617,7 +3865,7 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
#endif /* WITH_OPENEXR */
/* common stuff to do with images after loading */
-static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf))
+static void image_initialize_after_load(Image *ima, ImageUser *iuser, ImBuf *UNUSED(ibuf))
{
/* Preview is NULL when it has never been used as an icon before.
* Never handle previews/icons outside of main thread. */
@@ -3628,7 +3876,8 @@ static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf))
/* timer */
BKE_image_tag_time(ima);
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+ tile->ok = IMA_OK_LOADED;
}
static int imbuf_alpha_flags_for_image(Image *ima)
@@ -3712,19 +3961,25 @@ static ImBuf *load_sequence_single(
}
}
else {
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
*r_assign = true;
}
#else
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
*r_assign = true;
#endif
}
+ else {
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+ if (tile != NULL) {
+ tile->ok = 0;
+ }
+ }
return ibuf;
}
-static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry, int frame)
{
struct ImBuf *ibuf = NULL;
const bool is_multiview = BKE_image_is_multiview(ima);
@@ -3734,7 +3989,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
if (!is_multiview) {
ibuf = load_sequence_single(ima, iuser, frame, 0, &assign);
if (assign) {
- image_assign_ibuf(ima, ibuf, 0, frame);
+ image_assign_ibuf(ima, ibuf, 0, entry);
}
}
else {
@@ -3757,7 +4012,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
if (assign) {
for (i = 0; i < totviews; i++) {
- image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ image_assign_ibuf(ima, ibuf_arr[i], i, entry);
}
}
@@ -3775,9 +4030,10 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
return ibuf;
}
-static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int frame)
+static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int entry, int frame)
{
struct ImBuf *ibuf = NULL;
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
/* either we load from RenderResult, or we have to load a new one */
@@ -3793,7 +4049,7 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
ima->rr = NULL;
}
- ibuf = image_load_sequence_file(ima, iuser, frame);
+ ibuf = image_load_sequence_file(ima, iuser, entry, frame);
if (ibuf) { /* actually an error */
ima->type = IMA_TYPE_IMAGE;
@@ -3814,17 +4070,17 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
BKE_imbuf_stamp_info(ima->rr, ibuf);
- image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : 0, frame);
+ image_initialize_after_load(ima, iuser, ibuf);
+ image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : 0, entry);
}
// else printf("pass not found\n");
}
else {
- ima->ok = 0;
+ tile->ok = 0;
}
if (iuser) {
- iuser->ok = ima->ok;
+ iuser->ok = tile->ok;
}
return ibuf;
@@ -3837,6 +4093,8 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const i
ia = BLI_findlink(&ima->anims, view_id);
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+
if (ia->anim == NULL) {
char str[FILE_MAX];
int flags = IB_rect;
@@ -3876,14 +4134,14 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const i
ibuf = IMB_makeSingleUser(IMB_anim_absolute(ia->anim, fra, IMB_TC_RECORD_RUN, IMB_PROXY_NONE));
if (ibuf) {
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
}
else {
- ima->ok = 0;
+ tile->ok = 0;
}
}
else {
- ima->ok = 0;
+ tile->ok = 0;
}
return ibuf;
@@ -3894,6 +4152,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
struct ImBuf *ibuf = NULL;
const bool is_multiview = BKE_image_is_multiview(ima);
const int totfiles = image_num_files(ima);
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
int i;
if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) {
@@ -3929,7 +4188,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
image_assign_ibuf(ima, ibuf_arr[i], i, frame);
}
else {
- ima->ok = 0;
+ tile->ok = 0;
}
}
@@ -3948,7 +4207,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
}
if (iuser) {
- iuser->ok = ima->ok;
+ iuser->ok = tile->ok;
}
return ibuf;
@@ -4020,7 +4279,7 @@ static ImBuf *load_image_single(Image *ima,
else
#endif
{
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
*r_assign = true;
/* make packed file for autopack */
@@ -4035,7 +4294,8 @@ static ImBuf *load_image_single(Image *ima,
}
}
else {
- ima->ok = 0;
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+ tile->ok = 0;
}
return ibuf;
@@ -4109,7 +4369,8 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
}
if (iuser) {
- iuser->ok = ima->ok;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ iuser->ok = tile->ok;
}
return ibuf;
@@ -4132,7 +4393,7 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
if (rpass) {
ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0);
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
ibuf->rect_float = rpass->rect;
ibuf->flags |= IB_rectfloat;
@@ -4144,11 +4405,12 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
}
}
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
if (ibuf == NULL) {
- ima->ok = 0;
+ tile->ok = 0;
}
if (iuser) {
- iuser->ok = ima->ok;
+ iuser->ok = tile->ok;
}
return ibuf;
@@ -4268,7 +4530,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
}
}
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
/* make ibuf if needed, and initialize it */
if (ibuf == NULL) {
@@ -4345,7 +4607,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
ibuf->dither = dither;
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
return ibuf;
}
@@ -4355,7 +4618,7 @@ static int image_get_multiview_index(Image *ima, ImageUser *iuser)
const bool is_multilayer = BKE_image_is_multilayer(ima);
const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) &&
(iuser == NULL);
- int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX;
+ int index = BKE_image_has_multiple_ibufs(ima) ? 0 : IMA_NO_INDEX;
if (is_multilayer) {
return iuser ? iuser->multi_index : index;
@@ -4373,7 +4636,7 @@ static int image_get_multiview_index(Image *ima, ImageUser *iuser)
return index;
}
-static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
+static void image_get_entry_and_index(Image *ima, ImageUser *iuser, int *r_entry, int *r_index)
{
int frame = 0, index = image_get_multiview_index(ima, iuser);
@@ -4390,7 +4653,7 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
}
}
- *r_frame = frame;
+ *r_entry = frame;
*r_index = index;
}
@@ -4400,58 +4663,75 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
* call IMB_freeImBuf to de-reference the image buffer after
* it's done handling it.
*/
-static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
+static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry, int *r_index)
{
ImBuf *ibuf = NULL;
- int frame = 0, index = image_get_multiview_index(ima, iuser);
+ int entry = 0, index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
- ima->lastframe = frame;
+ entry = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+ ima->lastframe = entry;
}
else if (ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_IMAGE) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
- ima->lastframe = frame;
+ entry = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+ ima->lastframe = entry;
/* counter the fact that image is set as invalid when loading a frame
* that is not in the cache (through image_acquire_ibuf for instance),
* yet we have valid frames in the cache loaded */
if (ibuf) {
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
if (iuser) {
- iuser->ok = ima->ok;
+ iuser->ok = tile->ok;
}
}
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
+ entry = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
}
}
else if (ima->source == IMA_SRC_FILE) {
if (ima->type == IMA_TYPE_IMAGE) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
}
}
else if (ima->source == IMA_SRC_GENERATED) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
}
else if (ima->source == IMA_SRC_VIEWER) {
/* always verify entirely, not that this shouldn't happen
* as part of texture sampling in rendering anyway, so not
* a big bottleneck */
}
+ else if (ima->source == IMA_SRC_TILED) {
+ if (ELEM(ima->type, IMA_TYPE_IMAGE, IMA_TYPE_MULTILAYER)) {
+ entry = (iuser && iuser->tile) ? iuser->tile : 1001;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+
+ if ((ima->type == IMA_TYPE_IMAGE) && ibuf != NULL) {
+ ImageTile *tile = BKE_image_get_tile(ima, entry);
+ tile->ok = IMA_OK_LOADED;
+
+ /* iuser->ok is useless for tiled images because iuser->tile changes all the time. */
+ if (iuser != NULL) {
+ iuser->ok = 1;
+ }
+ }
+ }
+ }
- if (r_frame) {
- *r_frame = frame;
+ if (r_entry) {
+ *r_entry = entry;
}
if (r_index) {
@@ -4467,12 +4747,17 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
return false;
}
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+
if (iuser) {
if (iuser->ok == 0) {
return false;
}
}
- else if (ima->ok == 0) {
+ else if (tile == NULL) {
+ return false;
+ }
+ else if (tile->ok == 0) {
return false;
}
@@ -4486,7 +4771,7 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
ImBuf *ibuf = NULL;
- int frame = 0, index = 0;
+ int entry = 0, index = 0;
if (r_lock) {
*r_lock = NULL;
@@ -4497,29 +4782,40 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
return NULL;
}
- ibuf = image_get_cached_ibuf(ima, iuser, &frame, &index);
+ ibuf = image_get_cached_ibuf(ima, iuser, &entry, &index);
if (ibuf == NULL) {
/* we are sure we have to load the ibuf, using source and type */
if (ima->source == IMA_SRC_MOVIE) {
/* source is from single file, use flipbook to store ibuf */
- ibuf = image_load_movie_file(ima, iuser, frame);
+ ibuf = image_load_movie_file(ima, iuser, entry);
}
else if (ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_IMAGE) {
/* regular files, ibufs in flipbook, allows saving */
- ibuf = image_load_sequence_file(ima, iuser, frame);
+ ibuf = image_load_sequence_file(ima, iuser, entry, entry);
}
/* no else; on load the ima type can change */
if (ima->type == IMA_TYPE_MULTILAYER) {
/* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */
- ibuf = image_load_sequence_multilayer(ima, iuser, frame);
+ ibuf = image_load_sequence_multilayer(ima, iuser, entry, entry);
+ }
+ }
+ else if (ima->source == IMA_SRC_TILED) {
+ if (ima->type == IMA_TYPE_IMAGE) {
+ /* regular files, ibufs in flipbook, allows saving */
+ ibuf = image_load_sequence_file(ima, iuser, entry, 0);
+ }
+ /* no else; on load the ima type can change */
+ if (ima->type == IMA_TYPE_MULTILAYER) {
+ /* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */
+ ibuf = image_load_sequence_multilayer(ima, iuser, entry, 0);
}
}
else if (ima->source == IMA_SRC_FILE) {
if (ima->type == IMA_TYPE_IMAGE) {
- ibuf = image_load_image_file(ima, iuser, frame); /* cfra only for '#', this global is OK */
+ ibuf = image_load_image_file(ima, iuser, entry); /* cfra only for '#', this global is OK */
}
/* no else; on load the ima type can change */
if (ima->type == IMA_TYPE_MULTILAYER) {
@@ -4548,7 +4844,8 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
ima->gen_color,
&ima->colorspace_settings);
image_assign_ibuf(ima, ibuf, index, 0);
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
}
else if (ima->source == IMA_SRC_VIEWER) {
if (ima->type == IMA_TYPE_R_RESULT) {
@@ -4564,14 +4861,14 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
*r_lock = ima;
/* XXX anim play for viewer nodes not yet supported */
- frame = 0; // XXX iuser ? iuser->framenr : 0;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
+ entry = 0; // XXX iuser ? iuser->framenr : 0;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
if (!ibuf) {
/* Composite Viewer, all handled in compositor */
/* fake ibuf, will be filled in compositor */
ibuf = IMB_allocImBuf(256, 256, 32, IB_rect | IB_rectfloat);
- image_assign_ibuf(ima, ibuf, index, frame);
+ image_assign_ibuf(ima, ibuf, index, entry);
}
}
}
@@ -4655,13 +4952,13 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
/* ******** Pool for image buffers ******** */
-typedef struct ImagePoolEntry {
- struct ImagePoolEntry *next, *prev;
+typedef struct ImagePoolItem {
+ struct ImagePoolItem *next, *prev;
Image *image;
ImBuf *ibuf;
int index;
- int frame;
-} ImagePoolEntry;
+ int entry;
+} ImagePoolItem;
typedef struct ImagePool {
ListBase image_buffers;
@@ -4671,7 +4968,7 @@ typedef struct ImagePool {
ImagePool *BKE_image_pool_new(void)
{
ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
- pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolEntry), 0, 128, BLI_MEMPOOL_NOP);
+ pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolItem), 0, 128, BLI_MEMPOOL_NOP);
return pool;
}
@@ -4680,9 +4977,9 @@ void BKE_image_pool_free(ImagePool *pool)
{
/* Use single lock to dereference all the image buffers. */
BLI_mutex_lock(image_mutex);
- for (ImagePoolEntry *entry = pool->image_buffers.first; entry != NULL; entry = entry->next) {
- if (entry->ibuf) {
- IMB_freeImBuf(entry->ibuf);
+ for (ImagePoolItem *item = pool->image_buffers.first; item != NULL; item = item->next) {
+ if (item->ibuf != NULL) {
+ IMB_freeImBuf(item->ibuf);
}
}
BLI_mutex_unlock(image_mutex);
@@ -4691,17 +4988,17 @@ void BKE_image_pool_free(ImagePool *pool)
MEM_freeN(pool);
}
-BLI_INLINE ImBuf *image_pool_find_entry(
- ImagePool *pool, Image *image, int frame, int index, bool *found)
+BLI_INLINE ImBuf *image_pool_find_item(
+ ImagePool *pool, Image *image, int entry, int index, bool *found)
{
- ImagePoolEntry *entry;
+ ImagePoolItem *item;
*found = false;
- for (entry = pool->image_buffers.first; entry; entry = entry->next) {
- if (entry->image == image && entry->frame == frame && entry->index == index) {
+ for (item = pool->image_buffers.first; item; item = item->next) {
+ if (item->image == image && item->entry == entry && item->index == index) {
*found = true;
- return entry->ibuf;
+ return item->ibuf;
}
}
@@ -4711,7 +5008,7 @@ BLI_INLINE ImBuf *image_pool_find_entry(
ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool)
{
ImBuf *ibuf;
- int index, frame;
+ int index, entry;
bool found;
if (!image_quick_test(ima, iuser)) {
@@ -4723,32 +5020,32 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool
return BKE_image_acquire_ibuf(ima, iuser, NULL);
}
- image_get_frame_and_index(ima, iuser, &frame, &index);
+ image_get_entry_and_index(ima, iuser, &entry, &index);
- ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+ ibuf = image_pool_find_item(pool, ima, entry, index, &found);
if (found) {
return ibuf;
}
BLI_mutex_lock(image_mutex);
- ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+ ibuf = image_pool_find_item(pool, ima, entry, index, &found);
- /* will also create entry even in cases image buffer failed to load,
+ /* will also create item even in cases image buffer failed to load,
* prevents trying to load the same buggy file multiple times
*/
if (!found) {
- ImagePoolEntry *entry;
+ ImagePoolItem *item;
ibuf = image_acquire_ibuf(ima, iuser, NULL);
- entry = BLI_mempool_alloc(pool->memory_pool);
- entry->image = ima;
- entry->frame = frame;
- entry->index = index;
- entry->ibuf = ibuf;
+ item = BLI_mempool_alloc(pool->memory_pool);
+ item->image = ima;
+ item->entry = entry;
+ item->index = index;
+ item->ibuf = ibuf;
- BLI_addtail(&pool->image_buffers, entry);
+ BLI_addtail(&pool->image_buffers, item);
}
BLI_mutex_unlock(image_mutex);
@@ -4946,13 +5243,20 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
BLI_strncpy(filepath, ima->name, FILE_MAX);
}
- if (ima->source == IMA_SRC_SEQUENCE) {
+ if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
char head[FILE_MAX], tail[FILE_MAX];
unsigned short numlen;
- int frame = iuser ? iuser->framenr : ima->lastframe;
+
+ int index;
+ if (ima->source == IMA_SRC_SEQUENCE) {
+ index = iuser ? iuser->framenr : ima->lastframe;
+ }
+ else {
+ index = (iuser && iuser->tile) ? iuser->tile : 1001;
+ }
BLI_stringdec(filepath, head, tail, &numlen);
- BLI_stringenc(filepath, head, tail, numlen, frame);
+ BLI_stringenc(filepath, head, tail, numlen, index);
}
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
@@ -5031,15 +5335,16 @@ void BKE_image_get_aspect(Image *image, float *aspx, float *aspy)
}
}
-unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame)
+unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame, int tile)
{
- ImageUser iuser = {NULL};
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
void *lock;
ImBuf *ibuf;
unsigned char *pixels = NULL;
iuser.framenr = frame;
- iuser.ok = true;
+ iuser.tile = tile;
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
@@ -5060,15 +5365,16 @@ unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame)
return pixels;
}
-float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame)
+float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int tile)
{
- ImageUser iuser = {NULL};
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
void *lock;
ImBuf *ibuf;
float *pixels = NULL;
iuser.framenr = frame;
- iuser.ok = true;
+ iuser.tile = tile;
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
@@ -5117,6 +5423,12 @@ bool BKE_image_is_animated(Image *image)
return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
}
+/* Checks whether the image consists of multiple buffers. */
+bool BKE_image_has_multiple_ibufs(Image *image)
+{
+ return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED);
+}
+
/* Image modifications */
bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
{
@@ -5233,7 +5545,7 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
* References the result, #BKE_image_release_ibuf is to be called to de-reference.
* Use lock=NULL when calling #BKE_image_release_ibuf().
*
- * TODO(sergey): This is actually "get first entry from the cache", which is
+ * TODO(sergey): This is actually "get first item from the cache", which is
* not so much predictable. But using first loaded image buffer
* was also malicious logic and all the areas which uses this
* function are to be re-considered.