diff options
author | Jesse Yurkovich <jesse.y@gmail.com> | 2021-08-18 07:42:28 +0300 |
---|---|---|
committer | Jesse Yurkovich <jesse.y@gmail.com> | 2021-08-18 07:44:36 +0300 |
commit | 400cb25fc77a4131033f69cf328a31cdcf81edb5 (patch) | |
tree | e88d1f14569ddefaa0fe2b75401498fbf84b9af6 /source | |
parent | f41beca97787d017a437a63cc0da2ce991522dea (diff) |
UDIM: Support tile sets that do not start at 1001
Removes the artificial requirement that UDIM tile sets start at 1001.
Blender was already capable of handling sparse tile sets (non-contiguous
tiles) so the restriction around starting at 1001 was unnecessary in
general.
This required fixing a few UDIM-related python bugs around manually
updating the `tile_number` field on images as well. See the differential
for details. No script changes are necessary but they will now work,
correctly, in many more cases.
Differential Revision: https://developer.blender.org/D11859
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_image.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image.c | 87 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image_gpu.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image_save.c | 18 | ||||
-rw-r--r-- | source/blender/editors/space_image/image_ops.c | 32 | ||||
-rw-r--r-- | source/blender/editors/space_image/image_sequence.c | 34 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_image.c | 9 |
7 files changed, 130 insertions, 55 deletions
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index ac73bd2b595..3cab1a6b755 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -308,6 +308,8 @@ void BKE_image_get_tile_label(struct Image *ima, struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label); bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile); +void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number); +void BKE_image_sort_tiles(struct Image *ima); bool BKE_image_fill_tile(struct Image *ima, struct ImageTile *tile, diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ba54858ba84..d2ab54de697 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -670,24 +670,27 @@ bool BKE_image_has_opengl_texture(Image *ima) return false; } +static int image_get_tile_number_from_iuser(Image *ima, const ImageUser *iuser) +{ + BLI_assert(ima != NULL && ima->tiles.first); + ImageTile *tile = ima->tiles.first; + return (iuser && iuser->tile) ? iuser->tile : tile->tile_number; +} + 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 + /* Tiles 0 and 1001 are a special case and refer to the first tile, typically * coming from non-UDIM-aware code. */ if (ELEM(tile_number, 0, 1001)) { return ima->tiles.first; } - if (ima->source != IMA_SRC_TILED) { + /* Must have a tiled image and a valid tile number at this point. */ + if (ima->source != IMA_SRC_TILED || tile_number < 1001 || tile_number > IMA_UDIM_MAX) { return NULL; } @@ -702,7 +705,7 @@ ImageTile *BKE_image_get_tile(Image *ima, int tile_number) ImageTile *BKE_image_get_tile_from_iuser(Image *ima, const ImageUser *iuser) { - return BKE_image_get_tile(ima, (iuser && iuser->tile) ? iuser->tile : 1001); + return BKE_image_get_tile(ima, image_get_tile_number_from_iuser(ima, iuser)); } int BKE_image_get_tile_from_pos(struct Image *ima, @@ -3803,8 +3806,8 @@ bool BKE_image_remove_tile(struct Image *ima, ImageTile *tile) return false; } - if (tile == ima->tiles.first) { - /* Can't remove first tile. */ + if (BLI_listbase_is_single(&ima->tiles)) { + /* Can't remove the last remaining tile. */ return false; } @@ -3815,6 +3818,64 @@ bool BKE_image_remove_tile(struct Image *ima, ImageTile *tile) return true; } +void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_number) +{ + if (ima == NULL || tile == NULL || ima->source != IMA_SRC_TILED) { + return; + } + + if (new_tile_number < 1001 || new_tile_number > IMA_UDIM_MAX) { + return; + } + + const int old_tile_number = tile->tile_number; + tile->tile_number = new_tile_number; + + if (BKE_image_is_multiview(ima)) { + const int totviews = BLI_listbase_count(&ima->views); + for (int i = 0; i < totviews; i++) { + ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, old_tile_number); + image_remove_ibuf(ima, i, old_tile_number); + image_assign_ibuf(ima, ibuf, i, new_tile_number); + IMB_freeImBuf(ibuf); + } + } + else { + ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, 0, old_tile_number); + image_remove_ibuf(ima, 0, old_tile_number); + image_assign_ibuf(ima, ibuf, 0, new_tile_number); + IMB_freeImBuf(ibuf); + } + + for (int eye = 0; eye < 2; eye++) { + /* Reallocate GPU tile array. */ + if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != NULL) { + GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]); + ima->gputexture[TEXTARGET_2D_ARRAY][eye] = NULL; + } + if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != NULL) { + GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]); + ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = NULL; + } + } +} + +static int tile_sort_cb(const void *a, const void *b) +{ + const ImageTile *tile_a = a; + const ImageTile *tile_b = b; + return (tile_a->tile_number > tile_b->tile_number) ? 1 : 0; +} + +void BKE_image_sort_tiles(struct Image *ima) +{ + if (ima == NULL || ima->source != IMA_SRC_TILED) { + return; + } + + BLI_listbase_sort(&ima->tiles, tile_sort_cb); +} + bool BKE_image_fill_tile(struct Image *ima, ImageTile *tile, int width, @@ -4890,7 +4951,7 @@ static void image_get_entry_and_index(Image *ima, ImageUser *iuser, int *r_entry } } else if (ima->source == IMA_SRC_TILED) { - frame = (iuser && iuser->tile) ? iuser->tile : 1001; + frame = image_get_tile_number_from_iuser(ima, iuser); } *r_entry = frame; @@ -4955,7 +5016,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry, } else if (ima->source == IMA_SRC_TILED) { if (ELEM(ima->type, IMA_TYPE_IMAGE, IMA_TYPE_MULTILAYER)) { - entry = (iuser && iuser->tile) ? iuser->tile : 1001; + entry = image_get_tile_number_from_iuser(ima, iuser); ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry); if ((ima->type == IMA_TYPE_IMAGE) && ibuf != NULL) { @@ -5507,7 +5568,7 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) index = iuser ? iuser->framenr : ima->lastframe; } else { - index = (iuser && iuser->tile) ? iuser->tile : 1001; + index = image_get_tile_number_from_iuser(ima, iuser); } BLI_path_sequence_decode(filepath, head, tail, &numlen); diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c index bb7495437bb..d179dd40c33 100644 --- a/source/blender/blenkernel/intern/image_gpu.c +++ b/source/blender/blenkernel/intern/image_gpu.c @@ -108,8 +108,9 @@ static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multivi float array_w = GPU_texture_width(tilearray); float array_h = GPU_texture_height(tilearray); + /* Determine maximum tile number. */ + BKE_image_sort_tiles(ima); ImageTile *last_tile = (ImageTile *)ima->tiles.last; - /* Tiles are sorted by number. */ int max_tile = last_tile->tile_number - 1001; /* create image */ diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c index 360bad3e786..be86da05b57 100644 --- a/source/blender/blenkernel/intern/image_save.c +++ b/source/blender/blenkernel/intern/image_save.c @@ -404,11 +404,12 @@ bool BKE_image_save( if (ima->source == IMA_SRC_TILED) { /* Verify filepath for tiles images. */ - if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != 1001) { + ImageTile *first_tile = ima->tiles.first; + if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != first_tile->tile_number) { BKE_reportf(reports, RPT_ERROR, - "When saving a tiled image, the path '%s' must contain the UDIM tag 1001", - opts->filepath); + "When saving a tiled image, the path '%s' must contain the UDIM tile number %d", + opts->filepath, first_tile->tile_number); return false; } @@ -430,9 +431,14 @@ bool BKE_image_save( BLI_path_sequence_decode(filepath, head, tail, &numlen); /* Save all other tiles. */ - LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { - /* Tile 1001 was already saved before the loop. */ - if (tile->tile_number == 1001 || !ok) { + int index; + LISTBASE_FOREACH_INDEX (ImageTile *, tile, &ima->tiles, index) { + /* First tile was already saved before the loop. */ + if (index == 0) { + continue; + } + + if (!ok) { continue; } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 999d2956fef..29c1452b988 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1289,8 +1289,10 @@ static Image *image_open_single(Main *bmain, } if ((range->length > 1) && (ima->source == IMA_SRC_FILE)) { - if (range->udim_tiles.first && range->offset == 1001) { + if (range->udim_tiles.first) { ima->source = IMA_SRC_TILED; + ImageTile *first_tile = ima->tiles.first; + first_tile->tile_number = range->offset; LISTBASE_FOREACH (LinkData *, node, &range->udim_tiles) { BKE_image_add_tile(ima, POINTER_AS_INT(node->data), NULL); } @@ -1806,10 +1808,13 @@ static int image_save_options_init(Main *bmain, } /* append UDIM numbering if not present */ - if (ima->source == IMA_SRC_TILED && - (BLI_path_sequence_decode(ima->filepath, NULL, NULL, NULL) != 1001)) { + if (ima->source == IMA_SRC_TILED) { + char udim[6]; + ImageTile *tile = ima->tiles.first; + BLI_snprintf(udim, sizeof(udim), ".%d", tile->tile_number); + int len = strlen(opts->filepath); - STR_CONCAT(opts->filepath, len, ".1001"); + STR_CONCAT(opts->filepath, len, udim); } } @@ -3868,9 +3873,9 @@ static void tile_fill_init(PointerRNA *ptr, Image *ima, ImageTile *tile) /* Acquire ibuf to get the default values. * If the specified tile has no ibuf, try acquiring the main tile instead - * (unless the specified tile already was the main tile). */ + * (unless the specified tile already was the first tile). */ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); - if (ibuf == NULL && (tile != NULL) && (tile->tile_number != 1001)) { + if (ibuf == NULL && (tile != NULL) && (tile != ima->tiles.first)) { ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); } @@ -3932,27 +3937,30 @@ static int tile_add_exec(bContext *C, wmOperator *op) bool fill_tile = RNA_boolean_get(op->ptr, "fill"); char *label = RNA_string_get_alloc(op->ptr, "label", NULL, 0); - bool created_tile = false; + /* BKE_image_add_tile assumes a pre-sorted list of tiles. */ + BKE_image_sort_tiles(ima); + + ImageTile *last_tile_created = NULL; for (int tile_number = start_tile; tile_number <= end_tile; tile_number++) { ImageTile *tile = BKE_image_add_tile(ima, tile_number, label); if (tile != NULL) { - ima->active_tile_index = BLI_findindex(&ima->tiles, tile); - if (fill_tile) { do_fill_tile(op->ptr, ima, tile); } - created_tile = true; + last_tile_created = tile; } } MEM_freeN(label); - if (!created_tile) { + if (!last_tile_created) { BKE_report(op->reports, RPT_WARNING, "No UDIM tiles were created"); return OPERATOR_CANCELLED; } + ima->active_tile_index = BLI_findindex(&ima->tiles, last_tile_created); + WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); return OPERATOR_FINISHED; } @@ -4041,7 +4049,7 @@ static bool tile_remove_poll(bContext *C) { Image *ima = CTX_data_edit_image(C); - return (ima != NULL && ima->source == IMA_SRC_TILED && ima->active_tile_index != 0); + return (ima != NULL && ima->source == IMA_SRC_TILED && !BLI_listbase_is_single(&ima->tiles)); } static int tile_remove_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c index 02546e3e3b3..288b3d94b1d 100644 --- a/source/blender/editors/space_image/image_sequence.c +++ b/source/blender/editors/space_image/image_sequence.c @@ -124,7 +124,7 @@ static int image_cmp_frame(const void *a, const void *b) * * udim_tiles may get filled even if the result ultimately is false! */ -static int image_get_udim(char *filepath, ListBase *udim_tiles) +static bool image_get_udim(char *filepath, ListBase *udim_tiles, int *udim_start, int *udim_range) { char filename[FILE_MAX], dirname[FILE_MAXDIR]; BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename)); @@ -133,12 +133,12 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles) char base_head[FILE_MAX], base_tail[FILE_MAX]; int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits); - if (id < 1001 || id >= IMA_UDIM_MAX) { - return 0; + if (id < 1001 || id > IMA_UDIM_MAX) { + return false; } bool is_udim = true; - bool has_primary = false; + int min_udim = IMA_UDIM_MAX + 1; int max_udim = 0; struct direntry *dir; @@ -155,26 +155,27 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles) continue; } - if (id < 1001 || id >= IMA_UDIM_MAX) { + if (id < 1001 || id > IMA_UDIM_MAX) { is_udim = false; break; } - if (id == 1001) { - has_primary = true; - } BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id))); + min_udim = min_ii(min_udim, id); max_udim = max_ii(max_udim, id); } BLI_filelist_free(dir, totfile); - if (is_udim && has_primary) { + if (is_udim && min_udim <= IMA_UDIM_MAX) { char primary_filename[FILE_MAX]; - BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, 1001); + BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, min_udim); BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename); - return max_udim - 1000; + + *udim_start = min_udim; + *udim_range = max_udim - min_udim + 1; + return true; } - return 0; + return false; } /** @@ -185,11 +186,12 @@ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_u { /* UDIM */ if (detect_udim) { - int len_udim = image_get_udim(range->filepath, &range->udim_tiles); + int udim_start, udim_range; + bool result = image_get_udim(range->filepath, &range->udim_tiles, &udim_start, &udim_range); - if (len_udim > 0) { - range->offset = 1001; - range->length = len_udim; + if (result) { + range->offset = udim_start; + range->length = udim_range; return; } } diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index c058ab6cfcc..e44ddb07d53 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -290,15 +290,10 @@ static void rna_UDIMTile_tile_number_set(PointerRNA *ptr, int value) ImageTile *tile = (ImageTile *)ptr->data; Image *image = (Image *)ptr->owner_id; - /* The index of the first tile can't be changed. */ - if (tile->tile_number == 1001) { - return; - } - /* Check that no other tile already has that number. */ ImageTile *cur_tile = BKE_image_get_tile(image, value); - if (cur_tile == NULL || cur_tile == tile) { - tile->tile_number = value; + if (cur_tile == NULL) { + BKE_image_reassign_tile(image, tile, value); } } |