Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/image.c
| Show All 15 Lines | |||||
| * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. | * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. | ||||
| * All rights reserved. | * All rights reserved. | ||||
| */ | */ | ||||
| /** \file | /** \file | ||||
| * \ingroup bke | * \ingroup bke | ||||
| */ | */ | ||||
| #include <ctype.h> | |||||
| #include <fcntl.h> | #include <fcntl.h> | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #ifndef WIN32 | #ifndef WIN32 | ||||
| # include <unistd.h> | # include <unistd.h> | ||||
| #else | #else | ||||
| # include <io.h> | # include <io.h> | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
| #include "BLF_api.h" | #include "BLF_api.h" | ||||
| #include "PIL_time.h" | #include "PIL_time.h" | ||||
| #include "RE_pipeline.h" | #include "RE_pipeline.h" | ||||
| #include "SEQ_utils.h" /* SEQ_get_topmost_sequence() */ | #include "SEQ_utils.h" /* SEQ_get_topmost_sequence() */ | ||||
| #include "GPU_material.h" | |||||
| #include "GPU_texture.h" | #include "GPU_texture.h" | ||||
| #include "BLI_sys_types.h" /* for intptr_t support */ | #include "BLI_sys_types.h" /* for intptr_t support */ | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "BLO_read_write.h" | #include "BLO_read_write.h" | ||||
| ▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data) | ||||
| * don't make sense to add directories to until the image has been saved | * don't make sense to add directories to until the image has been saved | ||||
| * once to give it a meaningful value. */ | * once to give it a meaningful value. */ | ||||
| /* TODO re-assess whether this behavior is desired in the new generic code context. */ | /* TODO re-assess whether this behavior is desired in the new generic code context. */ | ||||
| if (!ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) || | if (!ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) || | ||||
| ima->filepath[0] == '\0') { | ima->filepath[0] == '\0') { | ||||
| return; | return; | ||||
| } | } | ||||
| if (BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath)) { | /* If this is a tiled image, and we're asked to resolve the tokens in the virtual | ||||
| * filepath, use the first tile to generate a concrete path for use during processing. */ | |||||
| bool result = false; | |||||
| if (ima->source == IMA_SRC_TILED && (flag & BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN) != 0) { | |||||
| char temp_path[FILE_MAX], orig_file[FILE_MAXFILE]; | |||||
| BLI_strncpy(temp_path, ima->filepath, sizeof(temp_path)); | |||||
| BLI_split_file_part(temp_path, orig_file, sizeof(orig_file)); | |||||
| eUDIM_TILE_FORMAT tile_format; | |||||
| char *udim_pattern = BKE_image_get_tile_strformat(temp_path, &tile_format); | |||||
| BKE_image_set_filepath_from_tile_number( | |||||
| temp_path, udim_pattern, tile_format, ((ImageTile *)ima->tiles.first)->tile_number); | |||||
| MEM_SAFE_FREE(udim_pattern); | |||||
| result = BKE_bpath_foreach_path_fixed_process(bpath_data, temp_path); | |||||
| if (result) { | |||||
| /* Put the filepath back together using the new directory and the original file name. */ | |||||
| char new_dir[FILE_MAXDIR]; | |||||
| BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir)); | |||||
| BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file); | |||||
| } | |||||
| } | |||||
| else { | |||||
| result = BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath); | |||||
| } | |||||
| if (result) { | |||||
| if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) { | if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) { | ||||
| if (!BKE_image_has_packedfile(ima) && | if (!BKE_image_has_packedfile(ima) && | ||||
| /* Image may have been painted onto (and not saved, T44543). */ | /* Image may have been painted onto (and not saved, T44543). */ | ||||
| !BKE_image_is_dirty(ima)) { | !BKE_image_is_dirty(ima)) { | ||||
| BKE_image_signal(bpath_data->bmain, ima, NULL, IMA_SIGNAL_RELOAD); | BKE_image_signal(bpath_data->bmain, ima, NULL, IMA_SIGNAL_RELOAD); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 599 Lines • ▼ Show 20 Lines | Image *BKE_image_load(Main *bmain, const char *filepath) | ||||
| char str[FILE_MAX]; | char str[FILE_MAX]; | ||||
| STRNCPY(str, filepath); | STRNCPY(str, filepath); | ||||
| BLI_path_abs(str, BKE_main_blendfile_path(bmain)); | BLI_path_abs(str, BKE_main_blendfile_path(bmain)); | ||||
| /* exists? */ | /* exists? */ | ||||
| file = BLI_open(str, O_BINARY | O_RDONLY, 0); | file = BLI_open(str, O_BINARY | O_RDONLY, 0); | ||||
| if (file == -1) { | if (file == -1) { | ||||
| if (!BKE_image_tile_filepath_exists(str)) { | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| } | |||||
| else { | |||||
| close(file); | close(file); | ||||
| } | |||||
| ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE); | ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE); | ||||
| STRNCPY(ima->filepath, filepath); | STRNCPY(ima->filepath, filepath); | ||||
| if (BLI_path_extension_check_array(filepath, imb_ext_movie)) { | if (BLI_path_extension_check_array(filepath, imb_ext_movie)) { | ||||
| ima->source = IMA_SRC_MOVIE; | ima->source = IMA_SRC_MOVIE; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 2,458 Lines • ▼ Show 20 Lines | case NTREE_COMPOSIT: | ||||
| ImageUser *iuser = node->storage; | ImageUser *iuser = node->storage; | ||||
| callback(ima, id, iuser, customdata); | callback(ima, id, iuser, customdata); | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| static void image_walk_gpu_materials( | |||||
| ID *id, | |||||
| ListBase *gpu_materials, | |||||
| void *customdata, | |||||
| void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata)) | |||||
| { | |||||
| LISTBASE_FOREACH (LinkData *, link, gpu_materials) { | |||||
| GPUMaterial *gpu_material = (GPUMaterial *)link->data; | |||||
| ListBase textures = GPU_material_textures(gpu_material); | |||||
| LISTBASE_FOREACH (GPUMaterialTexture *, gpu_material_texture, &textures) { | |||||
| if (gpu_material_texture->iuser_available) { | |||||
| callback(gpu_material_texture->ima, id, &gpu_material_texture->iuser, customdata); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| static void image_walk_id_all_users( | static void image_walk_id_all_users( | ||||
| ID *id, | ID *id, | ||||
| bool skip_nested_nodes, | bool skip_nested_nodes, | ||||
| void *customdata, | void *customdata, | ||||
| void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata)) | void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata)) | ||||
| { | { | ||||
| switch (GS(id->name)) { | switch (GS(id->name)) { | ||||
| case ID_OB: { | case ID_OB: { | ||||
| Object *ob = (Object *)id; | Object *ob = (Object *)id; | ||||
| if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) { | if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) { | ||||
| callback(ob->data, &ob->id, ob->iuser, customdata); | callback(ob->data, &ob->id, ob->iuser, customdata); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case ID_MA: { | case ID_MA: { | ||||
| Material *ma = (Material *)id; | Material *ma = (Material *)id; | ||||
| if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) { | if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) { | ||||
| image_walk_ntree_all_users(ma->nodetree, &ma->id, customdata, callback); | image_walk_ntree_all_users(ma->nodetree, &ma->id, customdata, callback); | ||||
| } | } | ||||
| image_walk_gpu_materials(id, &ma->gpumaterial, customdata, callback); | |||||
| break; | break; | ||||
| } | } | ||||
| case ID_LA: { | case ID_LA: { | ||||
| Light *light = (Light *)id; | Light *light = (Light *)id; | ||||
| if (light->nodetree && light->use_nodes && !skip_nested_nodes) { | if (light->nodetree && light->use_nodes && !skip_nested_nodes) { | ||||
| image_walk_ntree_all_users(light->nodetree, &light->id, customdata, callback); | image_walk_ntree_all_users(light->nodetree, &light->id, customdata, callback); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case ID_WO: { | case ID_WO: { | ||||
| World *world = (World *)id; | World *world = (World *)id; | ||||
| if (world->nodetree && world->use_nodes && !skip_nested_nodes) { | if (world->nodetree && world->use_nodes && !skip_nested_nodes) { | ||||
| image_walk_ntree_all_users(world->nodetree, &world->id, customdata, callback); | image_walk_ntree_all_users(world->nodetree, &world->id, customdata, callback); | ||||
| } | } | ||||
| image_walk_gpu_materials(id, &world->gpumaterial, customdata, callback); | |||||
| break; | break; | ||||
| } | } | ||||
| case ID_TE: { | case ID_TE: { | ||||
| Tex *tex = (Tex *)id; | Tex *tex = (Tex *)id; | ||||
| if (tex->type == TEX_IMAGE && tex->ima) { | if (tex->type == TEX_IMAGE && tex->ima) { | ||||
| callback(tex->ima, &tex->id, &tex->iuser, customdata); | callback(tex->ima, &tex->id, &tex->iuser, customdata); | ||||
| } | } | ||||
| if (tex->nodetree && tex->use_nodes && !skip_nested_nodes) { | if (tex->nodetree && tex->use_nodes && !skip_nested_nodes) { | ||||
| ▲ Show 20 Lines • Show All 266 Lines • ▼ Show 20 Lines | case IMA_SIGNAL_RELOAD: | ||||
| if (BKE_image_has_packedfile(ima)) { | if (BKE_image_has_packedfile(ima)) { | ||||
| BKE_image_free_buffers(ima); | BKE_image_free_buffers(ima); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_image_free_buffers(ima); | BKE_image_free_buffers(ima); | ||||
| } | } | ||||
| if (ima->source == IMA_SRC_TILED) { | |||||
| ListBase new_tiles = {NULL, NULL}; | |||||
| int new_start, new_range; | |||||
| char filepath[FILE_MAX]; | |||||
| BLI_strncpy(filepath, ima->filepath, sizeof(filepath)); | |||||
| BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); | |||||
| bool result = BKE_image_get_tile_info(filepath, &new_tiles, &new_start, &new_range); | |||||
| if (result) { | |||||
| /* Because the prior and new list of tiles are both sparse sequences, we need to be sure | |||||
| * to account for how the two sets might or might not overlap. To be complete, we start | |||||
| * the refresh process by clearing all existing tiles, stopping when there's only 1 tile | |||||
| * left. */ | |||||
| while (BKE_image_remove_tile(ima, ima->tiles.last)) { | |||||
| ; | |||||
| } | |||||
| int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number; | |||||
| bool needs_final_cleanup = true; | |||||
| /* Add in all the new tiles. */ | |||||
| LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) { | |||||
| int new_tile_number = POINTER_AS_INT(new_tile->data); | |||||
| BKE_image_add_tile(ima, new_tile_number, NULL); | |||||
| if (new_tile_number == remaining_tile_number) { | |||||
| needs_final_cleanup = false; | |||||
| } | |||||
| } | |||||
| /* Final cleanup if the prior remaining tile was never encountered in the new list. */ | |||||
| if (needs_final_cleanup) { | |||||
| BKE_image_remove_tile(ima, BKE_image_get_tile(ima, remaining_tile_number)); | |||||
| } | |||||
| } | |||||
| BLI_freelistN(&new_tiles); | |||||
| } | |||||
| if (iuser) { | if (iuser) { | ||||
| image_tag_reload(ima, NULL, iuser, ima); | image_tag_reload(ima, NULL, iuser, ima); | ||||
| } | } | ||||
| BKE_image_walk_all_users(bmain, ima, image_tag_reload); | BKE_image_walk_all_users(bmain, ima, image_tag_reload); | ||||
| break; | break; | ||||
| case IMA_SIGNAL_USER_NEW_IMAGE: | case IMA_SIGNAL_USER_NEW_IMAGE: | ||||
| if (iuser) { | if (iuser) { | ||||
| if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) { | if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) { | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | void BKE_image_get_tile_label(Image *ima, ImageTile *tile, char *label, int len_label) | ||||
| if (tile->label[0]) { | if (tile->label[0]) { | ||||
| BLI_strncpy(label, tile->label, len_label); | BLI_strncpy(label, tile->label, len_label); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_snprintf(label, len_label, "%d", tile->tile_number); | BLI_snprintf(label, len_label, "%d", tile->tile_number); | ||||
| } | } | ||||
| } | } | ||||
| bool BKE_image_get_tile_info(char *filepath, | |||||
| ListBase *udim_tiles, | |||||
| int *udim_start, | |||||
| int *udim_range) | |||||
| { | |||||
| char filename[FILE_MAXFILE], dirname[FILE_MAXDIR]; | |||||
| BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename)); | |||||
| BKE_image_ensure_tile_token(filename); | |||||
| eUDIM_TILE_FORMAT tile_format; | |||||
| char *udim_pattern = BKE_image_get_tile_strformat(filename, &tile_format); | |||||
| bool is_udim = true; | |||||
| int min_udim = IMA_UDIM_MAX + 1; | |||||
| int max_udim = 0; | |||||
| int id; | |||||
| struct direntry *dir; | |||||
| uint totfile = BLI_filelist_dir_contents(dirname, &dir); | |||||
| for (int i = 0; i < totfile; i++) { | |||||
| if (!(dir[i].type & S_IFREG)) { | |||||
| continue; | |||||
| } | |||||
| if (!BKE_image_get_tile_number_from_filepath(dir[i].relname, udim_pattern, tile_format, &id)) { | |||||
| continue; | |||||
| } | |||||
| if (id < 1001 || id > IMA_UDIM_MAX) { | |||||
| is_udim = false; | |||||
| break; | |||||
| } | |||||
| 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); | |||||
| MEM_SAFE_FREE(udim_pattern); | |||||
| if (is_udim && min_udim <= IMA_UDIM_MAX) { | |||||
| BLI_join_dirfile(filepath, FILE_MAX, dirname, filename); | |||||
| *udim_start = min_udim; | |||||
| *udim_range = max_udim - min_udim + 1; | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label) | ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label) | ||||
| { | { | ||||
| if (ima->source != IMA_SRC_TILED) { | if (ima->source != IMA_SRC_TILED) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| if (tile_number < 1001 || tile_number > IMA_UDIM_MAX) { | if (tile_number < 1001 || tile_number > IMA_UDIM_MAX) { | ||||
| return NULL; | return NULL; | ||||
| ▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | bool BKE_image_fill_tile(struct Image *ima, | ||||
| if (tile_ibuf != NULL) { | if (tile_ibuf != NULL) { | ||||
| image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number); | image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number); | ||||
| BKE_image_release_ibuf(ima, tile_ibuf, NULL); | BKE_image_release_ibuf(ima, tile_ibuf, NULL); | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void BKE_image_ensure_tile_token(char *filename) | |||||
| { | |||||
| if (filename == NULL) { | |||||
| return; | |||||
| } | |||||
| /* Is there a '<' character in the filename? Assume tokens already present. */ | |||||
| if (strstr(filename, "<") != NULL) { | |||||
| return; | |||||
| } | |||||
| /* Is there a sequence of digits in the filename? */ | |||||
| ushort digits; | |||||
| char head[FILE_MAX], tail[FILE_MAX]; | |||||
| BLI_path_sequence_decode(filename, head, tail, &digits); | |||||
| if (digits == 4) { | |||||
| sprintf(filename, "%s<UDIM>%s", head, tail); | |||||
| return; | |||||
| } | |||||
| /* Is there a sequence like u##_v#### in the filename? */ | |||||
| uint cur = 0; | |||||
| uint name_end = strlen(filename); | |||||
| uint u_digits = 0; | |||||
| uint v_digits = 0; | |||||
| uint u_start = (uint)-1; | |||||
| bool u_found = false; | |||||
| bool v_found = false; | |||||
| bool sep_found = false; | |||||
| while (cur < name_end) { | |||||
| if (filename[cur] == 'u') { | |||||
| u_found = true; | |||||
| u_digits = 0; | |||||
| u_start = cur; | |||||
| } | |||||
| else if (filename[cur] == 'v') { | |||||
| v_found = true; | |||||
| v_digits = 0; | |||||
| } | |||||
| else if (u_found && !v_found) { | |||||
| if (isdigit(filename[cur]) && u_digits < 2) { | |||||
| u_digits++; | |||||
| } | |||||
| else if (filename[cur] == '_') { | |||||
| sep_found = true; | |||||
| } | |||||
| else { | |||||
| u_found = false; | |||||
| } | |||||
| } | |||||
| else if (u_found && u_digits > 0 && v_found) { | |||||
| if (isdigit(filename[cur])) { | |||||
| if (v_digits < 4) { | |||||
| v_digits++; | |||||
| } | |||||
| else { | |||||
| u_found = false; | |||||
| v_found = false; | |||||
| } | |||||
| } | |||||
| else if (v_digits > 0) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| cur++; | |||||
| } | |||||
| if (u_found && sep_found && v_found && (u_digits + v_digits > 1)) { | |||||
| const char *token = "<UVTILE>"; | |||||
| const size_t token_length = strlen(token); | |||||
| memmove(filename + u_start + token_length, filename + cur, name_end - cur); | |||||
| memcpy(filename + u_start, token, token_length); | |||||
| filename[u_start + token_length + (name_end - cur)] = '\0'; | |||||
| } | |||||
| } | |||||
| bool BKE_image_tile_filepath_exists(const char *filepath) | |||||
| { | |||||
| BLI_assert(!BLI_path_is_rel(filepath)); | |||||
| char dirname[FILE_MAXDIR]; | |||||
| BLI_split_dir_part(filepath, dirname, sizeof(dirname)); | |||||
| eUDIM_TILE_FORMAT tile_format; | |||||
| char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format); | |||||
| bool found = false; | |||||
| struct direntry *dir; | |||||
| uint totfile = BLI_filelist_dir_contents(dirname, &dir); | |||||
| for (int i = 0; i < totfile; i++) { | |||||
| if (!(dir[i].type & S_IFREG)) { | |||||
| continue; | |||||
| } | |||||
| int id; | |||||
| if (!BKE_image_get_tile_number_from_filepath(dir[i].path, udim_pattern, tile_format, &id)) { | |||||
| continue; | |||||
| } | |||||
| if (id < 1001 || id > IMA_UDIM_MAX) { | |||||
| continue; | |||||
| } | |||||
| found = true; | |||||
| break; | |||||
| } | |||||
| BLI_filelist_free(dir, totfile); | |||||
| MEM_SAFE_FREE(udim_pattern); | |||||
| return found; | |||||
| } | |||||
| char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format) | |||||
| { | |||||
| if (filepath == NULL || r_tile_format == NULL) { | |||||
| return NULL; | |||||
| } | |||||
| if (strstr(filepath, "<UDIM>") != NULL) { | |||||
| *r_tile_format = UDIM_TILE_FORMAT_UDIM; | |||||
| return BLI_str_replaceN(filepath, "<UDIM>", "%d"); | |||||
| } | |||||
| if (strstr(filepath, "<UVTILE>") != NULL) { | |||||
| *r_tile_format = UDIM_TILE_FORMAT_UVTILE; | |||||
| return BLI_str_replaceN(filepath, "<UVTILE>", "u%d_v%d"); | |||||
| } | |||||
| *r_tile_format = UDIM_TILE_FORMAT_NONE; | |||||
| return NULL; | |||||
| } | |||||
| bool BKE_image_get_tile_number_from_filepath(const char *filepath, | |||||
| const char *pattern, | |||||
| eUDIM_TILE_FORMAT tile_format, | |||||
| int *r_tile_number) | |||||
| { | |||||
| if (filepath == NULL || pattern == NULL || r_tile_number == NULL) { | |||||
| return false; | |||||
| } | |||||
| int u, v; | |||||
| bool result = false; | |||||
| if (tile_format == UDIM_TILE_FORMAT_UDIM) { | |||||
| if (sscanf(filepath, pattern, &u) == 1) { | |||||
| *r_tile_number = u; | |||||
| result = true; | |||||
| } | |||||
| } | |||||
| else if (tile_format == UDIM_TILE_FORMAT_UVTILE) { | |||||
| if (sscanf(filepath, pattern, &u, &v) == 2) { | |||||
| *r_tile_number = 1001 + (u - 1) + ((v - 1) * 10); | |||||
| result = true; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| void BKE_image_set_filepath_from_tile_number(char *filepath, | |||||
| const char *pattern, | |||||
| eUDIM_TILE_FORMAT tile_format, | |||||
| int tile_number) | |||||
| { | |||||
| if (filepath == NULL || pattern == NULL) { | |||||
| return; | |||||
| } | |||||
| if (tile_format == UDIM_TILE_FORMAT_UDIM) { | |||||
| sprintf(filepath, pattern, tile_number); | |||||
| } | |||||
| else if (tile_format == UDIM_TILE_FORMAT_UVTILE) { | |||||
| int u = ((tile_number - 1001) % 10); | |||||
| int v = ((tile_number - 1001) / 10); | |||||
| sprintf(filepath, pattern, u + 1, v + 1); | |||||
| } | |||||
| } | |||||
| /* if layer or pass changes, we need an index for the imbufs list */ | /* 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! */ | /* note it is called for rendered results, but it doesn't use the index! */ | ||||
| RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) | RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) | ||||
| { | { | ||||
| RenderLayer *rl; | RenderLayer *rl; | ||||
| RenderPass *rpass = NULL; | RenderPass *rpass = NULL; | ||||
| if (rr == NULL) { | if (rr == NULL) { | ||||
| ▲ Show 20 Lines • Show All 1,556 Lines • ▼ Show 20 Lines | void BKE_image_user_id_eval_animation(Depsgraph *depsgraph, ID *id) | ||||
| * This does not consider nested node trees as these are handled | * This does not consider nested node trees as these are handled | ||||
| * as their own data-block. */ | * as their own data-block. */ | ||||
| bool skip_nested_nodes = true; | bool skip_nested_nodes = true; | ||||
| image_walk_id_all_users(id, skip_nested_nodes, depsgraph, image_user_id_eval_animation); | image_walk_id_all_users(id, skip_nested_nodes, depsgraph, image_user_id_eval_animation); | ||||
| } | } | ||||
| void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) | void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) | ||||
| { | { | ||||
| BKE_image_user_file_path_ex(iuser, ima, filepath, true); | |||||
| } | |||||
| void BKE_image_user_file_path_ex(ImageUser *iuser, Image *ima, char *filepath, bool resolve_udim) | |||||
| { | |||||
| if (BKE_image_is_multiview(ima)) { | if (BKE_image_is_multiview(ima)) { | ||||
| ImageView *iv = BLI_findlink(&ima->views, iuser->view); | ImageView *iv = BLI_findlink(&ima->views, iuser->view); | ||||
| if (iv->filepath[0]) { | if (iv->filepath[0]) { | ||||
| BLI_strncpy(filepath, iv->filepath, FILE_MAX); | BLI_strncpy(filepath, iv->filepath, FILE_MAX); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_strncpy(filepath, ima->filepath, FILE_MAX); | BLI_strncpy(filepath, ima->filepath, FILE_MAX); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_strncpy(filepath, ima->filepath, FILE_MAX); | BLI_strncpy(filepath, ima->filepath, FILE_MAX); | ||||
| } | } | ||||
| if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) { | if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) { | ||||
| char head[FILE_MAX], tail[FILE_MAX]; | char head[FILE_MAX], tail[FILE_MAX]; | ||||
| unsigned short numlen; | unsigned short numlen; | ||||
| int index; | int index; | ||||
| if (ima->source == IMA_SRC_SEQUENCE) { | if (ima->source == IMA_SRC_SEQUENCE) { | ||||
| index = iuser ? iuser->framenr : ima->lastframe; | index = iuser ? iuser->framenr : ima->lastframe; | ||||
| BLI_path_sequence_decode(filepath, head, tail, &numlen); | |||||
| BLI_path_sequence_encode(filepath, head, tail, numlen, index); | |||||
| } | } | ||||
| else { | else if (resolve_udim) { | ||||
| index = image_get_tile_number_from_iuser(ima, iuser); | index = image_get_tile_number_from_iuser(ima, iuser); | ||||
| } | |||||
| BLI_path_sequence_decode(filepath, head, tail, &numlen); | eUDIM_TILE_FORMAT tile_format; | ||||
| BLI_path_sequence_encode(filepath, head, tail, numlen, index); | char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format); | ||||
| BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, index); | |||||
| MEM_SAFE_FREE(udim_pattern); | |||||
| } | |||||
| } | } | ||||
| BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); | BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); | ||||
| } | } | ||||
| bool BKE_image_has_alpha(struct Image *image) | bool BKE_image_has_alpha(struct Image *image) | ||||
| { | { | ||||
| ImBuf *ibuf; | ImBuf *ibuf; | ||||
| ▲ Show 20 Lines • Show All 485 Lines • Show Last 20 Lines | |||||