diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index 1eb08fa1c95..058c8aeb9f2 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -29,18 +29,19 @@ set(SRC sequencer_channels_draw.cc sequencer_channels_edit.cc sequencer_drag_drop.cc - sequencer_draw.cc sequencer_edit.cc sequencer_gizmo_retime.cc sequencer_gizmo_retime_type.cc sequencer_modifier.cc sequencer_ops.cc sequencer_preview.cc + sequencer_preview_draw.cc sequencer_proxy.cc sequencer_retiming.cc sequencer_scopes.cc sequencer_select.cc sequencer_thumbnails.cc + sequencer_timeline_draw.cc sequencer_view.cc space_sequencer.cc diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 53c6e1302a4..e832f7301f4 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -58,10 +58,17 @@ typedef struct SeqChannelDrawContext { float scale; } SeqChannelDrawContext; -/* `sequencer_draw.cc` */ +/* `sequencer_timeline_draw.cc` */ void draw_timeline_seq(const struct bContext *C, struct ARegion *region); void draw_timeline_seq_display(const struct bContext *C, struct ARegion *region); +void color3ubv_from_seq(const struct Scene *curscene, + const struct Sequence *seq, + bool show_strip_color_tag, + uchar r_col[3]); + +/* `sequencer_preview_draw.cc` */ + void sequencer_draw_preview(const struct bContext *C, struct Scene *scene, struct ARegion *region, @@ -70,10 +77,8 @@ void sequencer_draw_preview(const struct bContext *C, int offset, bool draw_overlay, bool draw_backdrop); -void color3ubv_from_seq(const struct Scene *curscene, - const struct Sequence *seq, - bool show_strip_color_tag, - uchar r_col[3]); +bool sequencer_draw_get_transform_preview(SpaceSeq *sseq, Scene *scene); +int sequencer_draw_get_transform_preview_frame(Scene *scene); void sequencer_special_update_set(Sequence *seq); /* Get handle width in 2d-View space. */ diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc new file mode 100644 index 00000000000..c0d195709d6 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -0,0 +1,829 @@ +/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup spseq + */ + +#include +#include + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "IMB_imbuf_types.h" + +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_scene.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" + +#include "GPU_framebuffer.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_viewport.h" + +#include "ED_gpencil_legacy.hh" +#include "ED_screen.hh" +#include "ED_sequencer.hh" +#include "ED_space_api.hh" +#include "ED_util.hh" + +#include "BIF_glutil.hh" + +#include "SEQ_channels.h" +#include "SEQ_iterator.h" +#include "SEQ_prefetch.h" +#include "SEQ_proxy.h" +#include "SEQ_render.h" +#include "SEQ_select.h" +#include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" + +#include "UI_interface.hh" +#include "UI_resources.hh" +#include "UI_view2d.hh" + +#include "WM_api.hh" +#include "WM_types.hh" + +/* Own include. */ +#include "sequencer_intern.h" + +static Sequence *special_seq_update = nullptr; + +void sequencer_special_update_set(Sequence *seq) +{ + special_seq_update = seq; +} + +Sequence *ED_sequencer_special_preview_get() +{ + return special_seq_update; +} + +void ED_sequencer_special_preview_set(bContext *C, const int mval[2]) +{ + Scene *scene = CTX_data_scene(C); + ARegion *region = CTX_wm_region(C); + int hand; + Sequence *seq; + seq = find_nearest_seq(scene, ®ion->v2d, &hand, mval); + sequencer_special_update_set(seq); +} + +void ED_sequencer_special_preview_clear() +{ + sequencer_special_update_set(nullptr); +} + +ImBuf *sequencer_ibuf_get(Main *bmain, + ARegion *region, + Depsgraph *depsgraph, + Scene *scene, + SpaceSeq *sseq, + int timeline_frame, + int frame_ofs, + const char *viewname) +{ + SeqRenderData context = {nullptr}; + ImBuf *ibuf; + int rectx, recty; + double render_size; + short is_break = G.is_break; + + if (sseq->render_size == SEQ_RENDER_SIZE_NONE) { + return nullptr; + } + + if (sseq->render_size == SEQ_RENDER_SIZE_SCENE) { + render_size = scene->r.size / 100.0; + } + else { + render_size = SEQ_rendersize_to_scale_factor(sseq->render_size); + } + + rectx = roundf(render_size * scene->r.xsch); + recty = roundf(render_size * scene->r.ysch); + + SEQ_render_new_render_data( + bmain, depsgraph, scene, rectx, recty, sseq->render_size, false, &context); + context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); + context.use_proxies = (sseq->flag & SEQ_USE_PROXIES) != 0; + + /* Sequencer could start rendering, in this case we need to be sure it wouldn't be canceled + * by Escape pressed somewhere in the past. */ + G.is_break = false; + + GPUViewport *viewport = WM_draw_region_get_bound_viewport(region); + GPUFrameBuffer *fb = GPU_framebuffer_active_get(); + if (viewport) { + /* Unbind viewport to release the DRW context. */ + GPU_viewport_unbind(viewport); + } + else { + /* Rendering can change OGL context. Save & Restore frame-buffer. */ + GPU_framebuffer_restore(); + } + + if (special_seq_update) { + ibuf = SEQ_render_give_ibuf_direct(&context, timeline_frame + frame_ofs, special_seq_update); + } + else { + ibuf = SEQ_render_give_ibuf(&context, timeline_frame + frame_ofs, sseq->chanshown); + } + + if (viewport) { + /* Follows same logic as wm_draw_window_offscreen to make sure to restore the same + * viewport. */ + int view = (sseq->multiview_eye == STEREO_RIGHT_ID) ? 1 : 0; + GPU_viewport_bind(viewport, view, ®ion->winrct); + } + else if (fb) { + GPU_framebuffer_bind(fb); + } + + /* Restore state so real rendering would be canceled if needed. */ + G.is_break = is_break; + + return ibuf; +} + +static void sequencer_check_scopes(SequencerScopes *scopes, ImBuf *ibuf) +{ + if (scopes->reference_ibuf != ibuf) { + if (scopes->zebra_ibuf) { + IMB_freeImBuf(scopes->zebra_ibuf); + scopes->zebra_ibuf = nullptr; + } + + if (scopes->waveform_ibuf) { + IMB_freeImBuf(scopes->waveform_ibuf); + scopes->waveform_ibuf = nullptr; + } + + if (scopes->sep_waveform_ibuf) { + IMB_freeImBuf(scopes->sep_waveform_ibuf); + scopes->sep_waveform_ibuf = nullptr; + } + + if (scopes->vector_ibuf) { + IMB_freeImBuf(scopes->vector_ibuf); + scopes->vector_ibuf = nullptr; + } + + if (scopes->histogram_ibuf) { + IMB_freeImBuf(scopes->histogram_ibuf); + scopes->histogram_ibuf = nullptr; + } + } +} + +static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scope_fn)(ImBuf *ibuf)) +{ + ImBuf *display_ibuf = IMB_dupImBuf(ibuf); + ImBuf *scope; + + IMB_colormanagement_imbuf_make_display_space( + display_ibuf, &scene->view_settings, &scene->display_settings); + + scope = make_scope_fn(display_ibuf); + + IMB_freeImBuf(display_ibuf); + + return scope; +} + +static void sequencer_display_size(Scene *scene, float r_viewrect[2]) +{ + r_viewrect[0] = float(scene->r.xsch); + r_viewrect[1] = float(scene->r.ysch); + + r_viewrect[0] *= scene->r.xasp / scene->r.yasp; +} + +static void sequencer_draw_gpencil_overlay(const bContext *C) +{ + /* Draw grease-pencil (image aligned). */ + ED_annotation_draw_2dimage(C); + + /* Orthographic at pixel level. */ + UI_view2d_view_restore(C); + + /* Draw grease-pencil (screen aligned). */ + ED_annotation_draw_view2d(C, false); +} + +/** + * Draw content and safety borders. + */ +static void sequencer_draw_borders_overlay(const SpaceSeq *sseq, + const View2D *v2d, + const Scene *scene) +{ + float x1 = v2d->tot.xmin; + float y1 = v2d->tot.ymin; + float x2 = v2d->tot.xmax; + float y2 = v2d->tot.ymax; + + GPU_line_width(1.0f); + + /* Draw border. */ + const uint shdr_pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); + + immUniformThemeColor(TH_BACK); + immUniform1i("colors_len", 0); /* Simple dashes. */ + immUniform1f("dash_width", 6.0f); + immUniform1f("udash_factor", 0.5f); + + imm_draw_box_wire_2d(shdr_pos, x1 - 0.5f, y1 - 0.5f, x2 + 0.5f, y2 + 0.5f); + + /* Draw safety border. */ + if (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_SAFE_MARGINS) { + immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f); + rctf rect; + rect.xmin = x1; + rect.xmax = x2; + rect.ymin = y1; + rect.ymax = y2; + UI_draw_safe_areas(shdr_pos, &rect, scene->safe_areas.title, scene->safe_areas.action); + + if (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_SAFE_CENTER) { + + UI_draw_safe_areas( + shdr_pos, &rect, scene->safe_areas.title_center, scene->safe_areas.action_center); + } + } + + immUnbindProgram(); +} + +#if 0 +void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, SpaceSeq *sseq) +{ + /* NOTE: sequencer mask editing isn't finished, the draw code is working but editing not. + * For now just disable drawing since the strip frame will likely be offset. */ + + // if (sc->mode == SC_MODE_MASKEDIT) + if (0 && sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + Mask *mask = SEQ_active_mask_get(scene); + + if (mask) { + int width, height; + float aspx = 1.0f, aspy = 1.0f; + // ED_mask_get_size(C, &width, &height); + + // Scene *scene = CTX_data_scene(C); + BKE_render_resolution(&scene->r, false, &width, &height); + + ED_mask_draw_region(mask, + region, + 0, + 0, + 0, /* TODO */ + width, + height, + aspx, + aspy, + false, + true, + nullptr, + C); + } + } +} +#endif + +/* Force redraw, when prefetching and using cache view. */ +static void seq_prefetch_wm_notify(const bContext *C, Scene *scene) +{ + if (SEQ_prefetch_need_redraw(CTX_data_main(C), scene)) { + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, nullptr); + } +} + +static void *sequencer_OCIO_transform_ibuf(const bContext *C, + ImBuf *ibuf, + bool *r_glsl_used, + eGPUTextureFormat *r_format, + eGPUDataFormat *r_data, + void **r_buffer_cache_handle) +{ + void *display_buffer; + bool force_fallback = false; + *r_glsl_used = false; + force_fallback |= (ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL); + force_fallback |= (ibuf->dither != 0.0f); + + /* Default */ + *r_format = GPU_RGBA8; + *r_data = GPU_DATA_UBYTE; + + /* Fallback to CPU based color space conversion. */ + if (force_fallback) { + *r_glsl_used = false; + display_buffer = nullptr; + } + else if (ibuf->float_buffer.data) { + display_buffer = ibuf->float_buffer.data; + + *r_data = GPU_DATA_FLOAT; + if (ibuf->channels == 4) { + *r_format = GPU_RGBA16F; + } + else if (ibuf->channels == 3) { + /* Alpha is implicitly 1. */ + *r_format = GPU_RGB16F; + } + else { + BLI_assert_msg(0, "Incompatible number of channels for float buffer in sequencer"); + *r_format = GPU_RGBA16F; + display_buffer = nullptr; + } + + if (ibuf->float_buffer.colorspace) { + *r_glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx( + C, ibuf->float_buffer.colorspace, ibuf->dither, true); + } + else { + *r_glsl_used = IMB_colormanagement_setup_glsl_draw_ctx(C, ibuf->dither, true); + } + } + else if (ibuf->byte_buffer.data) { + display_buffer = ibuf->byte_buffer.data; + + *r_glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx( + C, ibuf->byte_buffer.colorspace, ibuf->dither, false); + } + else { + display_buffer = nullptr; + } + + /* There is data to be displayed, but GLSL is not initialized + * properly, in this case we fallback to CPU-based display transform. */ + if ((ibuf->byte_buffer.data || ibuf->float_buffer.data) && !*r_glsl_used) { + display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, r_buffer_cache_handle); + *r_format = GPU_RGBA8; + *r_data = GPU_DATA_UBYTE; + } + + return display_buffer; +} + +static void sequencer_stop_running_jobs(const bContext *C, Scene *scene) +{ + if (G.is_rendering == false && (scene->r.seq_prev_type) == OB_RENDER) { + /* Stop all running jobs, except screen one. Currently previews frustrate Render. + * Need to make so sequencers rendering doesn't conflict with compositor. */ + WM_jobs_kill_type(CTX_wm_manager(C), nullptr, WM_JOB_TYPE_COMPOSITE); + + /* In case of final rendering used for preview, kill all previews, + * otherwise threading conflict will happen in rendering module. */ + WM_jobs_kill_type(CTX_wm_manager(C), nullptr, WM_JOB_TYPE_RENDER_PREVIEW); + } +} + +static void sequencer_preview_clear() +{ + UI_ThemeClearColor(TH_SEQ_PREVIEW); +} + +static void sequencer_preview_get_rect(rctf *preview, + Scene *scene, + ARegion *region, + SpaceSeq *sseq, + bool draw_overlay, + bool draw_backdrop) +{ + View2D *v2d = ®ion->v2d; + float viewrect[2]; + + sequencer_display_size(scene, viewrect); + BLI_rctf_init(preview, -1.0f, 1.0f, -1.0f, 1.0f); + + if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) { + preview->xmax = v2d->tot.xmin + + (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->overlay_frame_rect.xmax); + preview->xmin = v2d->tot.xmin + + (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->overlay_frame_rect.xmin); + preview->ymax = v2d->tot.ymin + + (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->overlay_frame_rect.ymax); + preview->ymin = v2d->tot.ymin + + (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->overlay_frame_rect.ymin); + } + else if (draw_backdrop) { + float aspect = BLI_rcti_size_x(®ion->winrct) / float(BLI_rcti_size_y(®ion->winrct)); + float image_aspect = viewrect[0] / viewrect[1]; + + if (aspect >= image_aspect) { + preview->xmax = image_aspect / aspect; + preview->xmin = -preview->xmax; + } + else { + preview->ymax = aspect / image_aspect; + preview->ymin = -preview->ymax; + } + } + else { + *preview = v2d->tot; + } +} + +static void sequencer_draw_display_buffer(const bContext *C, + Scene *scene, + ARegion *region, + SpaceSeq *sseq, + ImBuf *ibuf, + ImBuf *scope, + bool draw_overlay, + bool draw_backdrop) +{ + void *display_buffer; + void *buffer_cache_handle = nullptr; + + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { + GPU_blend(GPU_BLEND_ALPHA); + } + + /* Format needs to be created prior to any #immBindShader call. + * Do it here because OCIO binds its own shader. */ + eGPUTextureFormat format; + eGPUDataFormat data; + bool glsl_used = false; + GPUVertFormat *imm_format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint texCoord = GPU_vertformat_attr_add( + imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + if (scope) { + ibuf = scope; + + if (ibuf->float_buffer.data && ibuf->byte_buffer.data == nullptr) { + IMB_rect_from_float(ibuf); + } + + display_buffer = ibuf->byte_buffer.data; + format = GPU_RGBA8; + data = GPU_DATA_UBYTE; + } + else { + display_buffer = sequencer_OCIO_transform_ibuf( + C, ibuf, &glsl_used, &format, &data, &buffer_cache_handle); + } + + if (draw_backdrop) { + GPU_matrix_push(); + GPU_matrix_identity_set(); + GPU_matrix_push_projection(); + GPU_matrix_identity_projection_set(); + } + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT; + GPUTexture *texture = GPU_texture_create_2d( + "seq_display_buf", ibuf->x, ibuf->y, 1, format, usage, nullptr); + GPU_texture_update(texture, data, display_buffer); + GPU_texture_filter_mode(texture, false); + + GPU_texture_bind(texture, 0); + + if (!glsl_used) { + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR); + immUniformColor3f(1.0f, 1.0f, 1.0f); + } + + immBegin(GPU_PRIM_TRI_FAN, 4); + + rctf preview; + rctf canvas; + sequencer_preview_get_rect(&preview, scene, region, sseq, draw_overlay, draw_backdrop); + + if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) { + canvas = scene->ed->overlay_frame_rect; + } + else { + BLI_rctf_init(&canvas, 0.0f, 1.0f, 0.0f, 1.0f); + } + + immAttr2f(texCoord, canvas.xmin, canvas.ymin); + immVertex2f(pos, preview.xmin, preview.ymin); + + immAttr2f(texCoord, canvas.xmin, canvas.ymax); + immVertex2f(pos, preview.xmin, preview.ymax); + + immAttr2f(texCoord, canvas.xmax, canvas.ymax); + immVertex2f(pos, preview.xmax, preview.ymax); + + immAttr2f(texCoord, canvas.xmax, canvas.ymin); + immVertex2f(pos, preview.xmax, preview.ymin); + + immEnd(); + + GPU_texture_unbind(texture); + GPU_texture_free(texture); + + if (!glsl_used) { + immUnbindProgram(); + } + else { + IMB_colormanagement_finish_glsl_draw(); + } + + if (buffer_cache_handle) { + IMB_display_buffer_release(buffer_cache_handle); + } + + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { + GPU_blend(GPU_BLEND_NONE); + } + + if (draw_backdrop) { + GPU_matrix_pop(); + GPU_matrix_pop_projection(); + } +} + +static ImBuf *sequencer_get_scope(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, bool draw_backdrop) +{ + ImBuf *scope = nullptr; + SequencerScopes *scopes = &sseq->scopes; + + if (!draw_backdrop && (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0)) { + sequencer_check_scopes(scopes, ibuf); + + switch (sseq->mainb) { + case SEQ_DRAW_IMG_IMBUF: + if (!scopes->zebra_ibuf) { + ImBuf *display_ibuf = IMB_dupImBuf(ibuf); + + if (display_ibuf->float_buffer.data) { + IMB_colormanagement_imbuf_make_display_space( + display_ibuf, &scene->view_settings, &scene->display_settings); + } + scopes->zebra_ibuf = make_zebra_view_from_ibuf(display_ibuf, sseq->zebra); + IMB_freeImBuf(display_ibuf); + } + scope = scopes->zebra_ibuf; + break; + case SEQ_DRAW_IMG_WAVEFORM: + if ((sseq->flag & SEQ_DRAW_COLOR_SEPARATED) != 0) { + if (!scopes->sep_waveform_ibuf) { + scopes->sep_waveform_ibuf = sequencer_make_scope( + scene, ibuf, make_sep_waveform_view_from_ibuf); + } + scope = scopes->sep_waveform_ibuf; + } + else { + if (!scopes->waveform_ibuf) { + scopes->waveform_ibuf = sequencer_make_scope( + scene, ibuf, make_waveform_view_from_ibuf); + } + scope = scopes->waveform_ibuf; + } + break; + case SEQ_DRAW_IMG_VECTORSCOPE: + if (!scopes->vector_ibuf) { + scopes->vector_ibuf = sequencer_make_scope(scene, ibuf, make_vectorscope_view_from_ibuf); + } + scope = scopes->vector_ibuf; + break; + case SEQ_DRAW_IMG_HISTOGRAM: + if (!scopes->histogram_ibuf) { + scopes->histogram_ibuf = sequencer_make_scope( + scene, ibuf, make_histogram_view_from_ibuf); + } + scope = scopes->histogram_ibuf; + break; + } + + /* Future files may have new scopes we don't catch above. */ + if (scope) { + scopes->reference_ibuf = ibuf; + } + } + return scope; +} + +bool sequencer_draw_get_transform_preview(SpaceSeq *sseq, Scene *scene) +{ + Sequence *last_seq = SEQ_select_active_get(scene); + if (last_seq == nullptr) { + return false; + } + + return (G.moving & G_TRANSFORM_SEQ) && (last_seq->flag & SELECT) && + ((last_seq->flag & SEQ_LEFTSEL) || (last_seq->flag & SEQ_RIGHTSEL)) && + (sseq->draw_flag & SEQ_DRAW_TRANSFORM_PREVIEW); +} + +int sequencer_draw_get_transform_preview_frame(Scene *scene) +{ + Sequence *last_seq = SEQ_select_active_get(scene); + /* #sequencer_draw_get_transform_preview must already have been called. */ + BLI_assert(last_seq != nullptr); + int preview_frame; + + if (last_seq->flag & SEQ_RIGHTSEL) { + preview_frame = SEQ_time_right_handle_frame_get(scene, last_seq) - 1; + } + else { + preview_frame = SEQ_time_left_handle_frame_get(scene, last_seq); + } + + return preview_frame; +} + +static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq, bool is_active_seq) +{ + SpaceSeq *sseq = CTX_wm_space_seq(C); + const ARegion *region = CTX_wm_region(C); + if (region->regiontype == RGN_TYPE_PREVIEW && !sequencer_view_preview_only_poll(C)) { + return; + } + if ((seq->flag & SELECT) == 0) { + return; + } + if (ED_screen_animation_no_scrub(CTX_wm_manager(C))) { + return; + } + if ((sseq->flag & SEQ_SHOW_OVERLAY) == 0 || + (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_OUTLINE_SELECTED) == 0) + { + return; + } + if (ELEM(sseq->mainb, SEQ_DRAW_IMG_WAVEFORM, SEQ_DRAW_IMG_VECTORSCOPE, SEQ_DRAW_IMG_HISTOGRAM)) { + return; + } + + float origin[2]; + SEQ_image_transform_origin_offset_pixelspace_get(CTX_data_scene(C), seq, origin); + + /* Origin. */ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA); + immUniform1f("outlineWidth", 1.5f); + immUniformColor3f(1.0f, 1.0f, 1.0f); + immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 1.0f); + immUniform1f("size", 15.0f * U.pixelsize); + immBegin(GPU_PRIM_POINTS, 1); + immVertex2f(pos, origin[0], origin[1]); + immEnd(); + immUnbindProgram(); + + /* Outline. */ + float seq_image_quad[4][2]; + SEQ_image_transform_final_quad_get(CTX_data_scene(C), seq, seq_image_quad); + + GPU_line_smooth(true); + GPU_blend(GPU_BLEND_ALPHA); + GPU_line_width(2); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + float col[3]; + if (is_active_seq) { + UI_GetThemeColor3fv(TH_SEQ_ACTIVE, col); + } + else { + UI_GetThemeColor3fv(TH_SEQ_SELECTED, col); + } + immUniformColor3fv(col); + immUniform1f("lineWidth", U.pixelsize); + immBegin(GPU_PRIM_LINE_LOOP, 4); + immVertex2f(pos, seq_image_quad[0][0], seq_image_quad[0][1]); + immVertex2f(pos, seq_image_quad[1][0], seq_image_quad[1][1]); + immVertex2f(pos, seq_image_quad[2][0], seq_image_quad[2][1]); + immVertex2f(pos, seq_image_quad[3][0], seq_image_quad[3][1]); + immEnd(); + immUnbindProgram(); + GPU_line_width(1); + GPU_blend(GPU_BLEND_NONE); + GPU_line_smooth(false); +} + +void sequencer_draw_preview(const bContext *C, + Scene *scene, + ARegion *region, + SpaceSeq *sseq, + int timeline_frame, + int offset, + bool draw_overlay, + bool draw_backdrop) +{ + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C); + View2D *v2d = ®ion->v2d; + ImBuf *ibuf = nullptr; + ImBuf *scope = nullptr; + float viewrect[2]; + const bool show_imbuf = ED_space_sequencer_check_show_imbuf(sseq); + const bool draw_gpencil = ((sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_GPENCIL) && sseq->gpd); + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + + sequencer_stop_running_jobs(C, scene); + if (G.is_rendering) { + return; + } + + int preview_frame = timeline_frame; + if (sequencer_draw_get_transform_preview(sseq, scene)) { + preview_frame = sequencer_draw_get_transform_preview_frame(scene); + } + + /* Get image. */ + ibuf = sequencer_ibuf_get( + bmain, region, depsgraph, scene, sseq, preview_frame, offset, names[sseq->multiview_eye]); + + /* Setup off-screen buffers. */ + GPUViewport *viewport = WM_draw_region_get_viewport(region); + GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport); + GPU_framebuffer_bind_no_srgb(framebuffer_overlay); + GPU_depth_test(GPU_DEPTH_NONE); + + if (sseq->render_size == SEQ_RENDER_SIZE_NONE) { + sequencer_preview_clear(); + return; + } + + /* Setup view. */ + sequencer_display_size(scene, viewrect); + UI_view2d_totRect_set(v2d, roundf(viewrect[0] + 0.5f), roundf(viewrect[1] + 0.5f)); + UI_view2d_curRect_validate(v2d); + UI_view2d_view_ortho(v2d); + + /* Draw background. */ + if (!draw_backdrop && + (!draw_overlay || (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_REFERENCE))) + { + sequencer_preview_clear(); + + if (sseq->flag & SEQ_USE_ALPHA) { + imm_draw_box_checker_2d(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax); + } + } + + if (ibuf) { + scope = sequencer_get_scope(scene, sseq, ibuf, draw_backdrop); + + /* Draw image. */ + sequencer_draw_display_buffer( + C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop); + + /* Draw over image. */ + if (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_METADATA && sseq->flag & SEQ_SHOW_OVERLAY) { + ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0); + } + } + + if (show_imbuf && (sseq->flag & SEQ_SHOW_OVERLAY)) { + sequencer_draw_borders_overlay(sseq, v2d, scene); + } + + if (!draw_backdrop && scene->ed != nullptr) { + Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); + SeqCollection *collection = SEQ_query_rendered_strips( + scene, channels, ed->seqbasep, timeline_frame, 0); + Sequence *seq; + Sequence *active_seq = SEQ_select_active_get(scene); + SEQ_ITERATOR_FOREACH (seq, collection) { + seq_draw_image_origin_and_outline(C, seq, seq == active_seq); + } + SEQ_collection_free(collection); + } + + if (draw_gpencil && show_imbuf && (sseq->flag & SEQ_SHOW_OVERLAY)) { + sequencer_draw_gpencil_overlay(C); + } + +#if 0 + sequencer_draw_maskedit(C, scene, region, sseq); +#endif + + /* Draw registered callbacks. */ + GPU_framebuffer_bind(framebuffer_overlay); + ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW); + GPU_framebuffer_bind_no_srgb(framebuffer_overlay); + + /* Scope is freed in sequencer_check_scopes when `ibuf` changes and redraw is needed. */ + if (ibuf) { + IMB_freeImBuf(ibuf); + } + + UI_view2d_view_restore(C); + seq_prefetch_wm_notify(C, scene); +} diff --git a/source/blender/editors/space_sequencer/sequencer_draw.cc b/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc similarity index 73% rename from source/blender/editors/space_sequencer/sequencer_draw.cc rename to source/blender/editors/space_sequencer/sequencer_timeline_draw.cc index 2bf4485fdac..bc88785c6d3 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc @@ -14,11 +14,6 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "IMB_imbuf_types.h" - -#include "DNA_anim_types.h" -#include "DNA_mask_types.h" -#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sound_types.h" @@ -34,16 +29,12 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf.h" -#include "GPU_framebuffer.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" -#include "GPU_matrix.h" -#include "GPU_state.h" #include "GPU_vertex_buffer.h" #include "GPU_viewport.h" #include "ED_anim_api.hh" -#include "ED_gpencil_legacy.hh" #include "ED_markers.hh" #include "ED_mask.hh" #include "ED_screen.hh" @@ -52,15 +43,12 @@ #include "ED_time_scrub_ui.hh" #include "ED_util.hh" -#include "BIF_glutil.hh" - #include "RNA_prototypes.h" #include "SEQ_channels.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_prefetch.h" -#include "SEQ_proxy.h" #include "SEQ_relations.h" #include "SEQ_render.h" #include "SEQ_select.h" @@ -1540,255 +1528,6 @@ static void draw_effect_inputs_highlight(const Scene *scene, Sequence *seq) GPU_blend(GPU_BLEND_NONE); } -void sequencer_special_update_set(Sequence *seq) -{ - special_seq_update = seq; -} - -Sequence *ED_sequencer_special_preview_get() -{ - return special_seq_update; -} - -void ED_sequencer_special_preview_set(bContext *C, const int mval[2]) -{ - Scene *scene = CTX_data_scene(C); - ARegion *region = CTX_wm_region(C); - int hand; - Sequence *seq; - seq = find_nearest_seq(scene, ®ion->v2d, &hand, mval); - sequencer_special_update_set(seq); -} - -void ED_sequencer_special_preview_clear() -{ - sequencer_special_update_set(nullptr); -} - -ImBuf *sequencer_ibuf_get(Main *bmain, - ARegion *region, - Depsgraph *depsgraph, - Scene *scene, - SpaceSeq *sseq, - int timeline_frame, - int frame_ofs, - const char *viewname) -{ - SeqRenderData context = {nullptr}; - ImBuf *ibuf; - int rectx, recty; - double render_size; - short is_break = G.is_break; - - if (sseq->render_size == SEQ_RENDER_SIZE_NONE) { - return nullptr; - } - - if (sseq->render_size == SEQ_RENDER_SIZE_SCENE) { - render_size = scene->r.size / 100.0; - } - else { - render_size = SEQ_rendersize_to_scale_factor(sseq->render_size); - } - - rectx = roundf(render_size * scene->r.xsch); - recty = roundf(render_size * scene->r.ysch); - - SEQ_render_new_render_data( - bmain, depsgraph, scene, rectx, recty, sseq->render_size, false, &context); - context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); - context.use_proxies = (sseq->flag & SEQ_USE_PROXIES) != 0; - - /* Sequencer could start rendering, in this case we need to be sure it wouldn't be canceled - * by Escape pressed somewhere in the past. */ - G.is_break = false; - - GPUViewport *viewport = WM_draw_region_get_bound_viewport(region); - GPUFrameBuffer *fb = GPU_framebuffer_active_get(); - if (viewport) { - /* Unbind viewport to release the DRW context. */ - GPU_viewport_unbind(viewport); - } - else { - /* Rendering can change OGL context. Save & Restore frame-buffer. */ - GPU_framebuffer_restore(); - } - - if (special_seq_update) { - ibuf = SEQ_render_give_ibuf_direct(&context, timeline_frame + frame_ofs, special_seq_update); - } - else { - ibuf = SEQ_render_give_ibuf(&context, timeline_frame + frame_ofs, sseq->chanshown); - } - - if (viewport) { - /* Follows same logic as wm_draw_window_offscreen to make sure to restore the same - * viewport. */ - int view = (sseq->multiview_eye == STEREO_RIGHT_ID) ? 1 : 0; - GPU_viewport_bind(viewport, view, ®ion->winrct); - } - else if (fb) { - GPU_framebuffer_bind(fb); - } - - /* Restore state so real rendering would be canceled if needed. */ - G.is_break = is_break; - - return ibuf; -} - -static void sequencer_check_scopes(SequencerScopes *scopes, ImBuf *ibuf) -{ - if (scopes->reference_ibuf != ibuf) { - if (scopes->zebra_ibuf) { - IMB_freeImBuf(scopes->zebra_ibuf); - scopes->zebra_ibuf = nullptr; - } - - if (scopes->waveform_ibuf) { - IMB_freeImBuf(scopes->waveform_ibuf); - scopes->waveform_ibuf = nullptr; - } - - if (scopes->sep_waveform_ibuf) { - IMB_freeImBuf(scopes->sep_waveform_ibuf); - scopes->sep_waveform_ibuf = nullptr; - } - - if (scopes->vector_ibuf) { - IMB_freeImBuf(scopes->vector_ibuf); - scopes->vector_ibuf = nullptr; - } - - if (scopes->histogram_ibuf) { - IMB_freeImBuf(scopes->histogram_ibuf); - scopes->histogram_ibuf = nullptr; - } - } -} - -static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scope_fn)(ImBuf *ibuf)) -{ - ImBuf *display_ibuf = IMB_dupImBuf(ibuf); - ImBuf *scope; - - IMB_colormanagement_imbuf_make_display_space( - display_ibuf, &scene->view_settings, &scene->display_settings); - - scope = make_scope_fn(display_ibuf); - - IMB_freeImBuf(display_ibuf); - - return scope; -} - -static void sequencer_display_size(Scene *scene, float r_viewrect[2]) -{ - r_viewrect[0] = float(scene->r.xsch); - r_viewrect[1] = float(scene->r.ysch); - - r_viewrect[0] *= scene->r.xasp / scene->r.yasp; -} - -static void sequencer_draw_gpencil_overlay(const bContext *C) -{ - /* Draw grease-pencil (image aligned). */ - ED_annotation_draw_2dimage(C); - - /* Orthographic at pixel level. */ - UI_view2d_view_restore(C); - - /* Draw grease-pencil (screen aligned). */ - ED_annotation_draw_view2d(C, false); -} - -/** - * Draw content and safety borders. - */ -static void sequencer_draw_borders_overlay(const SpaceSeq *sseq, - const View2D *v2d, - const Scene *scene) -{ - float x1 = v2d->tot.xmin; - float y1 = v2d->tot.ymin; - float x2 = v2d->tot.xmax; - float y2 = v2d->tot.ymax; - - GPU_line_width(1.0f); - - /* Draw border. */ - const uint shdr_pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); - - immUniformThemeColor(TH_BACK); - immUniform1i("colors_len", 0); /* Simple dashes. */ - immUniform1f("dash_width", 6.0f); - immUniform1f("udash_factor", 0.5f); - - imm_draw_box_wire_2d(shdr_pos, x1 - 0.5f, y1 - 0.5f, x2 + 0.5f, y2 + 0.5f); - - /* Draw safety border. */ - if (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_SAFE_MARGINS) { - immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f); - rctf rect; - rect.xmin = x1; - rect.xmax = x2; - rect.ymin = y1; - rect.ymax = y2; - UI_draw_safe_areas(shdr_pos, &rect, scene->safe_areas.title, scene->safe_areas.action); - - if (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_SAFE_CENTER) { - - UI_draw_safe_areas( - shdr_pos, &rect, scene->safe_areas.title_center, scene->safe_areas.action_center); - } - } - - immUnbindProgram(); -} - -#if 0 -void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, SpaceSeq *sseq) -{ - /* NOTE: sequencer mask editing isn't finished, the draw code is working but editing not. - * For now just disable drawing since the strip frame will likely be offset. */ - - // if (sc->mode == SC_MODE_MASKEDIT) - if (0 && sseq->mainb == SEQ_DRAW_IMG_IMBUF) { - Mask *mask = SEQ_active_mask_get(scene); - - if (mask) { - int width, height; - float aspx = 1.0f, aspy = 1.0f; - // ED_mask_get_size(C, &width, &height); - - // Scene *scene = CTX_data_scene(C); - BKE_render_resolution(&scene->r, false, &width, &height); - - ED_mask_draw_region(mask, - region, - 0, - 0, - 0, /* TODO */ - width, - height, - aspx, - aspy, - false, - true, - nullptr, - C); - } - } -} -#endif - /* Force redraw, when prefetching and using cache view. */ static void seq_prefetch_wm_notify(const bContext *C, Scene *scene) { @@ -1797,516 +1536,6 @@ static void seq_prefetch_wm_notify(const bContext *C, Scene *scene) } } -static void *sequencer_OCIO_transform_ibuf(const bContext *C, - ImBuf *ibuf, - bool *r_glsl_used, - eGPUTextureFormat *r_format, - eGPUDataFormat *r_data, - void **r_buffer_cache_handle) -{ - void *display_buffer; - bool force_fallback = false; - *r_glsl_used = false; - force_fallback |= (ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL); - force_fallback |= (ibuf->dither != 0.0f); - - /* Default */ - *r_format = GPU_RGBA8; - *r_data = GPU_DATA_UBYTE; - - /* Fallback to CPU based color space conversion. */ - if (force_fallback) { - *r_glsl_used = false; - display_buffer = nullptr; - } - else if (ibuf->float_buffer.data) { - display_buffer = ibuf->float_buffer.data; - - *r_data = GPU_DATA_FLOAT; - if (ibuf->channels == 4) { - *r_format = GPU_RGBA16F; - } - else if (ibuf->channels == 3) { - /* Alpha is implicitly 1. */ - *r_format = GPU_RGB16F; - } - else { - BLI_assert_msg(0, "Incompatible number of channels for float buffer in sequencer"); - *r_format = GPU_RGBA16F; - display_buffer = nullptr; - } - - if (ibuf->float_buffer.colorspace) { - *r_glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx( - C, ibuf->float_buffer.colorspace, ibuf->dither, true); - } - else { - *r_glsl_used = IMB_colormanagement_setup_glsl_draw_ctx(C, ibuf->dither, true); - } - } - else if (ibuf->byte_buffer.data) { - display_buffer = ibuf->byte_buffer.data; - - *r_glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx( - C, ibuf->byte_buffer.colorspace, ibuf->dither, false); - } - else { - display_buffer = nullptr; - } - - /* There is data to be displayed, but GLSL is not initialized - * properly, in this case we fallback to CPU-based display transform. */ - if ((ibuf->byte_buffer.data || ibuf->float_buffer.data) && !*r_glsl_used) { - display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, r_buffer_cache_handle); - *r_format = GPU_RGBA8; - *r_data = GPU_DATA_UBYTE; - } - - return display_buffer; -} - -static void sequencer_stop_running_jobs(const bContext *C, Scene *scene) -{ - if (G.is_rendering == false && (scene->r.seq_prev_type) == OB_RENDER) { - /* Stop all running jobs, except screen one. Currently previews frustrate Render. - * Need to make so sequencers rendering doesn't conflict with compositor. */ - WM_jobs_kill_type(CTX_wm_manager(C), nullptr, WM_JOB_TYPE_COMPOSITE); - - /* In case of final rendering used for preview, kill all previews, - * otherwise threading conflict will happen in rendering module. */ - WM_jobs_kill_type(CTX_wm_manager(C), nullptr, WM_JOB_TYPE_RENDER_PREVIEW); - } -} - -static void sequencer_preview_clear() -{ - UI_ThemeClearColor(TH_SEQ_PREVIEW); -} - -static void sequencer_preview_get_rect(rctf *preview, - Scene *scene, - ARegion *region, - SpaceSeq *sseq, - bool draw_overlay, - bool draw_backdrop) -{ - View2D *v2d = ®ion->v2d; - float viewrect[2]; - - sequencer_display_size(scene, viewrect); - BLI_rctf_init(preview, -1.0f, 1.0f, -1.0f, 1.0f); - - if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) { - preview->xmax = v2d->tot.xmin + - (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->overlay_frame_rect.xmax); - preview->xmin = v2d->tot.xmin + - (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->overlay_frame_rect.xmin); - preview->ymax = v2d->tot.ymin + - (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->overlay_frame_rect.ymax); - preview->ymin = v2d->tot.ymin + - (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->overlay_frame_rect.ymin); - } - else if (draw_backdrop) { - float aspect = BLI_rcti_size_x(®ion->winrct) / float(BLI_rcti_size_y(®ion->winrct)); - float image_aspect = viewrect[0] / viewrect[1]; - - if (aspect >= image_aspect) { - preview->xmax = image_aspect / aspect; - preview->xmin = -preview->xmax; - } - else { - preview->ymax = aspect / image_aspect; - preview->ymin = -preview->ymax; - } - } - else { - *preview = v2d->tot; - } -} - -static void sequencer_draw_display_buffer(const bContext *C, - Scene *scene, - ARegion *region, - SpaceSeq *sseq, - ImBuf *ibuf, - ImBuf *scope, - bool draw_overlay, - bool draw_backdrop) -{ - void *display_buffer; - void *buffer_cache_handle = nullptr; - - if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { - GPU_blend(GPU_BLEND_ALPHA); - } - - /* Format needs to be created prior to any #immBindShader call. - * Do it here because OCIO binds its own shader. */ - eGPUTextureFormat format; - eGPUDataFormat data; - bool glsl_used = false; - GPUVertFormat *imm_format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint texCoord = GPU_vertformat_attr_add( - imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - if (scope) { - ibuf = scope; - - if (ibuf->float_buffer.data && ibuf->byte_buffer.data == nullptr) { - IMB_rect_from_float(ibuf); - } - - display_buffer = ibuf->byte_buffer.data; - format = GPU_RGBA8; - data = GPU_DATA_UBYTE; - } - else { - display_buffer = sequencer_OCIO_transform_ibuf( - C, ibuf, &glsl_used, &format, &data, &buffer_cache_handle); - } - - if (draw_backdrop) { - GPU_matrix_push(); - GPU_matrix_identity_set(); - GPU_matrix_push_projection(); - GPU_matrix_identity_projection_set(); - } - eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT; - GPUTexture *texture = GPU_texture_create_2d( - "seq_display_buf", ibuf->x, ibuf->y, 1, format, usage, nullptr); - GPU_texture_update(texture, data, display_buffer); - GPU_texture_filter_mode(texture, false); - - GPU_texture_bind(texture, 0); - - if (!glsl_used) { - immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR); - immUniformColor3f(1.0f, 1.0f, 1.0f); - } - - immBegin(GPU_PRIM_TRI_FAN, 4); - - rctf preview; - rctf canvas; - sequencer_preview_get_rect(&preview, scene, region, sseq, draw_overlay, draw_backdrop); - - if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) { - canvas = scene->ed->overlay_frame_rect; - } - else { - BLI_rctf_init(&canvas, 0.0f, 1.0f, 0.0f, 1.0f); - } - - immAttr2f(texCoord, canvas.xmin, canvas.ymin); - immVertex2f(pos, preview.xmin, preview.ymin); - - immAttr2f(texCoord, canvas.xmin, canvas.ymax); - immVertex2f(pos, preview.xmin, preview.ymax); - - immAttr2f(texCoord, canvas.xmax, canvas.ymax); - immVertex2f(pos, preview.xmax, preview.ymax); - - immAttr2f(texCoord, canvas.xmax, canvas.ymin); - immVertex2f(pos, preview.xmax, preview.ymin); - - immEnd(); - - GPU_texture_unbind(texture); - GPU_texture_free(texture); - - if (!glsl_used) { - immUnbindProgram(); - } - else { - IMB_colormanagement_finish_glsl_draw(); - } - - if (buffer_cache_handle) { - IMB_display_buffer_release(buffer_cache_handle); - } - - if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { - GPU_blend(GPU_BLEND_NONE); - } - - if (draw_backdrop) { - GPU_matrix_pop(); - GPU_matrix_pop_projection(); - } -} - -static ImBuf *sequencer_get_scope(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, bool draw_backdrop) -{ - ImBuf *scope = nullptr; - SequencerScopes *scopes = &sseq->scopes; - - if (!draw_backdrop && (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0)) { - sequencer_check_scopes(scopes, ibuf); - - switch (sseq->mainb) { - case SEQ_DRAW_IMG_IMBUF: - if (!scopes->zebra_ibuf) { - ImBuf *display_ibuf = IMB_dupImBuf(ibuf); - - if (display_ibuf->float_buffer.data) { - IMB_colormanagement_imbuf_make_display_space( - display_ibuf, &scene->view_settings, &scene->display_settings); - } - scopes->zebra_ibuf = make_zebra_view_from_ibuf(display_ibuf, sseq->zebra); - IMB_freeImBuf(display_ibuf); - } - scope = scopes->zebra_ibuf; - break; - case SEQ_DRAW_IMG_WAVEFORM: - if ((sseq->flag & SEQ_DRAW_COLOR_SEPARATED) != 0) { - if (!scopes->sep_waveform_ibuf) { - scopes->sep_waveform_ibuf = sequencer_make_scope( - scene, ibuf, make_sep_waveform_view_from_ibuf); - } - scope = scopes->sep_waveform_ibuf; - } - else { - if (!scopes->waveform_ibuf) { - scopes->waveform_ibuf = sequencer_make_scope( - scene, ibuf, make_waveform_view_from_ibuf); - } - scope = scopes->waveform_ibuf; - } - break; - case SEQ_DRAW_IMG_VECTORSCOPE: - if (!scopes->vector_ibuf) { - scopes->vector_ibuf = sequencer_make_scope(scene, ibuf, make_vectorscope_view_from_ibuf); - } - scope = scopes->vector_ibuf; - break; - case SEQ_DRAW_IMG_HISTOGRAM: - if (!scopes->histogram_ibuf) { - scopes->histogram_ibuf = sequencer_make_scope( - scene, ibuf, make_histogram_view_from_ibuf); - } - scope = scopes->histogram_ibuf; - break; - } - - /* Future files may have new scopes we don't catch above. */ - if (scope) { - scopes->reference_ibuf = ibuf; - } - } - return scope; -} - -static bool sequencer_draw_get_transform_preview(SpaceSeq *sseq, Scene *scene) -{ - Sequence *last_seq = SEQ_select_active_get(scene); - if (last_seq == nullptr) { - return false; - } - - return (G.moving & G_TRANSFORM_SEQ) && (last_seq->flag & SELECT) && - ((last_seq->flag & SEQ_LEFTSEL) || (last_seq->flag & SEQ_RIGHTSEL)) && - (sseq->draw_flag & SEQ_DRAW_TRANSFORM_PREVIEW); -} - -static int sequencer_draw_get_transform_preview_frame(Scene *scene) -{ - Sequence *last_seq = SEQ_select_active_get(scene); - /* #sequencer_draw_get_transform_preview must already have been called. */ - BLI_assert(last_seq != nullptr); - int preview_frame; - - if (last_seq->flag & SEQ_RIGHTSEL) { - preview_frame = SEQ_time_right_handle_frame_get(scene, last_seq) - 1; - } - else { - preview_frame = SEQ_time_left_handle_frame_get(scene, last_seq); - } - - return preview_frame; -} - -static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq, bool is_active_seq) -{ - SpaceSeq *sseq = CTX_wm_space_seq(C); - const ARegion *region = CTX_wm_region(C); - if (region->regiontype == RGN_TYPE_PREVIEW && !sequencer_view_preview_only_poll(C)) { - return; - } - if ((seq->flag & SELECT) == 0) { - return; - } - if (ED_screen_animation_no_scrub(CTX_wm_manager(C))) { - return; - } - if ((sseq->flag & SEQ_SHOW_OVERLAY) == 0 || - (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_OUTLINE_SELECTED) == 0) - { - return; - } - if (ELEM(sseq->mainb, SEQ_DRAW_IMG_WAVEFORM, SEQ_DRAW_IMG_VECTORSCOPE, SEQ_DRAW_IMG_HISTOGRAM)) { - return; - } - - float origin[2]; - SEQ_image_transform_origin_offset_pixelspace_get(CTX_data_scene(C), seq, origin); - - /* Origin. */ - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA); - immUniform1f("outlineWidth", 1.5f); - immUniformColor3f(1.0f, 1.0f, 1.0f); - immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 1.0f); - immUniform1f("size", 15.0f * U.pixelsize); - immBegin(GPU_PRIM_POINTS, 1); - immVertex2f(pos, origin[0], origin[1]); - immEnd(); - immUnbindProgram(); - - /* Outline. */ - float seq_image_quad[4][2]; - SEQ_image_transform_final_quad_get(CTX_data_scene(C), seq, seq_image_quad); - - GPU_line_smooth(true); - GPU_blend(GPU_BLEND_ALPHA); - GPU_line_width(2); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - float col[3]; - if (is_active_seq) { - UI_GetThemeColor3fv(TH_SEQ_ACTIVE, col); - } - else { - UI_GetThemeColor3fv(TH_SEQ_SELECTED, col); - } - immUniformColor3fv(col); - immUniform1f("lineWidth", U.pixelsize); - immBegin(GPU_PRIM_LINE_LOOP, 4); - immVertex2f(pos, seq_image_quad[0][0], seq_image_quad[0][1]); - immVertex2f(pos, seq_image_quad[1][0], seq_image_quad[1][1]); - immVertex2f(pos, seq_image_quad[2][0], seq_image_quad[2][1]); - immVertex2f(pos, seq_image_quad[3][0], seq_image_quad[3][1]); - immEnd(); - immUnbindProgram(); - GPU_line_width(1); - GPU_blend(GPU_BLEND_NONE); - GPU_line_smooth(false); -} - -void sequencer_draw_preview(const bContext *C, - Scene *scene, - ARegion *region, - SpaceSeq *sseq, - int timeline_frame, - int offset, - bool draw_overlay, - bool draw_backdrop) -{ - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C); - View2D *v2d = ®ion->v2d; - ImBuf *ibuf = nullptr; - ImBuf *scope = nullptr; - float viewrect[2]; - const bool show_imbuf = ED_space_sequencer_check_show_imbuf(sseq); - const bool draw_gpencil = ((sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_GPENCIL) && sseq->gpd); - const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - - sequencer_stop_running_jobs(C, scene); - if (G.is_rendering) { - return; - } - - int preview_frame = timeline_frame; - if (sequencer_draw_get_transform_preview(sseq, scene)) { - preview_frame = sequencer_draw_get_transform_preview_frame(scene); - } - - /* Get image. */ - ibuf = sequencer_ibuf_get( - bmain, region, depsgraph, scene, sseq, preview_frame, offset, names[sseq->multiview_eye]); - - /* Setup off-screen buffers. */ - GPUViewport *viewport = WM_draw_region_get_viewport(region); - GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport); - GPU_framebuffer_bind_no_srgb(framebuffer_overlay); - GPU_depth_test(GPU_DEPTH_NONE); - - if (sseq->render_size == SEQ_RENDER_SIZE_NONE) { - sequencer_preview_clear(); - return; - } - - /* Setup view. */ - sequencer_display_size(scene, viewrect); - UI_view2d_totRect_set(v2d, roundf(viewrect[0] + 0.5f), roundf(viewrect[1] + 0.5f)); - UI_view2d_curRect_validate(v2d); - UI_view2d_view_ortho(v2d); - - /* Draw background. */ - if (!draw_backdrop && - (!draw_overlay || (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_REFERENCE))) - { - sequencer_preview_clear(); - - if (sseq->flag & SEQ_USE_ALPHA) { - imm_draw_box_checker_2d(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax); - } - } - - if (ibuf) { - scope = sequencer_get_scope(scene, sseq, ibuf, draw_backdrop); - - /* Draw image. */ - sequencer_draw_display_buffer( - C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop); - - /* Draw over image. */ - if (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_METADATA && sseq->flag & SEQ_SHOW_OVERLAY) { - ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0); - } - } - - if (show_imbuf && (sseq->flag & SEQ_SHOW_OVERLAY)) { - sequencer_draw_borders_overlay(sseq, v2d, scene); - } - - if (!draw_backdrop && scene->ed != nullptr) { - Editing *ed = SEQ_editing_get(scene); - ListBase *channels = SEQ_channels_displayed_get(ed); - SeqCollection *collection = SEQ_query_rendered_strips( - scene, channels, ed->seqbasep, timeline_frame, 0); - Sequence *seq; - Sequence *active_seq = SEQ_select_active_get(scene); - SEQ_ITERATOR_FOREACH (seq, collection) { - seq_draw_image_origin_and_outline(C, seq, seq == active_seq); - } - SEQ_collection_free(collection); - } - - if (draw_gpencil && show_imbuf && (sseq->flag & SEQ_SHOW_OVERLAY)) { - sequencer_draw_gpencil_overlay(C); - } - -#if 0 - sequencer_draw_maskedit(C, scene, region, sseq); -#endif - - /* Draw registered callbacks. */ - GPU_framebuffer_bind(framebuffer_overlay); - ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW); - GPU_framebuffer_bind_no_srgb(framebuffer_overlay); - - /* Scope is freed in sequencer_check_scopes when `ibuf` changes and redraw is needed. */ - if (ibuf) { - IMB_freeImBuf(ibuf); - } - - UI_view2d_view_restore(C); - seq_prefetch_wm_notify(C, scene); -} - static void draw_seq_timeline_channels(View2D *v2d) { uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);