diff options
Diffstat (limited to 'source/blender/sequencer')
-rw-r--r-- | source/blender/sequencer/SEQ_iterator.h | 8 | ||||
-rw-r--r-- | source/blender/sequencer/SEQ_render.h | 21 | ||||
-rw-r--r-- | source/blender/sequencer/SEQ_sequencer.h | 1 | ||||
-rw-r--r-- | source/blender/sequencer/SEQ_transform.h | 9 | ||||
-rw-r--r-- | source/blender/sequencer/SEQ_utils.h | 2 | ||||
-rw-r--r-- | source/blender/sequencer/intern/image_cache.c | 81 | ||||
-rw-r--r-- | source/blender/sequencer/intern/image_cache.h | 6 | ||||
-rw-r--r-- | source/blender/sequencer/intern/iterator.c | 120 | ||||
-rw-r--r-- | source/blender/sequencer/intern/render.c | 283 | ||||
-rw-r--r-- | source/blender/sequencer/intern/sequencer.c | 11 | ||||
-rw-r--r-- | source/blender/sequencer/intern/strip_transform.c | 98 | ||||
-rw-r--r-- | source/blender/sequencer/intern/utils.c | 1 |
12 files changed, 538 insertions, 103 deletions
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h index 4f7d603fd6a..d2a47a13db3 100644 --- a/source/blender/sequencer/SEQ_iterator.h +++ b/source/blender/sequencer/SEQ_iterator.h @@ -94,11 +94,15 @@ SeqCollection *SEQ_query_by_reference(struct Sequence *seq_reference, SeqCollection *collection)); SeqCollection *SEQ_query_selected_strips(struct ListBase *seqbase); SeqCollection *SEQ_query_unselected_strips(struct ListBase *seqbase); -SeqCollection *SEQ_query_all_strips(struct ListBase *seqbase); -SeqCollection *SEQ_query_all_strips_recursive(struct ListBase *seqbase); +SeqCollection *SEQ_query_all_strips(ListBase *seqbase); +SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase); +SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase, + const int timeline_frame, + const int displayed_channel); void SEQ_query_strip_effect_chain(struct Sequence *seq_reference, struct ListBase *seqbase, SeqCollection *collection); +void SEQ_filter_selected_strips(SeqCollection *collection); #ifdef __cplusplus } diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h index c138daf1318..e99dc6d344f 100644 --- a/source/blender/sequencer/SEQ_render.h +++ b/source/blender/sequencer/SEQ_render.h @@ -27,6 +27,8 @@ extern "C" { #endif +#define SEQ_RENDER_THUMB_SIZE 256 + struct ListBase; struct Main; struct Scene; @@ -67,6 +69,25 @@ struct ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, struct ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context, float timeline_frame, struct Sequence *seq); +void SEQ_render_thumbnails(const struct SeqRenderData *context, + struct Sequence *seq, + struct Sequence *seq_orig, + float start_frame, + float frame_step, + rctf *view_area, + const short *stop); +struct ImBuf *SEQ_get_thumbnail(const struct SeqRenderData *context, + struct Sequence *seq, + float timeline_frame, + rcti *crop, + bool clipped); +int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const struct Sequence *seq); +void SEQ_render_thumbnails_base_set(const struct SeqRenderData *context, + struct Sequence *seq, + struct Sequence *seq_orig, + rctf *view_area, + const short *stop); + void SEQ_render_init_colorspace(struct Sequence *seq); void SEQ_render_new_render_data(struct Main *bmain, struct Depsgraph *depsgraph, diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index d7800d208a4..7e733817630 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -64,6 +64,7 @@ short SEQ_tool_settings_snap_flag_get(struct Scene *scene); short SEQ_tool_settings_snap_mode_get(struct Scene *scene); int SEQ_tool_settings_snap_distance_get(struct Scene *scene); eSeqOverlapMode SEQ_tool_settings_overlap_mode_get(struct Scene *scene); +int SEQ_tool_settings_pivot_point_get(struct Scene *scene); struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSettings *tool_settings); struct Editing *SEQ_editing_get(const struct Scene *scene); struct Editing *SEQ_editing_ensure(struct Scene *scene); diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h index 1977835f627..328efb9424a 100644 --- a/source/blender/sequencer/SEQ_transform.h +++ b/source/blender/sequencer/SEQ_transform.h @@ -61,6 +61,15 @@ void SEQ_transform_offset_after_frame(struct Scene *scene, const int delta, const int timeline_frame); +/* Image transformation. */ +void SEQ_image_transform_mirror_factor_get(const struct Sequence *seq, float r_mirror[2]); +void SEQ_image_transform_origin_offset_pixelspace_get(const struct Scene *scene, + const struct Sequence *seq, + float r_origin[2]); +void SEQ_image_transform_final_quad_get(const struct Scene *scene, + const struct Sequence *seq, + float r_quad[4][2]); + #ifdef __cplusplus } #endif diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h index 09de7bc67e9..d30a1b2d7ae 100644 --- a/source/blender/sequencer/SEQ_utils.h +++ b/source/blender/sequencer/SEQ_utils.h @@ -34,6 +34,7 @@ struct Mask; struct Scene; struct Sequence; struct StripElem; +struct SeqRenderData; void SEQ_sort(struct ListBase *seqbase); void SEQ_sequence_base_unique_name_recursive(struct Scene *scene, @@ -57,7 +58,6 @@ void SEQ_set_scale_to_fit(const struct Sequence *seq, const int preview_height, const eSeqImageFitMethod fit_method); void SEQ_ensure_unique_name(struct Sequence *seq, struct Scene *scene); - #ifdef __cplusplus } #endif diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index 86bd840ce31..86c198075e9 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -104,6 +104,7 @@ #define DCACHE_IMAGES_PER_FILE 100 #define DCACHE_CURRENT_VERSION 2 #define COLORSPACE_NAME_MAX 64 /* XXX: defined in imb intern */ +#define THUMB_CACHE_LIMIT 5000 typedef struct DiskCacheHeaderEntry { unsigned char encoding; @@ -148,6 +149,7 @@ typedef struct SeqCache { struct BLI_mempool *items_pool; struct SeqCacheKey *last_key; SeqDiskCache *disk_cache; + int thumbnail_count; } SeqCache; typedef struct SeqCacheItem { @@ -776,7 +778,7 @@ static float seq_cache_timeline_frame_to_frame_index(Sequence *seq, float timeli /* With raw images, map timeline_frame to strip input media frame range. This means that static * images or extended frame range of movies will only generate one cache entry. No special * treatment in converting frame index to timeline_frame is needed. */ - if (type == SEQ_CACHE_STORE_RAW) { + if (type == SEQ_CACHE_STORE_RAW || type == SEQ_CACHE_STORE_THUMBNAIL) { return seq_give_frame_index(seq, timeline_frame); } @@ -875,7 +877,7 @@ static void seq_cache_put_ex(Scene *scene, SeqCacheKey *key, ImBuf *ibuf) if (BLI_ghash_reinsert(cache->hash, key, item, seq_cache_keyfree, seq_cache_valfree)) { IMB_refImBuf(ibuf); - if (!key->is_temp_cache) { + if (!key->is_temp_cache || key->type != SEQ_CACHE_STORE_THUMBNAIL) { cache->last_key = key; } } @@ -1161,6 +1163,7 @@ static void seq_cache_create(Main *bmain, Scene *scene) cache->hash = BLI_ghash_new(seq_cache_hashhash, seq_cache_hashcmp, "SeqCache hash"); cache->last_key = NULL; cache->bmain = bmain; + cache->thumbnail_count = 0; BLI_mutex_init(&cache->iterator_mutex); scene->ed->cache = cache; @@ -1217,7 +1220,7 @@ void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame) SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter); BLI_ghashIterator_step(&gh_iter); - if (key->is_temp_cache && key->task_id == id) { + if (key->is_temp_cache && key->task_id == id && key->type != SEQ_CACHE_STORE_THUMBNAIL) { /* Use frame_index here to avoid freeing raw images if they are used for multiple frames. */ float frame_index = seq_cache_timeline_frame_to_frame_index( key->seq, timeline_frame, key->type); @@ -1278,6 +1281,7 @@ void SEQ_cache_cleanup(Scene *scene) BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree); } cache->last_key = NULL; + cache->thumbnail_count = 0; seq_cache_unlock(scene); } @@ -1345,6 +1349,46 @@ void seq_cache_cleanup_sequence(Scene *scene, seq_cache_unlock(scene); } +void seq_cache_thumbnail_cleanup(Scene *scene, rctf *view_area_safe) +{ + /* Add offsets to the left and right end to keep some frames in cache. */ + view_area_safe->xmax += 200; + view_area_safe->xmin -= 200; + view_area_safe->ymin -= 1; + view_area_safe->ymax += 1; + + SeqCache *cache = seq_cache_get_from_scene(scene); + if (!cache) { + return; + } + + GHashIterator gh_iter; + BLI_ghashIterator_init(&gh_iter, cache->hash); + while (!BLI_ghashIterator_done(&gh_iter)) { + SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter); + BLI_ghashIterator_step(&gh_iter); + + const int frame_index = key->timeline_frame - key->seq->startdisp; + const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(key->seq); + const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * + frame_step; + const int nearest_guaranted_absolute_frame = relative_base_frame + key->seq->startdisp; + + if (nearest_guaranted_absolute_frame == key->timeline_frame) { + continue; + } + + if ((key->type & SEQ_CACHE_STORE_THUMBNAIL) && + (key->timeline_frame > view_area_safe->xmax || + key->timeline_frame < view_area_safe->xmin || key->seq->machine > view_area_safe->ymax || + key->seq->machine < view_area_safe->ymin)) { + BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree); + cache->thumbnail_count--; + } + } + cache->last_key = NULL; +} + struct ImBuf *seq_cache_get(const SeqRenderData *context, Sequence *seq, float timeline_frame, @@ -1436,6 +1480,37 @@ bool seq_cache_put_if_possible( return false; } +void seq_cache_thumbnail_put( + const SeqRenderData *context, Sequence *seq, float timeline_frame, ImBuf *i, rctf *view_area) +{ + Scene *scene = context->scene; + + if (!scene->ed->cache) { + seq_cache_create(context->bmain, scene); + } + + seq_cache_lock(scene); + SeqCache *cache = seq_cache_get_from_scene(scene); + SeqCacheKey *key = seq_cache_allocate_key( + cache, context, seq, timeline_frame, SEQ_CACHE_STORE_THUMBNAIL); + + /* Prevent reinserting, it breaks cache key linking. */ + if (BLI_ghash_haskey(cache->hash, key)) { + seq_cache_unlock(scene); + return; + } + + /* Limit cache to THUMB_CACHE_LIMIT (5000) images stored. */ + if (cache->thumbnail_count >= THUMB_CACHE_LIMIT) { + rctf view_area_safe = *view_area; + seq_cache_thumbnail_cleanup(scene, &view_area_safe); + } + + seq_cache_put_ex(scene, key, i); + cache->thumbnail_count++; + seq_cache_unlock(scene); +} + void seq_cache_put( const SeqRenderData *context, Sequence *seq, float timeline_frame, int type, ImBuf *i) { diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h index 63c559caee9..60031311985 100644 --- a/source/blender/sequencer/intern/image_cache.h +++ b/source/blender/sequencer/intern/image_cache.h @@ -46,6 +46,11 @@ void seq_cache_put(const struct SeqRenderData *context, float timeline_frame, int type, struct ImBuf *i); +void seq_cache_thumbnail_put(const struct SeqRenderData *context, + struct Sequence *seq, + float timeline_frame, + struct ImBuf *i, + rctf *view_area); bool seq_cache_put_if_possible(const struct SeqRenderData *context, struct Sequence *seq, float timeline_frame, @@ -60,6 +65,7 @@ void seq_cache_cleanup_sequence(struct Scene *scene, struct Sequence *seq_changed, int invalidate_types, bool force_seq_changed_range); +void seq_cache_thumbnail_cleanup(Scene *scene, rctf *view_area); bool seq_cache_is_full(void); #ifdef __cplusplus diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c index 58f68205f51..2429405350b 100644 --- a/source/blender/sequencer/intern/iterator.c +++ b/source/blender/sequencer/intern/iterator.c @@ -37,6 +37,8 @@ #include "BKE_scene.h" #include "SEQ_iterator.h" +#include "SEQ_time.h" +#include "render.h" /* -------------------------------------------------------------------- */ /** \Iterator API @@ -340,6 +342,114 @@ SeqCollection *SEQ_query_selected_strips(ListBase *seqbase) return collection; } +static SeqCollection *query_strips_at_frame(ListBase *seqbase, const int timeline_frame) +{ + SeqCollection *collection = SEQ_collection_create(__func__); + + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (SEQ_time_strip_intersects_frame(seq, timeline_frame)) { + SEQ_collection_append_strip(seq, collection); + } + } + return collection; +} + +static void collection_filter_channel_up_to_incl(SeqCollection *collection, const int channel) +{ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, collection) { + if (seq->machine <= channel) { + continue; + } + SEQ_collection_remove_strip(seq, collection); + } +} + +static bool seq_is_effect_of(const Sequence *seq_effect, const Sequence *possibly_input) +{ + if (seq_effect->seq1 == possibly_input || seq_effect->seq2 == possibly_input || + seq_effect->seq3 == possibly_input) { + return true; + } + return false; +} + +/* Check if seq must be rendered. This depends on whole stack in some cases, not only seq itself. + * Order of applying these conditions is important. */ +static bool must_render_strip(const Sequence *seq, SeqCollection *strips_at_timeline_frame) +{ + bool seq_have_effect_in_stack = false; + Sequence *seq_iter; + SEQ_ITERATOR_FOREACH (seq_iter, strips_at_timeline_frame) { + /* Strips is below another strip with replace blending are not rendered. */ + if (seq_iter->blend_mode == SEQ_BLEND_REPLACE && seq->machine < seq_iter->machine) { + return false; + } + + if ((seq_iter->type & SEQ_TYPE_EFFECT) != 0 && seq_is_effect_of(seq_iter, seq)) { + /* Strips in same channel or higher than its effect are rendered. */ + if (seq->machine >= seq_iter->machine) { + return true; + } + /* Mark that this strip has effect in stack, that is above the strip. */ + seq_have_effect_in_stack = true; + } + } + + /* All effects are rendered (with respect to conditions above). */ + if ((seq->type & SEQ_TYPE_EFFECT) != 0) { + return true; + } + + /* If strip has effects in stack, and all effects are above this strip, it is not rendered. */ + if (seq_have_effect_in_stack) { + return false; + } + + return true; +} + +/* Remove strips we don't want to render from collection. */ +static void collection_filter_rendered_strips(SeqCollection *collection) +{ + Sequence *seq; + + /* Remove sound strips and muted strips from collection, because these are not rendered. + * Function #must_render_strip() don't have to check for these strips anymore. */ + SEQ_ITERATOR_FOREACH (seq, collection) { + if (seq->type == SEQ_TYPE_SOUND_RAM || (seq->flag & SEQ_MUTE) != 0) { + SEQ_collection_remove_strip(seq, collection); + } + } + + SEQ_ITERATOR_FOREACH (seq, collection) { + if (must_render_strip(seq, collection)) { + continue; + } + SEQ_collection_remove_strip(seq, collection); + } +} + +/** + * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed + * + * \param seqbase: ListBase in which strips are queried + * \param timeline_frame: viewed frame + * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied + * \return strip collection + */ +SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase, + const int timeline_frame, + const int displayed_channel) +{ + SeqCollection *collection = query_strips_at_frame(seqbase, timeline_frame); + if (displayed_channel != 0) { + collection_filter_channel_up_to_incl(collection, displayed_channel); + } + collection_filter_rendered_strips(collection); + return collection; +} + /** * Query all unselected strips in seqbase. * @@ -396,3 +506,13 @@ void SEQ_query_strip_effect_chain(Sequence *seq_reference, } } } + +void SEQ_filter_selected_strips(SeqCollection *collection) +{ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, collection) { + if ((seq->flag & SELECT) == 0) { + SEQ_collection_remove_strip(seq, collection); + } + } +} diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 6c4502a3608..2578a6d4223 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -72,6 +72,7 @@ #include "SEQ_render.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" +#include "SEQ_transform.h" #include "SEQ_utils.h" #include "effects.h" @@ -262,94 +263,6 @@ StripElem *SEQ_render_give_stripelem(Sequence *seq, int timeline_frame) return se; } -static bool seq_is_effect_of(const Sequence *seq_effect, const Sequence *possibly_input) -{ - if (seq_effect->seq1 == possibly_input || seq_effect->seq2 == possibly_input || - seq_effect->seq3 == possibly_input) { - return true; - } - return false; -} - -/* Check if seq must be rendered. This depends on whole stack in some cases, not only seq itself. - * Order of applying these conditions is important. */ -static bool must_render_strip(const Sequence *seq, SeqCollection *strips_at_timeline_frame) -{ - bool seq_have_effect_in_stack = false; - Sequence *seq_iter; - SEQ_ITERATOR_FOREACH (seq_iter, strips_at_timeline_frame) { - /* Strips is below another strip with replace blending are not rendered. */ - if (seq_iter->blend_mode == SEQ_BLEND_REPLACE && seq->machine < seq_iter->machine) { - return false; - } - - if ((seq_iter->type & SEQ_TYPE_EFFECT) != 0 && seq_is_effect_of(seq_iter, seq)) { - /* Strips in same channel or higher than its effect are rendered. */ - if (seq->machine >= seq_iter->machine) { - return true; - } - /* Mark that this strip has effect in stack, that is above the strip. */ - seq_have_effect_in_stack = true; - } - } - - /* All effects are rendered (with respect to conditions above). */ - if ((seq->type & SEQ_TYPE_EFFECT) != 0) { - return true; - } - - /* If strip has effects in stack, and all effects are above this strip, it is not rendered. */ - if (seq_have_effect_in_stack) { - return false; - } - - return true; -} - -static SeqCollection *query_strips_at_frame(ListBase *seqbase, const int timeline_frame) -{ - SeqCollection *collection = SEQ_collection_create(__func__); - - LISTBASE_FOREACH (Sequence *, seq, seqbase) { - if (SEQ_time_strip_intersects_frame(seq, timeline_frame)) { - SEQ_collection_append_strip(seq, collection); - } - } - return collection; -} - -static void collection_filter_channel_up_to_incl(SeqCollection *collection, const int channel) -{ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, collection) { - if (seq->machine <= channel) { - continue; - } - SEQ_collection_remove_strip(seq, collection); - } -} - -/* Remove strips we don't want to render from collection. */ -static void collection_filter_rendered_strips(SeqCollection *collection) -{ - Sequence *seq; - - /* Remove sound strips and muted strips from collection, because these are not rendered. - * Function #must_render_strip() don't have to check for these strips anymore. */ - SEQ_ITERATOR_FOREACH (seq, collection) { - if (seq->type == SEQ_TYPE_SOUND_RAM || (seq->flag & SEQ_MUTE) != 0) { - SEQ_collection_remove_strip(seq, collection); - } - } - - SEQ_ITERATOR_FOREACH (seq, collection) { - if (must_render_strip(seq, collection)) { - continue; - } - SEQ_collection_remove_strip(seq, collection); - } -} - static int seq_channel_cmp_fn(const void *a, const void *b) { return (*(Sequence **)a)->machine - (*(Sequence **)b)->machine; @@ -360,13 +273,7 @@ int seq_get_shown_sequences(ListBase *seqbase, const int chanshown, Sequence **r_seq_arr) { - SeqCollection *collection = query_strips_at_frame(seqbase, timeline_frame); - - if (chanshown != 0) { - collection_filter_channel_up_to_incl(collection, chanshown); - } - collection_filter_rendered_strips(collection); - + SeqCollection *collection = SEQ_query_rendered_strips(seqbase, timeline_frame, chanshown); const int strip_count = BLI_gset_len(collection->set); if (strip_count > MAXSEQ) { @@ -504,7 +411,7 @@ static void sequencer_image_crop_transform_matrix(const Sequence *seq, const float image_center_offs_y = (out->y - in->y) / 2; const float translate_x = transform->xofs * preview_scale_factor + image_center_offs_x; const float translate_y = transform->yofs * preview_scale_factor + image_center_offs_y; - const float pivot[2] = {in->x / 2, in->y / 2}; + const float pivot[2] = {in->x * transform->origin[0], in->y * transform->origin[1]}; loc_rot_size_to_mat3(r_transform_matrix, (const float[]){translate_x, translate_y}, transform->rotation, @@ -527,6 +434,31 @@ static void sequencer_image_crop_init(const Sequence *seq, BLI_rctf_init(r_crop, left, in->x - right, bottom, in->y - top); } +static void sequencer_thumbnail_transform(ImBuf *in, ImBuf *out) +{ + float image_scale_factor = (float)out->x / in->x; + float transform_matrix[3][3]; + + /* Set to keep same loc,scale,rot but change scale to thumb size limit. */ + const float scale_x = 1 * image_scale_factor; + const float scale_y = 1 * image_scale_factor; + const float image_center_offs_x = (out->x - in->x) / 2; + const float image_center_offs_y = (out->y - in->y) / 2; + const float pivot[2] = {in->x / 2, in->y / 2}; + loc_rot_size_to_mat3(transform_matrix, + (const float[]){image_center_offs_x, image_center_offs_y}, + 0, + (const float[]){scale_x, scale_y}); + transform_pivot_set_m3(transform_matrix, pivot); + invert_m3(transform_matrix); + + /* No crop. */ + rctf source_crop; + BLI_rctf_init(&source_crop, 0, in->x, 0, in->y); + + IMB_transform(in, out, transform_matrix, &source_crop, IMB_FILTER_NEAREST); +} + static void sequencer_preprocess_transform_crop( ImBuf *in, ImBuf *out, const SeqRenderData *context, Sequence *seq, const bool is_proxy_image) { @@ -1989,7 +1921,164 @@ ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context, seq_render_state_init(&state); ImBuf *ibuf = seq_render_strip(context, &state, seq, timeline_frame); - return ibuf; } + +/* Gets the direct image from source and scales to thumbnail size. */ +static ImBuf *seq_get_uncached_thumbnail(const SeqRenderData *context, + SeqRenderState *state, + Sequence *seq, + float timeline_frame) +{ + bool is_proxy_image = false; + ImBuf *ibuf = do_render_strip_uncached(context, state, seq, timeline_frame, &is_proxy_image); + + if (ibuf == NULL) { + return NULL; + } + + float aspect_ratio = (float)ibuf->x / ibuf->y; + int rectx, recty; + /* Calculate new dimensions - THUMB_SIZE (256) for x or y. */ + if (ibuf->x > ibuf->y) { + rectx = SEQ_RENDER_THUMB_SIZE; + recty = round_fl_to_int(rectx / aspect_ratio); + } + else { + recty = SEQ_RENDER_THUMB_SIZE; + rectx = round_fl_to_int(recty * aspect_ratio); + } + + /* Scale ibuf to thumbnail size. */ + ImBuf *scaled_ibuf = IMB_allocImBuf(rectx, recty, 32, ibuf->rect_float ? IB_rectfloat : IB_rect); + sequencer_thumbnail_transform(ibuf, scaled_ibuf); + seq_imbuf_assign_spaces(context->scene, scaled_ibuf); + IMB_freeImBuf(ibuf); + + return scaled_ibuf; +} + +/* Get cached thumbnails. */ +ImBuf *SEQ_get_thumbnail( + const SeqRenderData *context, Sequence *seq, float timeline_frame, rcti *crop, bool clipped) +{ + ImBuf *ibuf = seq_cache_get(context, seq, roundf(timeline_frame), SEQ_CACHE_STORE_THUMBNAIL); + + if (!clipped || ibuf == NULL) { + return ibuf; + } + + /* Do clipping. */ + ImBuf *ibuf_cropped = IMB_dupImBuf(ibuf); + if (crop->xmin < 0 || crop->ymin < 0) { + crop->xmin = 0; + crop->ymin = 0; + } + if (crop->xmax >= ibuf->x || crop->ymax >= ibuf->y) { + crop->xmax = ibuf->x - 1; + crop->ymax = ibuf->y - 1; + } + IMB_rect_crop(ibuf_cropped, crop); + IMB_freeImBuf(ibuf); + return ibuf_cropped; +} + +/* Render the series of thumbnails and store in cache. */ +void SEQ_render_thumbnails(const SeqRenderData *context, + Sequence *seq, + Sequence *seq_orig, + float start_frame, + float frame_step, + rctf *view_area, + const short *stop) +{ + SeqRenderState state; + seq_render_state_init(&state); + + /* Adding the hold offset value (seq->anim_startofs) to the start frame. Position of image not + * affected, but frame loaded affected. */ + start_frame = start_frame - frame_step; + float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; + upper_thumb_bound = (upper_thumb_bound > view_area->xmax) ? view_area->xmax + frame_step : + upper_thumb_bound; + + while ((start_frame < upper_thumb_bound) & !*stop) { + ImBuf *ibuf = seq_cache_get( + context, seq_orig, round_fl_to_int(start_frame), SEQ_CACHE_STORE_THUMBNAIL); + if (ibuf) { + IMB_freeImBuf(ibuf); + start_frame += frame_step; + continue; + } + + ibuf = seq_get_uncached_thumbnail(context, &state, seq, round_fl_to_int(start_frame)); + + if (ibuf) { + seq_cache_thumbnail_put(context, seq_orig, round_fl_to_int(start_frame), ibuf, view_area); + IMB_freeImBuf(ibuf); + seq_orig->flag &= ~SEQ_FLAG_SKIP_THUMBNAILS; + } + else { + /* Can not open source file. */ + seq_orig->flag |= SEQ_FLAG_SKIP_THUMBNAILS; + return; + } + + start_frame += frame_step; + } +} + +/* Get frame step for equally spaced thumbnails. These thumbnails should always be present in + * memory, so they can be used when zooming.*/ +int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq) +{ + const int content_len = (seq->enddisp - seq->startdisp - seq->startstill - seq->endstill); + + /* Arbitrary, but due to performance reasons should be as low as possible. */ + const int thumbnails_base_set_count = min_ii(content_len / 100, 30); + if (thumbnails_base_set_count <= 0) { + return 0; + } + return content_len / thumbnails_base_set_count; +} + +/* Render set of evenly spaced thumbnails that are drawn when zooming. */ +void SEQ_render_thumbnails_base_set( + const SeqRenderData *context, Sequence *seq, Sequence *seq_orig, rctf *view_area, const short *stop) +{ + SeqRenderState state; + seq_render_state_init(&state); + + int timeline_frame = seq->startdisp; + const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq); + + while (timeline_frame < seq->enddisp && !*stop) { + ImBuf *ibuf = seq_cache_get( + context, seq_orig, roundf(timeline_frame), SEQ_CACHE_STORE_THUMBNAIL); + if (ibuf) { + IMB_freeImBuf(ibuf); + + if (frame_step == 0) { + return; + } + + timeline_frame += frame_step; + continue; + } + + ibuf = seq_get_uncached_thumbnail(context, &state, seq, timeline_frame); + + if (ibuf) { + seq_cache_thumbnail_put(context, seq_orig, timeline_frame, ibuf, view_area); + IMB_freeImBuf(ibuf); + } + + if (frame_step == 0) { + return; + } + + timeline_frame += frame_step; + } +} + /** \} */ diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index bf5942090c9..382bd51aae1 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -79,6 +79,8 @@ static Strip *seq_strip_alloc(int type) strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform"); strip->transform->scale_x = 1; strip->transform->scale_y = 1; + strip->transform->origin[0] = 0.5f; + strip->transform->origin[1] = 0.5f; strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop"); } @@ -321,6 +323,7 @@ SequencerToolSettings *SEQ_tool_settings_init(void) SEQ_SNAP_TO_STRIP_HOLD; tool_settings->snap_distance = 15; tool_settings->overlap_mode = SEQ_OVERLAP_SHUFFLE; + tool_settings->pivot_point = V3D_AROUND_LOCAL_ORIGINS; return tool_settings; } @@ -377,6 +380,12 @@ eSeqOverlapMode SEQ_tool_settings_overlap_mode_get(Scene *scene) return tool_settings->overlap_mode; } +int SEQ_tool_settings_pivot_point_get(Scene *scene) +{ + const SequencerToolSettings *tool_settings = SEQ_tool_settings_ensure(scene); + return tool_settings->pivot_point; +} + /** * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase * @@ -948,6 +957,8 @@ static bool seq_read_lib_cb(Sequence *seq, void *user_data) BLI_listbase_clear(&seq->anims); SEQ_modifier_blend_read_lib(reader, sce, &seq->modifiers); + + seq->flag &= ~SEQ_FLAG_SKIP_THUMBNAILS; return true; } diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 3a5f93a72b0..d5ff455c694 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -421,3 +421,101 @@ void SEQ_transform_offset_after_frame(Scene *scene, } } } + +void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2]) +{ + r_mirror[0] = 1.0f; + r_mirror[1] = 1.0f; + + if ((seq->flag & SEQ_FLIPX) != 0) { + r_mirror[0] = -1.0f; + } + if ((seq->flag & SEQ_FLIPY) != 0) { + r_mirror[1] = -1.0f; + } +} + +/** + * Get strip transform origin offset from image center + * Note: This function does not apply axis mirror. + * + * \param scene: Scene in which strips are located + * \param seq: Sequence to calculate image transform origin + * \param r_origin: return value + */ +void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene, + const Sequence *seq, + float r_origin[2]) +{ + float image_size[2]; + StripElem *strip_elem = seq->strip->stripdata; + if (strip_elem == NULL) { + image_size[0] = scene->r.xsch; + image_size[1] = scene->r.ysch; + } + else { + image_size[0] = strip_elem->orig_width; + image_size[1] = strip_elem->orig_height; + } + + const StripTransform *transform = seq->strip->transform; + r_origin[0] = (image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs; + r_origin[1] = (image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs; + + float mirror[2]; + SEQ_image_transform_mirror_factor_get(seq, mirror); + mul_v2_v2(r_origin, mirror); +} + +/** + * Get strip transform origin offset from image center + * + * \param scene: Scene in which strips are located + * \param seq: Sequence to calculate image transform origin + * \param r_origin: return value + */ + +void SEQ_image_transform_final_quad_get(const Scene *scene, + const Sequence *seq, + float r_quad[4][2]) +{ + StripTransform *transform = seq->strip->transform; + StripCrop *crop = seq->strip->crop; + + int imgage_size[2] = {scene->r.xsch, scene->r.ysch}; + if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) { + imgage_size[0] = seq->strip->stripdata->orig_width; + imgage_size[1] = seq->strip->stripdata->orig_height; + } + + float transform_matrix[3][3]; + loc_rot_size_to_mat3(transform_matrix, + (const float[]){transform->xofs, transform->yofs}, + transform->rotation, + (const float[]){transform->scale_x, transform->scale_y}); + const float origin[2] = {imgage_size[0] * transform->origin[0], + imgage_size[1] * transform->origin[1]}; + const float pivot[2] = {origin[0] - (imgage_size[0] / 2), origin[1] - (imgage_size[1] / 2)}; + transform_pivot_set_m3(transform_matrix, pivot); + + r_quad[0][0] = (imgage_size[0] / 2) - crop->right; + r_quad[0][1] = (imgage_size[1] / 2) - crop->top; + r_quad[1][0] = (imgage_size[0] / 2) - crop->right; + r_quad[1][1] = (-imgage_size[1] / 2) + crop->bottom; + r_quad[2][0] = (-imgage_size[0] / 2) + crop->left; + r_quad[2][1] = (-imgage_size[1] / 2) + crop->bottom; + r_quad[3][0] = (-imgage_size[0] / 2) + crop->left; + r_quad[3][1] = (imgage_size[1] / 2) - crop->top; + + mul_m3_v2(transform_matrix, r_quad[0]); + mul_m3_v2(transform_matrix, r_quad[1]); + mul_m3_v2(transform_matrix, r_quad[2]); + mul_m3_v2(transform_matrix, r_quad[3]); + + float mirror[2]; + SEQ_image_transform_mirror_factor_get(seq, mirror); + mul_v2_v2(r_quad[0], mirror); + mul_v2_v2(r_quad[1], mirror); + mul_v2_v2(r_quad[2], mirror); + mul_v2_v2(r_quad[3], mirror); +} diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 1d3e7e4a223..8421aab5217 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -42,6 +42,7 @@ #include "SEQ_edit.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" +#include "SEQ_render.h" #include "SEQ_select.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" |