diff options
-rw-r--r-- | source/blender/editors/space_image/image_ops.c | 153 | ||||
-rw-r--r-- | source/blender/editors/space_node/drawnode.c | 11 |
2 files changed, 141 insertions, 23 deletions
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index c2046e6b48e..b4d98b0d829 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -915,12 +915,23 @@ static void image_filesel(bContext *C, wmOperator *op, const char *path) /******************** open image operator ********************/ +typedef struct ImageOpenData { + PropertyPointerRNA pprop; + ImageUser *iuser; +} ImageOpenData; + +typedef struct ImageFrame { + struct ImageFrame *next, *prev; + int framenr; +} ImageFrame; + static void image_open_init(bContext *C, wmOperator *op) { - PropertyPointerRNA *pprop; + ImageOpenData *iod; - op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA"); - uiIDContextProperty(C, &pprop->ptr, &pprop->prop); + op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__); + iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data; + uiIDContextProperty(C, &iod->pprop.ptr, &iod->pprop.prop); } static void image_open_cancel(bContext *UNUSED(C), wmOperator *op) @@ -929,45 +940,145 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op) op->customdata = NULL; } +/** + * @brief Get a list of frames from the list of image files matching the first file name sequence pattern + * @param ptr [in] the RNA pointer containing the "directory" entry and "files" collection + * @param frames [out] the list of frame numbers found in the files matching the first one by name + * @param path [out] the full path of the first file in the list of image files + */ +static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen) +{ + char dir[FILE_MAXDIR]; + bool is_first_entry = true; + + RNA_string_get(ptr, "directory", dir); + RNA_BEGIN (ptr, itemptr, "files") + { + char base_head[FILE_MAX], base_tail[FILE_MAX]; + char head[FILE_MAX], tail[FILE_MAX]; + unsigned short digits; + char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); + ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame"); + + /* use the first file in the list as base filename */ + if (is_first_entry) { + BLI_join_dirfile(path, maxlen, dir, filename); + frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits); + BLI_addtail(frames, frame); + is_first_entry = false; + } + else { + frame->framenr = BLI_stringdec(filename, head, tail, &digits); + + /* still in the same sequence */ + if ((STREQLEN(base_head, head, FILE_MAX)) && + (STREQLEN(base_tail, tail, FILE_MAX))) + { + BLI_addtail(frames, frame); + } + else { + /* different file base name found, is ignored */ + MEM_freeN(frame); + break; + } + } + + MEM_freeN(filename); + } + RNA_END +} + +static int image_cmp_frame(void *a, void *b) +{ + ImageFrame *frame_a = (ImageFrame *)a; + ImageFrame *frame_b = (ImageFrame *)b; + + if (frame_a->framenr < frame_b->framenr) return -1; + if (frame_a->framenr > frame_b->framenr) return 1; + return 0; +} + +/** + * @brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames + * @param frames [in] the list of frame numbers, as a side-effect the list is sorted + * @param ofs [out] offest, the first frame number in the sequence + * @return the number of continuos frames in the sequence + */ +static int image_sequence_get_len(ListBase *frames, int *ofs) +{ + ImageFrame *frame; + + BLI_sortlist(frames, image_cmp_frame); + + frame = frames->first; + if (frame) { + int frame_curr = frame->framenr; + (*ofs) = frame_curr; + while (frame && (frame->framenr == frame_curr)) { + frame_curr++; + frame = frame->next; + } + return frame_curr - (*ofs); + } + return 0; +} + static int image_open_exec(bContext *C, wmOperator *op) { SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */ Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); ImageUser *iuser = NULL; - PropertyPointerRNA *pprop; + ImageOpenData *iod; PointerRNA idptr; Image *ima = NULL; - char str[FILE_MAX]; + char path[FILE_MAX]; + int frame_seq_len = 0; + int frame_ofs = 1; - RNA_string_get(op->ptr, "filepath", str); - /* default to frame 1 if there's no scene in context */ + if (RNA_struct_property_is_set(op->ptr, "files") && RNA_struct_property_is_set(op->ptr, "directory")) { + ListBase frames; + + frames.first = frames.last = NULL; + image_sequence_get_frames(op->ptr, &frames, path, sizeof(path)); + frame_seq_len = image_sequence_get_len(&frames, &frame_ofs); + BLI_freelistN(&frames); + } + else { + RNA_string_get(op->ptr, "filepath", path); + } errno = 0; - ima = BKE_image_load_exists(str); + ima = BKE_image_load_exists(path); if (!ima) { if (op->customdata) MEM_freeN(op->customdata); BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s", - str, errno ? strerror(errno) : TIP_("unsupported image format")); + path, errno ? strerror(errno) : TIP_("unsupported image format")); return OPERATOR_CANCELLED; } - + if (!op->customdata) image_open_init(C, op); /* hook into UI */ - pprop = op->customdata; + iod = op->customdata; - if (pprop->prop) { + if (iod->pprop.prop) { /* when creating new ID blocks, use is already 1, but RNA * pointer se also increases user, so this compensates it */ ima->id.us--; - + if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) { + ima->source = IMA_SRC_SEQUENCE; + } RNA_id_pointer_create(&ima->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); - RNA_property_update(C, &pprop->ptr, pprop->prop); + RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr); + RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop); + } + + if (iod->iuser) { + iuser = iod->iuser; } else if (sima) { ED_space_image_set(sima, scene, obedit, ima); @@ -975,15 +1086,17 @@ static int image_open_exec(bContext *C, wmOperator *op) } else { Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; - if (tex && tex->type == TEX_IMAGE) + if (tex && tex->type == TEX_IMAGE) { iuser = &tex->iuser; - + } } - + /* initialize because of new image */ if (iuser) { + iuser->frames = frame_seq_len; iuser->sfra = 1; - iuser->offset = 0; + iuser->framenr = 1; + iuser->offset = frame_ofs - 1; iuser->fie_ima = 2; } @@ -1065,7 +1178,7 @@ void IMAGE_OT_open(wmOperatorType *ot) /* properties */ WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); } /******************** Match movie length operator ********************/ diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index c30c4fe9ada..e8547b7c164 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -659,6 +659,8 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */ Scene *scene = CTX_data_scene(C); ImageUser *iuser = iuserptr->data; + Image *ima = imaptr->data; + char numstr[32]; const int framenr = BKE_image_user_frame_get(iuser, CFRA, 0, NULL); BLI_snprintf(numstr, sizeof(numstr), IFACE_("Frame: %d"), framenr); @@ -773,6 +775,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA PointerRNA imaptr = RNA_pointer_get(ptr, "image"); PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); + uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); @@ -798,6 +801,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin PointerRNA imaptr = RNA_pointer_get(ptr, "image"); PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); + uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); @@ -1103,13 +1107,13 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * bNode *node = ptr->data; PointerRNA imaptr, iuserptr; + RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr); + uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); - if (!node->id) return; imaptr = RNA_pointer_get(ptr, "image"); - RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr); - + node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr); } @@ -1119,6 +1123,7 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN PointerRNA iuserptr; RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr); + uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0); } |