Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_sequencer/sequencer_thumbnails.c
| Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static void thumbnail_endjob(void *data) | static void thumbnail_endjob(void *data) | ||||
| { | { | ||||
| ThumbnailDrawJob *tj = data; | ThumbnailDrawJob *tj = data; | ||||
| WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, tj->scene); | WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, tj->scene); | ||||
| } | } | ||||
| static bool handle_is_moving(Sequence *seq) | |||||
| { | |||||
| return (G.moving & G_TRANSFORM_SEQ) != 0 && (seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) != 0; | |||||
| } | |||||
| static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area) | static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area) | ||||
| { | { | ||||
| if (seq->type != SEQ_TYPE_MOVIE && seq->type != SEQ_TYPE_IMAGE) { | if (seq->type != SEQ_TYPE_MOVIE && seq->type != SEQ_TYPE_IMAGE) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (min_ii(seq->startdisp, seq->start) > view_area->xmax) { | if (seq->startdisp > view_area->xmax) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (max_ii(seq->enddisp, seq->start + seq->len) < view_area->xmin) { | if (seq->enddisp < view_area->xmin) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (seq->machine + 1.0f < view_area->ymin) { | if (seq->machine + 1.0f < view_area->ymin) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (seq->machine > view_area->ymax) { | if (seq->machine > view_area->ymax) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Handle is moved, but not for this strip. */ | |||||
| if ((G.moving & G_TRANSFORM_SEQ) != 0 && (seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0) { | |||||
| return false; | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| static void seq_get_thumb_image_dimensions(Sequence *seq, | static void seq_get_thumb_image_dimensions(Sequence *seq, | ||||
| float pixelx, | float pixelx, | ||||
| float pixely, | float pixely, | ||||
| float *r_thumb_width, | float *r_thumb_width, | ||||
| float *r_thumb_height, | float *r_thumb_height, | ||||
| Show All 26 Lines | static void seq_get_thumb_image_dimensions(Sequence *seq, | ||||
| } | } | ||||
| *r_thumb_height = thumb_height; | *r_thumb_height = thumb_height; | ||||
| *r_image_width = image_width; | *r_image_width = image_width; | ||||
| *r_image_height = image_height; | *r_image_height = image_height; | ||||
| *r_thumb_width = thumb_width; | *r_thumb_width = thumb_width; | ||||
| } | } | ||||
| static float seq_thumbnail_get_start_frame(Sequence *seq, float frame_step, rctf *view_area) | static float seq_thumbnail_get_start_frame(Sequence *seq) | ||||
| { | { | ||||
| if (seq->start > view_area->xmin && seq->start < view_area->xmax) { | if (seq->startstill) { | ||||
| return seq->start; | return seq->start; | ||||
| } | } | ||||
| return seq->startdisp; | |||||
| /* Drawing and caching both check to see if strip is in view area or not before calling this | |||||
| * function so assuming strip/part of strip in view. */ | |||||
| int no_invisible_thumbs = (view_area->xmin - seq->start) / frame_step; | |||||
| return ((no_invisible_thumbs - 1) * frame_step) + seq->start; | |||||
| } | } | ||||
| static void thumbnail_start_job(void *data, | static void thumbnail_start_job(void *data, | ||||
| short *stop, | short *stop, | ||||
| short *UNUSED(do_update), | short *UNUSED(do_update), | ||||
| float *UNUSED(progress)) | float *UNUSED(progress)) | ||||
| { | { | ||||
| ThumbnailDrawJob *tj = data; | ThumbnailDrawJob *tj = data; | ||||
| float start_frame, frame_step; | float start_frame, frame_step; | ||||
| GHashIterator gh_iter; | GHashIterator gh_iter; | ||||
| bool transform_update = (G.moving & G_TRANSFORM_SEQ) != 0; | |||||
| /* First pass: render visible images. */ | /* First pass: render visible images. */ | ||||
| BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash); | BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash); | ||||
| while (!BLI_ghashIterator_done(&gh_iter) & !*stop) { | while (!BLI_ghashIterator_done(&gh_iter) & !*stop) { | ||||
| Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter); | Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter); | ||||
| ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig); | ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig); | ||||
| if (check_seq_need_thumbnails(seq_orig, tj->view_area)) { | if (check_seq_need_thumbnails(seq_orig, tj->view_area)) { | ||||
| seq_get_thumb_image_dimensions( | seq_get_thumb_image_dimensions( | ||||
| val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, NULL, NULL, NULL); | val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, NULL, NULL, NULL); | ||||
| start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area); | start_frame = seq_thumbnail_get_start_frame(seq_orig); | ||||
| SEQ_render_thumbnails( | SEQ_render_thumbnails(&tj->context, | ||||
| &tj->context, val->seq_dupli, seq_orig, start_frame, frame_step, tj->view_area, stop); | val->seq_dupli, | ||||
| seq_orig, | |||||
| start_frame, | |||||
| frame_step, | |||||
| tj->view_area, | |||||
| transform_update, | |||||
| stop); | |||||
| SEQ_relations_sequence_free_anim(val->seq_dupli); | SEQ_relations_sequence_free_anim(val->seq_dupli); | ||||
| } | } | ||||
| BLI_ghashIterator_step(&gh_iter); | BLI_ghashIterator_step(&gh_iter); | ||||
| } | } | ||||
| /* Skip second pass when moving strips - first/last thumbnails are prioritized. */ | |||||
| if (transform_update) { | |||||
| return; | |||||
| } | |||||
| /* Second pass: render "guaranteed" set of images. */ | /* Second pass: render "guaranteed" set of images. */ | ||||
| BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash); | BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash); | ||||
| while (!BLI_ghashIterator_done(&gh_iter) & !*stop) { | while (!BLI_ghashIterator_done(&gh_iter) & !*stop) { | ||||
| Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter); | Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter); | ||||
| ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig); | ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig); | ||||
| if (check_seq_need_thumbnails(seq_orig, tj->view_area)) { | if (check_seq_need_thumbnails(val->seq_dupli, tj->view_area)) { | ||||
| seq_get_thumb_image_dimensions( | seq_get_thumb_image_dimensions( | ||||
| val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, NULL, NULL, NULL); | val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, NULL, NULL, NULL); | ||||
| start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area); | start_frame = seq_thumbnail_get_start_frame(seq_orig); | ||||
| SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop); | SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop); | ||||
| SEQ_relations_sequence_free_anim(val->seq_dupli); | SEQ_relations_sequence_free_anim(val->seq_dupli); | ||||
| } | } | ||||
| BLI_ghashIterator_step(&gh_iter); | BLI_ghashIterator_step(&gh_iter); | ||||
| } | } | ||||
| } | } | ||||
| static SeqRenderData sequencer_thumbnail_context_init(const bContext *C) | static SeqRenderData sequencer_thumbnail_context_init(const bContext *C) | ||||
| ▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | if (sequencer_thumbnail_v2d_is_navigating(C)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* During rendering, cache is wiped, it doesn't make sense to render thumbnails. */ | /* During rendering, cache is wiped, it doesn't make sense to render thumbnails. */ | ||||
| if (G.is_rendering) { | if (G.is_rendering) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Job start requested, but over area which has been processed. Unless `thumbnail_is_missing` is | /* Job start requested, but over area which should be rendered completely. Unless | ||||
| * true, ignore this request as all images are in view. */ | * `thumbnail_is_missing` is true, ignore this request as all images are in view. */ | ||||
| if (v2d->cur.xmax == sseq->runtime.last_thumbnail_area.xmax && | if (v2d->cur.xmax == sseq->runtime.last_thumbnail_area.xmax && | ||||
| v2d->cur.ymax == sseq->runtime.last_thumbnail_area.ymax && !thumbnail_is_missing) { | v2d->cur.ymax == sseq->runtime.last_thumbnail_area.ymax && !thumbnail_is_missing) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Stop the job first as view has changed. Pointless to continue old job. */ | /* Stop the job first as view has changed. Pointless to continue old job. */ | ||||
| if (v2d->cur.xmax != sseq->runtime.last_thumbnail_area.xmax || | if (v2d->cur.xmax != sseq->runtime.last_thumbnail_area.xmax || | ||||
| v2d->cur.ymax != sseq->runtime.last_thumbnail_area.ymax) { | v2d->cur.ymax != sseq->runtime.last_thumbnail_area.ymax) { | ||||
| WM_jobs_stop(CTX_wm_manager(C), NULL, thumbnail_start_job); | WM_jobs_stop(CTX_wm_manager(C), NULL, thumbnail_start_job); | ||||
| } | } | ||||
| sequencer_thumbnail_init_job(C, v2d, ed); | sequencer_thumbnail_init_job(C, v2d, ed); | ||||
| sseq->runtime.last_thumbnail_area = v2d->cur; | sseq->runtime.last_thumbnail_area = v2d->cur; | ||||
| } | } | ||||
| void last_displayed_thumbnails_list_free(void *val) | #define HANDLE_UPDATE_CACHE_LEN 10 | ||||
| #define HANDLE_UPDATE_CACHE_FRAME_INVALID MINAFRAME - 1 | |||||
| typedef struct ThumbnailRuntimeCache { | |||||
| GSet *last_displayed_thumbnails; | |||||
| int handle_update_cache[HANDLE_UPDATE_CACHE_LEN]; | |||||
| } ThumbnailRuntimeCache; | |||||
| void thumbnail_runtime_cache_free(void *val) | |||||
| { | { | ||||
| BLI_gset_free(val, NULL); | ThumbnailRuntimeCache *cache = (ThumbnailRuntimeCache *)val; | ||||
| BLI_gset_free(cache->last_displayed_thumbnails, NULL); | |||||
| } | } | ||||
| static GSet *last_displayed_thumbnails_list_ensure(const bContext *C, Sequence *seq) | static void handle_update_thumbnails_cache_reset(ThumbnailRuntimeCache *cache) | ||||
| { | |||||
| for (int i = 0; i < HANDLE_UPDATE_CACHE_LEN; i++) { | |||||
| cache->handle_update_cache[i] = HANDLE_UPDATE_CACHE_FRAME_INVALID; | |||||
| } | |||||
| } | |||||
| static void handle_update_thumbnails_cache_push(ThumbnailRuntimeCache *cache, int timeline_frame) | |||||
| { | |||||
| for (int i = HANDLE_UPDATE_CACHE_LEN - 1; i >= 1; i--) { | |||||
| cache->handle_update_cache[i] = cache->handle_update_cache[i - 1]; | |||||
| } | |||||
| cache->handle_update_cache[0] = timeline_frame; | |||||
| } | |||||
| static ThumbnailRuntimeCache *thumbnail_runtime_cache_ensure(const bContext *C, Sequence *seq) | |||||
| { | { | ||||
| SpaceSeq *sseq = CTX_wm_space_seq(C); | SpaceSeq *sseq = CTX_wm_space_seq(C); | ||||
| if (sseq->runtime.last_displayed_thumbnails == NULL) { | if (sseq->runtime.last_displayed_thumbnails == NULL) { | ||||
| sseq->runtime.last_displayed_thumbnails = BLI_ghash_ptr_new(__func__); | sseq->runtime.last_displayed_thumbnails = BLI_ghash_ptr_new(__func__); | ||||
| } | } | ||||
| GSet *displayed_thumbnails = BLI_ghash_lookup(sseq->runtime.last_displayed_thumbnails, seq); | ThumbnailRuntimeCache *cache = BLI_ghash_lookup(sseq->runtime.last_displayed_thumbnails, seq); | ||||
| if (displayed_thumbnails == NULL) { | if (cache == NULL) { | ||||
| displayed_thumbnails = BLI_gset_int_new(__func__); | cache = MEM_callocN(sizeof(ThumbnailRuntimeCache), __func__); | ||||
| BLI_ghash_insert(sseq->runtime.last_displayed_thumbnails, seq, displayed_thumbnails); | cache->last_displayed_thumbnails = BLI_gset_int_new(__func__); | ||||
| handle_update_thumbnails_cache_reset(cache); | |||||
| BLI_ghash_insert(sseq->runtime.last_displayed_thumbnails, seq, cache); | |||||
| } | } | ||||
| return displayed_thumbnails; | return cache; | ||||
| } | } | ||||
| static void last_displayed_thumbnails_list_cleanup(GSet *previously_displayed, | static void last_displayed_thumbnails_list_cleanup(ThumbnailRuntimeCache *cache, | ||||
| float range_start, | float range_start, | ||||
| float range_end) | float range_end) | ||||
| { | { | ||||
| /* To prevent thumnail flickering, don't change state of this cache when moving handles. */ | |||||
| if ((G.moving & G_TRANSFORM_SEQ) != 0) { | |||||
| return; | |||||
| } | |||||
| GSetIterator gset_iter; | GSetIterator gset_iter; | ||||
| BLI_gsetIterator_init(&gset_iter, previously_displayed); | BLI_gsetIterator_init(&gset_iter, cache->last_displayed_thumbnails); | ||||
| while (!BLI_gsetIterator_done(&gset_iter)) { | while (!BLI_gsetIterator_done(&gset_iter)) { | ||||
| int frame = (float)POINTER_AS_INT(BLI_gsetIterator_getKey(&gset_iter)); | int frame = (float)POINTER_AS_INT(BLI_gsetIterator_getKey(&gset_iter)); | ||||
| BLI_gsetIterator_step(&gset_iter); | BLI_gsetIterator_step(&gset_iter); | ||||
| if (frame > range_start && frame < range_end) { | if (frame > range_start && frame < range_end) { | ||||
| BLI_gset_remove(previously_displayed, POINTER_FROM_INT(frame), NULL); | BLI_gset_remove(cache->last_displayed_thumbnails, POINTER_FROM_INT(frame), NULL); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void last_displayed_thumbnails_push(ThumbnailRuntimeCache *cache, | |||||
| const int timeline_frame, | |||||
| const float thumb_x_start, | |||||
| const float thumb_x_end) | |||||
| { | |||||
| /* To prevent thumnail flickering, don't change state of this cache when moving handles. */ | |||||
| if ((G.moving & G_TRANSFORM_SEQ) != 0) { | |||||
| return; | |||||
| } | |||||
| /* Clear images in frame range occupied by new thumbnail. */ | |||||
| last_displayed_thumbnails_list_cleanup(cache, thumb_x_start, thumb_x_end); | |||||
| /* Insert new thumbnail frame to list. */ | |||||
| BLI_gset_add(cache->last_displayed_thumbnails, POINTER_FROM_INT(timeline_frame)); | |||||
| } | |||||
| static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame, | static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame, | ||||
| GSet *previously_displayed) | GSet *previously_displayed) | ||||
| { | { | ||||
| int best_diff = INT_MAX; | int best_diff = INT_MAX; | ||||
| int best_frame = timeline_frame; | int best_frame = timeline_frame; | ||||
| /* Previously displayed thumbnails. */ | /* Previously displayed thumbnails. */ | ||||
| GSetIterator gset_iter; | GSetIterator gset_iter; | ||||
| BLI_gsetIterator_init(&gset_iter, previously_displayed); | BLI_gsetIterator_init(&gset_iter, previously_displayed); | ||||
| while (!BLI_gsetIterator_done(&gset_iter)) { | while (!BLI_gsetIterator_done(&gset_iter)) { | ||||
| int frame = POINTER_AS_INT(BLI_gsetIterator_getKey(&gset_iter)); | int frame = POINTER_AS_INT(BLI_gsetIterator_getKey(&gset_iter)); | ||||
| int diff = abs(frame - timeline_frame); | int diff = abs(frame - timeline_frame); | ||||
| if (diff < best_diff) { | if (diff < best_diff) { | ||||
| best_diff = diff; | best_diff = diff; | ||||
| best_frame = frame; | best_frame = frame; | ||||
| } | } | ||||
| BLI_gsetIterator_step(&gset_iter); | BLI_gsetIterator_step(&gset_iter); | ||||
| } | } | ||||
| return best_frame; | return best_frame; | ||||
| } | } | ||||
| static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame) | static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame) | ||||
| { | { | ||||
| if (timeline_frame <= seq->startdisp) { | |||||
| return seq->startdisp; | |||||
| } | |||||
| /* Set of "guaranteed" thumbnails. */ | /* Set of "guaranteed" thumbnails. */ | ||||
| const int frame_index = timeline_frame - seq->startdisp; | |||||
| const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq); | const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq); | ||||
| const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * frame_step; | const int frame_index = timeline_frame - seq->start; | ||||
| const int nearest_guaranted_absolute_frame = relative_base_frame + seq->startdisp; | const int steps = round_fl_to_int((frame_index + frame_step * 0.5f) / frame_step); | ||||
| return nearest_guaranted_absolute_frame; | return seq->start + steps * frame_step; | ||||
| } | } | ||||
| static ImBuf *sequencer_thumbnail_closest_from_memory(const SeqRenderData *context, | static ImBuf *sequencer_thumbnail_closest_from_memory(ThumbnailRuntimeCache *cache, | ||||
| const SeqRenderData *context, | |||||
| Sequence *seq, | Sequence *seq, | ||||
| int timeline_frame, | int timeline_frame, | ||||
| GSet *previously_displayed, | |||||
| rcti *crop, | rcti *crop, | ||||
| bool clipped) | bool clipped) | ||||
| { | { | ||||
| int frame_previous = sequencer_thumbnail_closest_previous_frame_get(timeline_frame, | int frame_previous = sequencer_thumbnail_closest_previous_frame_get( | ||||
| previously_displayed); | timeline_frame, cache->last_displayed_thumbnails); | ||||
| ImBuf *ibuf_previous = SEQ_get_thumbnail(context, seq, frame_previous, crop, clipped); | ImBuf *ibuf_previous = SEQ_get_thumbnail(context, seq, frame_previous, crop, clipped); | ||||
| int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get(seq, timeline_frame); | int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get(seq, timeline_frame); | ||||
| ImBuf *ibuf_guaranteed = SEQ_get_thumbnail(context, seq, frame_guaranteed, crop, clipped); | ImBuf *ibuf_guaranteed = SEQ_get_thumbnail(context, seq, frame_guaranteed, crop, clipped); | ||||
| ImBuf *closest_in_memory = NULL; | ImBuf *closest_in_memory = NULL; | ||||
| if (ibuf_previous && ibuf_guaranteed) { | if (ibuf_previous && ibuf_guaranteed) { | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | void draw_seq_strip_thumbnail(View2D *v2d, | ||||
| float thumb_y_end = y1 + thumb_height - pixely; | float thumb_y_end = y1 + thumb_height - pixely; | ||||
| float cut_off = 0; | float cut_off = 0; | ||||
| float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; | float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; | ||||
| if (seq->type == SEQ_TYPE_IMAGE) { | if (seq->type == SEQ_TYPE_IMAGE) { | ||||
| upper_thumb_bound = seq->enddisp; | upper_thumb_bound = seq->enddisp; | ||||
| } | } | ||||
| float thumb_x_start = seq_thumbnail_get_start_frame(seq, thumb_width, &v2d->cur); | float thumb_x_start = seq_thumbnail_get_start_frame(seq); | ||||
| float thumb_x_end; | float thumb_x_end; | ||||
| while (thumb_x_start + thumb_width < v2d->cur.xmin) { | while (thumb_x_start + thumb_width < v2d->cur.xmin) { | ||||
| thumb_x_start += thumb_width; | thumb_x_start += thumb_width; | ||||
| } | } | ||||
| /* Ignore thumbs to the left of strip. */ | ThumbnailRuntimeCache *cache = thumbnail_runtime_cache_ensure(C, seq); | ||||
| while (thumb_x_start + thumb_width < seq->startdisp) { | |||||
| thumb_x_start += thumb_width; | |||||
| } | |||||
| GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq); | |||||
| /* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent | /* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent | ||||
| * flickering after zooming. */ | * flickering after zooming. */ | ||||
| if (!sequencer_thumbnail_v2d_is_navigating(C)) { | if (!sequencer_thumbnail_v2d_is_navigating(C)) { | ||||
| last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, -FLT_MAX, thumb_x_start); | last_displayed_thumbnails_list_cleanup(cache, -FLT_MAX, thumb_x_start); | ||||
| } | |||||
| if (!handle_is_moving(seq)) { | |||||
| handle_update_thumbnails_cache_reset(cache); | |||||
| } | } | ||||
| /* Start drawing. */ | /* Start drawing. */ | ||||
| while (thumb_x_start < upper_thumb_bound) { | while (thumb_x_start < upper_thumb_bound) { | ||||
| thumb_x_end = thumb_x_start + thumb_width; | thumb_x_end = thumb_x_start + thumb_width; | ||||
| clipped = false; | clipped = false; | ||||
| /* Checks to make sure that thumbs are loaded only when in view and within the confines of the | /* Checks to make sure that thumbs are loaded only when in view and within the confines of the | ||||
| Show All 25 Lines | while (thumb_x_start < upper_thumb_bound) { | ||||
| float cropx_max = ((thumb_x_end - thumb_x_start) / pixelx) / (zoom_y / pixely); | float cropx_max = ((thumb_x_end - thumb_x_start) / pixelx) / (zoom_y / pixely); | ||||
| if (cropx_max == (thumb_x_end - thumb_x_start)) { | if (cropx_max == (thumb_x_end - thumb_x_start)) { | ||||
| cropx_max = cropx_max + 1; | cropx_max = cropx_max + 1; | ||||
| } | } | ||||
| BLI_rcti_init(&crop, (int)(cropx_min), (int)cropx_max, 0, (int)(image_height)-1); | BLI_rcti_init(&crop, (int)(cropx_min), (int)cropx_max, 0, (int)(image_height)-1); | ||||
| int timeline_frame = round_fl_to_int(thumb_x_start); | int timeline_frame = round_fl_to_int(thumb_x_start); | ||||
| /* Get the image. */ | /* Get the image. When moving handles, use only thumbnails stored in memory. using precise | ||||
| ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped); | * frame position can cause flickering. */ | ||||
| ImBuf *ibuf = NULL; | |||||
| if (!handle_is_moving(seq)) { | |||||
| ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped); | |||||
| } | |||||
| /* Image is missing, start the job */ | |||||
| if (!ibuf) { | if (!ibuf) { | ||||
| /* When moving handle, start job only when first thumbnail is missing. */ | |||||
| if (timeline_frame == seq->startdisp && handle_is_moving(seq)) { | |||||
| sequencer_thumbnail_start_job_if_necessary(C, scene->ed, v2d, true); | |||||
| handle_update_thumbnails_cache_push(cache, timeline_frame); | |||||
| } | |||||
| else if ((G.moving & G_TRANSFORM_SEQ) == 0) { | |||||
| sequencer_thumbnail_start_job_if_necessary(C, scene->ed, v2d, true); | sequencer_thumbnail_start_job_if_necessary(C, scene->ed, v2d, true); | ||||
| } | |||||
| } | |||||
| /* Image for moved handle is missing, do lookup using recently rendered handle positions. */ | |||||
| if (!ibuf && handle_is_moving(seq) && timeline_frame == seq->startdisp) { | |||||
| for (int cache_slot = 0; cache_slot < HANDLE_UPDATE_CACHE_LEN; cache_slot++) { | |||||
| const int frame = cache->handle_update_cache[cache_slot]; | |||||
| if (frame == HANDLE_UPDATE_CACHE_FRAME_INVALID) { | |||||
| break; | |||||
| } | |||||
| ibuf = SEQ_get_thumbnail(&context, seq, frame, &crop, clipped); | |||||
| if (ibuf != NULL) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* No image still, look for image in memory. */ | |||||
| if (!ibuf) { | |||||
| ibuf = sequencer_thumbnail_closest_from_memory( | ibuf = sequencer_thumbnail_closest_from_memory( | ||||
| &context, seq, timeline_frame, last_displayed_thumbnails, &crop, clipped); | cache, &context, seq, timeline_frame, &crop, clipped); | ||||
| } | } | ||||
| /* Store recently rendered frames, so they can be reused when zooming. */ | /* Store recently rendered frames, so they can be reused when zooming. */ | ||||
| else if (!sequencer_thumbnail_v2d_is_navigating(C)) { | else if (!sequencer_thumbnail_v2d_is_navigating(C)) { | ||||
| /* Clear images in frame range occupied by new thumbnail. */ | last_displayed_thumbnails_push(cache, timeline_frame, thumb_x_start, thumb_x_end); | ||||
| last_displayed_thumbnails_list_cleanup( | |||||
| last_displayed_thumbnails, thumb_x_start, thumb_x_end); | |||||
| /* Insert new thumbnail frame to list. */ | |||||
| BLI_gset_add(last_displayed_thumbnails, POINTER_FROM_INT(timeline_frame)); | |||||
| } | } | ||||
| /* If there is no image still, abort. */ | /* If there is no image still, abort. */ | ||||
| if (!ibuf) { | if (!ibuf) { | ||||
| break; | break; | ||||
| } | } | ||||
| /* Transparency on overlap. */ | /* Transparency on overlap. */ | ||||
| Show All 24 Lines | ED_draw_imbuf_ctx_clipping(C, | ||||
| thumb_y_end, | thumb_y_end, | ||||
| zoom_x, | zoom_x, | ||||
| zoom_y); | zoom_y); | ||||
| IMB_freeImBuf(ibuf); | IMB_freeImBuf(ibuf); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| cut_off = 0; | cut_off = 0; | ||||
| thumb_x_start += thumb_width; | thumb_x_start += thumb_width; | ||||
| } | } | ||||
| last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, thumb_x_start, FLT_MAX); | last_displayed_thumbnails_list_cleanup(cache, thumb_x_start, FLT_MAX); | ||||
| } | } | ||||