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
This commit is contained in:
Jesse Yurkovich 2021-08-17 21:42:28 -07:00
parent f41beca977
commit 400cb25fc7
8 changed files with 135 additions and 56 deletions

View File

@ -246,7 +246,11 @@ static inline string image_user_file_path(BL::ImageUser &iuser,
string filepath_str = string(filepath);
if (load_tiled && ima.source() == BL::Image::source_TILED) {
string_replace(filepath_str, "1001", "<UDIM>");
string udim;
if (ima.tiles.length() > 0) {
udim = to_string(ima.tiles[0].number());
}
string_replace(filepath_str, udim, "<UDIM>");
}
return filepath_str;
}

View File

@ -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,

View File

@ -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);

View File

@ -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 */

View File

@ -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;
}

View File

@ -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))

View File

@ -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;
}
}

View File

@ -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);
}
}