diff --git a/rtdata/languages/default b/rtdata/languages/default index 307417524..069c87050 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -249,7 +249,7 @@ HISTOGRAM_TOOLTIP_L;Show/Hide CIELab luminance histogram. HISTOGRAM_TOOLTIP_MODE;Toggle between linear, log-linear and log-log scaling of the histogram. HISTOGRAM_TOOLTIP_R;Show/Hide red histogram. HISTOGRAM_TOOLTIP_RAW;Show/Hide raw histogram. -HISTOGRAM_TOOLTIP_TYPE;Toggle between histogram and waveform. +HISTOGRAM_TOOLTIP_TYPE;Toggle between histogram, waveform, Hue-Saturation vectorscope, and Hue-Chroma vectorscope. HISTORY_CHANGED;Changed HISTORY_CUSTOMCURVE;Custom curve HISTORY_FROMCLIPBOARD;From clipboard diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 4927c4e1f..f19eff54d 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1643,6 +1643,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (hListener->updateHistogram()) { updateLRGBHistograms(); } + if (hListener->updateVectorscope()) { + updateVectorscope(); + } if (hListener->updateWaveform()) { updateWaveforms(); } @@ -1765,6 +1768,8 @@ void ImProcCoordinator::notifyHistogramChanged() histBlueRaw, histChroma, histLRETI, + vectorscopeScale, + vectorscope, waveformScale, waveformWidth, waveformRed.get(), @@ -1835,6 +1840,55 @@ void ImProcCoordinator::updateLRGBHistograms() } +void ImProcCoordinator::updateVectorscope() +{ + if (!workimg) { + return; + } + + int x1, y1, x2, y2; + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + + constexpr int size = HistogramListener::vectorscope_size; + memset(vectorscope, 0, size * size * sizeof(vectorscope[0][0])); + + for (int i = y1; i < y2; i++) { + int ofs = (i * pW + x1) * 3; + + for (int j = x1; j < x2; j++) { + switch (hListener->vectorscopeType()) { + case 0: { + // HS + int r = 256 * workimg->data[ofs++]; + int g = 256 * workimg->data[ofs++]; + int b = 256 * workimg->data[ofs++]; + float h, s, l; + Color::rgb2hsl(r, g, b, h, s, l); + const int col = s * cos(2 * RT_PI * h) * (size / 2) + size / 2; + const int row = s * sin(2 * RT_PI * h) * (size / 2) + size / 2; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscope[row][col]++; + } + break; + } + + case 1: { + // CH + const int col = (size / 96000.0) * nprevl->a[i][j] + size / 2; + const int row = (size / 96000.0) * nprevl->b[i][j] + size / 2; + + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscope[row][col]++; + } + break; + } + } + } + } + + vectorscopeScale = workimg->getWidth() * workimg->getHeight(); +} + void ImProcCoordinator::updateWaveforms() { if (!workimg) { @@ -2314,7 +2368,7 @@ void ImProcCoordinator::setHighQualComputed() highQualityComputed = true; } -void ImProcCoordinator::updateWaveform() +void ImProcCoordinator::requestUpdateWaveform() { if (hListener) { updateWaveforms(); @@ -2322,7 +2376,7 @@ void ImProcCoordinator::updateWaveform() } } -void ImProcCoordinator::updateHistogram() +void ImProcCoordinator::requestUpdateHistogram() { if (hListener) { updateLRGBHistograms(); @@ -2330,4 +2384,12 @@ void ImProcCoordinator::updateHistogram() } } +void ImProcCoordinator::requestUpdateVectorscope() +{ + if (hListener) { + updateVectorscope(); + notifyHistogramChanged(); + } +} + } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 92b5e9346..14ee81934 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -126,6 +126,8 @@ protected: LUTu histBlue, histBlueRaw; LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; + int vectorscopeScale; + int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size]; /// Waveform's intensity. Same as height of reference image. int waveformScale; int waveformWidth; @@ -202,6 +204,7 @@ protected: void notifyHistogramChanged(); void reallocAll(); void updateLRGBHistograms(); + void updateVectorscope(); void updateWaveforms(); void setScale(int prevscale); void updatePreviewImage (int todo, bool panningRelatedChange); @@ -560,8 +563,9 @@ public: } denoiseInfoStore; - void updateHistogram() override; - void updateWaveform() override; + void requestUpdateHistogram() override; + void requestUpdateVectorscope() override; + void requestUpdateWaveform() override; }; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 4121b4f49..49f858cdc 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -308,6 +308,8 @@ class HistogramObservable; class HistogramListener { public: + static constexpr int vectorscope_size = 128; + virtual ~HistogramListener() = default; /** This member function is called when the histogram of the final image has changed. * @param histRed is the array of size 256 containing the histogram of the red channel @@ -330,6 +332,8 @@ public: const LUTu& histBlueRaw, const LUTu& histChroma, const LUTu& histLRETI, + int vectorscopeScale, + const int vectorscope[vectorscope_size][vectorscope_size], int waveformScale, int waveformWidth, const int waveformRed[][256], @@ -340,17 +344,23 @@ public: virtual void setObservable(HistogramObservable* observable) = 0; /** Returns if the listener wants the histogram to be updated. */ virtual bool updateHistogram(void) = 0; + /** Returns if the listener wants the vectorscope to be updated. */ + virtual bool updateVectorscope(void) = 0; /** Returns if the listener wants the waveform to be updated. */ virtual bool updateWaveform(void) = 0; + /** Returns the vectorscope type: 0 for H-S and 1 for H-C. */ + virtual int vectorscopeType(void) = 0; }; class HistogramObservable { public: /** Tells the observable to update the histogram data. */ - virtual void updateHistogram() = 0; + virtual void requestUpdateHistogram() = 0; + /** Tells the observable to update the vectorscope data. */ + virtual void requestUpdateVectorscope() = 0; /** Tells the observable to update the waveform data. */ - virtual void updateWaveform() = 0; + virtual void requestUpdateWaveform() = 0; }; /** This listener is used when the auto exposure has been recomputed (e.g. when the clipping ratio changed). */ diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 5bf3e54d8..e52c9f47a 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2247,6 +2247,8 @@ void EditorPanel::histogramChanged( const LUTu& histBlueRaw, const LUTu& histChroma, const LUTu& histLRETI, + int vectorscopeScale, + const int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size], int waveformScale, int waveformWidth, const int waveformRed[][256], @@ -2255,7 +2257,7 @@ void EditorPanel::histogramChanged( ) { if (histogramPanel) { - histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue); + histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue); } tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI); @@ -2272,12 +2274,32 @@ bool EditorPanel::updateHistogram(void) || histogram_scope_type == HistogramPanelListener::NONE; } +bool EditorPanel::updateVectorscope(void) +{ + return + histogram_scope_type == HistogramPanelListener::VECTORSCOPE_HS + || histogram_scope_type == HistogramPanelListener::VECTORSCOPE_CH + || histogram_scope_type == HistogramPanelListener::NONE; +} + bool EditorPanel::updateWaveform(void) { return histogram_scope_type == HistogramPanelListener::WAVEFORM || histogram_scope_type == HistogramPanelListener::NONE; } +int EditorPanel::vectorscopeType(void) +{ + switch (histogram_scope_type) { + case HistogramPanelListener::VECTORSCOPE_HS: + return 0; + case HistogramPanelListener::VECTORSCOPE_CH: + return 1; + default: + return -1; + } +} + void EditorPanel::scopeTypeChanged(ScopeType new_type) { histogram_scope_type = new_type; @@ -2289,9 +2311,13 @@ void EditorPanel::scopeTypeChanged(ScopeType new_type) // Make sure the new scope is updated since we only actively update the // current scope. if (new_type == HistogramPanelListener::HISTOGRAM) { - histogram_observable->updateHistogram(); + histogram_observable->requestUpdateHistogram(); + } else if (new_type == HistogramPanelListener::VECTORSCOPE_HS) { + histogram_observable->requestUpdateVectorscope(); + } else if (new_type == HistogramPanelListener::VECTORSCOPE_CH) { + histogram_observable->requestUpdateVectorscope(); } else if (new_type == HistogramPanelListener::WAVEFORM) { - histogram_observable->updateWaveform(); + histogram_observable->requestUpdateWaveform(); } } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 1794de11b..b9d196ccd 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -128,6 +128,8 @@ public: const LUTu& histBlueRaw, const LUTu& histChroma, const LUTu& histLRETI, + int vectorscopeScale, + const int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size], int waveformScale, int waveformWidth, const int waveformRed[][256], @@ -136,7 +138,9 @@ public: ) override; void setObservable(rtengine::HistogramObservable* observable) override; bool updateHistogram(void) override; + bool updateVectorscope(void) override; bool updateWaveform(void) override; + int vectorscopeType(void) override; // HistogramPanelListener void scopeTypeChanged(ScopeType new_type) override; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index d3d92880d..0967212d0 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -163,8 +163,12 @@ HistogramPanel::HistogramPanel () : panel_listener(nullptr) showMode->set_image(*mode2Image); if (options.histogramScopeType == 0) { // TODO: scopeType->set_image(*histImage); - } else { + } else if (options.histogramScopeType == 1) { // TODO: scopeType->set_image(*waveImage); + } else if (options.histogramScopeType == 2) { + // TODO: scopeType->set_image(*vectHsImage); + } else if (options.histogramScopeType == 3) { + // TODO: scopeType->set_image(*vectHcImage); } showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); @@ -254,7 +258,7 @@ void HistogramPanel::showRGBBar() gfxGrid->attach_next_to(*histogramRGBArea, *histogramArea, pos); setHistRGBInvalid(); - histogramRGBArea->setShow(true); + histogramRGBArea->setShow(options.histogramScopeType < 2); } void HistogramPanel::resized (Gtk::Allocation& req) @@ -331,12 +335,16 @@ void HistogramPanel::mode_released () void HistogramPanel::type_pressed() { - constexpr int TYPE_COUNT = 2; // Histogram and waveform. + constexpr int TYPE_COUNT = 4; // Histogram, waveform, and 2 vectorscopes. options.histogramScopeType = (options.histogramScopeType + 1) % TYPE_COUNT; if (options.histogramScopeType == 0) { // TODO: showMode->set_image(*histImage); - } else { + } else if (options.histogramScopeType == 1) { // TODO: showMode->set_image(*waveImage); + } else if (options.histogramScopeType == 2) { + // TODO: showMode->set_image(*vectHsImage); + } else if (options.histogramScopeType == 3) { + // TODO: showMode->set_image(*vectHcImage); } type_changed(); rgbv_toggled(); @@ -350,6 +358,9 @@ void HistogramPanel::type_changed() } if (options.histogramScopeType == 0) { + showRed->set_sensitive(); + showGreen->set_sensitive(); + showBlue->set_sensitive(); showValue->set_sensitive(!showRAW->get_active()); showChro->set_sensitive(!showRAW->get_active()); showRAW->set_sensitive(); @@ -359,7 +370,10 @@ void HistogramPanel::type_changed() updateHistAreaOptions(); panel_listener->scopeTypeChanged(HistogramPanelListener::HISTOGRAM); } - } else { + } else if (options.histogramScopeType == 1) { + showRed->set_sensitive(); + showGreen->set_sensitive(); + showBlue->set_sensitive(); showValue->set_sensitive(false); showChro->set_sensitive(false); showRAW->set_sensitive(false); @@ -369,6 +383,28 @@ void HistogramPanel::type_changed() updateHistAreaOptions(); panel_listener->scopeTypeChanged(HistogramPanelListener::WAVEFORM); } + } else { + showRed->set_sensitive(false); + showGreen->set_sensitive(false); + showBlue->set_sensitive(false); + showValue->set_sensitive(false); + showChro->set_sensitive(false); + showRAW->set_sensitive(false); + showMode->set_sensitive(false); + histogramRGBArea = histogramRGBAreaHori.get(); + if (panel_listener) { + updateHistAreaOptions(); + HistogramPanelListener::ScopeType type; + switch (options.histogramScopeType) { + case 2: + type = HistogramPanelListener::VECTORSCOPE_HS; + break; + case 3: + type = HistogramPanelListener::VECTORSCOPE_CH; + break; + } + panel_listener->scopeTypeChanged(type); + } } if (showBAR->get_active()) { @@ -395,7 +431,7 @@ void HistogramPanel::rgbv_toggled () histogramArea->updateBackBuffer (); histogramArea->queue_draw (); - histogramRGBArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), showBAR->get_active()); + histogramRGBArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), showBAR->get_active() && options.histogramScopeType < 2); histogramRGBArea->updateBackBuffer (0, 0, 0); histogramRGBArea->queue_draw (); } @@ -458,8 +494,14 @@ void HistogramPanel::setPanelListener(HistogramPanelListener* listener) HistogramPanelListener::ScopeType type; if (options.histogramScopeType == 0) { type = HistogramPanelListener::HISTOGRAM; - } else { + } else if (options.histogramScopeType == 1) { type = HistogramPanelListener::WAVEFORM; + } else if (options.histogramScopeType == 2) { + type = HistogramPanelListener::VECTORSCOPE_HS; + } else if (options.histogramScopeType == 3) { + type = HistogramPanelListener::VECTORSCOPE_CH; + } else { + type = HistogramPanelListener::NONE; } listener->scopeTypeChanged(type); } @@ -616,7 +658,7 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustrin drawBar(cc, b, 255.0, winw, winh, s); } - if((needLuma || needChroma) && options.histogramScopeType != 1) { + if((needLuma || needChroma) && options.histogramScopeType == 0) { float Lab_L, Lab_a, Lab_b; rtengine::Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, Lab_L, Lab_a, Lab_b, options.rtSettings.HistogramWorking); @@ -828,6 +870,9 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : lhist(256); chist(256); + const int vect_size = VECTORSCOPE_SIZE * Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, VECTORSCOPE_SIZE); + vect_buffer.reset(new unsigned char[vect_size]); + get_style_context()->add_class("drawingarea"); set_name("HistogramArea"); @@ -904,6 +949,8 @@ void HistogramArea::update( const LUTu& histRedRaw, const LUTu& histGreenRaw, const LUTu& histBlueRaw, + int vectorscopeScale, + const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE], int waveformScale, int waveformWidth, const int waveformRed[][256], @@ -936,6 +983,11 @@ void HistogramArea::update( memcpy(gw, waveformGreen, 256 * waveformWidth * sizeof(gw[0][0])); memcpy(bw, waveformBlue, 256 * waveformWidth * sizeof(bw[0][0])); wave_buffer_dirty = true; + } else if (scopeType >= 2) { + vectorscope_scale = vectorscopeScale; + memcpy(vect, vectorscope, VECTORSCOPE_SIZE * VECTORSCOPE_SIZE * + sizeof(vect[0][0])); + vect_buffer_dirty = true; } valid = true; } else { @@ -1009,7 +1061,7 @@ void HistogramArea::updateBackBuffer () int nrOfVGridPartitions = 8; // always show 8 stops (lines at 1,3,7,15,31,63,127) // draw vertical gridlines - if (options.histogramScopeType != 1) { + if (options.histogramScopeType == 0) { for (int i = 0; i <= nrOfVGridPartitions; i++) { double xpos = padding + 0.5; if (options.histogramDrawMode < 2) { @@ -1031,6 +1083,8 @@ void HistogramArea::updateBackBuffer () cr->line_to(w, ypos); cr->stroke(); } + } else if (options.histogramScopeType >= 2) { + // Vectorscope has no gridlines. } else if (options.histogramDrawMode == 0) { for (int i = 1; i < nrOfHGridPartitions; i++) { cr->move_to (padding, i * (double)h / nrOfHGridPartitions + 0.5); @@ -1156,6 +1210,8 @@ void HistogramArea::updateBackBuffer () } else if (scopeType == 1 && waveform_width > 0) { drawWaveform(cr, w, h); + } else if (scopeType >= 2) { + drawVectorscope(cr, w, h); } // Draw the frame's border @@ -1220,6 +1276,107 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, cr->fill(); } +void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, int h) +{ + // Arbitrary scale factor multiplied by vectorscope area and divided by + // current scale. + const float scale = 16.f * VECTORSCOPE_SIZE * VECTORSCOPE_SIZE / vectorscope_scale; + + // See Cairo documentation on stride. + const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, VECTORSCOPE_SIZE); + + if (vect_buffer_dirty && vectorscope_scale > 0) { + // TODO: Optimize. + for (int u = 0; u < VECTORSCOPE_SIZE; u++) { + for (int v = 0; v < VECTORSCOPE_SIZE; v++) { + const unsigned char value = LIM(scale * vect[u][v], 0, 0xff); + *(uint32_t*)&(vect_buffer[(VECTORSCOPE_SIZE - 1 - u) * cairo_stride + v * 4]) = + value | (value << 8) | (value << 16) | (value << 24); + } + } + + vect_buffer_dirty = false; + } + + const float scope_size = min(w, h) - 2 * padding; + const float o_x = (w - scope_size) / 2; + const float o_y = (h - scope_size) / 2; + const double s = RTScalable::getScale(); + auto orig_matrix = cr->get_matrix(); + const double line_spacing = 4.0 * s; + const double line_length = scope_size / 2.0 - 2.0 * line_spacing; + std::valarray ch_ds(1); + + cr->translate(w / 2.0, h / 2.0); + cr->set_source_rgba (1., 1., 1., 0.25); + cr->set_line_width (1.0 * s); + cr->set_antialias(Cairo::ANTIALIAS_SUBPIXEL); + ch_ds[0] = 4; + + if (scopeType == 2) { // Hue-Saturation. + // RYGCBM lines. + for (int i = 0; i < 6; i++) { + cr->move_to(line_spacing, 0); + cr->line_to(line_spacing + line_length, 0); + cr->rotate_degrees(60); + } + cr->stroke(); + // 100% saturation circle. + cr->arc(0, 0, scope_size / 2.0, 0, 2 * RT_PI); + cr->stroke(); + // 25%, 50%, and 75% saturation. + cr->set_dash(ch_ds, 0); + for (int i = 1; i < 4; i++) { + cr->arc(0, 0, i * scope_size / 8.0, 0, 2 * RT_PI); + cr->stroke(); + } + // HSV skin tone line derived from -I axis of YIQ. + cr->rotate(-0.134900 * RT_PI); + cr->move_to(line_spacing, 0); + cr->line_to(line_spacing + line_length, 0); + cr->stroke(); + cr->unset_dash(); + } else if (scopeType == 3) { // Hue-Chroma. + // a and b axes. + cr->move_to(0, line_spacing); + cr->line_to(0, line_spacing + line_length); + cr->move_to(0, -line_spacing); + cr->line_to(0, -line_spacing - line_length); + cr->move_to(line_spacing, 0); + cr->line_to(line_spacing + line_length, 0); + cr->move_to(-line_spacing, 0); + cr->line_to(-line_spacing - line_length, 0); + cr->stroke(); + // 25%, 50%, 75%, and 100% of standard chroma range. + cr->set_dash(ch_ds, 0); + for (int i = 1; i <= 4; i++) { + cr->arc(0, 0, i * scope_size / 8.0, 0, 2 * RT_PI); + cr->stroke(); + } + // CIELAB skin tone line, approximated by 50% saturation and + // value along the HSV skin tone line. + cr->rotate(-0.321713 * RT_PI); + cr->move_to(line_spacing, 0); + cr->line_to(line_spacing + line_length, 0); + cr->stroke(); + cr->unset_dash(); + } + cr->set_matrix(orig_matrix); + + // Vectorscope trace. + if (vectorscope_scale > 0) { + Cairo::RefPtr surface = Cairo::ImageSurface::create( + vect_buffer.get(), Cairo::FORMAT_ARGB32, VECTORSCOPE_SIZE, VECTORSCOPE_SIZE, cairo_stride); + cr->translate(o_x, o_y); + cr->scale(scope_size / VECTORSCOPE_SIZE, scope_size / VECTORSCOPE_SIZE); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + surface->finish(); + cr->set_matrix(orig_matrix); + } +} + void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h) { // Arbitrary scale factor divided by current scale. @@ -1310,7 +1467,7 @@ bool HistogramArea::on_button_release_event (GdkEventButton* event) bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) { - if (drawMode == 0 || scopeType == 1) { + if (drawMode == 0 || scopeType >= 1) { return false; } diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 83099c68e..a3d29bdd3 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -32,6 +32,11 @@ class HistogramArea; +namespace +{ +constexpr int VECTORSCOPE_SIZE = 128; +} + struct HistogramAreaIdleHelper { HistogramArea* harea; bool destroyed; @@ -156,6 +161,10 @@ private: protected: LUTu rhist, ghist, bhist, lhist, chist; LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused? + int vectorscope_scale; + int vect[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE]; + std::unique_ptr vect_buffer; + bool vect_buffer_dirty; int waveform_scale; int waveform_width; std::unique_ptr rwave, gwave, bwave; @@ -191,6 +200,8 @@ public: const LUTu& histRedRaw, const LUTu& histGreenRaw, const LUTu& histBlueRaw, + int vectorscopeScale, + const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE], int waveformScale, int waveformWidth, const int waveformRed[][256], @@ -208,6 +219,7 @@ public: private: void drawCurve(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int vsize); void drawMarks(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int & ui, int & oi); + void drawVectorscope(Cairo::RefPtr &cr, int hsize, int vsize); void drawWaveform(Cairo::RefPtr &cr, int hsize, int vsize); Gtk::SizeRequestMode get_request_mode_vfunc () const override; void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override; @@ -219,7 +231,7 @@ private: class HistogramPanelListener { public: - enum ScopeType {HISTOGRAM, WAVEFORM, NONE}; + enum ScopeType {HISTOGRAM, VECTORSCOPE_CH, VECTORSCOPE_HS, WAVEFORM, NONE}; virtual void scopeTypeChanged(ScopeType new_type) = 0; }; @@ -286,6 +298,8 @@ public: const LUTu& histRedRaw, const LUTu& histGreenRaw, const LUTu& histBlueRaw, + int vectorscopeScale, + const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE], int waveformScale, int waveformWidth, const int waveformRed[][256], @@ -293,7 +307,7 @@ public: const int waveformBlue[][256] ) { - histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue); + histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue); } // pointermotionlistener interface void pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw = false) override;