VSE: Scopes improvements #116798
|
@ -50,7 +50,7 @@ struct SpaceSeq_Runtime {
|
|||
int rename_channel_index = 0;
|
||||
float timeline_clamp_custom_range = 0;
|
||||
|
||||
SequencerScopes scopes;
|
||||
blender::ed::seq::SeqScopes scopes;
|
||||
|
||||
SpaceSeq_Runtime() = default;
|
||||
SpaceSeq_Runtime(const SpaceSeq_Runtime &) = delete;
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "WM_types.hh"
|
||||
|
||||
#include "sequencer_intern.hh"
|
||||
#include "sequencer_quads_batch.hh"
|
||||
#include "sequencer_scopes.hh"
|
||||
|
||||
static Sequence *special_seq_update = nullptr;
|
||||
|
@ -158,36 +159,6 @@ ImBuf *sequencer_ibuf_get(Main *bmain,
|
|||
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);
|
||||
|
@ -451,11 +422,9 @@ static void sequencer_draw_display_buffer(const bContext *C,
|
|||
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) {
|
||||
|
@ -472,21 +441,8 @@ static void sequencer_draw_display_buffer(const bContext *C,
|
|||
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);
|
||||
}
|
||||
void *display_buffer = sequencer_OCIO_transform_ibuf(
|
||||
C, ibuf, &glsl_used, &format, &data, &buffer_cache_handle);
|
||||
|
||||
if (draw_backdrop) {
|
||||
GPU_matrix_push();
|
||||
|
@ -558,68 +514,219 @@ static void sequencer_draw_display_buffer(const bContext *C,
|
|||
}
|
||||
}
|
||||
|
||||
static ImBuf *sequencer_get_scope(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, bool draw_backdrop)
|
||||
static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist,
|
||||
SeqQuadsBatch &quads,
|
||||
const rctf &area)
|
||||
{
|
||||
ImBuf *scope = nullptr;
|
||||
SequencerScopes *scopes = &sseq->runtime->scopes;
|
||||
if (hist.data.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!draw_backdrop && (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0)) {
|
||||
sequencer_check_scopes(scopes, ibuf);
|
||||
uchar col_grid[4] = {128, 128, 128, 128};
|
||||
|
||||
switch (sseq->mainb) {
|
||||
case SEQ_DRAW_IMG_IMBUF:
|
||||
if (!scopes->zebra_ibuf) {
|
||||
/* Grid lines. */
|
||||
float grid_x_0 = area.xmin;
|
||||
float grid_x_1 = area.xmax;
|
||||
if (hist.data.size() > 256) {
|
||||
grid_x_0 = area.xmin + (area.xmax - area.xmin) * (0.25f / 1.5f);
|
||||
grid_x_1 = area.xmin + (area.xmax - area.xmin) * (1.25f / 1.5f);
|
||||
}
|
||||
for (int line = 0; line <= 4; line++) {
|
||||
float x = grid_x_0 + (grid_x_1 - grid_x_0) * line / 4;
|
||||
quads.add_line(x, area.ymin, x, area.ymax, col_grid);
|
||||
}
|
||||
|
||||
if (ibuf->float_buffer.data) {
|
||||
ImBuf *display_ibuf = IMB_dupImBuf(ibuf);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
scopes->zebra_ibuf = make_zebra_view_from_ibuf(ibuf, sseq->zebra);
|
||||
}
|
||||
}
|
||||
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;
|
||||
/* Histogram area & line for each R/G/B channels, additively blended. */
|
||||
quads.draw();
|
||||
GPU_blend(GPU_BLEND_ADDITIVE);
|
||||
for (int ch = 0; ch < 3; ++ch) {
|
||||
if (hist.max_value[ch] == 0) {
|
||||
continue;
|
||||
}
|
||||
uchar col_line[4] = {32, 32, 32, 255};
|
||||
uchar col_area[4] = {64, 64, 64, 128};
|
||||
col_line[ch] = 224;
|
||||
col_area[ch] = 224;
|
||||
float y_scale = (area.ymax - area.ymin) / hist.max_value[ch] * 0.95f;
|
||||
float x_scale = (area.xmax - area.xmin) / hist.data.size();
|
||||
float yb = area.ymin;
|
||||
for (int bin = 0; bin < hist.data.size() - 1; bin++) {
|
||||
float x0 = area.xmin + (bin + 0.5f) * x_scale;
|
||||
float x1 = area.xmin + (bin + 1.5f) * x_scale;
|
||||
|
||||
aras_p marked this conversation as resolved
|
||||
/* Future files may have new scopes we don't catch above. */
|
||||
if (scope) {
|
||||
scopes->reference_ibuf = ibuf;
|
||||
float y0 = area.ymin + hist.data[bin][ch] * y_scale;
|
||||
float y1 = area.ymin + hist.data[bin + 1][ch] * y_scale;
|
||||
quads.add_quad(x0, yb, x0, y0, x1, yb, x1, y1, col_area);
|
||||
quads.add_line(x0, y0, x1, y1, col_line);
|
||||
}
|
||||
}
|
||||
return scope;
|
||||
quads.draw();
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
}
|
||||
|
||||
static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, bool draw_overlay)
|
||||
{
|
||||
using namespace blender::ed::seq;
|
||||
|
||||
/* Figure out draw coordinates. */
|
||||
rctf preview;
|
||||
rctf canvas;
|
||||
sequencer_preview_get_rect(&preview, scene, region, sseq, draw_overlay, false);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
SeqQuadsBatch quads;
|
||||
SeqScopes *scopes = &sseq->runtime->scopes;
|
||||
|
||||
/* Draw scope image if there is one. */
|
||||
bool use_blend = sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA;
|
||||
ImBuf *scope_image = nullptr;
|
||||
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
|
||||
scope_image = scopes->zebra_ibuf;
|
||||
}
|
||||
else if (sseq->mainb == SEQ_DRAW_IMG_WAVEFORM) {
|
||||
scope_image = (sseq->flag & SEQ_DRAW_COLOR_SEPARATED) != 0 ? scopes->sep_waveform_ibuf :
|
||||
scopes->waveform_ibuf;
|
||||
}
|
||||
else if (sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE) {
|
||||
scope_image = scopes->vector_ibuf;
|
||||
}
|
||||
else if (sseq->mainb == SEQ_DRAW_IMG_HISTOGRAM) {
|
||||
use_blend = true;
|
||||
}
|
||||
|
||||
if (use_blend) {
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
}
|
||||
|
||||
if (scope_image != nullptr) {
|
||||
if (scope_image->float_buffer.data && scope_image->byte_buffer.data == nullptr) {
|
||||
IMB_rect_from_float(scope_image);
|
||||
}
|
||||
|
||||
eGPUTextureFormat format = GPU_RGBA8;
|
||||
eGPUDataFormat data = GPU_DATA_UBYTE;
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
|
||||
GPUTexture *texture = GPU_texture_create_2d(
|
||||
"seq_display_buf", scope_image->x, scope_image->y, 1, format, usage, nullptr);
|
||||
GPU_texture_update(texture, data, scope_image->byte_buffer.data);
|
||||
GPU_texture_filter_mode(texture, false);
|
||||
|
||||
aras_p marked this conversation as resolved
Richard Antalik
commented
Use Use `BLI_snprintf()`
|
||||
GPU_texture_bind(texture, 0);
|
||||
|
||||
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);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR);
|
||||
immUniformColor3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
immBegin(GPU_PRIM_TRI_FAN, 4);
|
||||
|
||||
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);
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
|
||||
uchar col_bg[4] = {0, 0, 0, 255};
|
||||
uchar col_border[4] = {0, 160, 0, 255};
|
||||
if (scope_image == nullptr) {
|
||||
quads.add_quad(preview.xmin, preview.ymin, preview.xmax, preview.ymax, col_bg);
|
||||
}
|
||||
|
||||
if (sseq->mainb == SEQ_DRAW_IMG_HISTOGRAM) {
|
||||
draw_histogram(scopes->histogram, quads, preview);
|
||||
}
|
||||
|
||||
if (scope_image == nullptr) {
|
||||
quads.add_wire_quad(preview.xmin, preview.ymin, preview.xmax, preview.ymax, col_border);
|
||||
}
|
||||
quads.draw();
|
||||
|
||||
if (use_blend) {
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sequencer_calc_scopes(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, bool draw_backdrop)
|
||||
{
|
||||
using namespace blender::ed::seq;
|
||||
|
||||
if (draw_backdrop || (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->zebra == 0)) {
|
||||
return false; /* Not drawing any scopes. */
|
||||
}
|
||||
|
||||
SeqScopes *scopes = &sseq->runtime->scopes;
|
||||
if (scopes->reference_ibuf != ibuf) {
|
||||
scopes->cleanup();
|
||||
}
|
||||
|
||||
switch (sseq->mainb) {
|
||||
case SEQ_DRAW_IMG_IMBUF:
|
||||
if (!scopes->zebra_ibuf) {
|
||||
|
||||
if (ibuf->float_buffer.data) {
|
||||
ImBuf *display_ibuf = IMB_dupImBuf(ibuf);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
scopes->zebra_ibuf = make_zebra_view_from_ibuf(ibuf, sseq->zebra);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!scopes->waveform_ibuf) {
|
||||
scopes->waveform_ibuf = sequencer_make_scope(scene, ibuf, make_waveform_view_from_ibuf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SEQ_DRAW_IMG_VECTORSCOPE:
|
||||
if (!scopes->vector_ibuf) {
|
||||
scopes->vector_ibuf = sequencer_make_scope(scene, ibuf, make_vectorscope_view_from_ibuf);
|
||||
}
|
||||
break;
|
||||
case SEQ_DRAW_IMG_HISTOGRAM: {
|
||||
ImBuf *display_ibuf = IMB_dupImBuf(ibuf);
|
||||
IMB_colormanagement_imbuf_make_display_space(
|
||||
display_ibuf, &scene->view_settings, &scene->display_settings);
|
||||
scopes->histogram.calc_from_ibuf(display_ibuf);
|
||||
IMB_freeImBuf(display_ibuf);
|
||||
} break;
|
||||
default: /* Future files might have scopes we don't know about. */
|
||||
return false;
|
||||
}
|
||||
scopes->reference_ibuf = ibuf;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sequencer_draw_get_transform_preview(SpaceSeq *sseq, Scene *scene)
|
||||
|
@ -732,7 +839,6 @@ void sequencer_draw_preview(const bContext *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);
|
||||
|
@ -781,13 +887,17 @@ void sequencer_draw_preview(const bContext *C,
|
|||
}
|
||||
|
||||
if (ibuf) {
|
||||
scope = sequencer_get_scope(scene, sseq, ibuf, draw_backdrop);
|
||||
bool has_scope = sequencer_calc_scopes(scene, sseq, ibuf, draw_backdrop);
|
||||
if (has_scope) {
|
||||
/* Draw scope. */
|
||||
sequencer_draw_scopes(scene, region, sseq, draw_overlay);
|
||||
}
|
||||
else {
|
||||
/* Draw image. */
|
||||
sequencer_draw_display_buffer(C, scene, region, sseq, ibuf, draw_overlay, draw_backdrop);
|
||||
}
|
||||
|
||||
/* Draw image. */
|
||||
sequencer_draw_display_buffer(
|
||||
C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop);
|
||||
|
||||
/* Draw over image. */
|
||||
/* Draw metadata. */
|
||||
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);
|
||||
}
|
||||
|
@ -821,7 +931,6 @@ void sequencer_draw_preview(const bContext *C,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
@ -25,23 +26,32 @@
|
|||
# include "BLI_timeit.hh"
|
||||
#endif
|
||||
|
||||
SequencerScopes::~SequencerScopes()
|
||||
namespace blender::ed::seq {
|
||||
|
||||
SeqScopes::~SeqScopes()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void SeqScopes::cleanup()
|
||||
{
|
||||
if (zebra_ibuf) {
|
||||
IMB_freeImBuf(zebra_ibuf);
|
||||
zebra_ibuf = nullptr;
|
||||
}
|
||||
if (waveform_ibuf) {
|
||||
IMB_freeImBuf(waveform_ibuf);
|
||||
waveform_ibuf = nullptr;
|
||||
}
|
||||
if (sep_waveform_ibuf) {
|
||||
IMB_freeImBuf(sep_waveform_ibuf);
|
||||
sep_waveform_ibuf = nullptr;
|
||||
}
|
||||
if (vector_ibuf) {
|
||||
IMB_freeImBuf(vector_ibuf);
|
||||
vector_ibuf = nullptr;
|
||||
}
|
||||
if (histogram_ibuf) {
|
||||
IMB_freeImBuf(histogram_ibuf);
|
||||
}
|
||||
histogram.data.reinitialize(0);
|
||||
}
|
||||
|
||||
/* XXX(@ideasman42): why is this function better than BLI_math version?
|
||||
|
@ -459,127 +469,7 @@ ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc)
|
|||
return new_ibuf;
|
||||
}
|
||||
|
||||
static void draw_histogram_marker(ImBuf *ibuf, int x)
|
||||
{
|
||||
uchar *p = ibuf->byte_buffer.data;
|
||||
int barh = ibuf->y * 0.1;
|
||||
|
||||
p += 4 * (x + ibuf->x * (ibuf->y - barh + 1));
|
||||
|
||||
for (int i = 0; i < barh - 1; i++) {
|
||||
p[0] = p[1] = p[2] = 255;
|
||||
p += ibuf->x * 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
|
||||
{
|
||||
uchar *p = ibuf->byte_buffer.data;
|
||||
int barh = ibuf->y * val * 0.9f;
|
||||
|
||||
p += 4 * (x + ibuf->x);
|
||||
|
||||
for (int i = 0; i < barh; i++) {
|
||||
p[col] = 255;
|
||||
p += ibuf->x * 4;
|
||||
}
|
||||
}
|
||||
|
||||
#define HIS_STEPS 512
|
||||
|
||||
struct MakeHistogramViewData {
|
||||
const ImBuf *ibuf;
|
||||
};
|
||||
|
||||
static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata,
|
||||
const int y,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
const MakeHistogramViewData *data = static_cast<MakeHistogramViewData *>(userdata);
|
||||
const ImBuf *ibuf = data->ibuf;
|
||||
const uchar *src = ibuf->byte_buffer.data;
|
||||
|
||||
uint32_t(*cur_bins)[HIS_STEPS] = static_cast<uint32_t(*)[HIS_STEPS]>(tls->userdata_chunk);
|
||||
|
||||
for (int x = 0; x < ibuf->x; x++) {
|
||||
const uchar *pixel = src + (y * ibuf->x + x) * 4;
|
||||
|
||||
for (int j = 3; j--;) {
|
||||
cur_bins[j][pixel[j]]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void make_histogram_view_from_ibuf_reduce(const void *__restrict /*userdata*/,
|
||||
void *__restrict chunk_join,
|
||||
void *__restrict chunk)
|
||||
{
|
||||
uint32_t(*join_bins)[HIS_STEPS] = static_cast<uint32_t(*)[HIS_STEPS]>(chunk_join);
|
||||
uint32_t(*bins)[HIS_STEPS] = static_cast<uint32_t(*)[HIS_STEPS]>(chunk);
|
||||
for (int j = 3; j--;) {
|
||||
for (int i = 0; i < HIS_STEPS; i++) {
|
||||
join_bins[j][i] += bins[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
|
||||
{
|
||||
#ifdef DEBUG_TIME
|
||||
SCOPED_TIMER_AVERAGED(__func__);
|
||||
#endif
|
||||
ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
|
||||
int x;
|
||||
uint nr, ng, nb;
|
||||
|
||||
uint bins[3][HIS_STEPS];
|
||||
|
||||
memset(bins, 0, sizeof(bins));
|
||||
|
||||
MakeHistogramViewData data{};
|
||||
data.ibuf = ibuf;
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (ibuf->y >= 256);
|
||||
settings.userdata_chunk = bins;
|
||||
settings.userdata_chunk_size = sizeof(bins);
|
||||
settings.func_reduce = make_histogram_view_from_ibuf_reduce;
|
||||
BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_fn, &settings);
|
||||
|
||||
nr = nb = ng = 0;
|
||||
for (x = 0; x < HIS_STEPS; x++) {
|
||||
if (bins[0][x] > nr) {
|
||||
nr = bins[0][x];
|
||||
}
|
||||
if (bins[1][x] > ng) {
|
||||
ng = bins[1][x];
|
||||
}
|
||||
if (bins[2][x] > nb) {
|
||||
nb = bins[2][x];
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < HIS_STEPS; x++) {
|
||||
if (nr) {
|
||||
draw_histogram_bar(rval, x * 2 + 1, float(bins[0][x]) / nr, 0);
|
||||
draw_histogram_bar(rval, x * 2 + 2, float(bins[0][x]) / nr, 0);
|
||||
}
|
||||
if (ng) {
|
||||
draw_histogram_bar(rval, x * 2 + 1, float(bins[1][x]) / ng, 1);
|
||||
draw_histogram_bar(rval, x * 2 + 2, float(bins[1][x]) / ng, 1);
|
||||
}
|
||||
if (nb) {
|
||||
draw_histogram_bar(rval, x * 2 + 1, float(bins[2][x]) / nb, 2);
|
||||
draw_histogram_bar(rval, x * 2 + 2, float(bins[2][x]) / nb, 2);
|
||||
}
|
||||
}
|
||||
|
||||
wform_put_border(rval->byte_buffer.data, rval->x, rval->y);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
BLI_INLINE int get_bin_float(float f)
|
||||
static int get_bin_float(float f)
|
||||
{
|
||||
if (f < -0.25f) {
|
||||
return 0;
|
||||
|
@ -587,92 +477,65 @@ BLI_INLINE int get_bin_float(float f)
|
|||
if (f >= 1.25f) {
|
||||
return 511;
|
||||
}
|
||||
|
||||
return int(((f + 0.25f) / 1.5f) * 512);
|
||||
}
|
||||
|
||||
static void make_histogram_view_from_ibuf_float_fn(void *__restrict userdata,
|
||||
const int y,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
const MakeHistogramViewData *data = static_cast<const MakeHistogramViewData *>(userdata);
|
||||
const ImBuf *ibuf = static_cast<const ImBuf *>(data->ibuf);
|
||||
const float *src = ibuf->float_buffer.data;
|
||||
|
||||
uint32_t(*cur_bins)[HIS_STEPS] = static_cast<uint32_t(*)[HIS_STEPS]>(tls->userdata_chunk);
|
||||
|
||||
for (int x = 0; x < ibuf->x; x++) {
|
||||
const float *pixel = src + (y * ibuf->x + x) * 4;
|
||||
|
||||
for (int j = 3; j--;) {
|
||||
cur_bins[j][get_bin_float(pixel[j])]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
|
||||
void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf)
|
||||
{
|
||||
#ifdef DEBUG_TIME
|
||||
SCOPED_TIMER_AVERAGED(__func__);
|
||||
#endif
|
||||
ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
|
||||
int nr, ng, nb;
|
||||
int x;
|
||||
|
||||
uint bins[3][HIS_STEPS];
|
||||
const bool is_float = ibuf->float_buffer.data != nullptr;
|
||||
const int hist_size = is_float ? 512 : 256;
|
||||
|
||||
memset(bins, 0, sizeof(bins));
|
||||
Array<uint3> counts(hist_size, uint3(0));
|
||||
data = threading::parallel_reduce(
|
||||
IndexRange(ibuf->y),
|
||||
256,
|
||||
counts,
|
||||
[&](const IndexRange y_range, const Array<uint3> &init) {
|
||||
Array<uint3> res = init;
|
||||
|
||||
MakeHistogramViewData data{};
|
||||
data.ibuf = ibuf;
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (ibuf->y >= 256);
|
||||
settings.userdata_chunk = bins;
|
||||
settings.userdata_chunk_size = sizeof(bins);
|
||||
settings.func_reduce = make_histogram_view_from_ibuf_reduce;
|
||||
BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_fn, &settings);
|
||||
if (is_float) {
|
||||
/* Float images spead -0.25..+1.25 range over 512 bins. */
|
||||
for (const int y : y_range) {
|
||||
const float *src = ibuf->float_buffer.data + y * ibuf->x * 4;
|
||||
for (int x = 0; x < ibuf->x; x++) {
|
||||
res[get_bin_float(src[0])].x++;
|
||||
res[get_bin_float(src[1])].y++;
|
||||
res[get_bin_float(src[2])].z++;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Byte images just use 256 histogram bins, directly indexed by value. */
|
||||
for (const int y : y_range) {
|
||||
const uchar *src = ibuf->byte_buffer.data + y * ibuf->x * 4;
|
||||
for (int x = 0; x < ibuf->x; x++) {
|
||||
res[src[0]].x++;
|
||||
res[src[1]].y++;
|
||||
res[src[2]].z++;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
},
|
||||
[&](const Array<uint3> &a, const Array<uint3> &b) {
|
||||
BLI_assert(a.size() == b.size());
|
||||
Array<uint3> res(a.size());
|
||||
for (int i = 0; i < a.size(); i++) {
|
||||
res[i] = a[i] + b[i];
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
nr = nb = ng = 0;
|
||||
for (x = 0; x < HIS_STEPS; x++) {
|
||||
if (bins[0][x] > nr) {
|
||||
nr = bins[0][x];
|
||||
}
|
||||
if (bins[1][x] > ng) {
|
||||
ng = bins[1][x];
|
||||
}
|
||||
if (bins[2][x] > nb) {
|
||||
nb = bins[2][x];
|
||||
}
|
||||
max_value = uint3(0);
|
||||
for (const uint3 &v : data) {
|
||||
max_value = math::max(max_value, v);
|
||||
}
|
||||
|
||||
for (x = 0; x < HIS_STEPS; x++) {
|
||||
if (nr) {
|
||||
draw_histogram_bar(rval, x + 1, float(bins[0][x]) / nr, 0);
|
||||
}
|
||||
if (ng) {
|
||||
draw_histogram_bar(rval, x + 1, float(bins[1][x]) / ng, 1);
|
||||
}
|
||||
if (nb) {
|
||||
draw_histogram_bar(rval, x + 1, float(bins[2][x]) / nb, 2);
|
||||
}
|
||||
}
|
||||
|
||||
draw_histogram_marker(rval, get_bin_float(0.0));
|
||||
draw_histogram_marker(rval, get_bin_float(1.0));
|
||||
wform_put_border(rval->byte_buffer.data, rval->x, rval->y);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
#undef HIS_STEPS
|
||||
|
||||
ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf)
|
||||
{
|
||||
if (ibuf->float_buffer.data) {
|
||||
return make_histogram_view_from_ibuf_float(ibuf);
|
||||
}
|
||||
return make_histogram_view_from_ibuf_byte(ibuf);
|
||||
}
|
||||
|
||||
static void vectorscope_put_cross(uchar r, uchar g, uchar b, uchar *tgt, int w, int h, int size)
|
||||
|
@ -806,3 +669,5 @@ ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf)
|
|||
}
|
||||
return make_vectorscope_view_from_ibuf_byte(ibuf);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::seq
|
||||
|
|
|
@ -8,24 +8,40 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
struct ImBuf;
|
||||
|
||||
struct SequencerScopes {
|
||||
SequencerScopes() = default;
|
||||
~SequencerScopes();
|
||||
SequencerScopes(const SequencerScopes &) = delete;
|
||||
void operator=(const SequencerScopes &) = delete;
|
||||
namespace blender::ed::seq {
|
||||
|
||||
struct ScopeHistogram {
|
||||
Array<uint3> data;
|
||||
uint3 max_value;
|
||||
|
||||
void calc_from_ibuf(const ImBuf *ibuf);
|
||||
};
|
||||
|
||||
struct SeqScopes {
|
||||
SeqScopes() = default;
|
||||
~SeqScopes();
|
||||
SeqScopes(const SeqScopes &) = delete;
|
||||
void operator=(const SeqScopes &) = delete;
|
||||
|
||||
void cleanup();
|
||||
|
||||
ImBuf *reference_ibuf = nullptr;
|
||||
ImBuf *zebra_ibuf = nullptr;
|
||||
ImBuf *waveform_ibuf = nullptr;
|
||||
ImBuf *sep_waveform_ibuf = nullptr;
|
||||
ImBuf *vector_ibuf = nullptr;
|
||||
ImBuf *histogram_ibuf = nullptr;
|
||||
|
||||
ScopeHistogram histogram;
|
||||
};
|
||||
|
||||
ImBuf *make_waveform_view_from_ibuf(ImBuf *ibuf);
|
||||
ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf);
|
||||
ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf);
|
||||
ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc);
|
||||
ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf);
|
||||
|
||||
} // namespace blender::ed::seq
|
||||
|
|
Loading…
Reference in New Issue
Use
BLI_snprintf()