From 4cbd622569e954f9cae8c2c8cc2cedbf6d80927a Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 21 Jul 2020 22:45:10 -0700 Subject: [PATCH 01/56] Add initial implementation of waveform --- rtdata/languages/default | 1 + rtengine/improccoordinator.cc | 64 +++++++++++++- rtengine/improccoordinator.h | 7 ++ rtengine/rtengine.h | 7 +- rtgui/editorpanel.cc | 9 +- rtgui/editorpanel.h | 7 +- rtgui/histogrampanel.cc | 154 ++++++++++++++++++++++++++++++---- rtgui/histogrampanel.h | 27 +++++- rtgui/options.cc | 6 ++ rtgui/options.h | 1 + 10 files changed, 257 insertions(+), 26 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index a5f77403e..307417524 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -249,6 +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. HISTORY_CHANGED;Changed HISTORY_CUSTOMCURVE;Custom curve HISTORY_FROMCLIPBOARD;From clipboard diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index aa8770504..37a81f3d1 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -129,6 +129,8 @@ ImProcCoordinator::ImProcCoordinator() : histLRETI(256), + waveformWidth(0), + CAMBrightCurveJ(), CAMBrightCurveQ(), rCurve(), @@ -1639,7 +1641,30 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (hListener) { updateLRGBHistograms(); - hListener->histogramChanged(histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, histCCurve, /*histCLurve, histLLCurve,*/ histLCAM, histCCAM, histRedRaw, histGreenRaw, histBlueRaw, histChroma, histLRETI); + updateWaveforms(); + hListener->histogramChanged( + histRed, + histGreen, + histBlue, + histLuma, + histToneCurve, + histLCurve, + histCCurve, + /*histCLurve, + * histLLCurve,*/ + histLCAM, + histCCAM, + histRedRaw, + histGreenRaw, + histBlueRaw, + histChroma, + histLRETI, + waveformScale, + waveformWidth, + waveformRed.get(), + waveformGreen.get(), + waveformBlue.get() + ); } } @@ -1801,6 +1826,43 @@ void ImProcCoordinator::updateLRGBHistograms() } +void ImProcCoordinator::updateWaveforms() +{ + if (!workimg) { + waveformWidth = 0; + return; + } + + if (waveformWidth != workimg->getWidth()) { + // Resize waveform arrays. + waveformWidth = workimg->getWidth(); + waveformRed.reset(new int[waveformWidth][256]); + waveformGreen.reset(new int[waveformWidth][256]); + waveformBlue.reset(new int[waveformWidth][256]); + } + + int (*red)[256] = waveformRed.get(); + int (*green)[256] = waveformGreen.get(); + int (*blue)[256] = waveformBlue.get(); + + // Start with zero. + const int waveformSize = 256 * waveformWidth; + memset(waveformRed.get(), 0, waveformSize * sizeof(red[0][0])); + memset(waveformGreen.get(), 0, waveformSize * sizeof(green[0][0])); + memset(waveformBlue.get(), 0, waveformSize * sizeof(blue[0][0])); + + const int img_height = workimg->getHeight(); + for (int col = 0; col < waveformWidth; col++) { + for (int row = 0; row < img_height; row++) { + red[col][workimg->r(row, col)]++; + green[col][workimg->g(row, col)]++; + blue[col][workimg->b(row, col)]++; + } + } + + waveformScale = img_height; +} + bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, double tempBias) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index ab57a4419..367f12a43 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -126,6 +126,12 @@ protected: LUTu histBlue, histBlueRaw; LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; + /// Waveform's intensity. Same as height of reference image. + int waveformScale; + int waveformWidth; + std::unique_ptr waveformRed, waveformRedRaw; + std::unique_ptr waveformGreen, waveformGreenRaw; + std::unique_ptr waveformBlue, waveformBlueRaw; LUTf CAMBrightCurveJ, CAMBrightCurveQ; @@ -195,6 +201,7 @@ protected: void reallocAll(); void updateLRGBHistograms(); + void updateWaveforms(); void setScale(int prevscale); void updatePreviewImage (int todo, bool panningRelatedChange); diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 1671ae1f5..30fa2ec67 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -327,7 +327,12 @@ public: const LUTu& histGreenRaw, const LUTu& histBlueRaw, const LUTu& histChroma, - const LUTu& histLRETI + const LUTu& histLRETI, + int waveformScale, + int waveformWidth, + const int waveformRed[][256], + const int waveformGreen[][256], + const int waveformBlue[][256] ) = 0; }; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 669dd491a..28747e063 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2245,11 +2245,16 @@ void EditorPanel::histogramChanged( const LUTu& histGreenRaw, const LUTu& histBlueRaw, const LUTu& histChroma, - const LUTu& histLRETI + const LUTu& histLRETI, + int waveformScale, + int waveformWidth, + const int waveformRed[][256], + const int waveformGreen[][256], + const int waveformBlue[][256] ) { if (histogramPanel) { - histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw); + histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue); } tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI); diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 826793507..6a1fb585f 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -126,7 +126,12 @@ public: const LUTu& histGreenRaw, const LUTu& histBlueRaw, const LUTu& histChroma, - const LUTu& histLRETI + const LUTu& histLRETI, + int waveformScale, + int waveformWidth, + const int waveformRed[][256], + const int waveformGreen[][256], + const int waveformBlue[][256] ) override; // event handlers diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index b1c0b62df..588d6642e 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -85,6 +85,7 @@ HistogramPanel::HistogramPanel () showChro = Gtk::manage (new Gtk::ToggleButton ()); showRAW = Gtk::manage (new Gtk::ToggleButton ()); showMode = Gtk::manage (new Gtk::Button ()); + scopeType = Gtk::manage (new Gtk::Button ()); showBAR = Gtk::manage (new Gtk::ToggleButton ()); showRed->set_name("histButton"); @@ -101,6 +102,8 @@ HistogramPanel::HistogramPanel () showRAW->set_can_focus(false); showMode->set_name("histButton"); showMode->set_can_focus(false); + scopeType->set_name("histButton"); + scopeType->set_can_focus(false); showBAR->set_name("histButton"); showBAR->set_can_focus(false); @@ -111,6 +114,7 @@ HistogramPanel::HistogramPanel () showChro->set_relief (Gtk::RELIEF_NONE); showRAW->set_relief (Gtk::RELIEF_NONE); showMode->set_relief (Gtk::RELIEF_NONE); + scopeType->set_relief (Gtk::RELIEF_NONE); showBAR->set_relief (Gtk::RELIEF_NONE); showRed->set_tooltip_text (M("HISTOGRAM_TOOLTIP_R")); @@ -120,6 +124,7 @@ HistogramPanel::HistogramPanel () showChro->set_tooltip_text (M("HISTOGRAM_TOOLTIP_CHRO")); showRAW->set_tooltip_text (M("HISTOGRAM_TOOLTIP_RAW")); showMode->set_tooltip_text (M("HISTOGRAM_TOOLTIP_MODE")); + scopeType->set_tooltip_text (M("HISTOGRAM_TOOLTIP_TYPE")); showBAR->set_tooltip_text (M("HISTOGRAM_TOOLTIP_BAR")); buttonGrid = Gtk::manage (new Gtk::Grid ()); @@ -145,9 +150,15 @@ HistogramPanel::HistogramPanel () showMode->set_image(*mode1Image); else showMode->set_image(*mode2Image); + if (options.histogramScopeType == 0) { + // TODO: scopeType->set_image(*histImage); + } else { + // TODO: scopeType->set_image(*waveImage); + } showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); raw_toggled(); // Make sure the luma/chroma toggles are enabled or disabled + type_changed(); setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); @@ -156,6 +167,7 @@ HistogramPanel::HistogramPanel () setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showRAW , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(scopeType, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); showRed->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::red_toggled), showRed ); @@ -165,6 +177,7 @@ HistogramPanel::HistogramPanel () showChro->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::chro_toggled), showChro ); showRAW->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::raw_toggled), showRAW ); showMode->signal_released().connect( sigc::mem_fun(*this, &HistogramPanel::mode_released), showMode ); + scopeType->signal_pressed().connect( sigc::mem_fun(*this, &HistogramPanel::type_pressed), scopeType ); showBAR->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::bar_toggled), showBAR ); buttonGrid->add (*showRed); @@ -174,6 +187,7 @@ HistogramPanel::HistogramPanel () buttonGrid->add (*showChro); buttonGrid->add (*showRAW); buttonGrid->add (*showMode); + buttonGrid->add (*scopeType); buttonGrid->add (*showBAR); // Put the button vbox next to the window's border to be less disturbing @@ -266,8 +280,8 @@ void HistogramPanel::raw_toggled () showChro->set_sensitive(false); } else { showRAW->set_image(*rawImage_g); - showValue->set_sensitive(true); - showChro->set_sensitive(true); + showValue->set_sensitive(options.histogramScopeType != 1); + showChro->set_sensitive(options.histogramScopeType != 1); } rgbv_toggled(); @@ -285,6 +299,34 @@ void HistogramPanel::mode_released () rgbv_toggled(); } +void HistogramPanel::type_pressed() +{ + constexpr int TYPE_COUNT = 2; // Histogram and waveform. + options.histogramScopeType = (options.histogramScopeType + 1) % TYPE_COUNT; + if (options.histogramScopeType == 0) { + // TODO: showMode->set_image(*histImage); + } else { + // TODO: showMode->set_image(*waveImage); + } + type_changed(); + rgbv_toggled(); +} + +void HistogramPanel::type_changed() +{ + if (options.histogramScopeType == 0) { + showValue->set_sensitive(!showRAW->get_active()); + showChro->set_sensitive(!showRAW->get_active()); + showRAW->set_sensitive(); + showMode->set_sensitive(); + } else { + showValue->set_sensitive(false); + showChro->set_sensitive(false); + showRAW->set_sensitive(false); + showMode->set_sensitive(false); + } +} + void HistogramPanel::bar_toggled () { showBAR->set_image(showBAR->get_active() ? *barImage : *barImage_g); @@ -294,7 +336,7 @@ void HistogramPanel::bar_toggled () void HistogramPanel::rgbv_toggled () { // Update Display - histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), options.histogramDrawMode); + histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), options.histogramDrawMode, options.histogramScopeType); 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()); @@ -443,7 +485,7 @@ bool HistogramRGBArea::getShow() void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { - if (!get_realized () || !showMode || rawMode) { + if (!get_realized () || !showMode || rawMode || options.histogramScopeType == 1) { return; } @@ -655,7 +697,9 @@ void HistogramRGBArea::factorChanged (double newFactor) // // HistogramArea HistogramArea::HistogramArea (DrawModeListener *fml) : + waveform_width(0), valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), + scopeType(options.histogramScopeType), oldwidth(-1), oldheight(-1), needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), @@ -720,7 +764,7 @@ void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minim get_preferred_width_vfunc (minimum_width, natural_width); } -void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode) +void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type) { options.histogramRed = needRed = r; @@ -730,6 +774,7 @@ void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool options.histogramChroma = needChroma = c; options.histogramRAW = rawMode = raw; options.histogramDrawMode = drawMode = mode; + options.histogramScopeType = scopeType = type; updateBackBuffer (); } @@ -742,7 +787,12 @@ void HistogramArea::update( const LUTu& histChroma, const LUTu& histRedRaw, const LUTu& histGreenRaw, - const LUTu& histBlueRaw + const LUTu& histBlueRaw, + int waveformScale, + int waveformWidth, + const int waveformRed[][256], + const int waveformGreen[][256], + const int waveformBlue[][256] ) { if (histRed) { @@ -754,6 +804,19 @@ void HistogramArea::update( rhistRaw = histRedRaw; ghistRaw = histGreenRaw; bhistRaw = histBlueRaw; + waveform_scale = waveformScale; + if (waveform_width != waveformWidth) { + waveform_width = waveformWidth; + rwave.reset(new int[waveformWidth][256]); + gwave.reset(new int[waveformWidth][256]); + bwave.reset(new int[waveformWidth][256]); + } + int (* const rw)[256] = rwave.get(); + int (* const gw)[256] = gwave.get(); + int (* const bw)[256] = bwave.get(); + memcpy(rw, waveformRed, 256 * waveformWidth * sizeof(rw[0][0])); + memcpy(gw, waveformGreen, 256 * waveformWidth * sizeof(gw[0][0])); + memcpy(bw, waveformBlue, 256 * waveformWidth * sizeof(bw[0][0])); valid = true; } else { valid = false; @@ -826,20 +889,29 @@ void HistogramArea::updateBackBuffer () int nrOfVGridPartitions = 8; // always show 8 stops (lines at 1,3,7,15,31,63,127) // draw vertical gridlines - for (int i = 0; i <= nrOfVGridPartitions; i++) { - double xpos = padding + 0.5; - if (options.histogramDrawMode < 2) { - xpos += (pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; - } else { - xpos += HistogramScaling::log (255, pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + if (options.histogramScopeType != 1) { + for (int i = 0; i <= nrOfVGridPartitions; i++) { + double xpos = padding + 0.5; + if (options.histogramDrawMode < 2) { + xpos += (pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + } else { + xpos += HistogramScaling::log (255, pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + } + cr->move_to (xpos, 0.); + cr->line_to (xpos, h); + cr->stroke (); } - cr->move_to (xpos, 0.); - cr->line_to (xpos, h); - cr->stroke (); } // draw horizontal gridlines - if (options.histogramDrawMode == 0) { + if (options.histogramScopeType == 1) { + for (int i = 0; i <= nrOfVGridPartitions; i++) { + const double ypos = h - 1 - (pow(2.0,i) - 1) * (h - 1) / 255.0; + cr->move_to(padding, ypos); + cr->line_to(w - padding, ypos); + cr->stroke(); + } + } else if (options.histogramDrawMode == 0) { for (int i = 1; i < nrOfHGridPartitions; i++) { cr->move_to (padding, i * (double)h / nrOfHGridPartitions + 0.5); cr->line_to (w - padding, i * (double)h / nrOfHGridPartitions + 0.5); @@ -855,7 +927,7 @@ void HistogramArea::updateBackBuffer () cr->unset_dash(); - if (valid) { + if (valid && scopeType == 0) { // For RAW mode use the other hists LUTu& rh = rawMode ? rhistRaw : rhist; LUTu& gh = rawMode ? ghistRaw : ghist; @@ -962,6 +1034,8 @@ void HistogramArea::updateBackBuffer () drawMarks(cr, bhchanged, realhistheight, w, ui, oi); } + } else if (scopeType == 1 && waveform_width > 0) { + drawWaveform(cr, w, h); } // Draw the frame's border @@ -1026,6 +1100,48 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, cr->fill(); } +void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h) +{ + // Arbitrary scale factor divided by current scale. + const float scale = 32.f * 255.f / waveform_scale; + + // See Cairo documentation on stride. + const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, waveform_width); + std::unique_ptr buffer(new unsigned char[256 * cairo_stride]); + + // Clear waveform. + memset(buffer.get(), 0, 256 * cairo_stride); + + // TODO: Optimize. + for (int col = 0; col < waveform_width; col++) { + for (int val = 0; val < 256; val++) { + const float r = needRed ? scale * rwave[col][255 - val] : 0.f; + const float g = needGreen ? scale * gwave[col][255 - val] : 0.f; + const float b = needBlue ? scale * bwave[col][255 - val] : 0.f; + const float value = (r > g && r > b) ? r : ((g > b) ? g : b); + if (value <= 0) { + buffer[val * cairo_stride + col * 4 + 3] = 0; + } else { + buffer[val * cairo_stride + col * 4 + 3] = value; + buffer[val * cairo_stride + col * 4 + 2] = r; + buffer[val * cairo_stride + col * 4 + 1] = g; + buffer[val * cairo_stride + col * 4] = b; + } + } + } + + Cairo::RefPtr surface = Cairo::ImageSurface::create( + buffer.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); + auto orig_matrix = cr->get_matrix(); + cr->translate(padding, 0); + cr->scale(static_cast(w - 2 * padding) / waveform_width, h / 256.0); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + surface->finish(); + cr->set_matrix(orig_matrix); +} + bool HistogramArea::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) { @@ -1070,6 +1186,10 @@ bool HistogramArea::on_button_release_event (GdkEventButton* event) bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) { + if (drawMode == 0 || scopeType == 1) { + return false; + } + if (isPressed) { double mod = 1 + (event->x - movingPosition) / get_width(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 2a29ded9a..a8f5922ee 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -130,10 +130,14 @@ private: protected: LUTu rhist, ghist, bhist, lhist, chist; LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused? + int waveform_scale; + int waveform_width; + std::unique_ptr rwave, gwave, bwave; bool valid; int drawMode; DrawModeListener *myDrawModeListener; + int scopeType; int oldwidth, oldheight; bool needRed, needGreen, needBlue, needLuma, needChroma; @@ -158,9 +162,14 @@ public: const LUTu& histChroma, const LUTu& histRedRaw, const LUTu& histGreenRaw, - const LUTu& histBlueRaw + const LUTu& histBlueRaw, + int waveformScale, + int waveformWidth, + const int waveformRed[][256], + const int waveformGreen[][256], + const int waveformBlue[][256] ); - void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode); + void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; bool on_button_press_event (GdkEventButton* event) override; @@ -171,6 +180,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 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; void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; @@ -195,6 +205,7 @@ protected: Gtk::ToggleButton* showBAR; Gtk::ToggleButton* showChro; Gtk::Button* showMode; + Gtk::Button* scopeType; Gtk::Image *redImage; Gtk::Image *greenImage; @@ -232,9 +243,15 @@ public: const LUTu& histChroma, const LUTu& histRedRaw, const LUTu& histGreenRaw, - const LUTu& histBlueRaw) + const LUTu& histBlueRaw, + int waveformScale, + int waveformWidth, + const int waveformRed[][256], + const int waveformGreen[][256], + const int waveformBlue[][256] + ) { - histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw); + histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, 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; @@ -251,6 +268,8 @@ public: void chro_toggled (); void bar_toggled (); void mode_released (); + void type_pressed (); + void type_changed (); void rgbv_toggled (); void resized (Gtk::Allocation& req); diff --git a/rtgui/options.cc b/rtgui/options.cc index cc49f1fcd..b7eb9f810 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -450,6 +450,7 @@ void Options::setDefaults() histogramBar = true; histogramHeight = 200; histogramDrawMode = 0; + histogramScopeType = 0; curvebboxpos = 1; complexity = 1; prevdemo = PD_Sidecar; @@ -1426,6 +1427,10 @@ void Options::readFromFile(Glib::ustring fname) histogramDrawMode = keyFile.get_integer("GUI", "HistogramDrawMode"); } + if (keyFile.has_key("GUI", "HistogramScopeType")) { + histogramScopeType = keyFile.get_integer("GUI", "HistogramScopeType"); + } + if (keyFile.has_key("GUI", "NavigatorRGBUnit")) { navRGBUnit = (NavigatorUnit)keyFile.get_integer("GUI", "NavigatorRGBUnit"); } @@ -2233,6 +2238,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_boolean("GUI", "HistogramBar", histogramBar); keyFile.set_integer("GUI", "HistogramHeight", histogramHeight); keyFile.set_integer("GUI", "HistogramDrawMode", histogramDrawMode); + keyFile.set_integer("GUI", "HistogramScopeType", histogramScopeType); keyFile.set_integer("GUI", "NavigatorRGBUnit", (int)navRGBUnit); keyFile.set_integer("GUI", "NavigatorHSVUnit", (int)navHSVUnit); keyFile.set_boolean("GUI", "ShowFilmStripToolBar", showFilmStripToolBar); diff --git a/rtgui/options.h b/rtgui/options.h index 02d62292c..20678f2f9 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -312,6 +312,7 @@ public: bool histogramBar; int histogramHeight; int histogramDrawMode; + int histogramScopeType; bool FileBrowserToolbarSingleRow; bool hideTPVScrollbar; int whiteBalanceSpotSize; From 5eb6961049b89af23845eea428f4890505d07b99 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Fri, 24 Jul 2020 17:03:10 -0700 Subject: [PATCH 02/56] Adjust waveform padding Remove padding from left and right sides and add padding to top and bottom sides to improve visibility of extreme pixel values. --- rtgui/histogrampanel.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 588d6642e..9d6daf708 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -906,9 +906,9 @@ void HistogramArea::updateBackBuffer () // draw horizontal gridlines if (options.histogramScopeType == 1) { for (int i = 0; i <= nrOfVGridPartitions; i++) { - const double ypos = h - 1 - (pow(2.0,i) - 1) * (h - 1) / 255.0; - cr->move_to(padding, ypos); - cr->line_to(w - padding, ypos); + const double ypos = h - padding - (pow(2.0,i) - 1) * (h - 2 * padding - 1) / 255.0; + cr->move_to(0, ypos); + cr->line_to(w, ypos); cr->stroke(); } } else if (options.histogramDrawMode == 0) { @@ -1133,8 +1133,8 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h Cairo::RefPtr surface = Cairo::ImageSurface::create( buffer.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); auto orig_matrix = cr->get_matrix(); - cr->translate(padding, 0); - cr->scale(static_cast(w - 2 * padding) / waveform_width, h / 256.0); + cr->translate(0, padding); + cr->scale(static_cast(w) / waveform_width, (h - 2 * padding) / 256.0); cr->set_source(surface, 0, 0); cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); From 99b7a557c968240cb5593e645aef8426a2f3eac9 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 25 Jul 2020 13:05:10 -0700 Subject: [PATCH 03/56] Enable RGB bars for waveform --- rtgui/histogrampanel.cc | 242 ++++++++++++++++++++++++++-------------- rtgui/histogrampanel.h | 31 ++++- 2 files changed, 190 insertions(+), 83 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 9d6daf708..8c2d971eb 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -40,22 +40,33 @@ HistogramPanel::HistogramPanel () histogramArea = Gtk::manage (new HistogramArea (this)); setExpandAlignProperties(histogramArea, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - histogramRGBArea = Gtk::manage (new HistogramRGBArea ()); - setExpandAlignProperties(histogramRGBArea, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_END); - histogramRGBArea->show(); + histogramRGBAreaHori.reset(new HistogramRGBAreaHori()); + setExpandAlignProperties(histogramRGBAreaHori.get(), true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_END); + histogramRGBAreaHori->show(); + + histogramRGBAreaVert.reset(new HistogramRGBAreaVert()); + setExpandAlignProperties(histogramRGBAreaVert.get(), false, true, Gtk::ALIGN_END, Gtk::ALIGN_FILL); + histogramRGBAreaVert->show(); + + if (options.histogramScopeType == 1) { + histogramRGBArea = histogramRGBAreaVert.get(); + } else { + histogramRGBArea = histogramRGBAreaHori.get(); + } // connecting the two childs - histogramArea->signal_factor_changed().connect( sigc::mem_fun(*histogramRGBArea, &HistogramRGBArea::factorChanged) ); + histogramArea->signal_factor_changed().connect( sigc::mem_fun(*histogramRGBAreaHori, &HistogramRGBArea::factorChanged) ); + histogramArea->signal_factor_changed().connect( sigc::mem_fun(*histogramRGBAreaVert, &HistogramRGBArea::factorChanged) ); gfxGrid = Gtk::manage (new Gtk::Grid ()); - gfxGrid->set_orientation(Gtk::ORIENTATION_VERTICAL); gfxGrid->set_row_spacing(1); gfxGrid->set_column_spacing(1); - histogramRGBArea->setParent(gfxGrid); + histogramRGBAreaHori->setParent(gfxGrid); + histogramRGBAreaVert->setParent(gfxGrid); gfxGrid->add(*histogramArea); if (options.histogramBar) { - gfxGrid->add (*histogramRGBArea); + showRGBBar(); } redImage = new RTImage ("histogram-red-on-small.png"); @@ -227,6 +238,25 @@ HistogramPanel::~HistogramPanel () } +void HistogramPanel::showRGBBar() +{ + Gtk::PositionType pos; + + if (histogramRGBArea == histogramRGBAreaHori.get()) { + pos = Gtk::POS_BOTTOM; + } else { + if (options.histogramPosition == 1) { + pos = Gtk::POS_RIGHT; + } else { + pos = Gtk::POS_LEFT; + } + } + + gfxGrid->attach_next_to(*histogramRGBArea, *histogramArea, pos); + setHistRGBInvalid(); + histogramRGBArea->setShow(true); +} + void HistogramPanel::resized (Gtk::Allocation& req) { @@ -314,16 +344,27 @@ void HistogramPanel::type_pressed() void HistogramPanel::type_changed() { + if (showBAR->get_active()) { + histogramRGBArea->setShow(false); + gfxGrid->remove(*histogramRGBArea); + } + if (options.histogramScopeType == 0) { showValue->set_sensitive(!showRAW->get_active()); showChro->set_sensitive(!showRAW->get_active()); showRAW->set_sensitive(); showMode->set_sensitive(); + histogramRGBArea = histogramRGBAreaHori.get(); } else { showValue->set_sensitive(false); showChro->set_sensitive(false); showRAW->set_sensitive(false); showMode->set_sensitive(false); + histogramRGBArea = histogramRGBAreaVert.get(); + } + + if (showBAR->get_active()) { + showRGBBar(); } } @@ -331,6 +372,12 @@ void HistogramPanel::bar_toggled () { showBAR->set_image(showBAR->get_active() ? *barImage : *barImage_g); rgbv_toggled(); + + if (showBAR->get_active()) { + showRGBBar(); + } else { + gfxGrid->remove(*histogramRGBArea); + } } void HistogramPanel::rgbv_toggled () @@ -436,46 +483,41 @@ HistogramRGBArea::~HistogramRGBArea () } -Gtk::SizeRequestMode HistogramRGBArea::get_request_mode_vfunc () const +void HistogramRGBArea::getPreferredThickness(int& min_thickness, int& natural_thickness) const { - return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH; + int minimumLength = 0; + int naturalLength = 0; + getPreferredLength(minimumLength, naturalLength); + getPreferredThicknessForLength(minimumLength, min_thickness, natural_thickness); } -void HistogramRGBArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const -{ - int minimumWidth = 0; - int naturalWidth = 0; - get_preferred_width_vfunc(minimumWidth, naturalWidth); - get_preferred_height_for_width_vfunc (minimumWidth, minimum_height, natural_height); -} - -void HistogramRGBArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const +void HistogramRGBArea::getPreferredLength(int& min_length, int& natural_length) const { int s = RTScalable::getScale(); - minimum_width = 60 * s; - natural_width = 200 * s; + min_length = 60 * s; + natural_length = 200 * s; } -void HistogramRGBArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const +void HistogramRGBArea::getPreferredThicknessForLength(int length, int& min_thickness, int& natural_thickness) const { - int bHeight = width / 30; + int bThickness = length / 30; int s = RTScalable::getScale(); - if (bHeight > (10 * s)) { - bHeight = 10 * s; - } else if (bHeight < (5 * s)) { - bHeight = 5 * s; + if (bThickness > (10 * s)) { + bThickness = 10 * s; + } else if (bThickness < (5 * s)) { + bThickness = 5 * s; } - minimum_height = bHeight; - natural_height = bHeight; + min_thickness = bThickness; + natural_thickness = bThickness; } // unused? -void HistogramRGBArea::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const +void HistogramRGBArea::getPreferredLengthForThickness(int thickness, int& min_length, int& natural_length) const { - get_preferred_width_vfunc (minimum_width, natural_width); + getPreferredLength(min_length, natural_length); } bool HistogramRGBArea::getShow() @@ -483,9 +525,14 @@ bool HistogramRGBArea::getShow() return(showMode); } +void HistogramRGBArea::setShow(bool show) +{ + showMode = show; +} + void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { - if (!get_realized () || !showMode || rawMode || options.histogramScopeType == 1) { + if (!get_realized () || !showMode || rawMode) { return; } @@ -513,75 +560,39 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustrin cc->set_line_width (1.0 * s); if ( r != -1 && g != -1 && b != -1 ) { - double xpos; if (needRed) { // Red cc->set_source_rgb(1.0, 0.0, 0.0); - if (options.histogramDrawMode < 2) { - xpos = padding + r * (winw - padding * 2.0) / 255.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log (255, r) * (winw - padding * 2.0) / 255.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); + drawBar(cc, r, 255.0, winw, winh, s); } if (needGreen) { // Green cc->set_source_rgb(0.0, 1.0, 0.0); - if (options.histogramDrawMode < 2) { - xpos = padding + g * (winw - padding * 2.0) / 255.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log (255, g) * (winw - padding * 2.0) / 255.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); + drawBar(cc, g, 255.0, winw, winh, s); } if (needBlue) { // Blue cc->set_source_rgb(0.0, 0.4, 1.0); - if (options.histogramDrawMode < 2) { - xpos = padding + b * (winw - padding * 2.0) / 255.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log (255, b) * (winw - padding * 2.0) / 255.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); + drawBar(cc, b, 255.0, winw, winh, s); } - if(needLuma || needChroma) { + if((needLuma || needChroma) && options.histogramScopeType != 1) { 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); if (needLuma) { // Luma cc->set_source_rgb(1.0, 1.0, 1.0); - if (options.histogramDrawMode < 2) { - xpos = padding + static_cast(Lab_L) * (winw - padding * 2.0) / 100.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log(100, Lab_L) * (winw - padding * 2.0) / 100.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); + drawBar(cc, Lab_L, 100.0, winw, winh, s); } if (needChroma) { // Chroma double chromaval = sqrt(Lab_a * Lab_a + Lab_b * Lab_b) / 1.8; cc->set_source_rgb(0.9, 0.9, 0.0); - if (options.histogramDrawMode < 2) { - xpos = padding + chromaval * (winw - padding * 2.0) / 100.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log(100, chromaval) * (winw - padding * 2.0) / 100.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); + drawBar(cc, chromaval, 100.0, winw, winh, s); } } } @@ -639,15 +650,6 @@ void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bo options.histogramRAW = rawMode = raw; options.histogramBar = showMode = bar; - // Show/hide the RGB bar widget - if (bar && !barDisplayed) { - parent->add(*this); - barDisplayed = true; - } else if (!bar && barDisplayed) { - removeIfThere(parent, this, false); - barDisplayed = false; - } - } void HistogramRGBArea::on_realize () @@ -692,6 +694,82 @@ void HistogramRGBArea::factorChanged (double newFactor) factor = newFactor; } +void HistogramRGBAreaHori::drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) +{ + double pos; + if (options.histogramDrawMode < 2) { + pos = padding + value * (winw - padding * 2.0) / max_value + 0.5 * scale; + } else { + pos = padding + HistogramScaling::log (max_value, value) * (winw - padding * 2.0) / max_value + 0.5 * scale; + } + cc->move_to(pos, 0.0); + cc->line_to(pos, winh - 0.0); + cc->stroke(); +} + +Gtk::SizeRequestMode HistogramRGBAreaHori::get_request_mode_vfunc () const +{ + return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH; +} + +void HistogramRGBAreaHori::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const +{ + getPreferredThickness(minimum_height, natural_height); +} + +void HistogramRGBAreaHori::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const +{ + getPreferredLength(minimum_width, natural_width); +} + +void HistogramRGBAreaHori::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const +{ + getPreferredThicknessForLength(width, minimum_height, natural_height); +} + +void HistogramRGBAreaHori::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const +{ + getPreferredLengthForThickness(height, minimum_width, natural_width); +} + +void HistogramRGBAreaVert::drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) +{ + double pos; + if (options.histogramDrawMode < 2 || options.histogramScopeType == 1) { + pos = padding + value * (winh - padding * 2.0 - 1) / max_value + 0.5 * scale; + } else { + pos = padding + HistogramScaling::log (max_value, value) * (winh - padding * 2.0) / max_value + 0.5 * scale; + } + cc->move_to(0.0, winh - pos); + cc->line_to(winw, winh - pos); + cc->stroke(); +} + +Gtk::SizeRequestMode HistogramRGBAreaVert::get_request_mode_vfunc () const +{ + return Gtk::SIZE_REQUEST_WIDTH_FOR_HEIGHT; +} + +void HistogramRGBAreaVert::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const +{ + getPreferredLength(minimum_height, natural_height); +} + +void HistogramRGBAreaVert::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const +{ + getPreferredThickness(minimum_width, natural_width); +} + +void HistogramRGBAreaVert::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const +{ + getPreferredLengthForThickness(width, minimum_height, natural_height); +} + +void HistogramRGBAreaVert::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const +{ + getPreferredThicknessForLength(height, minimum_width, natural_width); +} + // // // diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index a8f5922ee..f97d5188b 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -53,7 +53,7 @@ public: double log (double vsize, double val); }; -class HistogramRGBArea final : public Gtk::DrawingArea, public BackBuffer, private HistogramScaling, public rtengine::NonCopyable +class HistogramRGBArea : public Gtk::DrawingArea, public BackBuffer, protected HistogramScaling, public rtengine::NonCopyable { private: typedef const double (*TMatrix)[3]; @@ -83,12 +83,21 @@ protected: HistogramRGBAreaIdleHelper* harih; + /** Draw an indicator bar for the value. */ + virtual void drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) = 0; + + void getPreferredThickness(int& min_thickness, int& natural_length) const; + void getPreferredLength(int& min_length, int& natural_length) const; + void getPreferredThicknessForLength(int length, int& min_thickness, int& natural_length) const; + void getPreferredLengthForThickness(int thickness, int& min_length, int& natural_length) const; + public: HistogramRGBArea(); ~HistogramRGBArea() override; void updateBackBuffer (int r, int g, int b, const Glib::ustring &profile = "", const Glib::ustring &profileW = ""); bool getShow (); + void setShow(bool show); void setParent (Gtk::Grid* p) { parent = p; @@ -102,13 +111,30 @@ public: bool on_button_press_event (GdkEventButton* event) override; void factorChanged (double newFactor); +}; + +class HistogramRGBAreaHori final : public HistogramRGBArea +{ private: + void drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) override; + Gtk::SizeRequestMode get_request_mode_vfunc () const override; void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override; void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const override; void get_preferred_width_for_height_vfunc (int h, int &minimum_width, int &natural_width) const override; +}; +class HistogramRGBAreaVert final : public HistogramRGBArea +{ +private: + void drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) override; + + Gtk::SizeRequestMode get_request_mode_vfunc () const override; + void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override; + void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; + void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const override; + void get_preferred_width_for_height_vfunc (int h, int &minimum_width, int &natural_width) const override; }; class DrawModeListener @@ -197,6 +223,8 @@ protected: Gtk::Grid* buttonGrid; HistogramArea* histogramArea; HistogramRGBArea* histogramRGBArea; + std::unique_ptr histogramRGBAreaHori; + std::unique_ptr histogramRGBAreaVert; Gtk::ToggleButton* showRed; Gtk::ToggleButton* showGreen; Gtk::ToggleButton* showBlue; @@ -229,6 +257,7 @@ protected: sigc::connection rconn; void setHistInvalid (); + void showRGBBar(); public: From 6df69b378623d4a96122f06d3d79f2bea69f9091 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 26 Jul 2020 13:27:17 -0700 Subject: [PATCH 04/56] Improve performance of histogram/waveform updates Only perform calculations for the currently shown scope. Cache the waveform so it can be reused when the scope is resized. Increase speed of waveform rendering. --- rtengine/improccoordinator.cc | 75 +++++++++++++------- rtengine/improccoordinator.h | 9 ++- rtengine/rtengine.h | 17 +++++ rtgui/editorpanel.cc | 41 ++++++++++- rtgui/editorpanel.h | 10 +++ rtgui/histogrampanel.cc | 130 +++++++++++++++++++++++----------- rtgui/histogrampanel.h | 15 ++++ 7 files changed, 228 insertions(+), 69 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 37a81f3d1..4927c4e1f 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1640,31 +1640,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } if (hListener) { - updateLRGBHistograms(); - updateWaveforms(); - hListener->histogramChanged( - histRed, - histGreen, - histBlue, - histLuma, - histToneCurve, - histLCurve, - histCCurve, - /*histCLurve, - * histLLCurve,*/ - histLCAM, - histCCAM, - histRedRaw, - histGreenRaw, - histBlueRaw, - histChroma, - histLRETI, - waveformScale, - waveformWidth, - waveformRed.get(), - waveformGreen.get(), - waveformBlue.get() - ); + if (hListener->updateHistogram()) { + updateLRGBHistograms(); + } + if (hListener->updateWaveform()) { + updateWaveforms(); + } + notifyHistogramChanged(); } } @@ -1765,6 +1747,33 @@ void ImProcCoordinator::setScale(int prevscale) } +void ImProcCoordinator::notifyHistogramChanged() +{ + if (hListener) { + hListener->histogramChanged( + histRed, + histGreen, + histBlue, + histLuma, + histToneCurve, + histLCurve, + histCCurve, + histLCAM, + histCCAM, + histRedRaw, + histGreenRaw, + histBlueRaw, + histChroma, + histLRETI, + waveformScale, + waveformWidth, + waveformRed.get(), + waveformGreen.get(), + waveformBlue.get() + ); + } +} + void ImProcCoordinator::updateLRGBHistograms() { @@ -2305,4 +2314,20 @@ void ImProcCoordinator::setHighQualComputed() highQualityComputed = true; } +void ImProcCoordinator::updateWaveform() +{ + if (hListener) { + updateWaveforms(); + notifyHistogramChanged(); + } +} + +void ImProcCoordinator::updateHistogram() +{ + if (hListener) { + updateLRGBHistograms(); + notifyHistogramChanged(); + } +} + } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 367f12a43..92b5e9346 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -54,7 +54,7 @@ class Crop; * but using this class' LUT and other precomputed parameters. The main preview area is displaying a non framed Crop object, * while detail windows are framed Crop objects. */ -class ImProcCoordinator final : public StagedImageProcessor +class ImProcCoordinator final : public StagedImageProcessor, public HistogramObservable { friend class Crop; @@ -199,6 +199,7 @@ protected: MyMutex minit; // to gain mutually exclusive access to ... to what exactly? + void notifyHistogramChanged(); void reallocAll(); void updateLRGBHistograms(); void updateWaveforms(); @@ -454,7 +455,11 @@ public: } void setHistogramListener (HistogramListener *h) override { + if (hListener) { + hListener->setObservable(nullptr); + } hListener = h; + h->setObservable(this); } void setAutoCamListener (AutoCamListener* acl) override { @@ -555,6 +560,8 @@ public: } denoiseInfoStore; + void updateHistogram() override; + void updateWaveform() override; }; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 30fa2ec67..4121b4f49 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -302,6 +302,8 @@ public: virtual void sizeChanged(int w, int h, int ow, int oh) = 0; }; +class HistogramObservable; + /** This listener is used when the histogram of the final image has changed. */ class HistogramListener { @@ -334,6 +336,21 @@ public: const int waveformGreen[][256], const int waveformBlue[][256] ) = 0; + /** Tells which observable is notifying the listener. */ + 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 waveform to be updated. */ + virtual bool updateWaveform(void) = 0; +}; + +class HistogramObservable +{ +public: + /** Tells the observable to update the histogram data. */ + virtual void updateHistogram() = 0; + /** Tells the observable to update the waveform data. */ + virtual void updateWaveform() = 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 28747e063..5bf3e54d8 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -470,7 +470,8 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iBeforeLockON (nullptr), iBeforeLockOFF (nullptr), previewHandler (nullptr), beforePreviewHandler (nullptr), beforeIarea (nullptr), beforeBox (nullptr), afterBox (nullptr), beforeLabel (nullptr), afterLabel (nullptr), beforeHeaderBox (nullptr), afterHeaderBox (nullptr), parent (nullptr), parentWindow (nullptr), openThm (nullptr), - selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false) + selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false), + histogram_observable(nullptr), histogram_scope_type(HistogramPanelListener::NONE) { epih = new EditorPanelIdleHelper; @@ -2260,6 +2261,40 @@ void EditorPanel::histogramChanged( tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI); } +void EditorPanel::setObservable(rtengine::HistogramObservable* observable) +{ + histogram_observable = observable; +} + +bool EditorPanel::updateHistogram(void) +{ + return histogram_scope_type == HistogramPanelListener::HISTOGRAM + || histogram_scope_type == HistogramPanelListener::NONE; +} + +bool EditorPanel::updateWaveform(void) +{ + return histogram_scope_type == HistogramPanelListener::WAVEFORM + || histogram_scope_type == HistogramPanelListener::NONE; +} + +void EditorPanel::scopeTypeChanged(ScopeType new_type) +{ + histogram_scope_type = new_type; + + if (!histogram_observable) { + return; + } + + // Make sure the new scope is updated since we only actively update the + // current scope. + if (new_type == HistogramPanelListener::HISTOGRAM) { + histogram_observable->updateHistogram(); + } else if (new_type == HistogramPanelListener::WAVEFORM) { + histogram_observable->updateWaveform(); + } +} + bool EditorPanel::CheckSidePanelsVisibility() { if (tbTopPanel_1) { @@ -2376,6 +2411,10 @@ void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition) break; } + if (histogramPanel) { + histogramPanel->setPanelListener(this); + } + iareapanel->imageArea->setPointerMotionHListener (histogramPanel); } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 6a1fb585f..1794de11b 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -55,6 +55,7 @@ class EditorPanel final : public ThumbnailListener, public HistoryBeforeLineListener, public rtengine::HistogramListener, + public HistogramPanelListener, public rtengine::NonCopyable { public: @@ -133,6 +134,12 @@ public: const int waveformGreen[][256], const int waveformBlue[][256] ) override; + void setObservable(rtengine::HistogramObservable* observable) override; + bool updateHistogram(void) override; + bool updateWaveform(void) override; + + // HistogramPanelListener + void scopeTypeChanged(ScopeType new_type) override; // event handlers void info_toggled (); @@ -265,4 +272,7 @@ private: bool isProcessing; IdleRegister idle_register; + + rtengine::HistogramObservable* histogram_observable; + ScopeType histogram_scope_type; }; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 8c2d971eb..d3d92880d 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -32,7 +32,7 @@ using namespace rtengine; // // // HistogramPanel -HistogramPanel::HistogramPanel () +HistogramPanel::HistogramPanel () : panel_listener(nullptr) { setExpandAlignProperties(this, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); set_name("HistogramPanel"); @@ -355,12 +355,20 @@ void HistogramPanel::type_changed() showRAW->set_sensitive(); showMode->set_sensitive(); histogramRGBArea = histogramRGBAreaHori.get(); + if (panel_listener) { + updateHistAreaOptions(); + panel_listener->scopeTypeChanged(HistogramPanelListener::HISTOGRAM); + } } else { showValue->set_sensitive(false); showChro->set_sensitive(false); showRAW->set_sensitive(false); showMode->set_sensitive(false); histogramRGBArea = histogramRGBAreaVert.get(); + if (panel_listener) { + updateHistAreaOptions(); + panel_listener->scopeTypeChanged(HistogramPanelListener::WAVEFORM); + } } if (showBAR->get_active()) { @@ -383,7 +391,8 @@ void HistogramPanel::bar_toggled () void HistogramPanel::rgbv_toggled () { // Update Display - histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), options.histogramDrawMode, options.histogramScopeType); + updateHistAreaOptions(); + 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()); @@ -441,6 +450,35 @@ void HistogramPanel::toggleButtonMode () showMode->set_image(*mode2Image); } +void HistogramPanel::setPanelListener(HistogramPanelListener* listener) +{ + panel_listener = listener; + + if (listener) { + HistogramPanelListener::ScopeType type; + if (options.histogramScopeType == 0) { + type = HistogramPanelListener::HISTOGRAM; + } else { + type = HistogramPanelListener::WAVEFORM; + } + listener->scopeTypeChanged(type); + } +} + +void HistogramPanel::updateHistAreaOptions() +{ + histogramArea->updateOptions( + showRed->get_active(), + showGreen->get_active(), + showBlue->get_active(), + showValue->get_active(), + showChro->get_active(), + showRAW->get_active(), + options.histogramDrawMode, + options.histogramScopeType + ); +} + // // // @@ -775,7 +813,7 @@ void HistogramRGBAreaVert::get_preferred_width_for_height_vfunc (int height, int // // HistogramArea HistogramArea::HistogramArea (DrawModeListener *fml) : - waveform_width(0), + waveform_width(0), wave_buffer_dirty(true), valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), scopeType(options.histogramScopeType), oldwidth(-1), oldheight(-1), @@ -854,7 +892,7 @@ void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool options.histogramDrawMode = drawMode = mode; options.histogramScopeType = scopeType = type; - updateBackBuffer (); + wave_buffer_dirty = true; } void HistogramArea::update( @@ -874,27 +912,31 @@ void HistogramArea::update( ) { if (histRed) { - rhist = histRed; - ghist = histGreen; - bhist = histBlue; - lhist = histLuma; - chist = histChroma; - rhistRaw = histRedRaw; - ghistRaw = histGreenRaw; - bhistRaw = histBlueRaw; - waveform_scale = waveformScale; - if (waveform_width != waveformWidth) { - waveform_width = waveformWidth; - rwave.reset(new int[waveformWidth][256]); - gwave.reset(new int[waveformWidth][256]); - bwave.reset(new int[waveformWidth][256]); + if (scopeType == 0) { + rhist = histRed; + ghist = histGreen; + bhist = histBlue; + lhist = histLuma; + chist = histChroma; + rhistRaw = histRedRaw; + ghistRaw = histGreenRaw; + bhistRaw = histBlueRaw; + } else if (scopeType == 1) { + waveform_scale = waveformScale; + if (waveform_width != waveformWidth) { + waveform_width = waveformWidth; + rwave.reset(new int[waveformWidth][256]); + gwave.reset(new int[waveformWidth][256]); + bwave.reset(new int[waveformWidth][256]); + } + int (* const rw)[256] = rwave.get(); + int (* const gw)[256] = gwave.get(); + int (* const bw)[256] = bwave.get(); + memcpy(rw, waveformRed, 256 * waveformWidth * sizeof(rw[0][0])); + memcpy(gw, waveformGreen, 256 * waveformWidth * sizeof(gw[0][0])); + memcpy(bw, waveformBlue, 256 * waveformWidth * sizeof(bw[0][0])); + wave_buffer_dirty = true; } - int (* const rw)[256] = rwave.get(); - int (* const gw)[256] = gwave.get(); - int (* const bw)[256] = bwave.get(); - memcpy(rw, waveformRed, 256 * waveformWidth * sizeof(rw[0][0])); - memcpy(gw, waveformGreen, 256 * waveformWidth * sizeof(gw[0][0])); - memcpy(bw, waveformBlue, 256 * waveformWidth * sizeof(bw[0][0])); valid = true; } else { valid = false; @@ -1185,31 +1227,35 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h // See Cairo documentation on stride. const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, waveform_width); - std::unique_ptr buffer(new unsigned char[256 * cairo_stride]); - // Clear waveform. - memset(buffer.get(), 0, 256 * cairo_stride); + if (wave_buffer_dirty) { + wave_buffer.reset(new unsigned char[256 * cairo_stride]); - // TODO: Optimize. - for (int col = 0; col < waveform_width; col++) { - for (int val = 0; val < 256; val++) { - const float r = needRed ? scale * rwave[col][255 - val] : 0.f; - const float g = needGreen ? scale * gwave[col][255 - val] : 0.f; - const float b = needBlue ? scale * bwave[col][255 - val] : 0.f; - const float value = (r > g && r > b) ? r : ((g > b) ? g : b); - if (value <= 0) { - buffer[val * cairo_stride + col * 4 + 3] = 0; - } else { - buffer[val * cairo_stride + col * 4 + 3] = value; - buffer[val * cairo_stride + col * 4 + 2] = r; - buffer[val * cairo_stride + col * 4 + 1] = g; - buffer[val * cairo_stride + col * 4] = b; + // Clear waveform. + memset(wave_buffer.get(), 0, 256 * cairo_stride); + + // TODO: Optimize. + for (int col = 0; col < waveform_width; col++) { + for (int val = 0; val < 256; val++) { + const unsigned char r = needRed ? scale * rwave[col][val] : 0; + const unsigned char g = needGreen ? scale * gwave[col][val] : 0; + const unsigned char b = needBlue ? scale * bwave[col][val] : 0; + const unsigned char value = (r > g && r > b) ? r : ((g > b) ? g : b); + if (value <= 0) { + *(uint32_t*)&(wave_buffer[(255 - val) * cairo_stride + col * 4]) = 0; + } else { + // Speedup with one memory access instead of four. + *(uint32_t*)&(wave_buffer[(255 - val) * cairo_stride + col * 4]) = + b | (g << 8) | (r << 16) | (value << 24); + } } } + + wave_buffer_dirty = false; } Cairo::RefPtr surface = Cairo::ImageSurface::create( - buffer.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); + wave_buffer.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); auto orig_matrix = cr->get_matrix(); cr->translate(0, padding); cr->scale(static_cast(w) / waveform_width, (h - 2 * padding) / 256.0); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index f97d5188b..83099c68e 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -159,6 +159,8 @@ protected: int waveform_scale; int waveform_width; std::unique_ptr rwave, gwave, bwave; + std::unique_ptr wave_buffer; + bool wave_buffer_dirty; bool valid; int drawMode; @@ -214,6 +216,14 @@ private: void get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const override; }; +class HistogramPanelListener +{ +public: + enum ScopeType {HISTOGRAM, WAVEFORM, NONE}; + + virtual void scopeTypeChanged(ScopeType new_type) = 0; +}; + class HistogramPanel final : public Gtk::Grid, public PointerMotionListener, public DrawModeListener, public rtengine::NonCopyable { @@ -255,9 +265,12 @@ protected: Gtk::Image *mode1Image; Gtk::Image *mode2Image; + HistogramPanelListener* panel_listener; + sigc::connection rconn; void setHistInvalid (); void showRGBBar(); + void updateHistAreaOptions(); public: @@ -304,4 +317,6 @@ public: // drawModeListener interface void toggleButtonMode () override; + + void setPanelListener(HistogramPanelListener* listener); }; From fbe73614c3c3ab888c2db9fd92e1fed4b8617b70 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Mon, 3 Aug 2020 18:23:25 -0700 Subject: [PATCH 05/56] Add H-S and H-C vectorscopes --- rtdata/languages/default | 2 +- rtengine/improccoordinator.cc | 66 ++++++++++++- rtengine/improccoordinator.h | 8 +- rtengine/rtengine.h | 14 ++- rtgui/editorpanel.cc | 32 +++++- rtgui/editorpanel.h | 4 + rtgui/histogrampanel.cc | 177 ++++++++++++++++++++++++++++++++-- rtgui/histogrampanel.h | 18 +++- 8 files changed, 299 insertions(+), 22 deletions(-) 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; From 603cd6ea3d0bc1f1c84ca73a24ef4f6f13fc712a Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 4 Aug 2020 12:09:33 -0700 Subject: [PATCH 06/56] Clip waveform display values to 255 --- rtgui/histogrampanel.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 0967212d0..a821f9f98 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1289,7 +1289,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in // 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); + const unsigned char value = min(scale * vect[u][v], 0xff); *(uint32_t*)&(vect_buffer[(VECTORSCOPE_SIZE - 1 - u) * cairo_stride + v * 4]) = value | (value << 8) | (value << 16) | (value << 24); } @@ -1394,9 +1394,9 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h // TODO: Optimize. for (int col = 0; col < waveform_width; col++) { for (int val = 0; val < 256; val++) { - const unsigned char r = needRed ? scale * rwave[col][val] : 0; - const unsigned char g = needGreen ? scale * gwave[col][val] : 0; - const unsigned char b = needBlue ? scale * bwave[col][val] : 0; + const unsigned char r = needRed ? min(scale * rwave[col][val], 0xff) : 0; + const unsigned char g = needGreen ? min(scale * gwave[col][val], 0xff) : 0; + const unsigned char b = needBlue ? min(scale * bwave[col][val], 0xff) : 0; const unsigned char value = (r > g && r > b) ? r : ((g > b) ? g : b); if (value <= 0) { *(uint32_t*)&(wave_buffer[(255 - val) * cairo_stride + col * 4]) = 0; From c9bf58a7a0fdd624c56d94a1d55a31dfba9dd471 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 4 Aug 2020 18:38:59 -0700 Subject: [PATCH 07/56] Add scope type icons --- .../svg/histogram-type-histogram-small.svg | 122 ++++++++++++++++ .../histogram-type-vectorscope-hc-small.svg | 131 +++++++++++++++++ .../histogram-type-vectorscope-hs-small.svg | 135 ++++++++++++++++++ .../svg/histogram-type-waveform-small.svg | 122 ++++++++++++++++ rtgui/histogrampanel.cc | 21 +-- rtgui/histogrampanel.h | 5 + 6 files changed, 528 insertions(+), 8 deletions(-) create mode 100644 rtdata/images/svg/histogram-type-histogram-small.svg create mode 100644 rtdata/images/svg/histogram-type-vectorscope-hc-small.svg create mode 100644 rtdata/images/svg/histogram-type-vectorscope-hs-small.svg create mode 100644 rtdata/images/svg/histogram-type-waveform-small.svg diff --git a/rtdata/images/svg/histogram-type-histogram-small.svg b/rtdata/images/svg/histogram-type-histogram-small.svg new file mode 100644 index 000000000..1d2f6547e --- /dev/null +++ b/rtdata/images/svg/histogram-type-histogram-small.svg @@ -0,0 +1,122 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-vectorscope-hc-small.svg b/rtdata/images/svg/histogram-type-vectorscope-hc-small.svg new file mode 100644 index 000000000..ef2e8b51f --- /dev/null +++ b/rtdata/images/svg/histogram-type-vectorscope-hc-small.svg @@ -0,0 +1,131 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-vectorscope-hs-small.svg b/rtdata/images/svg/histogram-type-vectorscope-hs-small.svg new file mode 100644 index 000000000..62bbf9586 --- /dev/null +++ b/rtdata/images/svg/histogram-type-vectorscope-hs-small.svg @@ -0,0 +1,135 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-waveform-small.svg b/rtdata/images/svg/histogram-type-waveform-small.svg new file mode 100644 index 000000000..5147ab2fc --- /dev/null +++ b/rtdata/images/svg/histogram-type-waveform-small.svg @@ -0,0 +1,122 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index a821f9f98..4519bd438 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -89,6 +89,11 @@ HistogramPanel::HistogramPanel () : panel_listener(nullptr) mode1Image = new RTImage ("histogram-mode-logx-small.png"); mode2Image = new RTImage ("histogram-mode-logxy-small.png"); + histImage.reset(new RTImage("histogram-type-histogram-small.png")); + waveImage.reset(new RTImage("histogram-type-waveform-small.png")); + vectHcImage.reset(new RTImage("histogram-type-vectorscope-hc-small.png")); + vectHsImage.reset(new RTImage("histogram-type-vectorscope-hs-small.png")); + showRed = Gtk::manage (new Gtk::ToggleButton ()); showGreen = Gtk::manage (new Gtk::ToggleButton ()); showBlue = Gtk::manage (new Gtk::ToggleButton ()); @@ -162,13 +167,13 @@ HistogramPanel::HistogramPanel () : panel_listener(nullptr) else showMode->set_image(*mode2Image); if (options.histogramScopeType == 0) { - // TODO: scopeType->set_image(*histImage); + scopeType->set_image(*histImage); } else if (options.histogramScopeType == 1) { - // TODO: scopeType->set_image(*waveImage); + scopeType->set_image(*waveImage); } else if (options.histogramScopeType == 2) { - // TODO: scopeType->set_image(*vectHsImage); + scopeType->set_image(*vectHsImage); } else if (options.histogramScopeType == 3) { - // TODO: scopeType->set_image(*vectHcImage); + scopeType->set_image(*vectHcImage); } showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); @@ -338,13 +343,13 @@ void HistogramPanel::type_pressed() 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); + scopeType->set_image(*histImage); } else if (options.histogramScopeType == 1) { - // TODO: showMode->set_image(*waveImage); + scopeType->set_image(*waveImage); } else if (options.histogramScopeType == 2) { - // TODO: showMode->set_image(*vectHsImage); + scopeType->set_image(*vectHsImage); } else if (options.histogramScopeType == 3) { - // TODO: showMode->set_image(*vectHcImage); + scopeType->set_image(*vectHcImage); } type_changed(); rgbv_toggled(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index a3d29bdd3..864fc3fb6 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -273,6 +273,11 @@ protected: Gtk::Image *barImage_g; Gtk::Image *chroImage_g; + std::unique_ptr histImage; + std::unique_ptr waveImage; + std::unique_ptr vectHcImage; + std::unique_ptr vectHsImage; + Gtk::Image *mode0Image; Gtk::Image *mode1Image; Gtk::Image *mode2Image; From ba57a6c6803984a7b7a6a8d48df61a2c36d779af Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 4 Aug 2020 23:07:03 -0700 Subject: [PATCH 08/56] Fix waveform and vectorscope crop behavior Properly scale values for the vectorscopes and only show the crop region for the waveform. --- rtengine/improccoordinator.cc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f19eff54d..9c18d0fa2 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1886,7 +1886,7 @@ void ImProcCoordinator::updateVectorscope() } } - vectorscopeScale = workimg->getWidth() * workimg->getHeight(); + vectorscopeScale = (x2 - x1) * (y2 - y1); } void ImProcCoordinator::updateWaveforms() @@ -1896,9 +1896,12 @@ void ImProcCoordinator::updateWaveforms() return; } - if (waveformWidth != workimg->getWidth()) { + int x1, y1, x2, y2; + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + + if (waveformWidth != x2 - x1) { // Resize waveform arrays. - waveformWidth = workimg->getWidth(); + waveformWidth = x2 - x1; waveformRed.reset(new int[waveformWidth][256]); waveformGreen.reset(new int[waveformWidth][256]); waveformBlue.reset(new int[waveformWidth][256]); @@ -1914,16 +1917,17 @@ void ImProcCoordinator::updateWaveforms() memset(waveformGreen.get(), 0, waveformSize * sizeof(green[0][0])); memset(waveformBlue.get(), 0, waveformSize * sizeof(blue[0][0])); - const int img_height = workimg->getHeight(); - for (int col = 0; col < waveformWidth; col++) { - for (int row = 0; row < img_height; row++) { - red[col][workimg->r(row, col)]++; - green[col][workimg->g(row, col)]++; - blue[col][workimg->b(row, col)]++; + for (int i = y1; i < y2; i++) { + int ofs = (i * pW + x1) * 3; + + for (int j = 0; j < waveformWidth; j++) { + red[j][workimg->data[ofs++]]++; + green[j][workimg->data[ofs++]]++; + blue[j][workimg->data[ofs++]]++; } } - waveformScale = img_height; + waveformScale = y2 - y1; } bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, double tempBias) From 9382306fedf4a6db74bfce4a134ae1831531a4f8 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Wed, 5 Aug 2020 11:57:34 -0700 Subject: [PATCH 09/56] Add CIELAB lightness to waveform --- rtengine/improccoordinator.cc | 8 +++++++- rtengine/improccoordinator.h | 1 + rtengine/rtengine.h | 3 ++- rtgui/editorpanel.cc | 5 +++-- rtgui/editorpanel.h | 3 ++- rtgui/histogrampanel.cc | 31 +++++++++++++++++++++++++++---- rtgui/histogrampanel.h | 11 +++++++---- 7 files changed, 49 insertions(+), 13 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 9c18d0fa2..a1648aeb4 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1774,7 +1774,8 @@ void ImProcCoordinator::notifyHistogramChanged() waveformWidth, waveformRed.get(), waveformGreen.get(), - waveformBlue.get() + waveformBlue.get(), + waveformLuma.get() ); } } @@ -1905,18 +1906,22 @@ void ImProcCoordinator::updateWaveforms() waveformRed.reset(new int[waveformWidth][256]); waveformGreen.reset(new int[waveformWidth][256]); waveformBlue.reset(new int[waveformWidth][256]); + waveformLuma.reset(new int[waveformWidth][256]); } int (*red)[256] = waveformRed.get(); int (*green)[256] = waveformGreen.get(); int (*blue)[256] = waveformBlue.get(); + int (*luma)[256] = waveformLuma.get(); // Start with zero. const int waveformSize = 256 * waveformWidth; memset(waveformRed.get(), 0, waveformSize * sizeof(red[0][0])); memset(waveformGreen.get(), 0, waveformSize * sizeof(green[0][0])); memset(waveformBlue.get(), 0, waveformSize * sizeof(blue[0][0])); + memset(waveformLuma.get(), 0, waveformSize * sizeof(luma[0][0])); + constexpr float luma_factor = 255.f / 32768.f; for (int i = y1; i < y2; i++) { int ofs = (i * pW + x1) * 3; @@ -1924,6 +1929,7 @@ void ImProcCoordinator::updateWaveforms() red[j][workimg->data[ofs++]]++; green[j][workimg->data[ofs++]]++; blue[j][workimg->data[ofs++]]++; + luma[j][(int)(nprevl->L[i][j + x1] * luma_factor)]++; } } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 14ee81934..5eeef3e9e 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -134,6 +134,7 @@ protected: std::unique_ptr waveformRed, waveformRedRaw; std::unique_ptr waveformGreen, waveformGreenRaw; std::unique_ptr waveformBlue, waveformBlueRaw; + std::unique_ptr waveformLuma; LUTf CAMBrightCurveJ, CAMBrightCurveQ; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 49f858cdc..aa5e6aed7 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -338,7 +338,8 @@ public: int waveformWidth, const int waveformRed[][256], const int waveformGreen[][256], - const int waveformBlue[][256] + const int waveformBlue[][256], + const int waveformLuma[][256] ) = 0; /** Tells which observable is notifying the listener. */ virtual void setObservable(HistogramObservable* observable) = 0; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index e52c9f47a..2d3099727 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2253,11 +2253,12 @@ void EditorPanel::histogramChanged( int waveformWidth, const int waveformRed[][256], const int waveformGreen[][256], - const int waveformBlue[][256] + const int waveformBlue[][256], + const int waveformLuma[][256] ) { if (histogramPanel) { - histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue); + histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue, waveformLuma); } tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI); diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index b9d196ccd..ed34c1931 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -134,7 +134,8 @@ public: int waveformWidth, const int waveformRed[][256], const int waveformGreen[][256], - const int waveformBlue[][256] + const int waveformBlue[][256], + const int waveformLuma[][256] ) override; void setObservable(rtengine::HistogramObservable* observable) override; bool updateHistogram(void) override; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 4519bd438..3c5fd4719 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -379,7 +379,7 @@ void HistogramPanel::type_changed() showRed->set_sensitive(); showGreen->set_sensitive(); showBlue->set_sensitive(); - showValue->set_sensitive(false); + showValue->set_sensitive(); showChro->set_sensitive(false); showRAW->set_sensitive(false); showMode->set_sensitive(false); @@ -663,7 +663,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 == 0) { + if((needLuma || needChroma) && options.histogramScopeType <= 1) { 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); @@ -673,7 +673,7 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustrin drawBar(cc, Lab_L, 100.0, winw, winh, s); } - if (needChroma) { + if (needChroma && options.histogramScopeType == 0) { // Chroma double chromaval = sqrt(Lab_a * Lab_a + Lab_b * Lab_b) / 1.8; cc->set_source_rgb(0.9, 0.9, 0.0); @@ -960,7 +960,8 @@ void HistogramArea::update( int waveformWidth, const int waveformRed[][256], const int waveformGreen[][256], - const int waveformBlue[][256] + const int waveformBlue[][256], + const int waveformLuma[][256] ) { if (histRed) { @@ -980,13 +981,16 @@ void HistogramArea::update( rwave.reset(new int[waveformWidth][256]); gwave.reset(new int[waveformWidth][256]); bwave.reset(new int[waveformWidth][256]); + lwave.reset(new int[waveformWidth][256]); } int (* const rw)[256] = rwave.get(); int (* const gw)[256] = gwave.get(); int (* const bw)[256] = bwave.get(); + int (* const lw)[256] = lwave.get(); memcpy(rw, waveformRed, 256 * waveformWidth * sizeof(rw[0][0])); memcpy(gw, waveformGreen, 256 * waveformWidth * sizeof(gw[0][0])); memcpy(bw, waveformBlue, 256 * waveformWidth * sizeof(bw[0][0])); + memcpy(lw, waveformLuma, 256 * waveformWidth * sizeof(lw[0][0])); wave_buffer_dirty = true; } else if (scopeType >= 2) { vectorscope_scale = vectorscopeScale; @@ -1392,9 +1396,11 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h if (wave_buffer_dirty) { wave_buffer.reset(new unsigned char[256 * cairo_stride]); + wave_buffer_luma.reset(new unsigned char[256 * cairo_stride]); // Clear waveform. memset(wave_buffer.get(), 0, 256 * cairo_stride); + memset(wave_buffer_luma.get(), 0, 256 * cairo_stride); // TODO: Optimize. for (int col = 0; col < waveform_width; col++) { @@ -1413,6 +1419,16 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h } } + if (needLuma) { + for (int col = 0; col < waveform_width; col++) { + for (int val = 0; val < 256; val++) { + const unsigned char l = min(scale * lwave[col][val], 0xff); + *(uint32_t*)&(wave_buffer_luma[(255 - val) * cairo_stride + col * 4]) = + l | (l << 8) | (l << 16) | (l << 24); + } + } + } + wave_buffer_dirty = false; } @@ -1424,6 +1440,13 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h cr->set_source(surface, 0, 0); cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); + if (needLuma) { + surface = Cairo::ImageSurface::create( + wave_buffer_luma.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + } surface->finish(); cr->set_matrix(orig_matrix); } diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 864fc3fb6..227001845 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -167,8 +167,9 @@ protected: bool vect_buffer_dirty; int waveform_scale; int waveform_width; - std::unique_ptr rwave, gwave, bwave; + std::unique_ptr rwave, gwave, bwave, lwave; std::unique_ptr wave_buffer; + std::unique_ptr wave_buffer_luma; bool wave_buffer_dirty; bool valid; @@ -206,7 +207,8 @@ public: int waveformWidth, const int waveformRed[][256], const int waveformGreen[][256], - const int waveformBlue[][256] + const int waveformBlue[][256], + const int waveformLuma[][256] ); void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type); void on_realize() override; @@ -309,10 +311,11 @@ public: int waveformWidth, const int waveformRed[][256], const int waveformGreen[][256], - const int waveformBlue[][256] + const int waveformBlue[][256], + const int waveformLuma[][256] ) { - histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue); + histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue, waveformLuma); } // 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; From 9a89eb545494d6f83ffedf1fcabea3f43a792ff5 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Wed, 5 Aug 2020 12:05:58 -0700 Subject: [PATCH 10/56] Fix RGB bars not showing for waveform The bars were not showing if the raw histogram button was activated. --- rtgui/histogrampanel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 3c5fd4719..d9f369509 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -617,7 +617,7 @@ void HistogramRGBArea::setShow(bool show) void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { - if (!get_realized () || !showMode || rawMode) { + if (!get_realized () || !showMode || (rawMode && options.histogramScopeType != 1)) { return; } From 426162f269fc1066052c6a5a6dd2bacd87bb4534 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Wed, 5 Aug 2020 12:23:34 -0700 Subject: [PATCH 11/56] Move lightness waveform behind RGB waveform --- rtgui/histogrampanel.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index d9f369509..b87d58d89 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1432,14 +1432,10 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h wave_buffer_dirty = false; } - Cairo::RefPtr surface = Cairo::ImageSurface::create( - wave_buffer.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); + Cairo::RefPtr surface; auto orig_matrix = cr->get_matrix(); cr->translate(0, padding); cr->scale(static_cast(w) / waveform_width, (h - 2 * padding) / 256.0); - cr->set_source(surface, 0, 0); - cr->set_operator(Cairo::OPERATOR_OVER); - cr->paint(); if (needLuma) { surface = Cairo::ImageSurface::create( wave_buffer_luma.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); @@ -1447,6 +1443,11 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); } + surface = Cairo::ImageSurface::create( + wave_buffer.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); surface->finish(); cr->set_matrix(orig_matrix); } From 698b2e18426df61b25aaf5e74a2055e7417088de Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Fri, 7 Aug 2020 15:18:02 -0700 Subject: [PATCH 12/56] Finish Cairo surface used for waveform --- rtgui/histogrampanel.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index b87d58d89..b6a27a3c1 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1442,6 +1442,7 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h cr->set_source(surface, 0, 0); cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); + surface->finish(); } surface = Cairo::ImageSurface::create( wave_buffer.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); From f7795278335f0bb5d58e8a5915a2e60b80377a0b Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Fri, 7 Aug 2020 17:26:22 -0700 Subject: [PATCH 13/56] Clip H-C vectorscope according to color profile --- rtengine/improccoordinator.cc | 12 +++- rtengine/improcfun.cc | 124 ++++++++++++++++++++++++++++++++++ rtengine/improcfun.h | 1 + 3 files changed, 135 insertions(+), 2 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index a1648aeb4..82527d530 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1853,6 +1853,13 @@ void ImProcCoordinator::updateVectorscope() constexpr int size = HistogramListener::vectorscope_size; memset(vectorscope, 0, size * size * sizeof(vectorscope[0][0])); + const int lab_img_size = (hListener->vectorscopeType() == 1) ? (x2 - x1) * (y2 - y1) : 0; + float L[lab_img_size], a[lab_img_size], b[lab_img_size]; + if (lab_img_size) { + ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L, a, b, params->icm); + } + + int ofs_lab = 0; for (int i = y1; i < y2; i++) { int ofs = (i * pW + x1) * 3; @@ -1875,12 +1882,13 @@ void ImProcCoordinator::updateVectorscope() 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; + const int col = (size / 96000.0) * a[ofs_lab] + size / 2; + const int row = (size / 96000.0) * b[ofs_lab] + size / 2; if (col >= 0 && col < size && row >= 0 && row < size) { vectorscope[row][col]++; } + ofs_lab++; break; } } diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 6051b6b0b..7e13fd214 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -5716,6 +5716,130 @@ void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib:: } } +void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, float L[], float a[], float b[], const procparams::ColorManagementParams &icm, bool consider_histogram_settings) const +{ // Adapted from ImProcFunctions::lab2rgb + const int src_width = src.getWidth(); + const int src_height = src.getHeight(); + + if (x < 0) { + x = 0; + } + + if (y < 0) { + y = 0; + } + + if (x + w > src_width) { + w = src_width - x; + } + + if (y + h > src_height) { + h = src_height - y; + } + + Glib::ustring profile; + + bool standard_gamma; + + if (settings->HistogramWorking && consider_histogram_settings) { + profile = icm.workingProfile; + standard_gamma = true; + } else { + profile = icm.outputProfile; + + if (icm.outputProfile.empty() || icm.outputProfile == ColorManagementParams::NoICMString) { + profile = "sRGB"; + } + + standard_gamma = false; + } + + cmsHPROFILE oprof = ICCStore::getInstance()->getProfile(profile); + + if (oprof) { + cmsHPROFILE oprofG = oprof; + + if (standard_gamma) { + oprofG = ICCStore::makeStdGammaProfile(oprof); + } + + cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + + lcmsMutex->lock(); + cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr); + cmsHTRANSFORM hTransform = cmsCreateTransform (oprofG, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); // NOCACHE is important for thread safety + cmsCloseProfile(LabIProf); + lcmsMutex->unlock(); + + // cmsDoTransform is relatively expensive +#ifdef _OPENMP + #pragma omp parallel +#endif + { + AlignedBuffer oBuf(3 * w); + float *outbuffer = oBuf.data; + int condition = y + h; + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + + for (int i = y; i < condition; i++) { + const int ix = 3 * (x + i * src_width); + int iy = 0; + float* rL = L + (i - y) * w; + float* ra = a + (i - y) * w; + float* rb = b + (i - y) * w; + + cmsDoTransform (hTransform, src.data + ix, outbuffer, w); + + for (int j = 0; j < w; j++) { + rL[j] = outbuffer[iy++] * 327.68f; + ra[j] = outbuffer[iy++] * 327.68f; + rb[j] = outbuffer[iy++] * 327.68f; + } + } + } // End of parallelization + + cmsDeleteTransform(hTransform); + + if (oprofG != oprof) { + cmsCloseProfile(oprofG); + } + } else { + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(profile); + const float wp[3][3] = { + {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, + {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, + {static_cast(wprof[2][0]), static_cast(wprof[2][1]), static_cast(wprof[2][2])} + }; + + const int x2 = x + w; + const int y2 = y + h; + constexpr float rgb_factor = 65355.f / 255.f; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + + for (int i = y; i < y2; i++) { + int offset = (i - y) * w; + for (int j = x; j < x2; j++) { + float X, Y, Z; + // lab2rgb uses gamma2curve, which is gammatab_srgb. + const auto& igamma = Color::igammatab_srgb; + Color::rgbxyz(igamma[rgb_factor * src.r(i, j)], igamma[rgb_factor * src.g(i, j)], igamma[rgb_factor * src.b(i, j)], X, Y, Z, wp); + Color::XYZ2Lab(X, Y, Z, L[offset], a[offset], b[offset]); + offset++; + } + } + } +} + void ImProcFunctions::lab2rgb(const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace) { TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(workingSpace); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 113667262..48f2cbc92 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -449,6 +449,7 @@ public: void labColorCorrectionRegions(LabImage *lab); Image8* lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true); + void rgb2lab(const Image8 &src, int x, int y, int w, int h, float L[], float a[], float b[], const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true) const; Imagefloat* lab2rgbOut(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); // CieImage *ciec; void workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, const Glib::ustring &profile, double gampos, double slpos, cmsHTRANSFORM &transform, bool normalizeIn = true, bool normalizeOut = true, bool keepTransForm = false) const; From 6c53317ac1364753571d4e575c8a809d8db667ae Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 8 Aug 2020 12:57:38 -0700 Subject: [PATCH 14/56] Add pointer indicator for vectorscopes --- rtgui/histogrampanel.cc | 100 ++++++++++++++++++++++++++++++++-------- rtgui/histogrampanel.h | 8 +++- 2 files changed, 89 insertions(+), 19 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index b6a27a3c1..1a9782f98 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -48,10 +48,16 @@ HistogramPanel::HistogramPanel () : panel_listener(nullptr) setExpandAlignProperties(histogramRGBAreaVert.get(), false, true, Gtk::ALIGN_END, Gtk::ALIGN_FILL); histogramRGBAreaVert->show(); - if (options.histogramScopeType == 1) { - histogramRGBArea = histogramRGBAreaVert.get(); - } else { - histogramRGBArea = histogramRGBAreaHori.get(); + switch (options.histogramScopeType) { + case 2: + case 3: + histogramRGBArea = nullptr; + break; + case 1: + histogramRGBArea = histogramRGBAreaVert.get(); + break; + default: + histogramRGBArea = histogramRGBAreaHori.get(); } // connecting the two childs @@ -253,6 +259,8 @@ void HistogramPanel::showRGBBar() if (histogramRGBArea == histogramRGBAreaHori.get()) { pos = Gtk::POS_BOTTOM; + } else if (histogramRGBArea == nullptr) { + return; } else { if (options.histogramPosition == 1) { pos = Gtk::POS_RIGHT; @@ -273,8 +281,10 @@ void HistogramPanel::resized (Gtk::Allocation& req) histogramArea->queue_draw (); // set histogramRGBArea invalid; - histogramRGBArea->updateBackBuffer(-1, -1, -1); - histogramRGBArea->queue_draw (); + if (histogramRGBArea) { + histogramRGBArea->updateBackBuffer(-1, -1, -1); + histogramRGBArea->queue_draw (); + } // Store current height of the histogram options.histogramHeight = get_height(); @@ -357,7 +367,7 @@ void HistogramPanel::type_pressed() void HistogramPanel::type_changed() { - if (showBAR->get_active()) { + if (showBAR->get_active() && histogramRGBArea) { histogramRGBArea->setShow(false); gfxGrid->remove(*histogramRGBArea); } @@ -396,7 +406,7 @@ void HistogramPanel::type_changed() showChro->set_sensitive(false); showRAW->set_sensitive(false); showMode->set_sensitive(false); - histogramRGBArea = histogramRGBAreaHori.get(); + histogramRGBArea = nullptr; if (panel_listener) { updateHistAreaOptions(); HistogramPanelListener::ScopeType type; @@ -424,7 +434,7 @@ void HistogramPanel::bar_toggled () if (showBAR->get_active()) { showRGBBar(); - } else { + } else if (histogramRGBArea) { gfxGrid->remove(*histogramRGBArea); } } @@ -436,9 +446,11 @@ 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() && options.histogramScopeType < 2); - histogramRGBArea->updateBackBuffer (0, 0, 0); - histogramRGBArea->queue_draw (); + if (histogramRGBArea) { + 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 (); + } } void HistogramPanel::setHistRGBInvalid () @@ -450,15 +462,27 @@ void HistogramPanel::setHistRGBInvalid () void HistogramPanel::pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw) { + bool update_hist_area; if (!validPos) { // do something to un-show vertical bars - histogramRGBArea->updateBackBuffer(-1, -1, -1); + if (histogramRGBArea) { + histogramRGBArea->updateBackBuffer(-1, -1, -1); + } + update_hist_area = histogramArea->updatePointer(-1, -1, -1); } else { // do something to show vertical bars - histogramRGBArea->updateBackBuffer(r, g, b, profile, profileW); + if (histogramRGBArea) { + histogramRGBArea->updateBackBuffer(r, g, b, profile, profileW); + } + update_hist_area = histogramArea->updatePointer(r, g, b, profile, profileW); + } + if (histogramRGBArea) { + histogramRGBArea->queue_draw(); + } + if (update_hist_area) { + histogramArea->queue_draw(); } - histogramRGBArea->queue_draw (); } /* @@ -522,7 +546,8 @@ void HistogramPanel::updateHistAreaOptions() showChro->get_active(), showRAW->get_active(), options.histogramDrawMode, - options.histogramScopeType + options.histogramScopeType, + showBAR->get_active() ); } @@ -866,7 +891,8 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : oldwidth(-1), oldheight(-1), needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), - isPressed(false), movingPosition(0.0) + isPressed(false), movingPosition(0.0), + pointer_red(-1), pointer_green(-1), pointer_blue(-1) { rhist(256); @@ -930,7 +956,7 @@ void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minim get_preferred_width_vfunc (minimum_width, natural_width); } -void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type) +void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type, bool pointer) { options.histogramRed = needRed = r; @@ -941,6 +967,7 @@ void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool options.histogramRAW = rawMode = raw; options.histogramDrawMode = drawMode = mode; options.histogramScopeType = scopeType = type; + options.histogramBar = needPointer = pointer; wave_buffer_dirty = true; } @@ -1232,6 +1259,24 @@ void HistogramArea::updateBackBuffer () setDirty(false); } +bool HistogramArea::updatePointer(int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) +{ + if (!needPointer || scopeType < 2) { + return false; + } + if (pointer_red == r && pointer_green == g && pointer_blue == b) { + return false; + } + + float L; + pointer_red = r; + pointer_green = g; + pointer_blue = b; + Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, L, pointer_a, pointer_b, options.rtSettings.HistogramWorking); + updateBackBuffer(); + return true; +} + void HistogramArea::on_realize () { @@ -1383,6 +1428,25 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in cr->paint(); surface->finish(); cr->set_matrix(orig_matrix); + + if (needPointer && pointer_red >= 0 && pointer_green >= 0 && pointer_blue >= 0) { + float cx, cy; + if (scopeType == 2) { + float H, S, L; + Color::rgb2hsl(pointer_red * 256.f, pointer_green * 256.f, pointer_blue * 256.f, H, S, L); + cx = (w + scope_size * S * cos(H * 2 * RT_PI)) / 2; + cy = (h - scope_size * S * sin(H * 2 * RT_PI)) / 2; + } else { + constexpr float ab_factor = 327.68f / 96000.f; + cx = w / 2.f + scope_size * pointer_a * ab_factor; + cy = h / 2.f - scope_size * pointer_b * ab_factor; + } + cr->arc(cx, cy, 2 * s, 0, 2 * RT_PI); + cr->set_source_rgb(0, 0, 0); + cr->fill_preserve(); + cr->set_source_rgb(1, 1, 1); + cr->stroke(); + } } } diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 227001845..75930db9b 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -182,16 +182,22 @@ protected: bool rawMode; bool isPressed; double movingPosition; + bool needPointer; double padding = 5.0; HistogramAreaIdleHelper* haih; + int pointer_red, pointer_green, pointer_blue; + float pointer_a, pointer_b; + public: explicit HistogramArea(DrawModeListener *fml = nullptr); ~HistogramArea() override; void updateBackBuffer (); + /// Update pointer values. Returns true if widget needs redrawing. + bool updatePointer(int r, int g, int b, const Glib::ustring &profile = "", const Glib::ustring &profileW = ""); void update( const LUTu& histRed, const LUTu& histGreen, @@ -210,7 +216,7 @@ public: const int waveformBlue[][256], const int waveformLuma[][256] ); - void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type); + void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type, bool pointer); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; bool on_button_press_event (GdkEventButton* event) override; From ec27ad4abc21ff97333fbc7d9657b75b8c259462 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 8 Aug 2020 17:11:18 -0700 Subject: [PATCH 15/56] Add waveform/vectorscope brightness feature --- rtgui/histogrampanel.cc | 28 +++++++++++++++++++++++----- rtgui/histogrampanel.h | 2 ++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 1a9782f98..06a0b912c 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -889,6 +889,7 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), scopeType(options.histogramScopeType), oldwidth(-1), oldheight(-1), + trace_brightness(1.0), needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), isPressed(false), movingPosition(0.0), @@ -1334,7 +1335,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in { // Arbitrary scale factor multiplied by vectorscope area and divided by // current scale. - const float scale = 16.f * VECTORSCOPE_SIZE * VECTORSCOPE_SIZE / vectorscope_scale; + const float scale = trace_brightness * 8.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); @@ -1453,7 +1454,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h) { // Arbitrary scale factor divided by current scale. - const float scale = 32.f * 255.f / waveform_scale; + const float scale = trace_brightness * 32.f * 255.f / waveform_scale; // See Cairo documentation on stride. const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, waveform_width); @@ -1561,12 +1562,15 @@ 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 == 0) { return false; } - if (isPressed) - { + if (!isPressed) { + return true; + } + + if (scopeType == 0) { // Adjust log scale. double mod = 1 + (event->x - movingPosition) / get_width(); factor /= mod; @@ -1579,6 +1583,20 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) setDirty(true); queue_draw (); + } else if (scopeType >= 1 && scopeType <= 3) { // Adjust brightness. + constexpr float MIN_BRIGHT = 0.1; + constexpr float MAX_BRIGHT = 3; + constexpr float RANGE = MAX_BRIGHT / MIN_BRIGHT; + double dx = (event->x - movingPosition) / get_width(); + float new_brightness = LIM(trace_brightness * pow(RANGE, dx), MIN_BRIGHT, MAX_BRIGHT); + if (new_brightness != trace_brightness) { + wave_buffer_dirty = true; + vect_buffer_dirty = true; + trace_brightness = new_brightness; + setDirty(true); + queue_draw(); + } + movingPosition = event->x; } return true; diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 75930db9b..fb38ee757 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -177,6 +177,8 @@ protected: DrawModeListener *myDrawModeListener; int scopeType; int oldwidth, oldheight; + /// Intensity of waveform and vectorscope trace. + float trace_brightness; bool needRed, needGreen, needBlue, needLuma, needChroma; bool rawMode; From 6cd87ad975d4be08a77b418ce44c905da2180656 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 9 Aug 2020 16:49:28 -0700 Subject: [PATCH 16/56] Use array2D for waveform and vectorscopes --- rtengine/improccoordinator.cc | 68 +++++++++-------- rtengine/improccoordinator.h | 8 +- rtengine/rtengine.h | 16 ++-- rtgui/editorpanel.cc | 14 ++-- rtgui/editorpanel.h | 17 +++-- rtgui/histogrampanel.cc | 139 +++++++++++++++++++--------------- rtgui/histogrampanel.h | 36 ++++----- 7 files changed, 160 insertions(+), 138 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 82527d530..3609617be 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -23,6 +23,7 @@ #include "improccoordinator.h" +#include "array2D.h" #include "cieimage.h" #include "color.h" #include "colortemp.h" @@ -47,6 +48,9 @@ namespace { + +constexpr int VECTORSCOPE_SIZE = 128; + using rtengine::Coord2D; Coord2D translateCoord(const rtengine::ImProcFunctions& ipf, int fw, int fh, int x, int y) { @@ -129,7 +133,11 @@ ImProcCoordinator::ImProcCoordinator() : histLRETI(256), - waveformWidth(0), + vectorscope(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), + waveformRed(0, 0), + waveformGreen(0, 0), + waveformBlue(0, 0), + waveformLuma(0, 0), CAMBrightCurveJ(), CAMBrightCurveQ(), @@ -1771,11 +1779,10 @@ void ImProcCoordinator::notifyHistogramChanged() vectorscopeScale, vectorscope, waveformScale, - waveformWidth, - waveformRed.get(), - waveformGreen.get(), - waveformBlue.get(), - waveformLuma.get() + waveformRed, + waveformGreen, + waveformBlue, + waveformLuma ); } } @@ -1850,8 +1857,8 @@ void ImProcCoordinator::updateVectorscope() 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])); + constexpr int size = VECTORSCOPE_SIZE; + memset((int*)vectorscope, 0, size * size * sizeof(vectorscope[0][0])); const int lab_img_size = (hListener->vectorscopeType() == 1) ? (x2 - x1) * (y2 - y1) : 0; float L[lab_img_size], a[lab_img_size], b[lab_img_size]; @@ -1901,43 +1908,44 @@ void ImProcCoordinator::updateVectorscope() void ImProcCoordinator::updateWaveforms() { if (!workimg) { - waveformWidth = 0; + // Resize to zero. + waveformRed(0, 0); + waveformGreen(0, 0); + waveformBlue(0, 0); + waveformLuma(0, 0); return; } int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + int waveform_width = waveformRed.getWidth(); - if (waveformWidth != x2 - x1) { + if (waveform_width != x2 - x1) { // Resize waveform arrays. - waveformWidth = x2 - x1; - waveformRed.reset(new int[waveformWidth][256]); - waveformGreen.reset(new int[waveformWidth][256]); - waveformBlue.reset(new int[waveformWidth][256]); - waveformLuma.reset(new int[waveformWidth][256]); + waveform_width = x2 - x1; + waveformRed(waveform_width, 256); + waveformGreen(waveform_width, 256); + waveformBlue(waveform_width, 256); + waveformLuma(waveform_width, 256); } - int (*red)[256] = waveformRed.get(); - int (*green)[256] = waveformGreen.get(); - int (*blue)[256] = waveformBlue.get(); - int (*luma)[256] = waveformLuma.get(); - // Start with zero. - const int waveformSize = 256 * waveformWidth; - memset(waveformRed.get(), 0, waveformSize * sizeof(red[0][0])); - memset(waveformGreen.get(), 0, waveformSize * sizeof(green[0][0])); - memset(waveformBlue.get(), 0, waveformSize * sizeof(blue[0][0])); - memset(waveformLuma.get(), 0, waveformSize * sizeof(luma[0][0])); + const int waveformSize = 256 * waveform_width; + memset((int*)waveformRed, 0, waveformSize * sizeof(waveformRed[0][0])); + memset((int*)waveformGreen, 0, waveformSize * sizeof(waveformGreen[0][0])); + memset((int*)waveformBlue, 0, waveformSize * sizeof(waveformBlue[0][0])); + memset((int*)waveformLuma, 0, waveformSize * sizeof(waveformLuma[0][0])); constexpr float luma_factor = 255.f / 32768.f; for (int i = y1; i < y2; i++) { int ofs = (i * pW + x1) * 3; + float* L_row = nprevl->L[i] + x1; - for (int j = 0; j < waveformWidth; j++) { - red[j][workimg->data[ofs++]]++; - green[j][workimg->data[ofs++]]++; - blue[j][workimg->data[ofs++]]++; - luma[j][(int)(nprevl->L[i][j + x1] * luma_factor)]++; + for (int j = 0; j < waveform_width; j++) { + waveformRed[workimg->data[ofs++]][j]++; + waveformGreen[workimg->data[ofs++]][j]++; + waveformBlue[workimg->data[ofs++]][j]++; + waveformLuma[LIM(L_row[j] * luma_factor, 0, 255)][j]++; } } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 5eeef3e9e..8a112b270 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -127,14 +127,10 @@ protected: LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; int vectorscopeScale; - int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size]; + array2D vectorscope; /// Waveform's intensity. Same as height of reference image. int waveformScale; - int waveformWidth; - std::unique_ptr waveformRed, waveformRedRaw; - std::unique_ptr waveformGreen, waveformGreenRaw; - std::unique_ptr waveformBlue, waveformBlueRaw; - std::unique_ptr waveformLuma; + array2D waveformRed, waveformGreen, waveformBlue, waveformLuma; LUTf CAMBrightCurveJ, CAMBrightCurveQ; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index aa5e6aed7..9c4092f2b 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -42,6 +42,9 @@ * */ +template +class array2D; + template class LUT; @@ -308,8 +311,6 @@ 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 @@ -333,13 +334,12 @@ public: const LUTu& histChroma, const LUTu& histLRETI, int vectorscopeScale, - const int vectorscope[vectorscope_size][vectorscope_size], + const array2D& vectorscope, int waveformScale, - int waveformWidth, - const int waveformRed[][256], - const int waveformGreen[][256], - const int waveformBlue[][256], - const int waveformLuma[][256] + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) = 0; /** Tells which observable is notifying the listener. */ virtual void setObservable(HistogramObservable* observable) = 0; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 2d3099727..7f5c99997 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -21,6 +21,7 @@ #include +#include "../rtengine/array2D.h" #include "../rtengine/imagesource.h" #include "../rtengine/iccstore.h" #include "batchqueue.h" @@ -2248,17 +2249,16 @@ void EditorPanel::histogramChanged( const LUTu& histChroma, const LUTu& histLRETI, int vectorscopeScale, - const int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size], + const array2D& vectorscope, int waveformScale, - int waveformWidth, - const int waveformRed[][256], - const int waveformGreen[][256], - const int waveformBlue[][256], - const int waveformLuma[][256] + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) { if (histogramPanel) { - histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue, waveformLuma); + histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); } tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI); diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index ed34c1931..2916dc822 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -32,6 +32,12 @@ #include "../rtengine/noncopyable.h" #include "../rtengine/rtengine.h" +namespace rtengine +{ +template +class array2D; +} + class BatchQueueEntry; class EditorPanel; class FilePanel; @@ -129,13 +135,12 @@ public: const LUTu& histChroma, const LUTu& histLRETI, int vectorscopeScale, - const int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size], + const array2D& vectorscope, int waveformScale, - int waveformWidth, - const int waveformRed[][256], - const int waveformGreen[][256], - const int waveformBlue[][256], - const int waveformLuma[][256] + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) override; void setObservable(rtengine::HistogramObservable* observable) override; bool updateHistogram(void) override; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 06a0b912c..416a114fd 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -22,6 +22,7 @@ #include "options.h" #include #include +#include "../rtengine/array2D.h" #include "../rtengine/LUT.h" #include "rtimage.h" #include "../rtengine/color.h" @@ -885,7 +886,10 @@ void HistogramRGBAreaVert::get_preferred_width_for_height_vfunc (int height, int // // HistogramArea HistogramArea::HistogramArea (DrawModeListener *fml) : - waveform_width(0), wave_buffer_dirty(true), + vect(0, 0), + vect_buffer_dirty(true), vect_buffer_size(0), + rwave(0, 0), gwave(0, 0),bwave(0, 0), lwave(0, 0), + wave_buffer_dirty(true), valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), scopeType(options.histogramScopeType), oldwidth(-1), oldheight(-1), @@ -902,9 +906,6 @@ 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"); @@ -983,13 +984,12 @@ void HistogramArea::update( const LUTu& histGreenRaw, const LUTu& histBlueRaw, int vectorscopeScale, - const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE], + const array2D& vectorscope, int waveformScale, - int waveformWidth, - const int waveformRed[][256], - const int waveformGreen[][256], - const int waveformBlue[][256], - const int waveformLuma[][256] + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) { if (histRed) { @@ -1003,27 +1003,26 @@ void HistogramArea::update( ghistRaw = histGreenRaw; bhistRaw = histBlueRaw; } else if (scopeType == 1) { + const int wave_width = waveformRed.getWidth(); + const int wave_height = waveformRed.getHeight(); waveform_scale = waveformScale; - if (waveform_width != waveformWidth) { - waveform_width = waveformWidth; - rwave.reset(new int[waveformWidth][256]); - gwave.reset(new int[waveformWidth][256]); - bwave.reset(new int[waveformWidth][256]); - lwave.reset(new int[waveformWidth][256]); + if (wave_width != rwave.getWidth() || wave_height != rwave.getHeight()) { + rwave(wave_width, wave_height); + gwave(wave_width, wave_height); + bwave(wave_width, wave_height); + lwave(wave_width, wave_height); } - int (* const rw)[256] = rwave.get(); - int (* const gw)[256] = gwave.get(); - int (* const bw)[256] = bwave.get(); - int (* const lw)[256] = lwave.get(); - memcpy(rw, waveformRed, 256 * waveformWidth * sizeof(rw[0][0])); - memcpy(gw, waveformGreen, 256 * waveformWidth * sizeof(gw[0][0])); - memcpy(bw, waveformBlue, 256 * waveformWidth * sizeof(bw[0][0])); - memcpy(lw, waveformLuma, 256 * waveformWidth * sizeof(lw[0][0])); + memcpy((int*)rwave, (const int*)waveformRed, wave_height * wave_width * sizeof(rwave[0][0])); + memcpy((int*)gwave, (const int*)waveformGreen, wave_height * wave_width * sizeof(gwave[0][0])); + memcpy((int*)bwave, (const int*)waveformBlue, wave_height * wave_width * sizeof(bwave[0][0])); + memcpy((int*)lwave, (const int*)waveformLuma, wave_height * wave_width * sizeof(lwave[0][0])); wave_buffer_dirty = true; } else if (scopeType >= 2) { vectorscope_scale = vectorscopeScale; - memcpy(vect, vectorscope, VECTORSCOPE_SIZE * VECTORSCOPE_SIZE * - sizeof(vect[0][0])); + if (vect.getWidth() != vectorscope.getWidth() || vect.getHeight() != vectorscope.getHeight()) { + vect(vectorscope.getWidth(), vectorscope.getHeight()); + } + memcpy((int*)vect, (const int*)vectorscope, vect.getHeight() * vect.getWidth() * sizeof(vect[0][0])); vect_buffer_dirty = true; } valid = true; @@ -1245,7 +1244,7 @@ void HistogramArea::updateBackBuffer () drawMarks(cr, bhchanged, realhistheight, w, ui, oi); } - } else if (scopeType == 1 && waveform_width > 0) { + } else if (scopeType == 1 && rwave.getWidth() > 0) { drawWaveform(cr, w, h); } else if (scopeType >= 2) { drawVectorscope(cr, w, h); @@ -1333,29 +1332,42 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, int h) { + const int vect_width = vect.getWidth(); + const int vect_height = vect.getHeight(); // Arbitrary scale factor multiplied by vectorscope area and divided by // current scale. - const float scale = trace_brightness * 8.f * VECTORSCOPE_SIZE * VECTORSCOPE_SIZE / vectorscope_scale; + const float scale = trace_brightness * 8.f * vect_width * vect_height / vectorscope_scale; // See Cairo documentation on stride. - const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, VECTORSCOPE_SIZE); + const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, vect_width); if (vect_buffer_dirty && vectorscope_scale > 0) { + if (vect_buffer_size != cairo_stride * vect_height) { + vect_buffer_size = cairo_stride * vect_height; + vect_buffer.reset(new unsigned char[vect_buffer_size]); + } + // TODO: Optimize. - for (int u = 0; u < VECTORSCOPE_SIZE; u++) { - for (int v = 0; v < VECTORSCOPE_SIZE; v++) { - const unsigned char value = min(scale * vect[u][v], 0xff); - *(uint32_t*)&(vect_buffer[(VECTORSCOPE_SIZE - 1 - u) * cairo_stride + v * 4]) = - value | (value << 8) | (value << 16) | (value << 24); + for (int y = 0; y < vect_height; y++) { + int* vect_row = vect[y]; + uint32_t* buffer_row = + (uint32_t*)&(vect_buffer[(vect_height - 1 - y) * cairo_stride]); + for (int x = 0; x < vect_width; x++) { + const unsigned char value = min(scale * vect_row[x], 0xff); + buffer_row[x] = 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 bool fit_width = + vect_width * (h - 2 * padding) > vect_height * (w - 2 * padding); + const float scope_scale = fit_width ? + (w - 2 * padding) / vect_width : (h - 2 * padding) / vect_height; + const float scope_size = scope_scale * max(vect_width, vect_height); + const float o_x = (w - scope_scale * vect_width) / 2; + const float o_y = (h - scope_scale * vect_height) / 2; const double s = RTScalable::getScale(); auto orig_matrix = cr->get_matrix(); const double line_spacing = 4.0 * s; @@ -1421,9 +1433,9 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in // Vectorscope trace. if (vectorscope_scale > 0) { Cairo::RefPtr surface = Cairo::ImageSurface::create( - vect_buffer.get(), Cairo::FORMAT_ARGB32, VECTORSCOPE_SIZE, VECTORSCOPE_SIZE, cairo_stride); + vect_buffer.get(), Cairo::FORMAT_ARGB32, vect_width, vect_height, cairo_stride); cr->translate(o_x, o_y); - cr->scale(scope_size / VECTORSCOPE_SIZE, scope_size / VECTORSCOPE_SIZE); + cr->scale(scope_scale, scope_scale); cr->set_source(surface, 0, 0); cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); @@ -1455,41 +1467,48 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h { // Arbitrary scale factor divided by current scale. const float scale = trace_brightness * 32.f * 255.f / waveform_scale; + const int wave_width = rwave.getWidth(); + const int wave_height = rwave.getHeight(); // See Cairo documentation on stride. - const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, waveform_width); + const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, rwave.getWidth()); if (wave_buffer_dirty) { - wave_buffer.reset(new unsigned char[256 * cairo_stride]); - wave_buffer_luma.reset(new unsigned char[256 * cairo_stride]); + wave_buffer.reset(new unsigned char[wave_height * cairo_stride]); + wave_buffer_luma.reset(new unsigned char[wave_height * cairo_stride]); // Clear waveform. - memset(wave_buffer.get(), 0, 256 * cairo_stride); - memset(wave_buffer_luma.get(), 0, 256 * cairo_stride); + memset(wave_buffer.get(), 0, wave_height * cairo_stride); + memset(wave_buffer_luma.get(), 0, wave_height * cairo_stride); // TODO: Optimize. - for (int col = 0; col < waveform_width; col++) { - for (int val = 0; val < 256; val++) { - const unsigned char r = needRed ? min(scale * rwave[col][val], 0xff) : 0; - const unsigned char g = needGreen ? min(scale * gwave[col][val], 0xff) : 0; - const unsigned char b = needBlue ? min(scale * bwave[col][val], 0xff) : 0; + for (int val = 0; val < wave_height; val++) { + int* r_row = rwave[val]; + int* g_row = gwave[val]; + int* b_row = bwave[val]; + uint32_t* buffer_row = (uint32_t*)&(wave_buffer[(255 - val) * cairo_stride]); + for (int col = 0; col < wave_width; col++) { + const unsigned char r = needRed ? min(scale * r_row[col], 0xff) : 0; + const unsigned char g = needGreen ? min(scale * g_row[col], 0xff) : 0; + const unsigned char b = needBlue ? min(scale * b_row[col], 0xff) : 0; const unsigned char value = (r > g && r > b) ? r : ((g > b) ? g : b); if (value <= 0) { - *(uint32_t*)&(wave_buffer[(255 - val) * cairo_stride + col * 4]) = 0; + buffer_row[col] = 0; } else { // Speedup with one memory access instead of four. - *(uint32_t*)&(wave_buffer[(255 - val) * cairo_stride + col * 4]) = - b | (g << 8) | (r << 16) | (value << 24); + buffer_row[col] = b | (g << 8) | (r << 16) | (value << 24); } } } if (needLuma) { - for (int col = 0; col < waveform_width; col++) { - for (int val = 0; val < 256; val++) { - const unsigned char l = min(scale * lwave[col][val], 0xff); - *(uint32_t*)&(wave_buffer_luma[(255 - val) * cairo_stride + col * 4]) = - l | (l << 8) | (l << 16) | (l << 24); + for (int val = 0; val < wave_height; val++) { + int* l_row = lwave[val]; + uint32_t* buffer_row = + (uint32_t*)&(wave_buffer_luma[(255 - val) * cairo_stride]); + for (int col = 0; col < wave_width; col++) { + const unsigned char l = min(scale * l_row[col], 0xff); + buffer_row[col] = l | (l << 8) | (l << 16) | (l << 24); } } } @@ -1500,17 +1519,17 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h Cairo::RefPtr surface; auto orig_matrix = cr->get_matrix(); cr->translate(0, padding); - cr->scale(static_cast(w) / waveform_width, (h - 2 * padding) / 256.0); + cr->scale(static_cast(w) / wave_width, (h - 2 * padding) / wave_height); if (needLuma) { surface = Cairo::ImageSurface::create( - wave_buffer_luma.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); + wave_buffer_luma.get(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); cr->set_source(surface, 0, 0); cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); surface->finish(); } surface = Cairo::ImageSurface::create( - wave_buffer.get(), Cairo::FORMAT_ARGB32, waveform_width, 256, cairo_stride); + wave_buffer.get(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); cr->set_source(surface, 0, 0); cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index fb38ee757..bda65df0c 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -27,16 +27,12 @@ #include "guiutils.h" #include "pointermotionlistener.h" +#include "../rtengine/array2D.h" #include "../rtengine/LUT.h" #include "../rtengine/noncopyable.h" class HistogramArea; -namespace -{ -constexpr int VECTORSCOPE_SIZE = 128; -} - struct HistogramAreaIdleHelper { HistogramArea* harea; bool destroyed; @@ -162,12 +158,12 @@ protected: LUTu rhist, ghist, bhist, lhist, chist; LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused? int vectorscope_scale; - int vect[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE]; + array2D vect; std::unique_ptr vect_buffer; bool vect_buffer_dirty; + int vect_buffer_size; int waveform_scale; - int waveform_width; - std::unique_ptr rwave, gwave, bwave, lwave; + array2D rwave, gwave, bwave, lwave; std::unique_ptr wave_buffer; std::unique_ptr wave_buffer_luma; bool wave_buffer_dirty; @@ -210,13 +206,12 @@ public: const LUTu& histGreenRaw, const LUTu& histBlueRaw, int vectorscopeScale, - const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE], + const array2D& vectorscope, int waveformScale, - int waveformWidth, - const int waveformRed[][256], - const int waveformGreen[][256], - const int waveformBlue[][256], - const int waveformLuma[][256] + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ); void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type, bool pointer); void on_realize() override; @@ -314,16 +309,15 @@ public: const LUTu& histGreenRaw, const LUTu& histBlueRaw, int vectorscopeScale, - const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE], + const array2D& vectorscope, int waveformScale, - int waveformWidth, - const int waveformRed[][256], - const int waveformGreen[][256], - const int waveformBlue[][256], - const int waveformLuma[][256] + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) { - histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue, waveformLuma); + histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); } // 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; From 8b3af4c520eb2fcbcf413019bee0ede637a16875 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 9 Aug 2020 16:59:27 -0700 Subject: [PATCH 17/56] Fix some cppcheck warnings --- rtengine/improccoordinator.cc | 13 ++++++++----- rtgui/histogrampanel.cc | 4 +++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 3609617be..7ae814f8c 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -133,7 +133,9 @@ ImProcCoordinator::ImProcCoordinator() : histLRETI(256), + vectorscopeScale(0), vectorscope(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), + waveformScale(0), waveformRed(0, 0), waveformGreen(0, 0), waveformBlue(0, 0), @@ -1861,8 +1863,9 @@ void ImProcCoordinator::updateVectorscope() memset((int*)vectorscope, 0, size * size * sizeof(vectorscope[0][0])); const int lab_img_size = (hListener->vectorscopeType() == 1) ? (x2 - x1) * (y2 - y1) : 0; - float L[lab_img_size], a[lab_img_size], b[lab_img_size]; + float a[lab_img_size], b[lab_img_size]; if (lab_img_size) { + float L[lab_img_size]; ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L, a, b, params->icm); } @@ -1874,11 +1877,11 @@ void ImProcCoordinator::updateVectorscope() switch (hListener->vectorscopeType()) { case 0: { // HS - int r = 256 * workimg->data[ofs++]; - int g = 256 * workimg->data[ofs++]; - int b = 256 * workimg->data[ofs++]; + int red = 256 * workimg->data[ofs++]; + int green = 256 * workimg->data[ofs++]; + int blue = 256 * workimg->data[ofs++]; float h, s, l; - Color::rgb2hsl(r, g, b, h, s, l); + Color::rgb2hsl(red, green, blue, 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) { diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 416a114fd..65e2acfdf 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -886,8 +886,10 @@ void HistogramRGBAreaVert::get_preferred_width_for_height_vfunc (int height, int // // HistogramArea HistogramArea::HistogramArea (DrawModeListener *fml) : + vectorscope_scale(0), vect(0, 0), vect_buffer_dirty(true), vect_buffer_size(0), + waveform_scale(0), rwave(0, 0), gwave(0, 0),bwave(0, 0), lwave(0, 0), wave_buffer_dirty(true), valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), @@ -1492,7 +1494,7 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h const unsigned char g = needGreen ? min(scale * g_row[col], 0xff) : 0; const unsigned char b = needBlue ? min(scale * b_row[col], 0xff) : 0; const unsigned char value = (r > g && r > b) ? r : ((g > b) ? g : b); - if (value <= 0) { + if (value == 0) { buffer_row[col] = 0; } else { // Speedup with one memory access instead of four. From f7c02af1849eb73b6abdebfd742b75a319f704f4 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 9 Aug 2020 17:22:23 -0700 Subject: [PATCH 18/56] Fix rendering of blank vectorscope --- rtgui/histogrampanel.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 65e2acfdf..ec8f9a326 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1367,7 +1367,8 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in vect_width * (h - 2 * padding) > vect_height * (w - 2 * padding); const float scope_scale = fit_width ? (w - 2 * padding) / vect_width : (h - 2 * padding) / vect_height; - const float scope_size = scope_scale * max(vect_width, vect_height); + const float scope_size = (vectorscope_scale > 0) ? + scope_scale * max(vect_width, vect_height) : min(w, h) - 2 * padding; const float o_x = (w - scope_scale * vect_width) / 2; const float o_y = (h - scope_scale * vect_height) / 2; const double s = RTScalable::getScale(); From e247a1e08655dbbd00f98d55fcdad7cd53b38200 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 9 Aug 2020 18:00:12 -0700 Subject: [PATCH 19/56] Increase visibility of vectorscope pointer --- rtgui/histogrampanel.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index ec8f9a326..236f5af02 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1457,10 +1457,19 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in cx = w / 2.f + scope_size * pointer_a * ab_factor; cy = h / 2.f - scope_size * pointer_b * ab_factor; } - cr->arc(cx, cy, 2 * s, 0, 2 * RT_PI); - cr->set_source_rgb(0, 0, 0); - cr->fill_preserve(); + cr->set_source_rgba(1, 1, 1, 0.5); + cr->set_dash(ch_ds, 0); + cr->move_to(0, cy); + cr->line_to(w, cy); + cr->move_to(cx, 0); + cr->line_to(cx, h); + cr->stroke(); + cr->unset_dash(); + cr->arc(cx, cy, 3 * s, 0, 2 * RT_PI); cr->set_source_rgb(1, 1, 1); + cr->fill_preserve(); + cr->set_source_rgb(0, 0, 0); + cr->set_line_width (1.0 * s); cr->stroke(); } } From 07d26c16edca47fd2ac0b8b1c3eaf47cbed8d197 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 15 Aug 2020 17:35:24 +0200 Subject: [PATCH 20/56] ImProcCoordinator::updateVectorscope(): fix crash caused by large stack allocation, speedup, fixed scaling from [0;255] to [0;65535] range --- rtengine/improccoordinator.cc | 73 +++++++++++++++++------------------ rtengine/rtengine.h | 2 +- rtgui/editorpanel.cc | 2 +- rtgui/editorpanel.h | 2 +- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 7ae814f8c..0a752784a 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -45,7 +45,8 @@ #ifdef _OPENMP #include #endif - +#define BENCHMARK +#include "StopWatch.h" namespace { @@ -1855,57 +1856,53 @@ void ImProcCoordinator::updateVectorscope() if (!workimg) { return; } - +BENCHFUN int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); constexpr int size = VECTORSCOPE_SIZE; memset((int*)vectorscope, 0, size * size * sizeof(vectorscope[0][0])); - const int lab_img_size = (hListener->vectorscopeType() == 1) ? (x2 - x1) * (y2 - y1) : 0; - float a[lab_img_size], b[lab_img_size]; + vectorscopeScale = (x2 - x1) * (y2 - y1); + const int lab_img_size = (hListener->vectorscopeType() == 1) ? vectorscopeScale : 0; + + std::unique_ptr a; + std::unique_ptr b; if (lab_img_size) { - float L[lab_img_size]; - ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L, a, b, params->icm); + a.reset(new float[lab_img_size]); + b.reset(new float[lab_img_size]); + std::unique_ptr L(new float[lab_img_size]); + ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); } - int ofs_lab = 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 red = 256 * workimg->data[ofs++]; - int green = 256 * workimg->data[ofs++]; - int blue = 256 * workimg->data[ofs++]; - float h, s, l; - Color::rgb2hsl(red, green, blue, 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; + if (hListener->vectorscopeType() == 0) { // HS + for (int i = y1; i < y2; ++i) { + int ofs = (i * pW + x1) * 3; + for (int j = x1; j < x2; ++j) { + const float red = 257.f * workimg->data[ofs++]; + const float green = 257.f * workimg->data[ofs++]; + const float blue = 257.f * workimg->data[ofs++]; + float h, s, l; + Color::rgb2hslfloat(red, green, blue, h, s, l); + const auto sincosval = xsincosf(2.f * RT_PI_F * h); + const int col = s * sincosval.y * (size / 2) + size / 2; + const int row = s * sincosval.x * (size / 2) + size / 2; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscope[row][col]++; } - - case 1: { - // CH - const int col = (size / 96000.0) * a[ofs_lab] + size / 2; - const int row = (size / 96000.0) * b[ofs_lab] + size / 2; - - if (col >= 0 && col < size && row >= 0 && row < size) { - vectorscope[row][col]++; - } - ofs_lab++; - break; + } + } + } else if (hListener->vectorscopeType() == 1) { // CH + for (int i = y1; i < y2; ++i) { + for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { + const int col = (size / 96000.f) * a[ofs_lab] + size / 2; + const int row = (size / 96000.f) * b[ofs_lab] + size / 2; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscope[row][col]++; } } } } - - vectorscopeScale = (x2 - x1) * (y2 - y1); } void ImProcCoordinator::updateWaveforms() diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 9c4092f2b..be33ea41e 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -350,7 +350,7 @@ public: /** 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; + virtual int vectorscopeType(void) const = 0; }; class HistogramObservable diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 7f5c99997..d80da8ef2 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2289,7 +2289,7 @@ bool EditorPanel::updateWaveform(void) || histogram_scope_type == HistogramPanelListener::NONE; } -int EditorPanel::vectorscopeType(void) +int EditorPanel::vectorscopeType(void) const { switch (histogram_scope_type) { case HistogramPanelListener::VECTORSCOPE_HS: diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 2916dc822..93e373924 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -146,7 +146,7 @@ public: bool updateHistogram(void) override; bool updateVectorscope(void) override; bool updateWaveform(void) override; - int vectorscopeType(void) override; + int vectorscopeType(void) const override; // HistogramPanelListener void scopeTypeChanged(ScopeType new_type) override; From e67b02da8ba629b58b95e86c316822313dbc50fc Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 15 Aug 2020 22:36:10 +0200 Subject: [PATCH 21/56] further cleanups --- rtengine/array2D.h | 1 + rtengine/improccoordinator.cc | 25 +++++++++---------------- rtengine/rtengine.h | 6 +++--- rtgui/editorpanel.cc | 6 +++--- rtgui/editorpanel.h | 6 +++--- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/rtengine/array2D.h b/rtengine/array2D.h index 512f7bcc1..e55326ef4 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -140,6 +140,7 @@ public: { buffer.clear(); rows.clear(); + width = 0; } // use with indices diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 0a752784a..a7f73a19a 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1864,17 +1864,6 @@ BENCHFUN memset((int*)vectorscope, 0, size * size * sizeof(vectorscope[0][0])); vectorscopeScale = (x2 - x1) * (y2 - y1); - const int lab_img_size = (hListener->vectorscopeType() == 1) ? vectorscopeScale : 0; - - std::unique_ptr a; - std::unique_ptr b; - if (lab_img_size) { - a.reset(new float[lab_img_size]); - b.reset(new float[lab_img_size]); - std::unique_ptr L(new float[lab_img_size]); - ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); - } - if (hListener->vectorscopeType() == 0) { // HS for (int i = y1; i < y2; ++i) { int ofs = (i * pW + x1) * 3; @@ -1893,6 +1882,10 @@ BENCHFUN } } } else if (hListener->vectorscopeType() == 1) { // CH + const std::unique_ptr a(new float[vectorscopeScale]); + const std::unique_ptr b(new float[vectorscopeScale]); + const std::unique_ptr L(new float[vectorscopeScale]); + ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); for (int i = y1; i < y2; ++i) { for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { const int col = (size / 96000.f) * a[ofs_lab] + size / 2; @@ -1908,11 +1901,11 @@ BENCHFUN void ImProcCoordinator::updateWaveforms() { if (!workimg) { - // Resize to zero. - waveformRed(0, 0); - waveformGreen(0, 0); - waveformBlue(0, 0); - waveformLuma(0, 0); + // free memory + waveformRed.free(); + waveformGreen.free(); + waveformBlue.free(); + waveformLuma.free(); return; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index be33ea41e..e6749a9f0 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -344,11 +344,11 @@ public: /** Tells which observable is notifying the listener. */ virtual void setObservable(HistogramObservable* observable) = 0; /** Returns if the listener wants the histogram to be updated. */ - virtual bool updateHistogram(void) = 0; + virtual bool updateHistogram(void) const = 0; /** Returns if the listener wants the vectorscope to be updated. */ - virtual bool updateVectorscope(void) = 0; + virtual bool updateVectorscope(void) const = 0; /** Returns if the listener wants the waveform to be updated. */ - virtual bool updateWaveform(void) = 0; + virtual bool updateWaveform(void) const = 0; /** Returns the vectorscope type: 0 for H-S and 1 for H-C. */ virtual int vectorscopeType(void) const = 0; }; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index d80da8ef2..594965ee6 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2269,13 +2269,13 @@ void EditorPanel::setObservable(rtengine::HistogramObservable* observable) histogram_observable = observable; } -bool EditorPanel::updateHistogram(void) +bool EditorPanel::updateHistogram(void) const { return histogram_scope_type == HistogramPanelListener::HISTOGRAM || histogram_scope_type == HistogramPanelListener::NONE; } -bool EditorPanel::updateVectorscope(void) +bool EditorPanel::updateVectorscope(void) const { return histogram_scope_type == HistogramPanelListener::VECTORSCOPE_HS @@ -2283,7 +2283,7 @@ bool EditorPanel::updateVectorscope(void) || histogram_scope_type == HistogramPanelListener::NONE; } -bool EditorPanel::updateWaveform(void) +bool EditorPanel::updateWaveform(void) const { return histogram_scope_type == HistogramPanelListener::WAVEFORM || histogram_scope_type == HistogramPanelListener::NONE; diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 93e373924..9f0ebf8cb 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -143,9 +143,9 @@ public: const array2D& waveformLuma ) override; void setObservable(rtengine::HistogramObservable* observable) override; - bool updateHistogram(void) override; - bool updateVectorscope(void) override; - bool updateWaveform(void) override; + bool updateHistogram(void) const override; + bool updateVectorscope(void) const override; + bool updateWaveform(void) const override; int vectorscopeType(void) const override; // HistogramPanelListener From 231c5e2c993cc40af6ab446ec9d1afd3ccfe5649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sun, 16 Aug 2020 10:25:22 +0200 Subject: [PATCH 22/56] Apply clang-tidy's `google-readability-casting` ``` clang-tidy-10 -header-filter=.* -p=build -fix -checks=google-readability-casting rtgui/histogrampanel.cc ``` --- rtgui/histogrampanel.cc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index e589ed9ba..32bc7c603 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -945,7 +945,7 @@ Gtk::SizeRequestMode HistogramArea::get_request_mode_vfunc () const void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const { - int s = (int)RTScalable::getScale(); + int s = RTScalable::getScale(); minimum_height = 100 * s; natural_height = 200 * s; } @@ -953,7 +953,7 @@ void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natura void HistogramArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const { - int s = (int)RTScalable::getScale(); + int s = RTScalable::getScale(); minimum_width = 200 * s; natural_width = 400 * s; } @@ -1105,7 +1105,7 @@ void HistogramArea::updateBackBuffer () cr->set_dash (ch_ds, 0); // determine the number of h-gridlines based on current h - int nrOfHGridPartitions = (int)rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2)); + int nrOfHGridPartitions = static_cast(rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2))); int nrOfVGridPartitions = 8; // always show 8 stops (lines at 1,3,7,15,31,63,127) // draw vertical gridlines @@ -1135,14 +1135,14 @@ void HistogramArea::updateBackBuffer () // 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); - cr->line_to (w - padding, i * (double)h / nrOfHGridPartitions + 0.5); + cr->move_to (padding, i * static_cast(h) / nrOfHGridPartitions + 0.5); + cr->line_to (w - padding, i * static_cast(h) / nrOfHGridPartitions + 0.5); cr->stroke (); } } else { for (int i = 1; i < nrOfHGridPartitions; i++) { - cr->move_to (padding, h - HistogramScaling::log (h, i * (double)h / nrOfHGridPartitions) + 0.5); - cr->line_to (w - padding, h - HistogramScaling::log (h, i * (double)h / nrOfHGridPartitions) + 0.5); + cr->move_to (padding, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); + cr->line_to (w - padding, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); cr->stroke (); } } @@ -1306,15 +1306,15 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, scale = scale <= 0.0 ? 0.001 : scale; // avoid division by zero and negative values for (int i = 0; i < 256; i++) { - double val = data[i] * (double)vsize / scale; + double val = data[i] * static_cast(vsize) / scale; if (drawMode > 0) { // scale y for single and double log-scale - val = HistogramScaling::log ((double)vsize, val); + val = HistogramScaling::log (static_cast(vsize), val); } double iscaled = i; if (drawMode == 2) { // scale x for double log-scale - iscaled = HistogramScaling::log (255.0, (double)i); + iscaled = HistogramScaling::log (255.0, static_cast(i)); } double posX = padding + iscaled * (hsize - padding * 2.0) / 255.0; @@ -1363,7 +1363,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in for (int y = 0; y < vect_height; y++) { int* vect_row = vect[y]; uint32_t* buffer_row = - (uint32_t*)&(vect_buffer[(vect_height - 1 - y) * cairo_stride]); + reinterpret_cast(&(vect_buffer[(vect_height - 1 - y) * cairo_stride])); for (int x = 0; x < vect_width; x++) { const unsigned char value = min(scale * vect_row[x], 0xff); buffer_row[x] = value | (value << 8) | (value << 16) | (value << 24); @@ -1508,7 +1508,7 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h int* r_row = rwave[val]; int* g_row = gwave[val]; int* b_row = bwave[val]; - uint32_t* buffer_row = (uint32_t*)&(wave_buffer[(255 - val) * cairo_stride]); + uint32_t* buffer_row = reinterpret_cast(&(wave_buffer[(255 - val) * cairo_stride])); for (int col = 0; col < wave_width; col++) { const unsigned char r = needRed ? min(scale * r_row[col], 0xff) : 0; const unsigned char g = needGreen ? min(scale * g_row[col], 0xff) : 0; @@ -1527,7 +1527,7 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h for (int val = 0; val < wave_height; val++) { int* l_row = lwave[val]; uint32_t* buffer_row = - (uint32_t*)&(wave_buffer_luma[(255 - val) * cairo_stride]); + reinterpret_cast(&(wave_buffer_luma[(255 - val) * cairo_stride])); for (int col = 0; col < wave_width; col++) { const unsigned char l = min(scale * l_row[col], 0xff); buffer_row[col] = l | (l << 8) | (l << 16) | (l << 24); From 3af822b6f7627773ec009861123f59054b200cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sun, 16 Aug 2020 11:22:10 +0200 Subject: [PATCH 23/56] Fix abuse of `array2D<>` - Add copy c'tor and assignment to `array2D<>` - Use `std::vector<>` instead of smart pointer to array - Constify a bit - Make use of `rtengine::max(...)` --- rtengine/array2D.h | 22 ++++++++++-- rtgui/histogrampanel.cc | 80 ++++++++++++++++++----------------------- rtgui/histogrampanel.h | 8 +++-- 3 files changed, 59 insertions(+), 51 deletions(-) diff --git a/rtengine/array2D.h b/rtengine/array2D.h index e55326ef4..a8eebde54 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -64,8 +64,7 @@ constexpr unsigned int ARRAY2D_BYREFERENCE = 2; template -class array2D : - public rtengine::NonCopyable +class array2D { private: @@ -125,6 +124,25 @@ public: } } + array2D(const array2D& other) : + width(other.width), + buffer(other.buffer) + { + initRows(other.rows.size()); + } + + array2D& operator =(const array2D& other) + { + if (this != &other) { + free(); + width = other.width; + buffer = other.buffer; + initRows(other.rows.size()); + } + + return *this; + } + void fill(const T val, bool multiThread = false) { const ssize_t height = rows.size(); diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 32bc7c603..96aa37d72 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -441,7 +441,7 @@ void HistogramPanel::type_changed() histogramRGBArea = nullptr; if (panel_listener) { updateHistAreaOptions(); - HistogramPanelListener::ScopeType type; + HistogramPanelListener::ScopeType type = HistogramPanelListener::NONE; switch (options.histogramScopeType) { case 2: type = HistogramPanelListener::VECTORSCOPE_HS; @@ -1015,26 +1015,14 @@ void HistogramArea::update( ghistRaw = histGreenRaw; bhistRaw = histBlueRaw; } else if (scopeType == 1) { - const int wave_width = waveformRed.getWidth(); - const int wave_height = waveformRed.getHeight(); waveform_scale = waveformScale; - if (wave_width != rwave.getWidth() || wave_height != rwave.getHeight()) { - rwave(wave_width, wave_height); - gwave(wave_width, wave_height); - bwave(wave_width, wave_height); - lwave(wave_width, wave_height); - } - memcpy((int*)rwave, (const int*)waveformRed, wave_height * wave_width * sizeof(rwave[0][0])); - memcpy((int*)gwave, (const int*)waveformGreen, wave_height * wave_width * sizeof(gwave[0][0])); - memcpy((int*)bwave, (const int*)waveformBlue, wave_height * wave_width * sizeof(bwave[0][0])); - memcpy((int*)lwave, (const int*)waveformLuma, wave_height * wave_width * sizeof(lwave[0][0])); + rwave = waveformRed; + gwave = waveformGreen; + bwave = waveformBlue; + lwave = waveformLuma; wave_buffer_dirty = true; } else if (scopeType >= 2) { - vectorscope_scale = vectorscopeScale; - if (vect.getWidth() != vectorscope.getWidth() || vect.getHeight() != vectorscope.getHeight()) { - vect(vectorscope.getWidth(), vectorscope.getHeight()); - } - memcpy((int*)vect, (const int*)vectorscope, vect.getHeight() * vect.getWidth() * sizeof(vect[0][0])); + vect = vectorscope; vect_buffer_dirty = true; } valid = true; @@ -1354,18 +1342,19 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, vect_width); if (vect_buffer_dirty && vectorscope_scale > 0) { - if (vect_buffer_size != cairo_stride * vect_height) { - vect_buffer_size = cairo_stride * vect_height; - vect_buffer.reset(new unsigned char[vect_buffer_size]); + if (vect_buffer.size() != static_cast(cairo_stride) * vect_height) { + vect_buffer.resize(cairo_stride * vect_height); } + assert(vect_buffer.size() % 4 == 0); + // TODO: Optimize. for (int y = 0; y < vect_height; y++) { - int* vect_row = vect[y]; - uint32_t* buffer_row = - reinterpret_cast(&(vect_buffer[(vect_height - 1 - y) * cairo_stride])); + const int* const vect_row = vect[y]; + std::uint32_t* const buffer_row = + reinterpret_cast(vect_buffer.data() + (vect_height - 1 - y) * cairo_stride); for (int x = 0; x < vect_width; x++) { - const unsigned char value = min(scale * vect_row[x], 0xff); + const unsigned char value = std::min(scale * vect_row[x], 0xff); buffer_row[x] = value | (value << 8) | (value << 16) | (value << 24); } } @@ -1378,7 +1367,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in const float scope_scale = fit_width ? (w - 2 * padding) / vect_width : (h - 2 * padding) / vect_height; const float scope_size = (vectorscope_scale > 0) ? - scope_scale * max(vect_width, vect_height) : min(w, h) - 2 * padding; + scope_scale * std::max(vect_width, vect_height) : std::min(w, h) - 2 * padding; const float o_x = (w - scope_scale * vect_width) / 2; const float o_y = (h - scope_scale * vect_height) / 2; const double s = RTScalable::getScale(); @@ -1446,7 +1435,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in // Vectorscope trace. if (vectorscope_scale > 0) { Cairo::RefPtr surface = Cairo::ImageSurface::create( - vect_buffer.get(), Cairo::FORMAT_ARGB32, vect_width, vect_height, cairo_stride); + vect_buffer.data(), Cairo::FORMAT_ARGB32, vect_width, vect_height, cairo_stride); cr->translate(o_x, o_y); cr->scale(scope_scale, scope_scale); cr->set_source(surface, 0, 0); @@ -1496,24 +1485,23 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, rwave.getWidth()); if (wave_buffer_dirty) { - wave_buffer.reset(new unsigned char[wave_height * cairo_stride]); - wave_buffer_luma.reset(new unsigned char[wave_height * cairo_stride]); + wave_buffer.assign(wave_height * cairo_stride, 0); + wave_buffer_luma.assign(wave_height * cairo_stride, 0); - // Clear waveform. - memset(wave_buffer.get(), 0, wave_height * cairo_stride); - memset(wave_buffer_luma.get(), 0, wave_height * cairo_stride); + assert(wave_buffer.size() % 4 == 0); + assert(wave_buffer_luma.size() % 4 == 0); // TODO: Optimize. for (int val = 0; val < wave_height; val++) { - int* r_row = rwave[val]; - int* g_row = gwave[val]; - int* b_row = bwave[val]; - uint32_t* buffer_row = reinterpret_cast(&(wave_buffer[(255 - val) * cairo_stride])); + const int* const r_row = rwave[val]; + const int* const g_row = gwave[val]; + const int* const b_row = bwave[val]; + std::uint32_t* const buffer_row = reinterpret_cast(wave_buffer.data() + (255 - val) * cairo_stride); for (int col = 0; col < wave_width; col++) { - const unsigned char r = needRed ? min(scale * r_row[col], 0xff) : 0; - const unsigned char g = needGreen ? min(scale * g_row[col], 0xff) : 0; - const unsigned char b = needBlue ? min(scale * b_row[col], 0xff) : 0; - const unsigned char value = (r > g && r > b) ? r : ((g > b) ? g : b); + const unsigned char r = needRed ? std::min(scale * r_row[col], 0xff) : 0; + const unsigned char g = needGreen ? std::min(scale * g_row[col], 0xff) : 0; + const unsigned char b = needBlue ? std::min(scale * b_row[col], 0xff) : 0; + const unsigned char value = rtengine::max(r, g, b); if (value == 0) { buffer_row[col] = 0; } else { @@ -1525,11 +1513,11 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h if (needLuma) { for (int val = 0; val < wave_height; val++) { - int* l_row = lwave[val]; - uint32_t* buffer_row = - reinterpret_cast(&(wave_buffer_luma[(255 - val) * cairo_stride])); + const int* const l_row = lwave[val]; + std::uint32_t* const buffer_row = + reinterpret_cast(wave_buffer_luma.data() + (255 - val) * cairo_stride); for (int col = 0; col < wave_width; col++) { - const unsigned char l = min(scale * l_row[col], 0xff); + const unsigned char l = std::min(scale * l_row[col], 0xff); buffer_row[col] = l | (l << 8) | (l << 16) | (l << 24); } } @@ -1544,14 +1532,14 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h cr->scale(static_cast(w) / wave_width, (h - 2 * padding) / wave_height); if (needLuma) { surface = Cairo::ImageSurface::create( - wave_buffer_luma.get(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); + wave_buffer_luma.data(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); cr->set_source(surface, 0, 0); cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); surface->finish(); } surface = Cairo::ImageSurface::create( - wave_buffer.get(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); + wave_buffer.data(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); cr->set_source(surface, 0, 0); cr->set_operator(Cairo::OPERATOR_OVER); cr->paint(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index b2a656161..6cdb77c18 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -18,6 +18,8 @@ */ #pragma once +#include + #include #include @@ -160,13 +162,13 @@ protected: LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused? int vectorscope_scale; array2D vect; - std::unique_ptr vect_buffer; + std::vector vect_buffer; bool vect_buffer_dirty; int vect_buffer_size; int waveform_scale; array2D rwave, gwave, bwave, lwave; - std::unique_ptr wave_buffer; - std::unique_ptr wave_buffer_luma; + std::vector wave_buffer; + std::vector wave_buffer_luma; bool wave_buffer_dirty; bool valid; From 9e040b3bc297530c80723e500ede6cd618c471af Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sun, 16 Aug 2020 11:46:17 +0200 Subject: [PATCH 24/56] ImProcCoordinator::updateVectorscope(): parallelize loops --- rtengine/array2D.h | 18 ++++++++++ rtengine/improccoordinator.cc | 68 +++++++++++++++++++++++++---------- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/rtengine/array2D.h b/rtengine/array2D.h index a8eebde54..ca4db3d06 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -211,6 +211,24 @@ public: } } + array2D& operator+=(const array2D& rhs) + { + if (rhs.getWidth() == this->getWidth() && rhs.getHeight() == this->getHeight()) { + for (int i = 0; i < getHeight(); ++i) { +#ifdef _OPENMP + #pragma omp simd +#endif + + for (int j = 0; j < getWidth(); ++j) { + rows[i][j] += rhs[i][j]; + } + } + } + + return *this; + } + + int getWidth() const { return width; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 1da11ab4e..e3882785c 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1863,35 +1863,65 @@ BENCHFUN vectorscopeScale = (x2 - x1) * (y2 - y1); if (hListener->vectorscopeType() == 0) { // HS - for (int i = y1; i < y2; ++i) { - int ofs = (i * pW + x1) * 3; - for (int j = x1; j < x2; ++j) { - const float red = 257.f * workimg->data[ofs++]; - const float green = 257.f * workimg->data[ofs++]; - const float blue = 257.f * workimg->data[ofs++]; - float h, s, l; - Color::rgb2hslfloat(red, green, blue, h, s, l); - const auto sincosval = xsincosf(2.f * RT_PI_F * h); - const int col = s * sincosval.y * (size / 2) + size / 2; - const int row = s * sincosval.x * (size / 2) + size / 2; - if (col >= 0 && col < size && row >= 0 && row < size) { - vectorscope[row][col]++; +#ifdef _OPENMP + #pragma omp parallel +#endif + { + array2D vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA); +#ifdef _OPENMP + #pragma omp for nowait +#endif + for (int i = y1; i < y2; ++i) { + int ofs = (i * pW + x1) * 3; + for (int j = x1; j < x2; ++j) { + const float red = 257.f * workimg->data[ofs++]; + const float green = 257.f * workimg->data[ofs++]; + const float blue = 257.f * workimg->data[ofs++]; + float h, s, l; + Color::rgb2hslfloat(red, green, blue, h, s, l); + const auto sincosval = xsincosf(2.f * RT_PI_F * h); + const int col = s * sincosval.y * (size / 2) + size / 2; + const int row = s * sincosval.x * (size / 2) + size / 2; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscopeThr[row][col]++; + } } } +#ifdef _OPENMP + #pragma omp critical +#endif + { + vectorscope += vectorscopeThr; + } } } else if (hListener->vectorscopeType() == 1) { // CH const std::unique_ptr a(new float[vectorscopeScale]); const std::unique_ptr b(new float[vectorscopeScale]); const std::unique_ptr L(new float[vectorscopeScale]); ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); - for (int i = y1; i < y2; ++i) { - for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { - const int col = (size / 96000.f) * a[ofs_lab] + size / 2; - const int row = (size / 96000.f) * b[ofs_lab] + size / 2; - if (col >= 0 && col < size && row >= 0 && row < size) { - vectorscope[row][col]++; +#ifdef _OPENMP + #pragma omp parallel +#endif + { + array2D vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA); +#ifdef _OPENMP + #pragma omp for nowait +#endif + for (int i = y1; i < y2; ++i) { + for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { + const int col = (size / 96000.f) * a[ofs_lab] + size / 2; + const int row = (size / 96000.f) * b[ofs_lab] + size / 2; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscopeThr[row][col]++; + } } } +#ifdef _OPENMP + #pragma omp critical +#endif + { + vectorscope += vectorscopeThr; + } } } } From d59f488aea7ba286072490a35b181460488e6d13 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sun, 16 Aug 2020 14:07:25 +0200 Subject: [PATCH 25/56] minor fixes --- rtgui/histogrampanel.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 96aa37d72..57bb9b4d0 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1448,9 +1448,9 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in float cx, cy; if (scopeType == 2) { float H, S, L; - Color::rgb2hsl(pointer_red * 256.f, pointer_green * 256.f, pointer_blue * 256.f, H, S, L); - cx = (w + scope_size * S * cos(H * 2 * RT_PI)) / 2; - cy = (h - scope_size * S * sin(H * 2 * RT_PI)) / 2; + Color::rgb2hslfloat(pointer_red * 257.f, pointer_green * 257.f, pointer_blue * 257.f, H, S, L); + cx = (w + scope_size * S * std::cos(H * 2 * RT_PI_F)) / 2; + cy = (h - scope_size * S * std::sin(H * 2 * RT_PI_F)) / 2; } else { constexpr float ab_factor = 327.68f / 96000.f; cx = w / 2.f + scope_size * pointer_a * ab_factor; From 7aa6b713c6c40cfe0f417ab27ed349011d22038b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sun, 16 Aug 2020 16:01:29 +0200 Subject: [PATCH 26/56] Fix vectorscope --- rtgui/histogrampanel.cc | 5 +++-- rtgui/histogrampanel.h | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 57bb9b4d0..4dffc80ac 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -898,7 +898,7 @@ void HistogramRGBAreaVert::get_preferred_width_for_height_vfunc (int height, int HistogramArea::HistogramArea (DrawModeListener *fml) : vectorscope_scale(0), vect(0, 0), - vect_buffer_dirty(true), vect_buffer_size(0), + vect_buffer_dirty(true), waveform_scale(0), rwave(0, 0), gwave(0, 0),bwave(0, 0), lwave(0, 0), wave_buffer_dirty(true), @@ -1022,6 +1022,7 @@ void HistogramArea::update( lwave = waveformLuma; wave_buffer_dirty = true; } else if (scopeType >= 2) { + vectorscope_scale = vectorscopeScale; vect = vectorscope; vect_buffer_dirty = true; } @@ -1343,7 +1344,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in if (vect_buffer_dirty && vectorscope_scale > 0) { if (vect_buffer.size() != static_cast(cairo_stride) * vect_height) { - vect_buffer.resize(cairo_stride * vect_height); + vect_buffer.resize(static_cast(cairo_stride) * vect_height); } assert(vect_buffer.size() % 4 == 0); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 6cdb77c18..935a30bfd 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -164,7 +164,6 @@ protected: array2D vect; std::vector vect_buffer; bool vect_buffer_dirty; - int vect_buffer_size; int waveform_scale; array2D rwave, gwave, bwave, lwave; std::vector wave_buffer; From 2858876f4485f9ad200b0d05421be0c1222b23c7 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sun, 16 Aug 2020 17:19:59 +0200 Subject: [PATCH 27/56] use array2D.fill() instead of memset() --- rtengine/improccoordinator.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index e3882785c..b1e7c8776 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1859,7 +1859,7 @@ BENCHFUN params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); constexpr int size = VECTORSCOPE_SIZE; - memset((int*)vectorscope, 0, size * size * sizeof(vectorscope[0][0])); + vectorscope.fill(0); vectorscopeScale = (x2 - x1) * (y2 - y1); if (hListener->vectorscopeType() == 0) { // HS @@ -1951,11 +1951,10 @@ void ImProcCoordinator::updateWaveforms() } // Start with zero. - const int waveformSize = 256 * waveform_width; - memset((int*)waveformRed, 0, waveformSize * sizeof(waveformRed[0][0])); - memset((int*)waveformGreen, 0, waveformSize * sizeof(waveformGreen[0][0])); - memset((int*)waveformBlue, 0, waveformSize * sizeof(waveformBlue[0][0])); - memset((int*)waveformLuma, 0, waveformSize * sizeof(waveformLuma[0][0])); + waveformRed.fill(0); + waveformGreen.fill(0); + waveformBlue.fill(0); + waveformLuma.fill(0); constexpr float luma_factor = 255.f / 32768.f; for (int i = y1; i < y2; i++) { From e667e3dce7fc80e659e7c5dd8ec651ae0a81ceab Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sun, 16 Aug 2020 21:34:11 +0200 Subject: [PATCH 28/56] Removed timing code and some includes --- rtengine/improccoordinator.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index b1e7c8776..f25395c2d 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -17,8 +17,6 @@ * along with RawTherapee. If not, see . */ #include -#include -#include #include #include "improccoordinator.h" @@ -27,7 +25,6 @@ #include "cieimage.h" #include "color.h" #include "colortemp.h" -#include "jaggedarray.h" #include "curves.h" #include "dcp.h" #include "iccstore.h" @@ -45,8 +42,7 @@ #ifdef _OPENMP #include #endif -#define BENCHMARK -#include "StopWatch.h" + namespace { @@ -1854,7 +1850,7 @@ void ImProcCoordinator::updateVectorscope() if (!workimg) { return; } -BENCHFUN + int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); From 371fc65416b19c19ba8a706bd5318c91680cca3a Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 16 Aug 2020 16:10:46 -0700 Subject: [PATCH 29/56] Improve type conversions --- rtgui/histogrampanel.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 4dffc80ac..60df46e34 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1368,7 +1368,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in const float scope_scale = fit_width ? (w - 2 * padding) / vect_width : (h - 2 * padding) / vect_height; const float scope_size = (vectorscope_scale > 0) ? - scope_scale * std::max(vect_width, vect_height) : std::min(w, h) - 2 * padding; + scope_scale * std::max(vect_width, vect_height) : std::min(w, h) - 2 * padding; const float o_x = (w - scope_scale * vect_width) / 2; const float o_y = (h - scope_scale * vect_height) / 2; const double s = RTScalable::getScale(); @@ -1486,8 +1486,9 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, rwave.getWidth()); if (wave_buffer_dirty) { - wave_buffer.assign(wave_height * cairo_stride, 0); - wave_buffer_luma.assign(wave_height * cairo_stride, 0); + const auto buffer_size = static_cast::size_type>(wave_height) * cairo_stride; + wave_buffer.assign(buffer_size, 0); + wave_buffer_luma.assign(buffer_size, 0); assert(wave_buffer.size() % 4 == 0); assert(wave_buffer_luma.size() % 4 == 0); From 350324affc4c75e29a55e4197c839344786a4bdd Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 16 Aug 2020 18:08:26 -0700 Subject: [PATCH 30/56] Disable double-clicking of waveform & vectorscopes --- rtgui/histogrampanel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 60df46e34..142bafb43 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1569,7 +1569,7 @@ bool HistogramArea::on_button_press_event (GdkEventButton* event) isPressed = true; movingPosition = event->x; - if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { + if (event->type == GDK_2BUTTON_PRESS && event->button == 1 && scopeType == 0) { drawMode = (drawMode + 1) % 3; options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; From cfc1e66024684da5b48a43ee11f20ae52802a4ea Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Wed, 19 Aug 2020 14:00:09 +0200 Subject: [PATCH 31/56] CH vectorscope: speedup by avoiding conversions --- rtengine/improccoordinator.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f25395c2d..accff6377 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -42,7 +42,8 @@ #ifdef _OPENMP #include #endif - +#define BENCHMARK +#include "StopWatch.h" namespace { @@ -1850,7 +1851,7 @@ void ImProcCoordinator::updateVectorscope() if (!workimg) { return; } - +BENCHFUN int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); @@ -1891,10 +1892,6 @@ void ImProcCoordinator::updateVectorscope() } } } else if (hListener->vectorscopeType() == 1) { // CH - const std::unique_ptr a(new float[vectorscopeScale]); - const std::unique_ptr b(new float[vectorscopeScale]); - const std::unique_ptr L(new float[vectorscopeScale]); - ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); #ifdef _OPENMP #pragma omp parallel #endif @@ -1904,9 +1901,11 @@ void ImProcCoordinator::updateVectorscope() #pragma omp for nowait #endif for (int i = y1; i < y2; ++i) { - for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { - const int col = (size / 96000.f) * a[ofs_lab] + size / 2; - const int row = (size / 96000.f) * b[ofs_lab] + size / 2; + const float* const a = nprevl->a[i] + x1; + const float* const b = nprevl->b[i] + x1; + for (int j = x1; j < x2; ++j) { + const int col = (size / 96000.f) * a[j] + size / 2; + const int row = (size / 96000.f) * b[j] + size / 2; if (col >= 0 && col < size && row >= 0 && row < size) { vectorscopeThr[row][col]++; } From 6c2463889b1f761afc5039e31a0f93f1520b0c0a Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Thu, 20 Aug 2020 12:31:37 +0200 Subject: [PATCH 32/56] Revert "CH vectorscope: speedup by avoiding conversions" This reverts commit cfc1e66024684da5b48a43ee11f20ae52802a4ea. --- rtengine/improccoordinator.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index accff6377..f25395c2d 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -42,8 +42,7 @@ #ifdef _OPENMP #include #endif -#define BENCHMARK -#include "StopWatch.h" + namespace { @@ -1851,7 +1850,7 @@ void ImProcCoordinator::updateVectorscope() if (!workimg) { return; } -BENCHFUN + int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); @@ -1892,6 +1891,10 @@ BENCHFUN } } } else if (hListener->vectorscopeType() == 1) { // CH + const std::unique_ptr a(new float[vectorscopeScale]); + const std::unique_ptr b(new float[vectorscopeScale]); + const std::unique_ptr L(new float[vectorscopeScale]); + ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); #ifdef _OPENMP #pragma omp parallel #endif @@ -1901,11 +1904,9 @@ BENCHFUN #pragma omp for nowait #endif for (int i = y1; i < y2; ++i) { - const float* const a = nprevl->a[i] + x1; - const float* const b = nprevl->b[i] + x1; - for (int j = x1; j < x2; ++j) { - const int col = (size / 96000.f) * a[j] + size / 2; - const int row = (size / 96000.f) * b[j] + size / 2; + for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { + const int col = (size / 96000.f) * a[ofs_lab] + size / 2; + const int row = (size / 96000.f) * b[ofs_lab] + size / 2; if (col >= 0 && col < size && row >= 0 && row < size) { vectorscopeThr[row][col]++; } From 6d8a31961fc50379ef404eb84c736a71b495cc7d Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Thu, 27 Aug 2020 16:35:39 -0700 Subject: [PATCH 33/56] Color the vectorscope lines --- rtgui/histogrampanel.cc | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 142bafb43..2c9d6bb0e 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1378,19 +1378,34 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in 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. + cr->set_line_width (2.0 * s); + constexpr double color_labels[6][3] = { + {1, 0, 0}, // R + {1, 1, 0}, // Y + {0, 1, 0}, // G + {0, 1, 1}, // C + {0, 0, 1}, // B + {1, 0, 1}, // M + }; for (int i = 0; i < 6; i++) { + auto gradient = Cairo::LinearGradient::create(0, 0, scope_size / 2.0, 0); + const double (&color)[3] = color_labels[i]; + cr->set_source(gradient); + gradient->add_color_stop_rgba(0, 1, 1, 1, 0.25); + gradient->add_color_stop_rgba(1, color[0], color[1], color[2], 0.5); cr->move_to(line_spacing, 0); cr->line_to(line_spacing + line_length, 0); - cr->rotate_degrees(60); + cr->rotate_degrees(-60); + cr->stroke(); } - cr->stroke(); + cr->set_line_width (1.0 * s); + cr->set_source_rgba (1, 1, 1, 0.25); // 100% saturation circle. cr->arc(0, 0, scope_size / 2.0, 0, 2 * RT_PI); cr->stroke(); @@ -1408,15 +1423,30 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in cr->unset_dash(); } else if (scopeType == 3) { // Hue-Chroma. // a and b axes. + Cairo::RefPtr gradient; + cr->set_line_width (2.0 * s); + gradient = Cairo::LinearGradient::create(0, -scope_size / 2.0, 0, scope_size / 2.0); + cr->set_source(gradient); + gradient->add_color_stop_rgba(0, 1, 1, 0, 0.5); // "yellow" + gradient->add_color_stop_rgba(0.5, 1, 1, 1, 0.25); // neutral + gradient->add_color_stop_rgba(1, 0, 0, 1, 0.5); // "blue" 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->stroke(); + gradient = Cairo::LinearGradient::create(-scope_size / 2.0, 0, scope_size / 2.0, 0); + cr->set_source(gradient); + gradient->add_color_stop_rgba(0, 0, 1, 0, 0.5); // "green" + gradient->add_color_stop_rgba(0.5, 1, 1, 1, 0.25); // neutral + gradient->add_color_stop_rgba(1, 1, 0, 1, 0.5); // "magenta" 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(); + cr->set_source_rgba (1, 1, 1, 0.25); + cr->set_line_width (1.0 * s); // 25%, 50%, 75%, and 100% of standard chroma range. cr->set_dash(ch_ds, 0); for (int i = 1; i <= 4; i++) { From b2942fd949f38ee97a567bcdff6f6960fb3d6e83 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Fri, 28 Aug 2020 22:33:52 -0700 Subject: [PATCH 34/56] Improve performance of scopes If a scope update is requested, don't recalculate scope data if it is already up-to-date. Eliminate double and triple scope rendering. --- rtengine/improccoordinator.cc | 195 ++++++++++++++++++++++------------ rtengine/improccoordinator.h | 19 +++- rtengine/rtengine.h | 17 +-- rtgui/editorpanel.cc | 65 ++++++------ rtgui/editorpanel.h | 7 +- rtgui/histogrampanel.cc | 80 +++++++++----- rtgui/histogrampanel.h | 23 ++-- 7 files changed, 259 insertions(+), 147 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f25395c2d..ea4c8a92b 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -131,7 +131,8 @@ ImProcCoordinator::ImProcCoordinator() : histLRETI(256), vectorscopeScale(0), - vectorscope(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), + vectorscope_hc(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), + vectorscope_hs(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), waveformScale(0), waveformRed(0, 0), waveformGreen(0, 0), @@ -1644,12 +1645,16 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) imageListener->imageReady(params->crop); } + hist_lrgb_dirty = vectorscope_hc_dirty = vectorscope_hs_dirty = waveform_dirty = true; if (hListener) { if (hListener->updateHistogram()) { updateLRGBHistograms(); } - if (hListener->updateVectorscope()) { - updateVectorscope(); + if (hListener->updateVectorscopeHC()) { + updateVectorscopeHC(); + } + if (hListener->updateVectorscopeHS()) { + updateVectorscopeHS(); } if (hListener->updateWaveform()) { updateWaveforms(); @@ -1774,7 +1779,8 @@ void ImProcCoordinator::notifyHistogramChanged() histChroma, histLRETI, vectorscopeScale, - vectorscope, + vectorscope_hc, + vectorscope_hs, waveformScale, waveformRed, waveformGreen, @@ -1784,9 +1790,13 @@ void ImProcCoordinator::notifyHistogramChanged() } } -void ImProcCoordinator::updateLRGBHistograms() +bool ImProcCoordinator::updateLRGBHistograms() { + if (!hist_lrgb_dirty) { + return false; + } + int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); @@ -1843,86 +1853,109 @@ void ImProcCoordinator::updateLRGBHistograms() } } + hist_lrgb_dirty = false; + return true; + } -void ImProcCoordinator::updateVectorscope() +bool ImProcCoordinator::updateVectorscopeHC() { - if (!workimg) { - return; + if (!workimg || !vectorscope_hc_dirty) { + return false; } int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); constexpr int size = VECTORSCOPE_SIZE; - vectorscope.fill(0); + vectorscope_hc.fill(0); vectorscopeScale = (x2 - x1) * (y2 - y1); - if (hListener->vectorscopeType() == 0) { // HS + + const std::unique_ptr a(new float[vectorscopeScale]); + const std::unique_ptr b(new float[vectorscopeScale]); + const std::unique_ptr L(new float[vectorscopeScale]); + ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); #ifdef _OPENMP - #pragma omp parallel + #pragma omp parallel #endif - { - array2D vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA); + { + array2D vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA); #ifdef _OPENMP - #pragma omp for nowait + #pragma omp for nowait #endif - for (int i = y1; i < y2; ++i) { - int ofs = (i * pW + x1) * 3; - for (int j = x1; j < x2; ++j) { - const float red = 257.f * workimg->data[ofs++]; - const float green = 257.f * workimg->data[ofs++]; - const float blue = 257.f * workimg->data[ofs++]; - float h, s, l; - Color::rgb2hslfloat(red, green, blue, h, s, l); - const auto sincosval = xsincosf(2.f * RT_PI_F * h); - const int col = s * sincosval.y * (size / 2) + size / 2; - const int row = s * sincosval.x * (size / 2) + size / 2; - if (col >= 0 && col < size && row >= 0 && row < size) { - vectorscopeThr[row][col]++; - } + for (int i = y1; i < y2; ++i) { + for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { + const int col = (size / 96000.f) * a[ofs_lab] + size / 2; + const int row = (size / 96000.f) * b[ofs_lab] + size / 2; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscopeThr[row][col]++; } } -#ifdef _OPENMP - #pragma omp critical -#endif - { - vectorscope += vectorscopeThr; - } } - } else if (hListener->vectorscopeType() == 1) { // CH - const std::unique_ptr a(new float[vectorscopeScale]); - const std::unique_ptr b(new float[vectorscopeScale]); - const std::unique_ptr L(new float[vectorscopeScale]); - ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); #ifdef _OPENMP - #pragma omp parallel + #pragma omp critical #endif { - array2D vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA); -#ifdef _OPENMP - #pragma omp for nowait -#endif - for (int i = y1; i < y2; ++i) { - for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { - const int col = (size / 96000.f) * a[ofs_lab] + size / 2; - const int row = (size / 96000.f) * b[ofs_lab] + size / 2; - if (col >= 0 && col < size && row >= 0 && row < size) { - vectorscopeThr[row][col]++; - } - } - } -#ifdef _OPENMP - #pragma omp critical -#endif - { - vectorscope += vectorscopeThr; - } + vectorscope_hc += vectorscopeThr; } } + + vectorscope_hc_dirty = false; + return true; } -void ImProcCoordinator::updateWaveforms() +bool ImProcCoordinator::updateVectorscopeHS() +{ + if (!workimg || !vectorscope_hs_dirty) { + return false; + } + + int x1, y1, x2, y2; + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + + constexpr int size = VECTORSCOPE_SIZE; + vectorscope_hs.fill(0); + + vectorscopeScale = (x2 - x1) * (y2 - y1); + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + array2D vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA); +#ifdef _OPENMP + #pragma omp for nowait +#endif + for (int i = y1; i < y2; ++i) { + int ofs = (i * pW + x1) * 3; + for (int j = x1; j < x2; ++j) { + const float red = 257.f * workimg->data[ofs++]; + const float green = 257.f * workimg->data[ofs++]; + const float blue = 257.f * workimg->data[ofs++]; + float h, s, l; + Color::rgb2hslfloat(red, green, blue, h, s, l); + const auto sincosval = xsincosf(2.f * RT_PI_F * h); + const int col = s * sincosval.y * (size / 2) + size / 2; + const int row = s * sincosval.x * (size / 2) + size / 2; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscopeThr[row][col]++; + } + } + } +#ifdef _OPENMP + #pragma omp critical +#endif + { + vectorscope_hs += vectorscopeThr; + } + } + + vectorscope_hs_dirty = false; + return true; +} + +bool ImProcCoordinator::updateWaveforms() { if (!workimg) { // free memory @@ -1930,7 +1963,11 @@ void ImProcCoordinator::updateWaveforms() waveformGreen.free(); waveformBlue.free(); waveformLuma.free(); - return; + return true; + } + + if (!waveform_dirty) { + return false; } int x1, y1, x2, y2; @@ -1966,6 +2003,8 @@ void ImProcCoordinator::updateWaveforms() } waveformScale = y2 - y1; + waveform_dirty = false; + return true; } bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, double tempBias) @@ -2412,24 +2451,44 @@ void ImProcCoordinator::setHighQualComputed() void ImProcCoordinator::requestUpdateWaveform() { - if (hListener) { - updateWaveforms(); + if (!hListener) { + return; + } + bool updated = updateWaveforms(); + if (updated) { notifyHistogramChanged(); } } void ImProcCoordinator::requestUpdateHistogram() { - if (hListener) { - updateLRGBHistograms(); + if (!hListener) { + return; + } + bool updated = updateLRGBHistograms(); + if (updated) { notifyHistogramChanged(); } } -void ImProcCoordinator::requestUpdateVectorscope() +void ImProcCoordinator::requestUpdateVectorscopeHC() { - if (hListener) { - updateVectorscope(); + if (!hListener) { + return; + } + bool updated = updateVectorscopeHC(); + if (updated) { + notifyHistogramChanged(); + } +} + +void ImProcCoordinator::requestUpdateVectorscopeHS() +{ + if (!hListener) { + return; + } + bool updated = updateVectorscopeHS(); + if (updated) { notifyHistogramChanged(); } } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 8a112b270..791679678 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -126,10 +126,13 @@ protected: LUTu histBlue, histBlueRaw; LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; + bool hist_lrgb_dirty; int vectorscopeScale; - array2D vectorscope; + bool vectorscope_hc_dirty, vectorscope_hs_dirty; + array2D vectorscope_hc, vectorscope_hs; /// Waveform's intensity. Same as height of reference image. int waveformScale; + bool waveform_dirty; array2D waveformRed, waveformGreen, waveformBlue, waveformLuma; LUTf CAMBrightCurveJ, CAMBrightCurveQ; @@ -200,9 +203,14 @@ protected: void notifyHistogramChanged(); void reallocAll(); - void updateLRGBHistograms(); - void updateVectorscope(); - void updateWaveforms(); + /// Updates L, R, G, and B histograms. Returns true unless not updated. + bool updateLRGBHistograms(); + /// Updates the H-C vectorscope. Returns true unless not updated. + bool updateVectorscopeHC(); + /// Updates the H-S vectorscope. Returns true unless not updated. + bool updateVectorscopeHS(); + /// Updates all waveforms. Returns true unless not updated. + bool updateWaveforms(); void setScale(int prevscale); void updatePreviewImage (int todo, bool panningRelatedChange); @@ -561,7 +569,8 @@ public: } denoiseInfoStore; void requestUpdateHistogram() override; - void requestUpdateVectorscope() override; + void requestUpdateVectorscopeHC() override; + void requestUpdateVectorscopeHS() override; void requestUpdateWaveform() override; }; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index e6749a9f0..43848e70c 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -334,7 +334,8 @@ public: const LUTu& histChroma, const LUTu& histLRETI, int vectorscopeScale, - const array2D& vectorscope, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, int waveformScale, const array2D& waveformRed, const array2D& waveformGreen, @@ -345,12 +346,12 @@ public: virtual void setObservable(HistogramObservable* observable) = 0; /** Returns if the listener wants the histogram to be updated. */ virtual bool updateHistogram(void) const = 0; - /** Returns if the listener wants the vectorscope to be updated. */ - virtual bool updateVectorscope(void) const = 0; + /** Returns if the listener wants the H-C vectorscope to be updated. */ + virtual bool updateVectorscopeHC(void) const = 0; + /** Returns if the listener wants the H-S vectorscope to be updated. */ + virtual bool updateVectorscopeHS(void) const = 0; /** Returns if the listener wants the waveform to be updated. */ virtual bool updateWaveform(void) const = 0; - /** Returns the vectorscope type: 0 for H-S and 1 for H-C. */ - virtual int vectorscopeType(void) const = 0; }; class HistogramObservable @@ -358,8 +359,10 @@ class HistogramObservable public: /** Tells the observable to update the histogram data. */ virtual void requestUpdateHistogram() = 0; - /** Tells the observable to update the vectorscope data. */ - virtual void requestUpdateVectorscope() = 0; + /** Tells the observable to update the H-C vectorscope data. */ + virtual void requestUpdateVectorscopeHC() = 0; + /** Tells the observable to update the H-S vectorscope data. */ + virtual void requestUpdateVectorscopeHS() = 0; /** Tells the observable to update the waveform data. */ virtual void requestUpdateWaveform() = 0; }; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index d3d339783..c53877736 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -472,7 +472,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) beforeIarea (nullptr), beforeBox (nullptr), afterBox (nullptr), beforeLabel (nullptr), afterLabel (nullptr), beforeHeaderBox (nullptr), afterHeaderBox (nullptr), parent (nullptr), parentWindow (nullptr), openThm (nullptr), selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false), - histogram_observable(nullptr), histogram_scope_type(HistogramPanelListener::NONE) + histogram_observable(nullptr), histogram_scope_type(ScopeType::NONE) { epih = new EditorPanelIdleHelper; @@ -2249,7 +2249,8 @@ void EditorPanel::histogramChanged( const LUTu& histChroma, const LUTu& histLRETI, int vectorscopeScale, - const array2D& vectorscope, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, int waveformScale, const array2D& waveformRed, const array2D& waveformGreen, @@ -2258,7 +2259,7 @@ void EditorPanel::histogramChanged( ) { if (histogramPanel) { - histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); + histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscopeHC, vectorscopeHS, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); } tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI); @@ -2271,34 +2272,28 @@ void EditorPanel::setObservable(rtengine::HistogramObservable* observable) bool EditorPanel::updateHistogram(void) const { - return histogram_scope_type == HistogramPanelListener::HISTOGRAM - || histogram_scope_type == HistogramPanelListener::NONE; + return histogram_scope_type == ScopeType::HISTOGRAM + || histogram_scope_type == ScopeType::NONE; } -bool EditorPanel::updateVectorscope(void) const +bool EditorPanel::updateVectorscopeHC(void) const { return - histogram_scope_type == HistogramPanelListener::VECTORSCOPE_HS - || histogram_scope_type == HistogramPanelListener::VECTORSCOPE_CH - || histogram_scope_type == HistogramPanelListener::NONE; + histogram_scope_type == ScopeType::VECTORSCOPE_HC + || histogram_scope_type == ScopeType::NONE; +} + +bool EditorPanel::updateVectorscopeHS(void) const +{ + return + histogram_scope_type == ScopeType::VECTORSCOPE_HS + || histogram_scope_type == ScopeType::NONE; } bool EditorPanel::updateWaveform(void) const { - return histogram_scope_type == HistogramPanelListener::WAVEFORM - || histogram_scope_type == HistogramPanelListener::NONE; -} - -int EditorPanel::vectorscopeType(void) const -{ - switch (histogram_scope_type) { - case HistogramPanelListener::VECTORSCOPE_HS: - return 0; - case HistogramPanelListener::VECTORSCOPE_CH: - return 1; - default: - return -1; - } + return histogram_scope_type == ScopeType::WAVEFORM + || histogram_scope_type == ScopeType::NONE; } void EditorPanel::scopeTypeChanged(ScopeType new_type) @@ -2311,14 +2306,22 @@ 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->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->requestUpdateWaveform(); + switch (new_type) { + case ScopeType::HISTOGRAM: + histogram_observable->requestUpdateHistogram(); + break; + case ScopeType::VECTORSCOPE_HC: + histogram_observable->requestUpdateVectorscopeHC(); + break; + case ScopeType::VECTORSCOPE_HS: + histogram_observable->requestUpdateVectorscopeHS(); + break; + case ScopeType::WAVEFORM: + histogram_observable->requestUpdateWaveform(); + break; + case ScopeType::HISTOGRAM_RAW: + case ScopeType::NONE: + break; } } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 9f0ebf8cb..f6bc0b606 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -135,7 +135,8 @@ public: const LUTu& histChroma, const LUTu& histLRETI, int vectorscopeScale, - const array2D& vectorscope, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, int waveformScale, const array2D& waveformRed, const array2D& waveformGreen, @@ -144,9 +145,9 @@ public: ) override; void setObservable(rtengine::HistogramObservable* observable) override; bool updateHistogram(void) const override; - bool updateVectorscope(void) const override; + bool updateVectorscopeHC(void) const override; + bool updateVectorscopeHS(void) const override; bool updateWaveform(void) const override; - int vectorscopeType(void) const override; // HistogramPanelListener void scopeTypeChanged(ScopeType new_type) override; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 2c9d6bb0e..a07133204 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -309,8 +309,10 @@ void HistogramPanel::showRGBBar() void HistogramPanel::resized (Gtk::Allocation& req) { - histogramArea->updateBackBuffer (); - histogramArea->queue_draw (); + if (!histogramArea->updatePending()) { + histogramArea->updateBackBuffer (); + histogramArea->queue_draw (); + } // set histogramRGBArea invalid; if (histogramRGBArea) { @@ -394,7 +396,10 @@ void HistogramPanel::type_pressed() scopeType->set_image(*vectHcImage); } type_changed(); - rgbv_toggled(); + updateHistAreaOptions(); + if (histogramRGBArea) { + updateHistRGBAreaOptions(); + } } void HistogramPanel::type_changed() @@ -415,7 +420,7 @@ void HistogramPanel::type_changed() histogramRGBArea = histogramRGBAreaHori.get(); if (panel_listener) { updateHistAreaOptions(); - panel_listener->scopeTypeChanged(HistogramPanelListener::HISTOGRAM); + panel_listener->scopeTypeChanged(ScopeType::HISTOGRAM); } } else if (options.histogramScopeType == 1) { showRed->set_sensitive(); @@ -428,7 +433,7 @@ void HistogramPanel::type_changed() histogramRGBArea = histogramRGBAreaVert.get(); if (panel_listener) { updateHistAreaOptions(); - panel_listener->scopeTypeChanged(HistogramPanelListener::WAVEFORM); + panel_listener->scopeTypeChanged(ScopeType::WAVEFORM); } } else { showRed->set_sensitive(false); @@ -441,13 +446,13 @@ void HistogramPanel::type_changed() histogramRGBArea = nullptr; if (panel_listener) { updateHistAreaOptions(); - HistogramPanelListener::ScopeType type = HistogramPanelListener::NONE; + ScopeType type = ScopeType::NONE; switch (options.histogramScopeType) { case 2: - type = HistogramPanelListener::VECTORSCOPE_HS; + type = ScopeType::VECTORSCOPE_HS; break; case 3: - type = HistogramPanelListener::VECTORSCOPE_CH; + type = ScopeType::VECTORSCOPE_HC; break; } panel_listener->scopeTypeChanged(type); @@ -479,7 +484,7 @@ void HistogramPanel::rgbv_toggled () histogramArea->queue_draw (); if (histogramRGBArea) { - 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); + updateHistRGBAreaOptions(); histogramRGBArea->updateBackBuffer (0, 0, 0); histogramRGBArea->queue_draw (); } @@ -532,17 +537,17 @@ void HistogramPanel::setPanelListener(HistogramPanelListener* listener) panel_listener = listener; if (listener) { - HistogramPanelListener::ScopeType type; + ScopeType type; if (options.histogramScopeType == 0) { - type = HistogramPanelListener::HISTOGRAM; + type = ScopeType::HISTOGRAM; } else if (options.histogramScopeType == 1) { - type = HistogramPanelListener::WAVEFORM; + type = ScopeType::WAVEFORM; } else if (options.histogramScopeType == 2) { - type = HistogramPanelListener::VECTORSCOPE_HS; + type = ScopeType::VECTORSCOPE_HS; } else if (options.histogramScopeType == 3) { - type = HistogramPanelListener::VECTORSCOPE_CH; + type = ScopeType::VECTORSCOPE_HC; } else { - type = HistogramPanelListener::NONE; + type = ScopeType::NONE; } listener->scopeTypeChanged(type); } @@ -563,6 +568,19 @@ void HistogramPanel::updateHistAreaOptions() ); } +void HistogramPanel::updateHistRGBAreaOptions() +{ + 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 + ); +} + // // // @@ -897,8 +915,8 @@ void HistogramRGBAreaVert::get_preferred_width_for_height_vfunc (int height, int // HistogramArea HistogramArea::HistogramArea (DrawModeListener *fml) : vectorscope_scale(0), - vect(0, 0), - vect_buffer_dirty(true), + vect_hc(0, 0), vect_hs(0, 0), + vect_hc_buffer_dirty(true), vect_hs_buffer_dirty(true), waveform_scale(0), rwave(0, 0), gwave(0, 0),bwave(0, 0), lwave(0, 0), wave_buffer_dirty(true), @@ -986,6 +1004,11 @@ void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool wave_buffer_dirty = true; } +bool HistogramArea::updatePending(void) +{ + return haih->pending > 0 && !haih->destroyed; +} + void HistogramArea::update( const LUTu& histRed, const LUTu& histGreen, @@ -996,7 +1019,8 @@ void HistogramArea::update( const LUTu& histGreenRaw, const LUTu& histBlueRaw, int vectorscopeScale, - const array2D& vectorscope, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, int waveformScale, const array2D& waveformRed, const array2D& waveformGreen, @@ -1021,10 +1045,14 @@ void HistogramArea::update( bwave = waveformBlue; lwave = waveformLuma; wave_buffer_dirty = true; - } else if (scopeType >= 2) { + } else if (scopeType == 2) { vectorscope_scale = vectorscopeScale; - vect = vectorscope; - vect_buffer_dirty = true; + vect_hs = vectorscopeHS; + vect_hs_buffer_dirty = true; + } else if (scopeType == 3) { + vectorscope_scale = vectorscopeScale; + vect_hc = vectorscopeHC; + vect_hc_buffer_dirty = true; } valid = true; } else { @@ -1060,7 +1088,6 @@ void HistogramArea::update( void HistogramArea::updateBackBuffer () { - if (!get_realized ()) { return; } @@ -1333,6 +1360,10 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, int h) { + const auto& vect = (scopeType == 3) ? vect_hc : vect_hs; + auto& vect_buffer = (scopeType == 3) ? vect_hc_buffer : vect_hs_buffer; + auto& vect_buffer_dirty = (scopeType == 3) ? vect_hc_buffer_dirty : vect_hs_buffer_dirty; + const int vect_width = vect.getWidth(); const int vect_height = vect.getHeight(); // Arbitrary scale factor multiplied by vectorscope area and divided by @@ -1582,7 +1613,7 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h bool HistogramArea::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) { - if (get_width() != oldwidth || get_height() != oldheight || isDirty ()) { + if (!updatePending() && (get_width() != oldwidth || get_height() != oldheight || isDirty())) { updateBackBuffer (); } @@ -1651,8 +1682,7 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) double dx = (event->x - movingPosition) / get_width(); float new_brightness = LIM(trace_brightness * pow(RANGE, dx), MIN_BRIGHT, MAX_BRIGHT); if (new_brightness != trace_brightness) { - wave_buffer_dirty = true; - vect_buffer_dirty = true; + wave_buffer_dirty = vect_hc_buffer_dirty = vect_hs_buffer_dirty = true; trace_brightness = new_brightness; setDirty(true); queue_draw(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 935a30bfd..975a6d8ab 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -36,6 +36,11 @@ class HistogramArea; +enum ScopeType +{ + HISTOGRAM, HISTOGRAM_RAW, VECTORSCOPE_HC, VECTORSCOPE_HS, WAVEFORM, NONE +}; + struct HistogramAreaIdleHelper { HistogramArea* harea; bool destroyed; @@ -161,9 +166,9 @@ protected: LUTu rhist, ghist, bhist, lhist, chist; LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused? int vectorscope_scale; - array2D vect; - std::vector vect_buffer; - bool vect_buffer_dirty; + array2D vect_hc, vect_hs; + std::vector vect_hc_buffer, vect_hs_buffer; + bool vect_hc_buffer_dirty, vect_hs_buffer_dirty; int waveform_scale; array2D rwave, gwave, bwave, lwave; std::vector wave_buffer; @@ -208,7 +213,8 @@ public: const LUTu& histGreenRaw, const LUTu& histBlueRaw, int vectorscopeScale, - const array2D& vectorscope, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, int waveformScale, const array2D& waveformRed, const array2D& waveformGreen, @@ -216,6 +222,7 @@ public: const array2D& waveformLuma ); void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type, bool pointer); + bool updatePending(); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; bool on_button_press_event (GdkEventButton* event) override; @@ -238,8 +245,6 @@ private: class HistogramPanelListener { public: - enum ScopeType {HISTOGRAM, VECTORSCOPE_CH, VECTORSCOPE_HS, WAVEFORM, NONE}; - virtual void scopeTypeChanged(ScopeType new_type) = 0; }; @@ -297,6 +302,7 @@ protected: void setHistInvalid (); void showRGBBar(); void updateHistAreaOptions(); + void updateHistRGBAreaOptions(); public: @@ -313,7 +319,8 @@ public: const LUTu& histGreenRaw, const LUTu& histBlueRaw, int vectorscopeScale, - const array2D& vectorscope, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, int waveformScale, const array2D& waveformRed, const array2D& waveformGreen, @@ -321,7 +328,7 @@ public: const array2D& waveformLuma ) { - histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); + histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscopeHC, vectorscopeHS, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); } // 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; From bb0c625960e069756a3646dceb5d6eca5ebe34ba Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Mon, 7 Sep 2020 16:37:40 -0700 Subject: [PATCH 35/56] Use enum for scope types --- rtgui/histogrampanel.cc | 301 ++++++++++++++++++++++------------------ rtgui/histogrampanel.h | 10 +- rtgui/options.cc | 4 +- rtgui/options.h | 11 +- 4 files changed, 184 insertions(+), 142 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index a07133204..a9c8a95d6 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -79,15 +79,18 @@ HistogramPanel::HistogramPanel () : histogramRGBAreaVert->show(); switch (options.histogramScopeType) { - case 2: - case 3: + case ScopeType::NONE: + case ScopeType::VECTORSCOPE_HC: + case ScopeType::VECTORSCOPE_HS: histogramRGBArea = nullptr; break; - case 1: + case ScopeType::WAVEFORM: histogramRGBArea = histogramRGBAreaVert.get(); break; - default: + case ScopeType::HISTOGRAM: + case ScopeType::HISTOGRAM_RAW: histogramRGBArea = histogramRGBAreaHori.get(); + break; } // connecting the two childs @@ -202,14 +205,22 @@ HistogramPanel::HistogramPanel () : showMode->set_image(*mode1Image); else showMode->set_image(*mode2Image); - if (options.histogramScopeType == 0) { - scopeType->set_image(*histImage); - } else if (options.histogramScopeType == 1) { - scopeType->set_image(*waveImage); - } else if (options.histogramScopeType == 2) { - scopeType->set_image(*vectHsImage); - } else if (options.histogramScopeType == 3) { - scopeType->set_image(*vectHcImage); + switch(options.histogramScopeType) { + case ScopeType::HISTOGRAM: + scopeType->set_image(*histImage); + break; + case ScopeType::WAVEFORM: + scopeType->set_image(*waveImage); + break; + case ScopeType::VECTORSCOPE_HS: + scopeType->set_image(*vectHsImage); + break; + case ScopeType::VECTORSCOPE_HC: + scopeType->set_image(*vectHcImage); + break; + case ScopeType::HISTOGRAM_RAW: + case ScopeType::NONE: + break; } showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); @@ -303,7 +314,10 @@ void HistogramPanel::showRGBBar() gfxGrid->attach_next_to(*histogramRGBArea, *histogramArea, pos); setHistRGBInvalid(); - histogramRGBArea->setShow(options.histogramScopeType < 2); + histogramRGBArea->setShow( + options.histogramScopeType == ScopeType::HISTOGRAM + || options.histogramScopeType == ScopeType::WAVEFORM + ); } void HistogramPanel::resized (Gtk::Allocation& req) @@ -363,8 +377,11 @@ void HistogramPanel::raw_toggled () showChro->set_sensitive(false); } else { showRAW->set_image(*rawImage_g); - showValue->set_sensitive(options.histogramScopeType != 1); - showChro->set_sensitive(options.histogramScopeType != 1); + showValue->set_sensitive( + options.histogramScopeType == ScopeType::HISTOGRAM + || options.histogramScopeType == ScopeType::WAVEFORM + ); + showChro->set_sensitive(options.histogramScopeType == ScopeType::HISTOGRAM); } rgbv_toggled(); @@ -384,17 +401,28 @@ void HistogramPanel::mode_released () void HistogramPanel::type_pressed() { - constexpr int TYPE_COUNT = 4; // Histogram, waveform, and 2 vectorscopes. - options.histogramScopeType = (options.histogramScopeType + 1) % TYPE_COUNT; - if (options.histogramScopeType == 0) { - scopeType->set_image(*histImage); - } else if (options.histogramScopeType == 1) { - scopeType->set_image(*waveImage); - } else if (options.histogramScopeType == 2) { - scopeType->set_image(*vectHsImage); - } else if (options.histogramScopeType == 3) { - scopeType->set_image(*vectHcImage); + // Switch to next type. + switch (options.histogramScopeType) { + case ScopeType::NONE: // Default to histogram. + case ScopeType::HISTOGRAM_RAW: // Not supported as a true scope type. + case ScopeType::VECTORSCOPE_HC: + options.histogramScopeType = ScopeType::HISTOGRAM; + scopeType->set_image(*histImage); + break; + case ScopeType::HISTOGRAM: + options.histogramScopeType = ScopeType::WAVEFORM; + scopeType->set_image(*waveImage); + break; + case ScopeType::WAVEFORM: + options.histogramScopeType = ScopeType::VECTORSCOPE_HS; + scopeType->set_image(*vectHsImage); + break; + case ScopeType::VECTORSCOPE_HS: + options.histogramScopeType = ScopeType::VECTORSCOPE_HC; + scopeType->set_image(*vectHcImage); + break; } + type_changed(); updateHistAreaOptions(); if (histogramRGBArea) { @@ -409,54 +437,46 @@ void HistogramPanel::type_changed() gfxGrid->remove(*histogramRGBArea); } - 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(); - showMode->set_sensitive(); - histogramRGBArea = histogramRGBAreaHori.get(); - if (panel_listener) { - updateHistAreaOptions(); - panel_listener->scopeTypeChanged(ScopeType::HISTOGRAM); - } - } else if (options.histogramScopeType == 1) { - showRed->set_sensitive(); - showGreen->set_sensitive(); - showBlue->set_sensitive(); - showValue->set_sensitive(); - showChro->set_sensitive(false); - showRAW->set_sensitive(false); - showMode->set_sensitive(false); - histogramRGBArea = histogramRGBAreaVert.get(); - if (panel_listener) { - updateHistAreaOptions(); - panel_listener->scopeTypeChanged(ScopeType::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 = nullptr; - if (panel_listener) { - updateHistAreaOptions(); - ScopeType type = ScopeType::NONE; - switch (options.histogramScopeType) { - case 2: - type = ScopeType::VECTORSCOPE_HS; - break; - case 3: - type = ScopeType::VECTORSCOPE_HC; - break; - } - panel_listener->scopeTypeChanged(type); - } + switch (options.histogramScopeType) { + case ScopeType::HISTOGRAM: + case ScopeType::HISTOGRAM_RAW: + showRed->set_sensitive(); + showGreen->set_sensitive(); + showBlue->set_sensitive(); + showValue->set_sensitive(!showRAW->get_active()); + showChro->set_sensitive(!showRAW->get_active()); + showRAW->set_sensitive(); + showMode->set_sensitive(); + histogramRGBArea = histogramRGBAreaHori.get(); + break; + case ScopeType::WAVEFORM: + showRed->set_sensitive(); + showGreen->set_sensitive(); + showBlue->set_sensitive(); + showValue->set_sensitive(); + showChro->set_sensitive(false); + showRAW->set_sensitive(false); + showMode->set_sensitive(false); + histogramRGBArea = histogramRGBAreaVert.get(); + break; + case ScopeType::VECTORSCOPE_HC: + case ScopeType::VECTORSCOPE_HS: + 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 = nullptr; + break; + case ScopeType::NONE: + break; + } + + if (panel_listener) { + updateHistAreaOptions(); + panel_listener->scopeTypeChanged(options.histogramScopeType); } if (showBAR->get_active()) { @@ -537,19 +557,7 @@ void HistogramPanel::setPanelListener(HistogramPanelListener* listener) panel_listener = listener; if (listener) { - ScopeType type; - if (options.histogramScopeType == 0) { - type = ScopeType::HISTOGRAM; - } else if (options.histogramScopeType == 1) { - type = ScopeType::WAVEFORM; - } else if (options.histogramScopeType == 2) { - type = ScopeType::VECTORSCOPE_HS; - } else if (options.histogramScopeType == 3) { - type = ScopeType::VECTORSCOPE_HC; - } else { - type = ScopeType::NONE; - } - listener->scopeTypeChanged(type); + listener->scopeTypeChanged(options.histogramScopeType); } } @@ -577,7 +585,7 @@ void HistogramPanel::updateHistRGBAreaOptions() showValue->get_active(), showChro->get_active(), showRAW->get_active(), - showBAR->get_active() && options.histogramScopeType < 2 + showBAR->get_active() ); } @@ -671,7 +679,8 @@ void HistogramRGBArea::setShow(bool show) void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { - if (!get_realized () || !showMode || (rawMode && options.histogramScopeType != 1)) { + //if (!get_realized () || !showMode || (rawMode && options.histogramScopeType == ScopeType::HISTOGRAM) || options.histogramScopeType == ScopeType::HISTOGRAM_RAW) { + if (!get_realized () || !showMode || !((!rawMode && options.histogramScopeType == ScopeType::HISTOGRAM) || options.histogramScopeType == ScopeType::WAVEFORM)) { return; } @@ -717,7 +726,11 @@ 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 == ScopeType::HISTOGRAM + || options.histogramScopeType == ScopeType::WAVEFORM) + ) { 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); @@ -727,7 +740,7 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustrin drawBar(cc, Lab_L, 100.0, winw, winh, s); } - if (needChroma && options.histogramScopeType == 0) { + if (needChroma && options.histogramScopeType == ScopeType::HISTOGRAM) { // Chroma double chromaval = sqrt(Lab_a * Lab_a + Lab_b * Lab_b) / 1.8; cc->set_source_rgb(0.9, 0.9, 0.0); @@ -874,7 +887,7 @@ void HistogramRGBAreaHori::get_preferred_width_for_height_vfunc (int height, int void HistogramRGBAreaVert::drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) { double pos; - if (options.histogramDrawMode < 2 || options.histogramScopeType == 1) { + if (options.histogramDrawMode < 2 || options.histogramScopeType == ScopeType::WAVEFORM) { pos = padding + value * (winh - padding * 2.0 - 1) / max_value + 0.5 * scale; } else { pos = padding + HistogramScaling::log (max_value, value) * (winh - padding * 2.0) / max_value + 0.5 * scale; @@ -988,7 +1001,7 @@ void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minim get_preferred_width_vfunc (minimum_width, natural_width); } -void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type, bool pointer) +void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, ScopeType type, bool pointer) { options.histogramRed = needRed = r; @@ -1029,30 +1042,38 @@ void HistogramArea::update( ) { if (histRed) { - if (scopeType == 0) { - rhist = histRed; - ghist = histGreen; - bhist = histBlue; - lhist = histLuma; - chist = histChroma; - rhistRaw = histRedRaw; - ghistRaw = histGreenRaw; - bhistRaw = histBlueRaw; - } else if (scopeType == 1) { - waveform_scale = waveformScale; - rwave = waveformRed; - gwave = waveformGreen; - bwave = waveformBlue; - lwave = waveformLuma; - wave_buffer_dirty = true; - } else if (scopeType == 2) { - vectorscope_scale = vectorscopeScale; - vect_hs = vectorscopeHS; - vect_hs_buffer_dirty = true; - } else if (scopeType == 3) { - vectorscope_scale = vectorscopeScale; - vect_hc = vectorscopeHC; - vect_hc_buffer_dirty = true; + switch (scopeType) { + case ScopeType::HISTOGRAM: + rhist = histRed; + ghist = histGreen; + bhist = histBlue; + lhist = histLuma; + chist = histChroma; + rhistRaw = histRedRaw; + ghistRaw = histGreenRaw; + bhistRaw = histBlueRaw; + break; + case ScopeType::WAVEFORM: + waveform_scale = waveformScale; + rwave = waveformRed; + gwave = waveformGreen; + bwave = waveformBlue; + lwave = waveformLuma; + wave_buffer_dirty = true; + break; + case ScopeType::VECTORSCOPE_HS: + vectorscope_scale = vectorscopeScale; + vect_hs = vectorscopeHS; + vect_hs_buffer_dirty = true; + break; + case ScopeType::VECTORSCOPE_HC: + vectorscope_scale = vectorscopeScale; + vect_hc = vectorscopeHC; + vect_hc_buffer_dirty = true; + break; + case ScopeType::HISTOGRAM_RAW: + case ScopeType::NONE: + break; } valid = true; } else { @@ -1125,7 +1146,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 == 0) { + if (options.histogramScopeType == ScopeType::HISTOGRAM || options.histogramScopeType == ScopeType::HISTOGRAM_RAW) { for (int i = 0; i <= nrOfVGridPartitions; i++) { double xpos = padding + 0.5; if (options.histogramDrawMode < 2) { @@ -1140,14 +1161,14 @@ void HistogramArea::updateBackBuffer () } // draw horizontal gridlines - if (options.histogramScopeType == 1) { + if (options.histogramScopeType == ScopeType::WAVEFORM) { for (int i = 0; i <= nrOfVGridPartitions; i++) { const double ypos = h - padding - (pow(2.0,i) - 1) * (h - 2 * padding - 1) / 255.0; cr->move_to(0, ypos); cr->line_to(w, ypos); cr->stroke(); } - } else if (options.histogramScopeType >= 2) { + } else if (options.histogramScopeType == ScopeType::VECTORSCOPE_HC || options.histogramScopeType == ScopeType::VECTORSCOPE_HS) { // Vectorscope has no gridlines. } else if (options.histogramDrawMode == 0) { for (int i = 1; i < nrOfHGridPartitions; i++) { @@ -1165,7 +1186,7 @@ void HistogramArea::updateBackBuffer () cr->unset_dash(); - if (valid && scopeType == 0) { + if (valid && (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW)) { // For RAW mode use the other hists LUTu& rh = rawMode ? rhistRaw : rhist; LUTu& gh = rawMode ? ghistRaw : ghist; @@ -1272,9 +1293,9 @@ void HistogramArea::updateBackBuffer () drawMarks(cr, bhchanged, realhistheight, w, ui, oi); } - } else if (scopeType == 1 && rwave.getWidth() > 0) { + } else if (scopeType == ScopeType::WAVEFORM && rwave.getWidth() > 0) { drawWaveform(cr, w, h); - } else if (scopeType >= 2) { + } else if (scopeType == ScopeType::VECTORSCOPE_HC || scopeType == ScopeType::VECTORSCOPE_HS) { drawVectorscope(cr, w, h); } @@ -1289,7 +1310,7 @@ void HistogramArea::updateBackBuffer () bool HistogramArea::updatePointer(int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { - if (!needPointer || scopeType < 2) { + if (!needPointer || !(scopeType == ScopeType::VECTORSCOPE_HC || scopeType == ScopeType::VECTORSCOPE_HS)) { return false; } if (pointer_red == r && pointer_green == g && pointer_blue == b) { @@ -1360,9 +1381,13 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, int h) { - const auto& vect = (scopeType == 3) ? vect_hc : vect_hs; - auto& vect_buffer = (scopeType == 3) ? vect_hc_buffer : vect_hs_buffer; - auto& vect_buffer_dirty = (scopeType == 3) ? vect_hc_buffer_dirty : vect_hs_buffer_dirty; + if (scopeType != ScopeType::VECTORSCOPE_HC && scopeType != ScopeType::VECTORSCOPE_HS) { + return; + } + + const auto& vect = (scopeType == ScopeType::VECTORSCOPE_HC) ? vect_hc : vect_hs; + auto& vect_buffer = (scopeType == ScopeType::VECTORSCOPE_HC) ? vect_hc_buffer : vect_hs_buffer; + auto& vect_buffer_dirty = (scopeType == ScopeType::VECTORSCOPE_HC) ? vect_hc_buffer_dirty : vect_hs_buffer_dirty; const int vect_width = vect.getWidth(); const int vect_height = vect.getHeight(); @@ -1413,7 +1438,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in cr->set_antialias(Cairo::ANTIALIAS_SUBPIXEL); ch_ds[0] = 4; - if (scopeType == 2) { // Hue-Saturation. + if (scopeType == ScopeType::VECTORSCOPE_HS) { // Hue-Saturation. // RYGCBM lines. cr->set_line_width (2.0 * s); constexpr double color_labels[6][3] = { @@ -1452,7 +1477,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in cr->line_to(line_spacing + line_length, 0); cr->stroke(); cr->unset_dash(); - } else if (scopeType == 3) { // Hue-Chroma. + } else if (scopeType == ScopeType::VECTORSCOPE_HC) { // Hue-Chroma. // a and b axes. Cairo::RefPtr gradient; cr->set_line_width (2.0 * s); @@ -1508,7 +1533,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in if (needPointer && pointer_red >= 0 && pointer_green >= 0 && pointer_blue >= 0) { float cx, cy; - if (scopeType == 2) { + if (scopeType == ScopeType::VECTORSCOPE_HS) { float H, S, L; Color::rgb2hslfloat(pointer_red * 257.f, pointer_green * 257.f, pointer_blue * 257.f, H, S, L); cx = (w + scope_size * S * std::cos(H * 2 * RT_PI_F)) / 2; @@ -1630,7 +1655,10 @@ bool HistogramArea::on_button_press_event (GdkEventButton* event) isPressed = true; movingPosition = event->x; - if (event->type == GDK_2BUTTON_PRESS && event->button == 1 && scopeType == 0) { + if ( + event->type == GDK_2BUTTON_PRESS && event->button == 1 + && (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW) + ) { drawMode = (drawMode + 1) % 3; options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; @@ -1654,7 +1682,10 @@ bool HistogramArea::on_button_release_event (GdkEventButton* event) bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) { - if (drawMode == 0 && scopeType == 0) { + if ( + drawMode == 0 + && (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW) + ) { return false; } @@ -1662,7 +1693,7 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) return true; } - if (scopeType == 0) { // Adjust log scale. + if (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW) { // Adjust log scale. double mod = 1 + (event->x - movingPosition) / get_width(); factor /= mod; @@ -1675,7 +1706,11 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) setDirty(true); queue_draw (); - } else if (scopeType >= 1 && scopeType <= 3) { // Adjust brightness. + } else if ( + scopeType == ScopeType::WAVEFORM + || scopeType == ScopeType::VECTORSCOPE_HC + || scopeType == ScopeType::VECTORSCOPE_HS + ) { // Adjust brightness. constexpr float MIN_BRIGHT = 0.1; constexpr float MAX_BRIGHT = 3; constexpr float RANGE = MAX_BRIGHT / MIN_BRIGHT; diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 975a6d8ab..7167168ff 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -28,6 +28,7 @@ #include "delayed.h" #include "guiutils.h" +#include "options.h" #include "pointermotionlistener.h" #include "../rtengine/array2D.h" @@ -36,10 +37,7 @@ class HistogramArea; -enum ScopeType -{ - HISTOGRAM, HISTOGRAM_RAW, VECTORSCOPE_HC, VECTORSCOPE_HS, WAVEFORM, NONE -}; +using ScopeType = Options::ScopeType; struct HistogramAreaIdleHelper { HistogramArea* harea; @@ -178,7 +176,7 @@ protected: bool valid; int drawMode; DrawModeListener *myDrawModeListener; - int scopeType; + ScopeType scopeType; int oldwidth, oldheight; /// Intensity of waveform and vectorscope trace. float trace_brightness; @@ -221,7 +219,7 @@ public: const array2D& waveformBlue, const array2D& waveformLuma ); - void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, int type, bool pointer); + void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, ScopeType type, bool pointer); bool updatePending(); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; diff --git a/rtgui/options.cc b/rtgui/options.cc index 5e1685b20..3e9c49e1e 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -450,7 +450,7 @@ void Options::setDefaults() histogramBar = true; histogramHeight = 200; histogramDrawMode = 0; - histogramScopeType = 0; + histogramScopeType = ScopeType::HISTOGRAM; curvebboxpos = 1; complexity = 2; prevdemo = PD_Sidecar; @@ -1434,7 +1434,7 @@ void Options::readFromFile(Glib::ustring fname) } if (keyFile.has_key("GUI", "HistogramScopeType")) { - histogramScopeType = keyFile.get_integer("GUI", "HistogramScopeType"); + histogramScopeType = static_cast(keyFile.get_integer("GUI", "HistogramScopeType")); } if (keyFile.has_key("GUI", "NavigatorRGBUnit")) { diff --git a/rtgui/options.h b/rtgui/options.h index 20678f2f9..19d394a05 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -306,13 +306,22 @@ public: double sndLngEditProcDoneSecs; // Minimum processing time seconds till the sound is played bool sndEnable; + enum ScopeType + { + HISTOGRAM = 0, + HISTOGRAM_RAW = 1, + VECTORSCOPE_HC = 2, + VECTORSCOPE_HS = 3, + WAVEFORM = 4, + NONE = -1 + }; int histogramPosition; // 0=disabled, 1=left pane, 2=right pane bool histogramRed, histogramGreen, histogramBlue; bool histogramLuma, histogramChroma, histogramRAW; bool histogramBar; int histogramHeight; int histogramDrawMode; - int histogramScopeType; + ScopeType histogramScopeType; bool FileBrowserToolbarSingleRow; bool hideTPVScrollbar; int whiteBalanceSpotSize; From c03efe4878e132a05b27abb3f92c0b79c9e06db0 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 12 Sep 2020 17:52:24 -0700 Subject: [PATCH 36/56] Add dedicated buttons for scope switching Previously, changing to a different scope was done by clicking the scope type button and cycling through all scopes. This commit decreases the number of clicks needed to switch between two scopes by adding a radio selector. The radio buttons can be shown or hidden by pressing the scope type button. This commit also makes the raw histogram one of the scope types. --- .../histogram-type-histogram-off-small.svg | 122 ++++++++ ...istogram-type-vectorscope-hc-off-small.svg | 131 ++++++++ ...istogram-type-vectorscope-hs-off-small.svg | 135 ++++++++ .../svg/histogram-type-waveform-off-small.svg | 122 ++++++++ rtdata/languages/default | 7 +- rtengine/improccoordinator.cc | 14 + rtengine/improccoordinator.h | 3 + rtengine/rtengine.h | 4 + rtgui/editorpanel.cc | 10 +- rtgui/editorpanel.h | 1 + rtgui/histogrampanel.cc | 293 +++++++++++++----- rtgui/histogrampanel.h | 33 +- rtgui/options.cc | 13 +- rtgui/options.h | 3 +- 14 files changed, 791 insertions(+), 100 deletions(-) create mode 100644 rtdata/images/svg/histogram-type-histogram-off-small.svg create mode 100644 rtdata/images/svg/histogram-type-vectorscope-hc-off-small.svg create mode 100644 rtdata/images/svg/histogram-type-vectorscope-hs-off-small.svg create mode 100644 rtdata/images/svg/histogram-type-waveform-off-small.svg diff --git a/rtdata/images/svg/histogram-type-histogram-off-small.svg b/rtdata/images/svg/histogram-type-histogram-off-small.svg new file mode 100644 index 000000000..456ead7e2 --- /dev/null +++ b/rtdata/images/svg/histogram-type-histogram-off-small.svg @@ -0,0 +1,122 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-vectorscope-hc-off-small.svg b/rtdata/images/svg/histogram-type-vectorscope-hc-off-small.svg new file mode 100644 index 000000000..3a105a671 --- /dev/null +++ b/rtdata/images/svg/histogram-type-vectorscope-hc-off-small.svg @@ -0,0 +1,131 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-vectorscope-hs-off-small.svg b/rtdata/images/svg/histogram-type-vectorscope-hs-off-small.svg new file mode 100644 index 000000000..253d2d9c3 --- /dev/null +++ b/rtdata/images/svg/histogram-type-vectorscope-hs-off-small.svg @@ -0,0 +1,135 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-waveform-off-small.svg b/rtdata/images/svg/histogram-type-waveform-off-small.svg new file mode 100644 index 000000000..787d6fe09 --- /dev/null +++ b/rtdata/images/svg/histogram-type-waveform-off-small.svg @@ -0,0 +1,122 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtdata/languages/default b/rtdata/languages/default index 1bcc1ab51..0ec86d367 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -249,7 +249,12 @@ 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, waveform, Hue-Saturation vectorscope, and Hue-Chroma vectorscope. +HISTOGRAM_TOOLTIP_TYPE;Toggle visibility of the scope selection buttons. +HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM;Histogram +HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW;Raw Histogram +HISTOGRAM_TOOLTIP_TYPE_WAVEFORM;Waveform +HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HC;Hue-Chroma Vectorscope +HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HS;Hue-Saturation Vectorscope HISTORY_CHANGED;Changed HISTORY_CUSTOMCURVE;Custom curve HISTORY_FROMCLIPBOARD;From clipboard diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index ea4c8a92b..f8d75b050 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -358,6 +358,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw); + hist_raw_dirty = !hListener->updateHistogramRaw(); highDetailPreprocessComputed = highDetailNeeded; @@ -2471,6 +2472,19 @@ void ImProcCoordinator::requestUpdateHistogram() } } +void ImProcCoordinator::requestUpdateHistogramRaw() +{ + if (!hListener) { + return; + } + // Don't need to actually update histogram because it is always + // up-to-date. + if (hist_raw_dirty) { + hist_raw_dirty = false; + notifyHistogramChanged(); + } +} + void ImProcCoordinator::requestUpdateVectorscopeHC() { if (!hListener) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 791679678..d39fa3f9e 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -127,6 +127,8 @@ protected: LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; bool hist_lrgb_dirty; + /// Used to simulate a lazy update of the raw histogram. + bool hist_raw_dirty; int vectorscopeScale; bool vectorscope_hc_dirty, vectorscope_hs_dirty; array2D vectorscope_hc, vectorscope_hs; @@ -569,6 +571,7 @@ public: } denoiseInfoStore; void requestUpdateHistogram() override; + void requestUpdateHistogramRaw() override; void requestUpdateVectorscopeHC() override; void requestUpdateVectorscopeHS() override; void requestUpdateWaveform() override; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 43848e70c..6f6baccd4 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -346,6 +346,8 @@ public: virtual void setObservable(HistogramObservable* observable) = 0; /** Returns if the listener wants the histogram to be updated. */ virtual bool updateHistogram(void) const = 0; + /** Returns if the listener wants the raw histogram to be updated. */ + virtual bool updateHistogramRaw(void) const = 0; /** Returns if the listener wants the H-C vectorscope to be updated. */ virtual bool updateVectorscopeHC(void) const = 0; /** Returns if the listener wants the H-S vectorscope to be updated. */ @@ -359,6 +361,8 @@ class HistogramObservable public: /** Tells the observable to update the histogram data. */ virtual void requestUpdateHistogram() = 0; + /** Tells the observable to update the raw histogram data. */ + virtual void requestUpdateHistogramRaw() = 0; /** Tells the observable to update the H-C vectorscope data. */ virtual void requestUpdateVectorscopeHC() = 0; /** Tells the observable to update the H-S vectorscope data. */ diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index c53877736..205cf2bf2 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2276,6 +2276,12 @@ bool EditorPanel::updateHistogram(void) const || histogram_scope_type == ScopeType::NONE; } +bool EditorPanel::updateHistogramRaw(void) const +{ + return histogram_scope_type == ScopeType::HISTOGRAM_RAW + || histogram_scope_type == ScopeType::NONE; +} + bool EditorPanel::updateVectorscopeHC(void) const { return @@ -2310,6 +2316,9 @@ void EditorPanel::scopeTypeChanged(ScopeType new_type) case ScopeType::HISTOGRAM: histogram_observable->requestUpdateHistogram(); break; + case ScopeType::HISTOGRAM_RAW: + histogram_observable->requestUpdateHistogramRaw(); + break; case ScopeType::VECTORSCOPE_HC: histogram_observable->requestUpdateVectorscopeHC(); break; @@ -2319,7 +2328,6 @@ void EditorPanel::scopeTypeChanged(ScopeType new_type) case ScopeType::WAVEFORM: histogram_observable->requestUpdateWaveform(); break; - case ScopeType::HISTOGRAM_RAW: case ScopeType::NONE: break; } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index f6bc0b606..abfcb0a8f 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -145,6 +145,7 @@ public: ) override; void setObservable(rtengine::HistogramObservable* observable) override; bool updateHistogram(void) const override; + bool updateHistogramRaw(void) const override; bool updateVectorscopeHC(void) const override; bool updateVectorscopeHS(void) const override; bool updateWaveform(void) const override; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index a9c8a95d6..449566007 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -80,6 +80,7 @@ HistogramPanel::HistogramPanel () : switch (options.histogramScopeType) { case ScopeType::NONE: + case ScopeType::HISTOGRAM_RAW: case ScopeType::VECTORSCOPE_HC: case ScopeType::VECTORSCOPE_HS: histogramRGBArea = nullptr; @@ -88,7 +89,6 @@ HistogramPanel::HistogramPanel () : histogramRGBArea = histogramRGBAreaVert.get(); break; case ScopeType::HISTOGRAM: - case ScopeType::HISTOGRAM_RAW: histogramRGBArea = histogramRGBAreaHori.get(); break; } @@ -113,7 +113,6 @@ HistogramPanel::HistogramPanel () : blueImage = new RTImage ("histogram-blue-on-small.png"); valueImage = new RTImage ("histogram-silver-on-small.png"); chroImage = new RTImage ("histogram-gold-on-small.png"); - rawImage = new RTImage ("histogram-bayer-on-small.png"); barImage = new RTImage ("histogram-bar-on-small.png"); redImage_g = new RTImage ("histogram-red-off-small.png"); @@ -121,7 +120,6 @@ HistogramPanel::HistogramPanel () : blueImage_g = new RTImage ("histogram-blue-off-small.png"); valueImage_g = new RTImage ("histogram-silver-off-small.png"); chroImage_g = new RTImage ("histogram-gold-off-small.png"); - rawImage_g = new RTImage ("histogram-bayer-off-small.png"); barImage_g = new RTImage ("histogram-bar-off-small.png"); mode0Image = new RTImage ("histogram-mode-linear-small.png"); @@ -129,20 +127,43 @@ HistogramPanel::HistogramPanel () : mode2Image = new RTImage ("histogram-mode-logxy-small.png"); histImage.reset(new RTImage("histogram-type-histogram-small.png")); + histRawImage.reset(new RTImage("histogram-bayer-on-small.png")); waveImage.reset(new RTImage("histogram-type-waveform-small.png")); vectHcImage.reset(new RTImage("histogram-type-vectorscope-hc-small.png")); vectHsImage.reset(new RTImage("histogram-type-vectorscope-hs-small.png")); + histImageOn.reset(new RTImage("histogram-type-histogram-small.png")); + histRawImageOn.reset(new RTImage("histogram-bayer-on-small.png")); + waveImageOn.reset(new RTImage("histogram-type-waveform-small.png")); + vectHcImageOn.reset(new RTImage("histogram-type-vectorscope-hc-small.png")); + vectHsImageOn.reset(new RTImage("histogram-type-vectorscope-hs-small.png")); + histImageOff.reset(new RTImage("histogram-type-histogram-off-small.png")); + histRawImageOff.reset(new RTImage("histogram-bayer-off-small.png")); + waveImageOff.reset(new RTImage("histogram-type-waveform-off-small.png")); + vectHcImageOff.reset(new RTImage("histogram-type-vectorscope-hc-off-small.png")); + vectHsImageOff.reset(new RTImage("histogram-type-vectorscope-hs-off-small.png")); + showRed = Gtk::manage (new Gtk::ToggleButton ()); showGreen = Gtk::manage (new Gtk::ToggleButton ()); showBlue = Gtk::manage (new Gtk::ToggleButton ()); showValue = Gtk::manage (new Gtk::ToggleButton ()); showChro = Gtk::manage (new Gtk::ToggleButton ()); - showRAW = Gtk::manage (new Gtk::ToggleButton ()); showMode = Gtk::manage (new Gtk::Button ()); - scopeType = Gtk::manage (new Gtk::Button ()); + scopeType = Gtk::manage (new Gtk::ToggleButton ()); showBAR = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::RadioButtonGroup scopeTypeGroup; + scopeHistBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeHistRawBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeWaveBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeVectHcBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeVectHsBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeHistBtn->set_mode(false); + scopeHistRawBtn->set_mode(false); + scopeWaveBtn->set_mode(false); + scopeVectHcBtn->set_mode(false); + scopeVectHsBtn->set_mode(false); + showRed->set_name("histButton"); showRed->set_can_focus(false); showGreen->set_name("histButton"); @@ -153,44 +174,65 @@ HistogramPanel::HistogramPanel () : showValue->set_can_focus(false); showChro->set_name("histButton"); showChro->set_can_focus(false); - showRAW->set_name("histButton"); - showRAW->set_can_focus(false); showMode->set_name("histButton"); showMode->set_can_focus(false); scopeType->set_name("histButton"); scopeType->set_can_focus(false); showBAR->set_name("histButton"); showBAR->set_can_focus(false); + scopeHistBtn->set_name("histButton"); + scopeHistBtn->set_can_focus(false); + scopeHistRawBtn->set_name("histButton"); + scopeHistRawBtn->set_can_focus(false); + scopeWaveBtn->set_name("histButton"); + scopeWaveBtn->set_can_focus(false); + scopeVectHcBtn->set_name("histButton"); + scopeVectHcBtn->set_can_focus(false); + scopeVectHsBtn->set_name("histButton"); + scopeVectHsBtn->set_can_focus(false); showRed->set_relief (Gtk::RELIEF_NONE); showGreen->set_relief (Gtk::RELIEF_NONE); showBlue->set_relief (Gtk::RELIEF_NONE); showValue->set_relief (Gtk::RELIEF_NONE); showChro->set_relief (Gtk::RELIEF_NONE); - showRAW->set_relief (Gtk::RELIEF_NONE); showMode->set_relief (Gtk::RELIEF_NONE); scopeType->set_relief (Gtk::RELIEF_NONE); showBAR->set_relief (Gtk::RELIEF_NONE); + scopeHistBtn->set_relief (Gtk::RELIEF_NONE); + scopeHistRawBtn->set_relief (Gtk::RELIEF_NONE); + scopeWaveBtn->set_relief (Gtk::RELIEF_NONE); + scopeVectHcBtn->set_relief (Gtk::RELIEF_NONE); + scopeVectHsBtn->set_relief (Gtk::RELIEF_NONE); showRed->set_tooltip_text (M("HISTOGRAM_TOOLTIP_R")); showGreen->set_tooltip_text (M("HISTOGRAM_TOOLTIP_G")); showBlue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_B")); showValue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_L")); showChro->set_tooltip_text (M("HISTOGRAM_TOOLTIP_CHRO")); - showRAW->set_tooltip_text (M("HISTOGRAM_TOOLTIP_RAW")); showMode->set_tooltip_text (M("HISTOGRAM_TOOLTIP_MODE")); scopeType->set_tooltip_text (M("HISTOGRAM_TOOLTIP_TYPE")); showBAR->set_tooltip_text (M("HISTOGRAM_TOOLTIP_BAR")); + scopeHistBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM")); + scopeHistRawBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW")); + scopeWaveBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_WAVEFORM")); + scopeVectHcBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HC")); + scopeVectHsBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HS")); buttonGrid = Gtk::manage (new Gtk::Grid ()); - buttonGrid->set_orientation(Gtk::ORIENTATION_VERTICAL); + buttonGrid->set_orientation(Gtk::ORIENTATION_HORIZONTAL); + persistentButtons = Gtk::manage(new Gtk::Box()); + persistentButtons->set_orientation(Gtk::ORIENTATION_VERTICAL); + scopeButtons = Gtk::manage(new Gtk::Box()); + scopeButtons->set_orientation(Gtk::ORIENTATION_VERTICAL); + showRed->set_active (options.histogramRed); showGreen->set_active (options.histogramGreen); showBlue->set_active (options.histogramBlue); showValue->set_active (options.histogramLuma); showChro->set_active (options.histogramChroma); - showRAW->set_active (options.histogramRAW); // no showMode->set_active(), as it's not a ToggleButton + scopeType->set_active(options.histogramShowScopeButtons); showBAR->set_active (options.histogramBar); showRed->set_image (showRed->get_active() ? *redImage : *redImage_g); @@ -198,33 +240,43 @@ HistogramPanel::HistogramPanel () : showBlue->set_image (showBlue->get_active() ? *blueImage : *blueImage_g); showValue->set_image (showValue->get_active() ? *valueImage : *valueImage_g); showChro->set_image (showChro->get_active() ? *chroImage : *chroImage_g); - showRAW->set_image (showRAW->get_active() ? *rawImage : *rawImage_g); if (options.histogramDrawMode == 0) showMode->set_image(*mode0Image); else if (options.histogramDrawMode == 1) showMode->set_image(*mode1Image); else showMode->set_image(*mode2Image); + scopeHistBtn->set_image(*histImageOff); + scopeHistRawBtn->set_image(*histRawImageOff); + scopeWaveBtn->set_image(*waveImageOff); + scopeVectHcBtn->set_image(*vectHcImageOff); + scopeVectHsBtn->set_image(*vectHsImageOff); switch(options.histogramScopeType) { case ScopeType::HISTOGRAM: - scopeType->set_image(*histImage); - break; - case ScopeType::WAVEFORM: - scopeType->set_image(*waveImage); - break; - case ScopeType::VECTORSCOPE_HS: - scopeType->set_image(*vectHsImage); - break; - case ScopeType::VECTORSCOPE_HC: - scopeType->set_image(*vectHcImage); + scopeHistBtn->set_active(); + scopeHistBtn->set_image(*histImageOn); break; case ScopeType::HISTOGRAM_RAW: + scopeHistRawBtn->set_active(); + scopeHistRawBtn->set_image(*histRawImageOn); + break; + case ScopeType::WAVEFORM: + scopeWaveBtn->set_active(); + scopeWaveBtn->set_image(*waveImageOn); + break; + case ScopeType::VECTORSCOPE_HS: + scopeVectHsBtn->set_active(); + scopeVectHsBtn->set_image(*vectHsImageOn); + break; + case ScopeType::VECTORSCOPE_HC: + scopeVectHcBtn->set_active(); + scopeVectHcBtn->set_image(*vectHcImageOn); + break; case ScopeType::NONE: break; } showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); - raw_toggled(); // Make sure the luma/chroma toggles are enabled or disabled type_changed(); setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); @@ -232,7 +284,6 @@ HistogramPanel::HistogramPanel () : setExpandAlignProperties(showBlue , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showValue, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showRAW , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(scopeType, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); @@ -242,31 +293,48 @@ HistogramPanel::HistogramPanel () : showBlue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::blue_toggled), showBlue ); showValue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::value_toggled), showValue ); showChro->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::chro_toggled), showChro ); - showRAW->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::raw_toggled), showRAW ); showMode->signal_released().connect( sigc::mem_fun(*this, &HistogramPanel::mode_released), showMode ); - scopeType->signal_pressed().connect( sigc::mem_fun(*this, &HistogramPanel::type_pressed), scopeType ); + scopeType->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::type_pressed) ); showBAR->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::bar_toggled), showBAR ); + scopeHistBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeHistBtn)); + scopeHistRawBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeHistRawBtn)); + scopeWaveBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeWaveBtn)); + scopeVectHcBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHcBtn)); + scopeVectHsBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHsBtn)); - buttonGrid->add (*showRed); - buttonGrid->add (*showGreen); - buttonGrid->add (*showBlue); - buttonGrid->add (*showValue); - buttonGrid->add (*showChro); - buttonGrid->add (*showRAW); - buttonGrid->add (*showMode); - buttonGrid->add (*scopeType); - buttonGrid->add (*showBAR); + persistentButtons->add(*showRed); + persistentButtons->add(*showGreen); + persistentButtons->add(*showBlue); + persistentButtons->add(*showValue); + persistentButtons->add(*showChro); + persistentButtons->add(*showMode); + persistentButtons->add(*scopeType); + persistentButtons->add(*showBAR); + + scopeButtons->add(*scopeHistBtn); + scopeButtons->add(*scopeHistRawBtn); + scopeButtons->add(*scopeWaveBtn); + scopeButtons->add(*scopeVectHsBtn); + scopeButtons->add(*scopeVectHcBtn); // Put the button vbox next to the window's border to be less disturbing if (options.histogramPosition == 1) { + buttonGrid->add(*persistentButtons); + buttonGrid->add(*scopeButtons); + add (*buttonGrid); add (*gfxGrid); } else { + buttonGrid->add(*scopeButtons); + buttonGrid->add(*persistentButtons); + add (*gfxGrid); add (*buttonGrid); } show_all (); + scopeButtons->set_no_show_all(); + scopeButtons->set_visible(options.histogramShowScopeButtons); rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); } @@ -280,7 +348,6 @@ HistogramPanel::~HistogramPanel () delete blueImage; delete valueImage; delete chroImage; - delete rawImage; delete mode0Image; delete mode1Image; delete mode2Image; @@ -291,7 +358,6 @@ HistogramPanel::~HistogramPanel () delete blueImage_g; delete valueImage_g; delete chroImage_g; - delete rawImage_g; delete barImage_g; } @@ -369,24 +435,6 @@ void HistogramPanel::chro_toggled () rgbv_toggled(); } -void HistogramPanel::raw_toggled () -{ - if (showRAW->get_active()) { - showRAW->set_image(*rawImage); - showValue->set_sensitive(false); - showChro->set_sensitive(false); - } else { - showRAW->set_image(*rawImage_g); - showValue->set_sensitive( - options.histogramScopeType == ScopeType::HISTOGRAM - || options.histogramScopeType == ScopeType::WAVEFORM - ); - showChro->set_sensitive(options.histogramScopeType == ScopeType::HISTOGRAM); - } - - rgbv_toggled(); -} - void HistogramPanel::mode_released () { options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; @@ -401,28 +449,72 @@ void HistogramPanel::mode_released () void HistogramPanel::type_pressed() { - // Switch to next type. + options.histogramShowScopeButtons = scopeType->get_active(); + scopeButtons->set_visible(scopeType->get_active()); +} + +void HistogramPanel::type_selected(Gtk::RadioButton* button) +{ + ScopeType new_type = ScopeType::NONE; + + if (button == scopeHistBtn) { + new_type = ScopeType::HISTOGRAM; + } else if (button == scopeHistRawBtn) { + new_type = ScopeType::HISTOGRAM_RAW; + } else if (button == scopeWaveBtn) { + new_type = ScopeType::WAVEFORM; + } else if (button == scopeVectHcBtn) { + new_type = ScopeType::VECTORSCOPE_HC; + } else if (button == scopeVectHsBtn) { + new_type = ScopeType::VECTORSCOPE_HS; + } + + if (new_type == options.histogramScopeType) { + return; + } + switch (options.histogramScopeType) { - case ScopeType::NONE: // Default to histogram. - case ScopeType::HISTOGRAM_RAW: // Not supported as a true scope type. - case ScopeType::VECTORSCOPE_HC: - options.histogramScopeType = ScopeType::HISTOGRAM; - scopeType->set_image(*histImage); - break; case ScopeType::HISTOGRAM: - options.histogramScopeType = ScopeType::WAVEFORM; - scopeType->set_image(*waveImage); + scopeHistBtn->set_image(*histImageOff); + break; + case ScopeType::HISTOGRAM_RAW: + scopeHistRawBtn->set_image(*histRawImageOff); break; case ScopeType::WAVEFORM: - options.histogramScopeType = ScopeType::VECTORSCOPE_HS; - scopeType->set_image(*vectHsImage); + scopeWaveBtn->set_image(*waveImageOff); + break; + case ScopeType::VECTORSCOPE_HC: + scopeVectHcBtn->set_image(*vectHcImageOff); break; case ScopeType::VECTORSCOPE_HS: - options.histogramScopeType = ScopeType::VECTORSCOPE_HC; - scopeType->set_image(*vectHcImage); + scopeVectHsBtn->set_image(*vectHsImageOff); + break; + case ScopeType::NONE: break; } + switch (new_type) { + case ScopeType::HISTOGRAM: + scopeHistBtn->set_image(*histImageOn); + break; + case ScopeType::HISTOGRAM_RAW: + scopeHistRawBtn->set_image(*histRawImageOn); + break; + case ScopeType::WAVEFORM: + scopeWaveBtn->set_image(*waveImageOn); + break; + case ScopeType::VECTORSCOPE_HC: + scopeVectHcBtn->set_image(*vectHcImageOn); + break; + case ScopeType::VECTORSCOPE_HS: + scopeVectHsBtn->set_image(*vectHsImageOn); + break; + case ScopeType::NONE: + break; + } + + options.histogramScopeType = new_type; + type_changed(); updateHistAreaOptions(); if (histogramRGBArea) { @@ -439,15 +531,24 @@ void HistogramPanel::type_changed() switch (options.histogramScopeType) { case ScopeType::HISTOGRAM: + showRed->set_sensitive(); + showGreen->set_sensitive(); + showBlue->set_sensitive(); + showValue->set_sensitive(); + showChro->set_sensitive(); + showMode->set_sensitive(); + scopeType->set_image(*histImage); + histogramRGBArea = histogramRGBAreaHori.get(); + break; case ScopeType::HISTOGRAM_RAW: showRed->set_sensitive(); showGreen->set_sensitive(); showBlue->set_sensitive(); - showValue->set_sensitive(!showRAW->get_active()); - showChro->set_sensitive(!showRAW->get_active()); - showRAW->set_sensitive(); + showValue->set_sensitive(false); + showChro->set_sensitive(false); showMode->set_sensitive(); - histogramRGBArea = histogramRGBAreaHori.get(); + scopeType->set_image(*histRawImage); + histogramRGBArea = nullptr; break; case ScopeType::WAVEFORM: showRed->set_sensitive(); @@ -455,8 +556,8 @@ void HistogramPanel::type_changed() showBlue->set_sensitive(); showValue->set_sensitive(); showChro->set_sensitive(false); - showRAW->set_sensitive(false); showMode->set_sensitive(false); + scopeType->set_image(*waveImage); histogramRGBArea = histogramRGBAreaVert.get(); break; case ScopeType::VECTORSCOPE_HC: @@ -466,8 +567,12 @@ void HistogramPanel::type_changed() showBlue->set_sensitive(false); showValue->set_sensitive(false); showChro->set_sensitive(false); - showRAW->set_sensitive(false); showMode->set_sensitive(false); + if (options.histogramScopeType == ScopeType::VECTORSCOPE_HC) { + scopeType->set_image(*vectHcImage); + } else { + scopeType->set_image(*vectHsImage); + } histogramRGBArea = nullptr; break; case ScopeType::NONE: @@ -533,11 +638,31 @@ void HistogramPanel::reorder (Gtk::PositionType align) removeIfThere(this, gfxGrid, false); add (*gfxGrid); gfxGrid->unreference(); + + if (histogramRGBArea == histogramRGBAreaVert.get()) { + gfxGrid->remove(*histogramRGBArea); + gfxGrid->add(*histogramRGBArea); + } + + scopeButtons->reference(); + removeIfThere(buttonGrid, scopeButtons, false); + buttonGrid->add(*scopeButtons); + scopeButtons->unreference(); } else { buttonGrid->reference(); removeIfThere(this, buttonGrid, false); add (*buttonGrid); buttonGrid->unreference(); + + if (histogramRGBArea == histogramRGBAreaVert.get()) { + gfxGrid->remove(*histogramArea); + gfxGrid->add(*histogramArea); + } + + persistentButtons->reference(); + removeIfThere(buttonGrid, persistentButtons, false); + buttonGrid->add(*persistentButtons); + persistentButtons->unreference(); } } @@ -569,7 +694,6 @@ void HistogramPanel::updateHistAreaOptions() showBlue->get_active(), showValue->get_active(), showChro->get_active(), - showRAW->get_active(), options.histogramDrawMode, options.histogramScopeType, showBAR->get_active() @@ -584,7 +708,6 @@ void HistogramPanel::updateHistRGBAreaOptions() showBlue->get_active(), showValue->get_active(), showChro->get_active(), - showRAW->get_active(), showBAR->get_active() ); } @@ -606,7 +729,7 @@ double HistogramScaling::log(double vsize, double val) HistogramRGBArea::HistogramRGBArea () : val(0), r(0), g(0), b(0), valid(false), needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), - needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), + needLuma(options.histogramLuma), needChroma(options.histogramChroma), showMode(options.histogramBar), barDisplayed(options.histogramBar), parent(nullptr) { get_style_context()->add_class("drawingarea"); @@ -679,8 +802,7 @@ void HistogramRGBArea::setShow(bool show) void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { - //if (!get_realized () || !showMode || (rawMode && options.histogramScopeType == ScopeType::HISTOGRAM) || options.histogramScopeType == ScopeType::HISTOGRAM_RAW) { - if (!get_realized () || !showMode || !((!rawMode && options.histogramScopeType == ScopeType::HISTOGRAM) || options.histogramScopeType == ScopeType::WAVEFORM)) { + if (!get_realized () || !showMode || !(options.histogramScopeType == ScopeType::HISTOGRAM || options.histogramScopeType == ScopeType::WAVEFORM)) { return; } @@ -791,7 +913,7 @@ void HistogramRGBArea::update (int valh, int rh, int gh, int bh) ); } -void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, bool bar) +void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool bar) { options.histogramRed = needRed = r; @@ -799,7 +921,6 @@ void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bo options.histogramBlue = needBlue = b; options.histogramLuma = needLuma = l; options.histogramChroma = needChroma = c; - options.histogramRAW = rawMode = raw; options.histogramBar = showMode = bar; } @@ -938,7 +1059,7 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : oldwidth(-1), oldheight(-1), trace_brightness(1.0), needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), - needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), + needLuma(options.histogramLuma), needChroma(options.histogramChroma), isPressed(false), movingPosition(0.0), pointer_red(-1), pointer_green(-1), pointer_blue(-1) { @@ -1001,7 +1122,7 @@ void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minim get_preferred_width_vfunc (minimum_width, natural_width); } -void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, ScopeType type, bool pointer) +void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, ScopeType type, bool pointer) { options.histogramRed = needRed = r; @@ -1009,7 +1130,6 @@ void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool options.histogramBlue = needBlue = b; options.histogramLuma = needLuma = l; options.histogramChroma = needChroma = c; - options.histogramRAW = rawMode = raw; options.histogramDrawMode = drawMode = mode; options.histogramScopeType = scopeType = type; options.histogramBar = needPointer = pointer; @@ -1049,6 +1169,8 @@ void HistogramArea::update( bhist = histBlue; lhist = histLuma; chist = histChroma; + break; + case ScopeType::HISTOGRAM_RAW: rhistRaw = histRedRaw; ghistRaw = histGreenRaw; bhistRaw = histBlueRaw; @@ -1071,7 +1193,6 @@ void HistogramArea::update( vect_hc = vectorscopeHC; vect_hc_buffer_dirty = true; break; - case ScopeType::HISTOGRAM_RAW: case ScopeType::NONE: break; } @@ -1187,6 +1308,8 @@ void HistogramArea::updateBackBuffer () cr->unset_dash(); if (valid && (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW)) { + bool rawMode = scopeType == ScopeType::HISTOGRAM_RAW; + // For RAW mode use the other hists LUTu& rh = rawMode ? rhistRaw : rhist; LUTu& gh = rawMode ? ghistRaw : ghist; diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 7167168ff..980a56f4f 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -80,7 +80,6 @@ protected: bool needBlue; bool needLuma; bool needChroma; - bool rawMode; bool showMode; bool barDisplayed; @@ -111,7 +110,7 @@ public: }; void update (int val, int rh, int gh, int bh); - void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, bool show); + void updateOptions (bool r, bool g, bool b, bool l, bool c, bool show); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; @@ -182,7 +181,6 @@ protected: float trace_brightness; bool needRed, needGreen, needBlue, needLuma, needChroma; - bool rawMode; bool isPressed; double movingPosition; bool needPointer; @@ -219,7 +217,7 @@ public: const array2D& waveformBlue, const array2D& waveformLuma ); - void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode, ScopeType type, bool pointer); + void updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, ScopeType type, bool pointer); bool updatePending(); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; @@ -255,6 +253,8 @@ protected: Gtk::Grid* gfxGrid; Gtk::Grid* buttonGrid; + Gtk::Box* persistentButtons; + Gtk::Box* scopeButtons; HistogramArea* histogramArea; HistogramRGBArea* histogramRGBArea; std::unique_ptr histogramRGBAreaHori; @@ -263,17 +263,21 @@ protected: Gtk::ToggleButton* showGreen; Gtk::ToggleButton* showBlue; Gtk::ToggleButton* showValue; - Gtk::ToggleButton* showRAW; Gtk::ToggleButton* showBAR; Gtk::ToggleButton* showChro; Gtk::Button* showMode; - Gtk::Button* scopeType; + Gtk::ToggleButton* scopeType; + + Gtk::RadioButton* scopeHistBtn; + Gtk::RadioButton* scopeHistRawBtn; + Gtk::RadioButton* scopeWaveBtn; + Gtk::RadioButton* scopeVectHcBtn; + Gtk::RadioButton* scopeVectHsBtn; Gtk::Image *redImage; Gtk::Image *greenImage; Gtk::Image *blueImage; Gtk::Image *valueImage; - Gtk::Image *rawImage; Gtk::Image *barImage; Gtk::Image *chroImage; @@ -281,15 +285,26 @@ protected: Gtk::Image *greenImage_g; Gtk::Image *blueImage_g; Gtk::Image *valueImage_g; - Gtk::Image *rawImage_g; Gtk::Image *barImage_g; Gtk::Image *chroImage_g; std::unique_ptr histImage; + std::unique_ptr histRawImage; std::unique_ptr waveImage; std::unique_ptr vectHcImage; std::unique_ptr vectHsImage; + std::unique_ptr histImageOn; + std::unique_ptr histRawImageOn; + std::unique_ptr waveImageOn; + std::unique_ptr vectHcImageOn; + std::unique_ptr vectHsImageOn; + std::unique_ptr histImageOff; + std::unique_ptr histRawImageOff; + std::unique_ptr waveImageOff; + std::unique_ptr vectHcImageOff; + std::unique_ptr vectHsImageOff; + Gtk::Image *mode0Image; Gtk::Image *mode1Image; Gtk::Image *mode2Image; @@ -339,11 +354,11 @@ public: void green_toggled (); void blue_toggled (); void value_toggled (); - void raw_toggled (); void chro_toggled (); void bar_toggled (); void mode_released (); void type_pressed (); + void type_selected(Gtk::RadioButton* button); void type_changed (); void rgbv_toggled (); void resized (Gtk::Allocation& req); diff --git a/rtgui/options.cc b/rtgui/options.cc index 3e9c49e1e..06726452e 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -446,11 +446,11 @@ void Options::setDefaults() histogramBlue = true; histogramLuma = false; histogramChroma = false; - histogramRAW = false; histogramBar = true; histogramHeight = 200; histogramDrawMode = 0; histogramScopeType = ScopeType::HISTOGRAM; + histogramShowScopeButtons = false; curvebboxpos = 1; complexity = 2; prevdemo = PD_Sidecar; @@ -1418,7 +1418,10 @@ void Options::readFromFile(Glib::ustring fname) } if (keyFile.has_key("GUI", "HistogramRAW")) { - histogramRAW = keyFile.get_boolean("GUI", "HistogramRAW"); + // Legacy option, replaced by HistogramScopeType. + if (keyFile.get_boolean("GUI", "HistogramRAW")) { + histogramScopeType = ScopeType::HISTOGRAM_RAW; + } } if (keyFile.has_key("GUI", "HistogramBar")) { @@ -1437,6 +1440,10 @@ void Options::readFromFile(Glib::ustring fname) histogramScopeType = static_cast(keyFile.get_integer("GUI", "HistogramScopeType")); } + if (keyFile.has_key("GUI", "HistogramShowScopeButtons")) { + histogramShowScopeButtons = keyFile.get_boolean("GUI", "HistogramShowScopeButtons"); + } + if (keyFile.has_key("GUI", "NavigatorRGBUnit")) { navRGBUnit = (NavigatorUnit)keyFile.get_integer("GUI", "NavigatorRGBUnit"); } @@ -2256,11 +2263,11 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_boolean("GUI", "HistogramBlue", histogramBlue); keyFile.set_boolean("GUI", "HistogramLuma", histogramLuma); keyFile.set_boolean("GUI", "HistogramChroma", histogramChroma); - keyFile.set_boolean("GUI", "HistogramRAW", histogramRAW); keyFile.set_boolean("GUI", "HistogramBar", histogramBar); keyFile.set_integer("GUI", "HistogramHeight", histogramHeight); keyFile.set_integer("GUI", "HistogramDrawMode", histogramDrawMode); keyFile.set_integer("GUI", "HistogramScopeType", histogramScopeType); + keyFile.set_boolean("GUI", "HistogramShowScopeButtons", histogramShowScopeButtons); keyFile.set_integer("GUI", "NavigatorRGBUnit", (int)navRGBUnit); keyFile.set_integer("GUI", "NavigatorHSVUnit", (int)navHSVUnit); keyFile.set_boolean("GUI", "ShowFilmStripToolBar", showFilmStripToolBar); diff --git a/rtgui/options.h b/rtgui/options.h index 19d394a05..4bc4ccc42 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -317,11 +317,12 @@ public: }; int histogramPosition; // 0=disabled, 1=left pane, 2=right pane bool histogramRed, histogramGreen, histogramBlue; - bool histogramLuma, histogramChroma, histogramRAW; + bool histogramLuma, histogramChroma; bool histogramBar; int histogramHeight; int histogramDrawMode; ScopeType histogramScopeType; + bool histogramShowScopeButtons; bool FileBrowserToolbarSingleRow; bool hideTPVScrollbar; int whiteBalanceSpotSize; From af29bf84e6809640e1fa3740c5004ea0f244e05f Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 13 Sep 2020 12:33:25 -0700 Subject: [PATCH 37/56] Fix cppcheck warnings for uninitialized variables --- rtengine/improccoordinator.cc | 6 ++++++ rtgui/histogrampanel.cc | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f8d75b050..339cdfa07 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -130,10 +130,16 @@ ImProcCoordinator::ImProcCoordinator() : histLRETI(256), + hist_lrgb_dirty(false), + hist_raw_dirty(false), + vectorscopeScale(0), + vectorscope_hc_dirty(false), + vectorscope_hs_dirty(false), vectorscope_hc(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), vectorscope_hs(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), waveformScale(0), + waveform_dirty(false), waveformRed(0, 0), waveformGreen(0, 0), waveformBlue(0, 0), diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 449566007..23d443aea 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1061,7 +1061,9 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), needLuma(options.histogramLuma), needChroma(options.histogramChroma), isPressed(false), movingPosition(0.0), - pointer_red(-1), pointer_green(-1), pointer_blue(-1) + needPointer(false), + pointer_red(-1), pointer_green(-1), pointer_blue(-1), + pointer_a(0), pointer_b(0) { rhist(256); From 97c7794a5a3d4c6f862ebf78bcd2c719b4f2de38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Mon, 14 Sep 2020 09:44:29 +0200 Subject: [PATCH 38/56] Turn `Options::ScopeType` into a scoped enum :) Also remove global `using ...` from header file. --- rtgui/editorpanel.cc | 2 ++ rtgui/editorpanel.h | 4 ++-- rtgui/histogrampanel.cc | 1 + rtgui/histogrampanel.h | 8 +++----- rtgui/options.cc | 2 +- rtgui/options.h | 20 ++++++++++---------- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 205cf2bf2..ab7aa873d 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -48,6 +48,8 @@ using namespace rtengine::procparams; +using ScopeType = Options::ScopeType; + namespace { diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index abfcb0a8f..a277ffd3a 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -151,7 +151,7 @@ public: bool updateWaveform(void) const override; // HistogramPanelListener - void scopeTypeChanged(ScopeType new_type) override; + void scopeTypeChanged(Options::ScopeType new_type) override; // event handlers void info_toggled (); @@ -286,5 +286,5 @@ private: IdleRegister idle_register; rtengine::HistogramObservable* histogram_observable; - ScopeType histogram_scope_type; + Options::ScopeType histogram_scope_type; }; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 23d443aea..41605d638 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -29,6 +29,7 @@ using namespace rtengine; +using ScopeType = Options::ScopeType; // // diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 980a56f4f..4417e2373 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -37,8 +37,6 @@ class HistogramArea; -using ScopeType = Options::ScopeType; - struct HistogramAreaIdleHelper { HistogramArea* harea; bool destroyed; @@ -175,7 +173,7 @@ protected: bool valid; int drawMode; DrawModeListener *myDrawModeListener; - ScopeType scopeType; + Options::ScopeType scopeType; int oldwidth, oldheight; /// Intensity of waveform and vectorscope trace. float trace_brightness; @@ -217,7 +215,7 @@ public: const array2D& waveformBlue, const array2D& waveformLuma ); - void updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, ScopeType type, bool pointer); + void updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, Options::ScopeType type, bool pointer); bool updatePending(); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; @@ -241,7 +239,7 @@ private: class HistogramPanelListener { public: - virtual void scopeTypeChanged(ScopeType new_type) = 0; + virtual void scopeTypeChanged(Options::ScopeType new_type) = 0; }; class HistogramPanel final : public Gtk::Grid, public PointerMotionListener, public DrawModeListener, public rtengine::NonCopyable diff --git a/rtgui/options.cc b/rtgui/options.cc index 06726452e..d71fcc57d 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -2266,7 +2266,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_boolean("GUI", "HistogramBar", histogramBar); keyFile.set_integer("GUI", "HistogramHeight", histogramHeight); keyFile.set_integer("GUI", "HistogramDrawMode", histogramDrawMode); - keyFile.set_integer("GUI", "HistogramScopeType", histogramScopeType); + keyFile.set_integer("GUI", "HistogramScopeType", rtengine::toUnderlying(histogramScopeType)); keyFile.set_boolean("GUI", "HistogramShowScopeButtons", histogramShowScopeButtons); keyFile.set_integer("GUI", "NavigatorRGBUnit", (int)navRGBUnit); keyFile.set_integer("GUI", "NavigatorHSVUnit", (int)navHSVUnit); diff --git a/rtgui/options.h b/rtgui/options.h index 4bc4ccc42..e64c31ad1 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -168,13 +168,22 @@ private: const Glib::ustring& entryName, Glib::ustring& destination); public: - enum class NavigatorUnit { PERCENT, R0_255, R0_1, _COUNT }; + + enum class ScopeType { + NONE = -1, + HISTOGRAM, + HISTOGRAM_RAW, + VECTORSCOPE_HC, + VECTORSCOPE_HS, + WAVEFORM + }; + bool savesParamsAtExit; SaveFormat saveFormat, saveFormatBatch; Glib::ustring savePathTemplate; @@ -306,15 +315,6 @@ public: double sndLngEditProcDoneSecs; // Minimum processing time seconds till the sound is played bool sndEnable; - enum ScopeType - { - HISTOGRAM = 0, - HISTOGRAM_RAW = 1, - VECTORSCOPE_HC = 2, - VECTORSCOPE_HS = 3, - WAVEFORM = 4, - NONE = -1 - }; int histogramPosition; // 0=disabled, 1=left pane, 2=right pane bool histogramRed, histogramGreen, histogramBlue; bool histogramLuma, histogramChroma; From 98ae27f60ed9766d68e78ac1493661ec42e397c0 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 22 Sep 2020 21:32:49 -0700 Subject: [PATCH 39/56] Fix initialization of vectorscope pointer --- rtgui/histogrampanel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 41605d638..070d6bf41 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1062,7 +1062,7 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), needLuma(options.histogramLuma), needChroma(options.histogramChroma), isPressed(false), movingPosition(0.0), - needPointer(false), + needPointer(options.histogramBar), pointer_red(-1), pointer_green(-1), pointer_blue(-1), pointer_a(0), pointer_b(0) { From 79e79321ecf6c4d8d96979de82f59df9f44bf4df Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 22 Sep 2020 21:35:08 -0700 Subject: [PATCH 40/56] Remove spacing around vectorscope lines --- rtgui/histogrampanel.cc | 53 +++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 070d6bf41..a0acaebc9 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1555,8 +1555,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in const float o_y = (h - scope_scale * vect_height) / 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; + const double line_length = scope_size / 2.0; std::valarray ch_ds(1); cr->translate(w / 2.0, h / 2.0); @@ -1569,21 +1568,23 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in cr->set_line_width (2.0 * s); constexpr double color_labels[6][3] = { {1, 0, 0}, // R - {1, 1, 0}, // Y {0, 1, 0}, // G - {0, 1, 1}, // C {0, 0, 1}, // B + {0, 1, 1}, // C {1, 0, 1}, // M + {1, 1, 0}, // Y }; - for (int i = 0; i < 6; i++) { - auto gradient = Cairo::LinearGradient::create(0, 0, scope_size / 2.0, 0); - const double (&color)[3] = color_labels[i]; + for (int i = 0; i < 3; i++) { + auto gradient = Cairo::LinearGradient::create(-line_length, 0, line_length, 0); + const double (&color_1)[3] = color_labels[i]; + const double (&color_2)[3] = color_labels[i + 3]; cr->set_source(gradient); - gradient->add_color_stop_rgba(0, 1, 1, 1, 0.25); - gradient->add_color_stop_rgba(1, color[0], color[1], color[2], 0.5); - cr->move_to(line_spacing, 0); - cr->line_to(line_spacing + line_length, 0); - cr->rotate_degrees(-60); + gradient->add_color_stop_rgba(0, color_2[0], color_2[1], color_2[2], 0.5); + gradient->add_color_stop_rgba(0.5, 1, 1, 1, 0.25); + gradient->add_color_stop_rgba(1, color_1[0], color_1[1], color_1[2], 0.5); + cr->move_to(-line_length, 0); + cr->line_to(line_length, 0); + cr->rotate_degrees(-120); cr->stroke(); } cr->set_line_width (1.0 * s); @@ -1599,33 +1600,33 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in } // 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->move_to(0, 0); + cr->line_to(line_length, 0); cr->stroke(); cr->unset_dash(); } else if (scopeType == ScopeType::VECTORSCOPE_HC) { // Hue-Chroma. // a and b axes. Cairo::RefPtr gradient; cr->set_line_width (2.0 * s); - gradient = Cairo::LinearGradient::create(0, -scope_size / 2.0, 0, scope_size / 2.0); + gradient = Cairo::LinearGradient::create(0, -line_length, 0, line_length); cr->set_source(gradient); gradient->add_color_stop_rgba(0, 1, 1, 0, 0.5); // "yellow" gradient->add_color_stop_rgba(0.5, 1, 1, 1, 0.25); // neutral gradient->add_color_stop_rgba(1, 0, 0, 1, 0.5); // "blue" - 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(0, 0); + cr->line_to(0, line_length); + cr->move_to(0, 0); + cr->line_to(0, -line_length); cr->stroke(); - gradient = Cairo::LinearGradient::create(-scope_size / 2.0, 0, scope_size / 2.0, 0); + gradient = Cairo::LinearGradient::create(-line_length, 0, line_length, 0); cr->set_source(gradient); gradient->add_color_stop_rgba(0, 0, 1, 0, 0.5); // "green" gradient->add_color_stop_rgba(0.5, 1, 1, 1, 0.25); // neutral gradient->add_color_stop_rgba(1, 1, 0, 1, 0.5); // "magenta" - 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->move_to(0, 0); + cr->line_to(line_length, 0); + cr->move_to(0, 0); + cr->line_to(-line_length, 0); cr->stroke(); cr->set_source_rgba (1, 1, 1, 0.25); cr->set_line_width (1.0 * s); @@ -1638,8 +1639,8 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in // 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->move_to(0, 0); + cr->line_to(line_length, 0); cr->stroke(); cr->unset_dash(); } From 6e7185081a16a29437b816776ca84e9a61be7180 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 22 Sep 2020 22:10:57 -0700 Subject: [PATCH 41/56] Fix scaling of H-C vectorscope --- rtengine/improccoordinator.cc | 5 +++-- rtgui/histogrampanel.cc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 339cdfa07..72dfb0cd3 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1875,6 +1875,7 @@ bool ImProcCoordinator::updateVectorscopeHC() params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); constexpr int size = VECTORSCOPE_SIZE; + constexpr float norm_factor = size / (128.f * 655.36f); vectorscope_hc.fill(0); vectorscopeScale = (x2 - x1) * (y2 - y1); @@ -1893,8 +1894,8 @@ bool ImProcCoordinator::updateVectorscopeHC() #endif for (int i = y1; i < y2; ++i) { for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { - const int col = (size / 96000.f) * a[ofs_lab] + size / 2; - const int row = (size / 96000.f) * b[ofs_lab] + size / 2; + const int col = norm_factor * a[ofs_lab] + size / 2 + 0.5f; + const int row = norm_factor * b[ofs_lab] + size / 2 + 0.5f; if (col >= 0 && col < size && row >= 0 && row < size) { vectorscopeThr[row][col]++; } diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index a0acaebc9..b79262426 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1666,7 +1666,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in cx = (w + scope_size * S * std::cos(H * 2 * RT_PI_F)) / 2; cy = (h - scope_size * S * std::sin(H * 2 * RT_PI_F)) / 2; } else { - constexpr float ab_factor = 327.68f / 96000.f; + constexpr float ab_factor = 1.f / 256.f; cx = w / 2.f + scope_size * pointer_a * ab_factor; cy = h / 2.f - scope_size * pointer_b * ab_factor; } From 8d2754575a35e8ad84377440e160a79de9930c3d Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Wed, 23 Sep 2020 18:17:15 +0200 Subject: [PATCH 42/56] remove call to fomerly removed function --- rtengine/improcfun.cc | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 7e13fd214..47f95a852 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -5739,31 +5739,21 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo Glib::ustring profile; - bool standard_gamma; + cmsHPROFILE oprof = nullptr; if (settings->HistogramWorking && consider_histogram_settings) { profile = icm.workingProfile; - standard_gamma = true; } else { profile = icm.outputProfile; if (icm.outputProfile.empty() || icm.outputProfile == ColorManagementParams::NoICMString) { profile = "sRGB"; } - - standard_gamma = false; + oprof = ICCStore::getInstance()->getProfile(profile); } - cmsHPROFILE oprof = ICCStore::getInstance()->getProfile(profile); - if (oprof) { - cmsHPROFILE oprofG = oprof; - - if (standard_gamma) { - oprofG = ICCStore::makeStdGammaProfile(oprof); - } - - cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; // NOCACHE is important for thread safety if (icm.outputBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; @@ -5771,7 +5761,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo lcmsMutex->lock(); cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr); - cmsHTRANSFORM hTransform = cmsCreateTransform (oprofG, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); // NOCACHE is important for thread safety + cmsHTRANSFORM hTransform = cmsCreateTransform (oprof, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); cmsCloseProfile(LabIProf); lcmsMutex->unlock(); @@ -5806,10 +5796,6 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo } // End of parallelization cmsDeleteTransform(hTransform); - - if (oprofG != oprof) { - cmsCloseProfile(oprofG); - } } else { TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(profile); const float wp[3][3] = { From 1a5456dbd10c44a684d938a3579d57979eadef4c Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 26 Sep 2020 11:54:05 -0700 Subject: [PATCH 43/56] Implement RGB parade --- .../svg/histogram-type-parade-off-small.svg | 132 ++++++++++++++ .../svg/histogram-type-parade-small.svg | 132 ++++++++++++++ rtdata/languages/default | 1 + rtgui/editorpanel.cc | 2 + rtgui/histogrampanel.cc | 168 ++++++++++++++++-- rtgui/histogrampanel.h | 9 + rtgui/options.h | 1 + 7 files changed, 428 insertions(+), 17 deletions(-) create mode 100644 rtdata/images/svg/histogram-type-parade-off-small.svg create mode 100644 rtdata/images/svg/histogram-type-parade-small.svg diff --git a/rtdata/images/svg/histogram-type-parade-off-small.svg b/rtdata/images/svg/histogram-type-parade-off-small.svg new file mode 100644 index 000000000..015960fcc --- /dev/null +++ b/rtdata/images/svg/histogram-type-parade-off-small.svg @@ -0,0 +1,132 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-parade-small.svg b/rtdata/images/svg/histogram-type-parade-small.svg new file mode 100644 index 000000000..f299f8ab2 --- /dev/null +++ b/rtdata/images/svg/histogram-type-parade-small.svg @@ -0,0 +1,132 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/languages/default b/rtdata/languages/default index 0ec86d367..fbfab9b86 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -252,6 +252,7 @@ HISTOGRAM_TOOLTIP_RAW;Show/Hide raw histogram. HISTOGRAM_TOOLTIP_TYPE;Toggle visibility of the scope selection buttons. HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM;Histogram HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW;Raw Histogram +HISTOGRAM_TOOLTIP_TYPE_PARADE;RGB Parade HISTOGRAM_TOOLTIP_TYPE_WAVEFORM;Waveform HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HC;Hue-Chroma Vectorscope HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HS;Hue-Saturation Vectorscope diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index ab7aa873d..34d677206 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2301,6 +2301,7 @@ bool EditorPanel::updateVectorscopeHS(void) const bool EditorPanel::updateWaveform(void) const { return histogram_scope_type == ScopeType::WAVEFORM + || histogram_scope_type == ScopeType::PARADE || histogram_scope_type == ScopeType::NONE; } @@ -2327,6 +2328,7 @@ void EditorPanel::scopeTypeChanged(ScopeType new_type) case ScopeType::VECTORSCOPE_HS: histogram_observable->requestUpdateVectorscopeHS(); break; + case ScopeType::PARADE: case ScopeType::WAVEFORM: histogram_observable->requestUpdateWaveform(); break; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index b79262426..68f0d91b6 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -86,6 +86,7 @@ HistogramPanel::HistogramPanel () : case ScopeType::VECTORSCOPE_HS: histogramRGBArea = nullptr; break; + case ScopeType::PARADE: case ScopeType::WAVEFORM: histogramRGBArea = histogramRGBAreaVert.get(); break; @@ -129,17 +130,20 @@ HistogramPanel::HistogramPanel () : histImage.reset(new RTImage("histogram-type-histogram-small.png")); histRawImage.reset(new RTImage("histogram-bayer-on-small.png")); + paradeImage.reset(new RTImage("histogram-type-parade-small.png")); waveImage.reset(new RTImage("histogram-type-waveform-small.png")); vectHcImage.reset(new RTImage("histogram-type-vectorscope-hc-small.png")); vectHsImage.reset(new RTImage("histogram-type-vectorscope-hs-small.png")); histImageOn.reset(new RTImage("histogram-type-histogram-small.png")); histRawImageOn.reset(new RTImage("histogram-bayer-on-small.png")); + paradeImageOn.reset(new RTImage("histogram-type-parade-small.png")); waveImageOn.reset(new RTImage("histogram-type-waveform-small.png")); vectHcImageOn.reset(new RTImage("histogram-type-vectorscope-hc-small.png")); vectHsImageOn.reset(new RTImage("histogram-type-vectorscope-hs-small.png")); histImageOff.reset(new RTImage("histogram-type-histogram-off-small.png")); histRawImageOff.reset(new RTImage("histogram-bayer-off-small.png")); + paradeImageOff.reset(new RTImage("histogram-type-parade-off-small.png")); waveImageOff.reset(new RTImage("histogram-type-waveform-off-small.png")); vectHcImageOff.reset(new RTImage("histogram-type-vectorscope-hc-off-small.png")); vectHsImageOff.reset(new RTImage("histogram-type-vectorscope-hs-off-small.png")); @@ -156,11 +160,13 @@ HistogramPanel::HistogramPanel () : Gtk::RadioButtonGroup scopeTypeGroup; scopeHistBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); scopeHistRawBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeParadeBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); scopeWaveBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); scopeVectHcBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); scopeVectHsBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); scopeHistBtn->set_mode(false); scopeHistRawBtn->set_mode(false); + scopeParadeBtn->set_mode(false); scopeWaveBtn->set_mode(false); scopeVectHcBtn->set_mode(false); scopeVectHsBtn->set_mode(false); @@ -185,6 +191,8 @@ HistogramPanel::HistogramPanel () : scopeHistBtn->set_can_focus(false); scopeHistRawBtn->set_name("histButton"); scopeHistRawBtn->set_can_focus(false); + scopeParadeBtn->set_name("histButton"); + scopeParadeBtn->set_can_focus(false); scopeWaveBtn->set_name("histButton"); scopeWaveBtn->set_can_focus(false); scopeVectHcBtn->set_name("histButton"); @@ -202,6 +210,7 @@ HistogramPanel::HistogramPanel () : showBAR->set_relief (Gtk::RELIEF_NONE); scopeHistBtn->set_relief (Gtk::RELIEF_NONE); scopeHistRawBtn->set_relief (Gtk::RELIEF_NONE); + scopeParadeBtn->set_relief (Gtk::RELIEF_NONE); scopeWaveBtn->set_relief (Gtk::RELIEF_NONE); scopeVectHcBtn->set_relief (Gtk::RELIEF_NONE); scopeVectHsBtn->set_relief (Gtk::RELIEF_NONE); @@ -216,6 +225,7 @@ HistogramPanel::HistogramPanel () : showBAR->set_tooltip_text (M("HISTOGRAM_TOOLTIP_BAR")); scopeHistBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM")); scopeHistRawBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW")); + scopeParadeBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_PARADE")); scopeWaveBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_WAVEFORM")); scopeVectHcBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HC")); scopeVectHsBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HS")); @@ -249,6 +259,7 @@ HistogramPanel::HistogramPanel () : showMode->set_image(*mode2Image); scopeHistBtn->set_image(*histImageOff); scopeHistRawBtn->set_image(*histRawImageOff); + scopeParadeBtn->set_image(*paradeImageOff); scopeWaveBtn->set_image(*waveImageOff); scopeVectHcBtn->set_image(*vectHcImageOff); scopeVectHsBtn->set_image(*vectHsImageOff); @@ -261,6 +272,10 @@ HistogramPanel::HistogramPanel () : scopeHistRawBtn->set_active(); scopeHistRawBtn->set_image(*histRawImageOn); break; + case ScopeType::PARADE: + scopeParadeBtn->set_active(); + scopeParadeBtn->set_image(*paradeImageOn); + break; case ScopeType::WAVEFORM: scopeWaveBtn->set_active(); scopeWaveBtn->set_image(*waveImageOn); @@ -279,6 +294,8 @@ HistogramPanel::HistogramPanel () : showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); type_changed(); + updateHistAreaOptions(); + updateHistRGBAreaOptions(); setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); @@ -299,6 +316,7 @@ HistogramPanel::HistogramPanel () : showBAR->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::bar_toggled), showBAR ); scopeHistBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeHistBtn)); scopeHistRawBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeHistRawBtn)); + scopeParadeBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeParadeBtn)); scopeWaveBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeWaveBtn)); scopeVectHcBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHcBtn)); scopeVectHsBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHsBtn)); @@ -314,6 +332,7 @@ HistogramPanel::HistogramPanel () : scopeButtons->add(*scopeHistBtn); scopeButtons->add(*scopeHistRawBtn); + scopeButtons->add(*scopeParadeBtn); scopeButtons->add(*scopeWaveBtn); scopeButtons->add(*scopeVectHsBtn); scopeButtons->add(*scopeVectHcBtn); @@ -462,6 +481,8 @@ void HistogramPanel::type_selected(Gtk::RadioButton* button) new_type = ScopeType::HISTOGRAM; } else if (button == scopeHistRawBtn) { new_type = ScopeType::HISTOGRAM_RAW; + } else if (button == scopeParadeBtn) { + new_type = ScopeType::PARADE; } else if (button == scopeWaveBtn) { new_type = ScopeType::WAVEFORM; } else if (button == scopeVectHcBtn) { @@ -481,6 +502,9 @@ void HistogramPanel::type_selected(Gtk::RadioButton* button) case ScopeType::HISTOGRAM_RAW: scopeHistRawBtn->set_image(*histRawImageOff); break; + case ScopeType::PARADE: + scopeParadeBtn->set_image(*paradeImageOff); + break; case ScopeType::WAVEFORM: scopeWaveBtn->set_image(*waveImageOff); break; @@ -501,6 +525,9 @@ void HistogramPanel::type_selected(Gtk::RadioButton* button) case ScopeType::HISTOGRAM_RAW: scopeHistRawBtn->set_image(*histRawImageOn); break; + case ScopeType::PARADE: + scopeParadeBtn->set_image(*paradeImageOn); + break; case ScopeType::WAVEFORM: scopeWaveBtn->set_image(*waveImageOn); break; @@ -551,6 +578,7 @@ void HistogramPanel::type_changed() scopeType->set_image(*histRawImage); histogramRGBArea = nullptr; break; + case ScopeType::PARADE: case ScopeType::WAVEFORM: showRed->set_sensitive(); showGreen->set_sensitive(); @@ -558,7 +586,11 @@ void HistogramPanel::type_changed() showValue->set_sensitive(); showChro->set_sensitive(false); showMode->set_sensitive(false); - scopeType->set_image(*waveImage); + if (options.histogramScopeType == ScopeType::PARADE) { + scopeType->set_image(*paradeImage); + } else { + scopeType->set_image(*waveImage); + } histogramRGBArea = histogramRGBAreaVert.get(); break; case ScopeType::VECTORSCOPE_HC: @@ -803,7 +835,11 @@ void HistogramRGBArea::setShow(bool show) void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { - if (!get_realized () || !showMode || !(options.histogramScopeType == ScopeType::HISTOGRAM || options.histogramScopeType == ScopeType::WAVEFORM)) { + if (!get_realized () || !showMode || !( + options.histogramScopeType == ScopeType::HISTOGRAM + || options.histogramScopeType == ScopeType::PARADE + || options.histogramScopeType == ScopeType::WAVEFORM + )) { return; } @@ -852,6 +888,7 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustrin if( (needLuma || needChroma) && (options.histogramScopeType == ScopeType::HISTOGRAM + || options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) ) { float Lab_L, Lab_a, Lab_b; @@ -1009,7 +1046,7 @@ void HistogramRGBAreaHori::get_preferred_width_for_height_vfunc (int height, int void HistogramRGBAreaVert::drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) { double pos; - if (options.histogramDrawMode < 2 || options.histogramScopeType == ScopeType::WAVEFORM) { + if (options.histogramDrawMode < 2 || options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { pos = padding + value * (winh - padding * 2.0 - 1) / max_value + 0.5 * scale; } else { pos = padding + HistogramScaling::log (max_value, value) * (winh - padding * 2.0) / max_value + 0.5 * scale; @@ -1054,7 +1091,7 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : vect_hc_buffer_dirty(true), vect_hs_buffer_dirty(true), waveform_scale(0), rwave(0, 0), gwave(0, 0),bwave(0, 0), lwave(0, 0), - wave_buffer_dirty(true), + parade_buffer_dirty(true), wave_buffer_dirty(true), valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), scopeType(options.histogramScopeType), oldwidth(-1), oldheight(-1), @@ -1178,13 +1215,14 @@ void HistogramArea::update( ghistRaw = histGreenRaw; bhistRaw = histBlueRaw; break; + case ScopeType::PARADE: case ScopeType::WAVEFORM: waveform_scale = waveformScale; rwave = waveformRed; gwave = waveformGreen; bwave = waveformBlue; lwave = waveformLuma; - wave_buffer_dirty = true; + parade_buffer_dirty = wave_buffer_dirty = true; break; case ScopeType::VECTORSCOPE_HS: vectorscope_scale = vectorscopeScale; @@ -1285,7 +1323,7 @@ void HistogramArea::updateBackBuffer () } // draw horizontal gridlines - if (options.histogramScopeType == ScopeType::WAVEFORM) { + if (options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { for (int i = 0; i <= nrOfVGridPartitions; i++) { const double ypos = h - padding - (pow(2.0,i) - 1) * (h - 2 * padding - 1) / 255.0; cr->move_to(0, ypos); @@ -1419,6 +1457,8 @@ void HistogramArea::updateBackBuffer () drawMarks(cr, bhchanged, realhistheight, w, ui, oi); } + } else if (scopeType == ScopeType::PARADE && rwave.getWidth() > 0) { + drawParade(cr, w, h); } else if (scopeType == ScopeType::WAVEFORM && rwave.getWidth() > 0) { drawWaveform(cr, w, h); } else if (scopeType == ScopeType::VECTORSCOPE_HC || scopeType == ScopeType::VECTORSCOPE_HS) { @@ -1505,6 +1545,101 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, cr->fill(); } +void HistogramArea::drawParade(Cairo::RefPtr &cr, int w, int h) +{ + // Arbitrary scale factor divided by current scale. + const float scale = trace_brightness * 32.f * 255.f / waveform_scale; + const int wave_width = rwave.getWidth(); + const int wave_height = rwave.getHeight(); + + // See Cairo documentation on stride. + const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, rwave.getWidth()); + + if (parade_buffer_dirty) { + const auto buffer_size = static_cast::size_type>(wave_height) * cairo_stride; + parade_buffer_r.assign(buffer_size, 0); + parade_buffer_g.assign(buffer_size, 0); + parade_buffer_b.assign(buffer_size, 0); + wave_buffer_luma.assign(buffer_size, 0); + + assert(parade_buffer_r.size() % 4 == 0); + assert(parade_buffer_g.size() % 4 == 0); + assert(parade_buffer_b.size() % 4 == 0); + assert(wave_buffer_luma.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const r_row = rwave[val]; + const int* const g_row = gwave[val]; + const int* const b_row = bwave[val]; + std::uint32_t* const buffer_r_row = reinterpret_cast(parade_buffer_r.data() + (255 - val) * cairo_stride); + std::uint32_t* const buffer_g_row = reinterpret_cast(parade_buffer_g.data() + (255 - val) * cairo_stride); + std::uint32_t* const buffer_b_row = reinterpret_cast(parade_buffer_b.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char r = std::min(scale * r_row[col], 0xff); + const unsigned char g = std::min(scale * g_row[col], 0xff); + const unsigned char b = std::min(scale * b_row[col], 0xff); + if (r == 0) { + buffer_r_row[col] = 0; + } else { + buffer_r_row[col] = (r << 16) | (r << 24); + } + if (g == 0) { + buffer_g_row[col] = 0; + } else { + buffer_g_row[col] = (g << 8) | (g << 24); + } + if (b == 0) { + buffer_b_row[col] = 0; + } else { + const unsigned char green = b / 2; // Make blue easier to see. + buffer_b_row[col] = b | (green << 8) | (b << 24); + } + } + } + + for (int val = 0; val < wave_height; val++) { + const int* const l_row = lwave[val]; + std::uint32_t* const buffer_row = + reinterpret_cast(wave_buffer_luma.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char l = std::min(scale * l_row[col], 0xff); + buffer_row[col] = l | (l << 8) | (l << 16) | (l << 24); + } + } + + parade_buffer_dirty = false; + } + + std::vector buffers; + if (needLuma) { + buffers.push_back(wave_buffer_luma.data()); + } + if (needRed) { + buffers.push_back(parade_buffer_r.data()); + } + if (needGreen) { + buffers.push_back(parade_buffer_g.data()); + } + if (needBlue) { + buffers.push_back(parade_buffer_b.data()); + } + + auto orig_matrix = cr->get_matrix(); + const double display_wave_width = static_cast(w) / buffers.size(); + for (int i = 0; i < buffers.size(); i++) { + Cairo::RefPtr surface; + cr->translate(i * display_wave_width, padding); + cr->scale(display_wave_width / wave_width, (h - 2 * padding) / wave_height); + surface = Cairo::ImageSurface::create( + buffers[i], Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + surface->finish(); + cr->set_matrix(orig_matrix); + } +} + void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, int h) { if (scopeType != ScopeType::VECTORSCOPE_HC && scopeType != ScopeType::VECTORSCOPE_HS) { @@ -1726,15 +1861,13 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h } } - if (needLuma) { - for (int val = 0; val < wave_height; val++) { - const int* const l_row = lwave[val]; - std::uint32_t* const buffer_row = - reinterpret_cast(wave_buffer_luma.data() + (255 - val) * cairo_stride); - for (int col = 0; col < wave_width; col++) { - const unsigned char l = std::min(scale * l_row[col], 0xff); - buffer_row[col] = l | (l << 8) | (l << 16) | (l << 24); - } + for (int val = 0; val < wave_height; val++) { + const int* const l_row = lwave[val]; + std::uint32_t* const buffer_row = + reinterpret_cast(wave_buffer_luma.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char l = std::min(scale * l_row[col], 0xff); + buffer_row[col] = l | (l << 8) | (l << 16) | (l << 24); } } @@ -1834,7 +1967,8 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) setDirty(true); queue_draw (); } else if ( - scopeType == ScopeType::WAVEFORM + scopeType == ScopeType::PARADE + || scopeType == ScopeType::WAVEFORM || scopeType == ScopeType::VECTORSCOPE_HC || scopeType == ScopeType::VECTORSCOPE_HS ) { // Adjust brightness. @@ -1844,7 +1978,7 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) double dx = (event->x - movingPosition) / get_width(); float new_brightness = LIM(trace_brightness * pow(RANGE, dx), MIN_BRIGHT, MAX_BRIGHT); if (new_brightness != trace_brightness) { - wave_buffer_dirty = vect_hc_buffer_dirty = vect_hs_buffer_dirty = true; + parade_buffer_dirty = wave_buffer_dirty = vect_hc_buffer_dirty = vect_hs_buffer_dirty = true; trace_brightness = new_brightness; setDirty(true); queue_draw(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 4417e2373..cca27a0d9 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -166,6 +166,10 @@ protected: bool vect_hc_buffer_dirty, vect_hs_buffer_dirty; int waveform_scale; array2D rwave, gwave, bwave, lwave; + std::vector parade_buffer_r; + std::vector parade_buffer_g; + std::vector parade_buffer_b; + bool parade_buffer_dirty; std::vector wave_buffer; std::vector wave_buffer_luma; bool wave_buffer_dirty; @@ -227,6 +231,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 drawParade(Cairo::RefPtr &cr, int hsize, int vsize); 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; @@ -268,6 +273,7 @@ protected: Gtk::RadioButton* scopeHistBtn; Gtk::RadioButton* scopeHistRawBtn; + Gtk::RadioButton* scopeParadeBtn; Gtk::RadioButton* scopeWaveBtn; Gtk::RadioButton* scopeVectHcBtn; Gtk::RadioButton* scopeVectHsBtn; @@ -288,17 +294,20 @@ protected: std::unique_ptr histImage; std::unique_ptr histRawImage; + std::unique_ptr paradeImage; std::unique_ptr waveImage; std::unique_ptr vectHcImage; std::unique_ptr vectHsImage; std::unique_ptr histImageOn; std::unique_ptr histRawImageOn; + std::unique_ptr paradeImageOn; std::unique_ptr waveImageOn; std::unique_ptr vectHcImageOn; std::unique_ptr vectHsImageOn; std::unique_ptr histImageOff; std::unique_ptr histRawImageOff; + std::unique_ptr paradeImageOff; std::unique_ptr waveImageOff; std::unique_ptr vectHcImageOff; std::unique_ptr vectHsImageOff; diff --git a/rtgui/options.h b/rtgui/options.h index e64c31ad1..aa5cff373 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -179,6 +179,7 @@ public: NONE = -1, HISTOGRAM, HISTOGRAM_RAW, + PARADE, VECTORSCOPE_HC, VECTORSCOPE_HS, WAVEFORM From 0ad5f9587f3a14fd28548616948ef0f9fac6a2e2 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 26 Sep 2020 12:40:14 -0700 Subject: [PATCH 44/56] Fix segfault Make sure histogramRGBArea isn't null before using it. --- rtgui/histogrampanel.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 68f0d91b6..93091733c 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -295,7 +295,9 @@ HistogramPanel::HistogramPanel () : type_changed(); updateHistAreaOptions(); - updateHistRGBAreaOptions(); + if (histogramRGBArea) { + updateHistRGBAreaOptions(); + } setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); From cecb753595d850bfaab0e827384bf8ae5f918f62 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 26 Sep 2020 16:30:51 -0700 Subject: [PATCH 45/56] Increase performance of some scopes --- rtgui/histogrampanel.cc | 116 +++++++++++++++++++++++----------------- rtgui/histogrampanel.h | 4 +- 2 files changed, 70 insertions(+), 50 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 93091733c..0df6496c7 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1093,7 +1093,8 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : vect_hc_buffer_dirty(true), vect_hs_buffer_dirty(true), waveform_scale(0), rwave(0, 0), gwave(0, 0),bwave(0, 0), lwave(0, 0), - parade_buffer_dirty(true), wave_buffer_dirty(true), + parade_buffer_r_dirty(true), parade_buffer_g_dirty(true), parade_buffer_b_dirty(true), + wave_buffer_dirty(true), wave_buffer_luma_dirty(true), valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), scopeType(options.histogramScopeType), oldwidth(-1), oldheight(-1), @@ -1166,6 +1167,7 @@ void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minim void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, ScopeType type, bool pointer) { + wave_buffer_dirty = wave_buffer_dirty || needRed != r || needGreen != g || needBlue != b; options.histogramRed = needRed = r; options.histogramGreen = needGreen = g; @@ -1175,8 +1177,6 @@ void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, int m options.histogramDrawMode = drawMode = mode; options.histogramScopeType = scopeType = type; options.histogramBar = needPointer = pointer; - - wave_buffer_dirty = true; } bool HistogramArea::updatePending(void) @@ -1224,7 +1224,7 @@ void HistogramArea::update( gwave = waveformGreen; bwave = waveformBlue; lwave = waveformLuma; - parade_buffer_dirty = wave_buffer_dirty = true; + parade_buffer_r_dirty = parade_buffer_g_dirty = parade_buffer_b_dirty = wave_buffer_dirty = wave_buffer_luma_dirty = true; break; case ScopeType::VECTORSCOPE_HS: vectorscope_scale = vectorscopeScale; @@ -1556,49 +1556,67 @@ void HistogramArea::drawParade(Cairo::RefPtr &cr, int w, int h) // See Cairo documentation on stride. const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, rwave.getWidth()); + const auto buffer_size = static_cast::size_type>(wave_height) * cairo_stride; - if (parade_buffer_dirty) { - const auto buffer_size = static_cast::size_type>(wave_height) * cairo_stride; + if (parade_buffer_r_dirty && needRed) { parade_buffer_r.assign(buffer_size, 0); - parade_buffer_g.assign(buffer_size, 0); - parade_buffer_b.assign(buffer_size, 0); - wave_buffer_luma.assign(buffer_size, 0); - assert(parade_buffer_r.size() % 4 == 0); - assert(parade_buffer_g.size() % 4 == 0); - assert(parade_buffer_b.size() % 4 == 0); - assert(wave_buffer_luma.size() % 4 == 0); for (int val = 0; val < wave_height; val++) { const int* const r_row = rwave[val]; - const int* const g_row = gwave[val]; - const int* const b_row = bwave[val]; std::uint32_t* const buffer_r_row = reinterpret_cast(parade_buffer_r.data() + (255 - val) * cairo_stride); - std::uint32_t* const buffer_g_row = reinterpret_cast(parade_buffer_g.data() + (255 - val) * cairo_stride); - std::uint32_t* const buffer_b_row = reinterpret_cast(parade_buffer_b.data() + (255 - val) * cairo_stride); for (int col = 0; col < wave_width; col++) { const unsigned char r = std::min(scale * r_row[col], 0xff); - const unsigned char g = std::min(scale * g_row[col], 0xff); - const unsigned char b = std::min(scale * b_row[col], 0xff); - if (r == 0) { - buffer_r_row[col] = 0; - } else { + if (r != 0) { buffer_r_row[col] = (r << 16) | (r << 24); } - if (g == 0) { - buffer_g_row[col] = 0; - } else { + } + } + + parade_buffer_r_dirty = false; + } + + if (parade_buffer_g_dirty && needGreen) { + parade_buffer_g.assign(buffer_size, 0); + assert(parade_buffer_g.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const g_row = gwave[val]; + std::uint32_t* const buffer_g_row = reinterpret_cast(parade_buffer_g.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char g = std::min(scale * g_row[col], 0xff); + if (g != 0) { buffer_g_row[col] = (g << 8) | (g << 24); } - if (b == 0) { - buffer_b_row[col] = 0; - } else { + } + } + + parade_buffer_g_dirty = false; + } + + if (parade_buffer_b_dirty && needBlue) { + parade_buffer_b.assign(buffer_size, 0); + assert(parade_buffer_b.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const b_row = bwave[val]; + std::uint32_t* const buffer_b_row = reinterpret_cast(parade_buffer_b.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char b = std::min(scale * b_row[col], 0xff); + if (b != 0) { const unsigned char green = b / 2; // Make blue easier to see. buffer_b_row[col] = b | (green << 8) | (b << 24); } } } + parade_buffer_b_dirty = false; + } + + if (wave_buffer_luma_dirty && needLuma) { + wave_buffer_luma.assign(buffer_size, 0); + assert(wave_buffer_luma.size() % 4 == 0); + for (int val = 0; val < wave_height; val++) { const int* const l_row = lwave[val]; std::uint32_t* const buffer_row = @@ -1609,7 +1627,7 @@ void HistogramArea::drawParade(Cairo::RefPtr &cr, int w, int h) } } - parade_buffer_dirty = false; + wave_buffer_luma_dirty = false; } std::vector buffers; @@ -1668,7 +1686,6 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in assert(vect_buffer.size() % 4 == 0); - // TODO: Optimize. for (int y = 0; y < vect_height; y++) { const int* const vect_row = vect[y]; std::uint32_t* const buffer_row = @@ -1834,16 +1851,12 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h // See Cairo documentation on stride. const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, rwave.getWidth()); + const auto buffer_size = static_cast::size_type>(wave_height) * cairo_stride; - if (wave_buffer_dirty) { - const auto buffer_size = static_cast::size_type>(wave_height) * cairo_stride; + if (wave_buffer_dirty && (needRed || needGreen || needBlue)) { wave_buffer.assign(buffer_size, 0); - wave_buffer_luma.assign(buffer_size, 0); - assert(wave_buffer.size() % 4 == 0); - assert(wave_buffer_luma.size() % 4 == 0); - // TODO: Optimize. for (int val = 0; val < wave_height; val++) { const int* const r_row = rwave[val]; const int* const g_row = gwave[val]; @@ -1854,15 +1867,20 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h const unsigned char g = needGreen ? std::min(scale * g_row[col], 0xff) : 0; const unsigned char b = needBlue ? std::min(scale * b_row[col], 0xff) : 0; const unsigned char value = rtengine::max(r, g, b); - if (value == 0) { - buffer_row[col] = 0; - } else { - // Speedup with one memory access instead of four. + if (value != 0) { + // Ensures correct order regardless of endianness. buffer_row[col] = b | (g << 8) | (r << 16) | (value << 24); } } } + wave_buffer_dirty = false; + } + + if (wave_buffer_luma_dirty && needLuma) { + wave_buffer_luma.assign(buffer_size, 0); + assert(wave_buffer_luma.size() % 4 == 0); + for (int val = 0; val < wave_height; val++) { const int* const l_row = lwave[val]; std::uint32_t* const buffer_row = @@ -1873,7 +1891,7 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h } } - wave_buffer_dirty = false; + wave_buffer_luma_dirty = false; } Cairo::RefPtr surface; @@ -1888,12 +1906,14 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h cr->paint(); surface->finish(); } - surface = Cairo::ImageSurface::create( - wave_buffer.data(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); - cr->set_source(surface, 0, 0); - cr->set_operator(Cairo::OPERATOR_OVER); - cr->paint(); - surface->finish(); + if (needRed || needGreen || needBlue) { + surface = Cairo::ImageSurface::create( + wave_buffer.data(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + surface->finish(); + } cr->set_matrix(orig_matrix); } @@ -1980,7 +2000,7 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) double dx = (event->x - movingPosition) / get_width(); float new_brightness = LIM(trace_brightness * pow(RANGE, dx), MIN_BRIGHT, MAX_BRIGHT); if (new_brightness != trace_brightness) { - parade_buffer_dirty = wave_buffer_dirty = vect_hc_buffer_dirty = vect_hs_buffer_dirty = true; + parade_buffer_r_dirty = parade_buffer_g_dirty = parade_buffer_b_dirty = wave_buffer_dirty = wave_buffer_luma_dirty = vect_hc_buffer_dirty = vect_hs_buffer_dirty = true; trace_brightness = new_brightness; setDirty(true); queue_draw(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index cca27a0d9..fdce93d00 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -169,10 +169,10 @@ protected: std::vector parade_buffer_r; std::vector parade_buffer_g; std::vector parade_buffer_b; - bool parade_buffer_dirty; + bool parade_buffer_r_dirty, parade_buffer_g_dirty, parade_buffer_b_dirty; std::vector wave_buffer; std::vector wave_buffer_luma; - bool wave_buffer_dirty; + bool wave_buffer_dirty, wave_buffer_luma_dirty; bool valid; int drawMode; From b8af429f0edecd9868447d35a0b1c7a3b5fd7e44 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Mon, 28 Sep 2020 22:17:49 -0700 Subject: [PATCH 46/56] Prevent null pointer access Thanks to Ingo for fixing the segfault. --- rtengine/improccoordinator.cc | 2 +- rtengine/improccoordinator.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 72dfb0cd3..a88f6401f 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -364,7 +364,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw); - hist_raw_dirty = !hListener->updateHistogramRaw(); + hist_raw_dirty = !(hListener && hListener->updateHistogramRaw()); highDetailPreprocessComputed = highDetailNeeded; diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index d39fa3f9e..3020d68d5 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -469,7 +469,9 @@ public: hListener->setObservable(nullptr); } hListener = h; - h->setObservable(this); + if (h) { + h->setObservable(this); + } } void setAutoCamListener (AutoCamListener* acl) override { From 6b667ead58172179aceee7e9c730333b466a6d01 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Fri, 2 Oct 2020 21:55:15 -0700 Subject: [PATCH 47/56] Swap positions of scope buttons Make the scope type buttons the primary buttons and the other options secondary. --- .../images/svg/histogram-ellipsis-small.svg | 135 +++++++++++++++ rtdata/languages/default | 3 +- rtgui/histogrampanel.cc | 163 +++++++++--------- rtgui/histogrampanel.h | 13 +- rtgui/options.cc | 8 +- rtgui/options.h | 2 +- 6 files changed, 223 insertions(+), 101 deletions(-) create mode 100644 rtdata/images/svg/histogram-ellipsis-small.svg diff --git a/rtdata/images/svg/histogram-ellipsis-small.svg b/rtdata/images/svg/histogram-ellipsis-small.svg new file mode 100644 index 000000000..4fdb17907 --- /dev/null +++ b/rtdata/images/svg/histogram-ellipsis-small.svg @@ -0,0 +1,135 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/languages/default b/rtdata/languages/default index fbfab9b86..d7f5734ae 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -244,12 +244,13 @@ GIMP_PLUGIN_INFO;Welcome to the RawTherapee GIMP plugin!\nOnce you are done edit HISTOGRAM_TOOLTIP_B;Show/Hide blue histogram. HISTOGRAM_TOOLTIP_BAR;Show/Hide RGB indicator bar. HISTOGRAM_TOOLTIP_CHRO;Show/Hide chromaticity histogram. +HISTOGRAM_TOOLTIP_CROSSHAIR;Show/Hide indicator crosshair. HISTOGRAM_TOOLTIP_G;Show/Hide green histogram. 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 visibility of the scope selection buttons. +HISTOGRAM_TOOLTIP_SHOW_OPTIONS;Toggle visibility of the scope option buttons. HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM;Histogram HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW;Raw Histogram HISTOGRAM_TOOLTIP_TYPE_PARADE;RGB Parade diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 0df6496c7..66b322085 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -128,13 +128,6 @@ HistogramPanel::HistogramPanel () : mode1Image = new RTImage ("histogram-mode-logx-small.png"); mode2Image = new RTImage ("histogram-mode-logxy-small.png"); - histImage.reset(new RTImage("histogram-type-histogram-small.png")); - histRawImage.reset(new RTImage("histogram-bayer-on-small.png")); - paradeImage.reset(new RTImage("histogram-type-parade-small.png")); - waveImage.reset(new RTImage("histogram-type-waveform-small.png")); - vectHcImage.reset(new RTImage("histogram-type-vectorscope-hc-small.png")); - vectHsImage.reset(new RTImage("histogram-type-vectorscope-hs-small.png")); - histImageOn.reset(new RTImage("histogram-type-histogram-small.png")); histRawImageOn.reset(new RTImage("histogram-bayer-on-small.png")); paradeImageOn.reset(new RTImage("histogram-type-parade-small.png")); @@ -154,8 +147,8 @@ HistogramPanel::HistogramPanel () : showValue = Gtk::manage (new Gtk::ToggleButton ()); showChro = Gtk::manage (new Gtk::ToggleButton ()); showMode = Gtk::manage (new Gtk::Button ()); - scopeType = Gtk::manage (new Gtk::ToggleButton ()); showBAR = Gtk::manage (new Gtk::ToggleButton ()); + scopeOptions = Gtk::manage (new Gtk::ToggleButton ()); Gtk::RadioButtonGroup scopeTypeGroup; scopeHistBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); @@ -183,8 +176,8 @@ HistogramPanel::HistogramPanel () : showChro->set_can_focus(false); showMode->set_name("histButton"); showMode->set_can_focus(false); - scopeType->set_name("histButton"); - scopeType->set_can_focus(false); + scopeOptions->set_name("histButton"); + scopeOptions->set_can_focus(false); showBAR->set_name("histButton"); showBAR->set_can_focus(false); scopeHistBtn->set_name("histButton"); @@ -206,7 +199,7 @@ HistogramPanel::HistogramPanel () : showValue->set_relief (Gtk::RELIEF_NONE); showChro->set_relief (Gtk::RELIEF_NONE); showMode->set_relief (Gtk::RELIEF_NONE); - scopeType->set_relief (Gtk::RELIEF_NONE); + scopeOptions->set_relief (Gtk::RELIEF_NONE); showBAR->set_relief (Gtk::RELIEF_NONE); scopeHistBtn->set_relief (Gtk::RELIEF_NONE); scopeHistRawBtn->set_relief (Gtk::RELIEF_NONE); @@ -221,8 +214,7 @@ HistogramPanel::HistogramPanel () : showValue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_L")); showChro->set_tooltip_text (M("HISTOGRAM_TOOLTIP_CHRO")); showMode->set_tooltip_text (M("HISTOGRAM_TOOLTIP_MODE")); - scopeType->set_tooltip_text (M("HISTOGRAM_TOOLTIP_TYPE")); - showBAR->set_tooltip_text (M("HISTOGRAM_TOOLTIP_BAR")); + scopeOptions->set_tooltip_text(M("HISTOGRAM_TOOLTIP_SHOW_OPTIONS")); scopeHistBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM")); scopeHistRawBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW")); scopeParadeBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_PARADE")); @@ -234,8 +226,8 @@ HistogramPanel::HistogramPanel () : buttonGrid->set_orientation(Gtk::ORIENTATION_HORIZONTAL); persistentButtons = Gtk::manage(new Gtk::Box()); persistentButtons->set_orientation(Gtk::ORIENTATION_VERTICAL); - scopeButtons = Gtk::manage(new Gtk::Box()); - scopeButtons->set_orientation(Gtk::ORIENTATION_VERTICAL); + optionButtons = Gtk::manage(new Gtk::Box()); + optionButtons->set_orientation(Gtk::ORIENTATION_VERTICAL); showRed->set_active (options.histogramRed); showGreen->set_active (options.histogramGreen); @@ -243,7 +235,7 @@ HistogramPanel::HistogramPanel () : showValue->set_active (options.histogramLuma); showChro->set_active (options.histogramChroma); // no showMode->set_active(), as it's not a ToggleButton - scopeType->set_active(options.histogramShowScopeButtons); + scopeOptions->set_active(options.histogramShowOptionButtons); showBAR->set_active (options.histogramBar); showRed->set_image (showRed->get_active() ? *redImage : *redImage_g); @@ -291,22 +283,19 @@ HistogramPanel::HistogramPanel () : case ScopeType::NONE: break; } + scopeOptions->set_image(*Gtk::manage(new RTImage("histogram-ellipsis-small.png"))); showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); - type_changed(); - updateHistAreaOptions(); - if (histogramRGBArea) { - updateHistRGBAreaOptions(); - } - setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showBlue , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showValue, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(scopeType, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(scopeOptions, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(persistentButtons, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); + setExpandAlignProperties(optionButtons, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); showRed->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::red_toggled), showRed ); showGreen->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::green_toggled), showGreen ); @@ -314,7 +303,7 @@ HistogramPanel::HistogramPanel () : showValue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::value_toggled), showValue ); showChro->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::chro_toggled), showChro ); showMode->signal_released().connect( sigc::mem_fun(*this, &HistogramPanel::mode_released), showMode ); - scopeType->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::type_pressed) ); + scopeOptions->signal_toggled().connect(sigc::mem_fun(*this, &HistogramPanel::scopeOptionsToggled)); showBAR->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::bar_toggled), showBAR ); scopeHistBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeHistBtn)); scopeHistRawBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeHistRawBtn)); @@ -323,31 +312,34 @@ HistogramPanel::HistogramPanel () : scopeVectHcBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHcBtn)); scopeVectHsBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHsBtn)); - persistentButtons->add(*showRed); - persistentButtons->add(*showGreen); - persistentButtons->add(*showBlue); - persistentButtons->add(*showValue); - persistentButtons->add(*showChro); - persistentButtons->add(*showMode); - persistentButtons->add(*scopeType); - persistentButtons->add(*showBAR); + optionButtons->add(*showRed); + optionButtons->add(*showGreen); + optionButtons->add(*showBlue); + optionButtons->add(*showValue); + optionButtons->add(*showChro); + optionButtons->add(*showMode); + optionButtons->add(*showBAR); - scopeButtons->add(*scopeHistBtn); - scopeButtons->add(*scopeHistRawBtn); - scopeButtons->add(*scopeParadeBtn); - scopeButtons->add(*scopeWaveBtn); - scopeButtons->add(*scopeVectHsBtn); - scopeButtons->add(*scopeVectHcBtn); + Gtk::VSeparator* separator = Gtk::manage(new Gtk::VSeparator()); + setExpandAlignProperties(separator, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_END); + persistentButtons->add(*scopeHistBtn); + persistentButtons->add(*scopeHistRawBtn); + persistentButtons->add(*scopeParadeBtn); + persistentButtons->add(*scopeWaveBtn); + persistentButtons->add(*scopeVectHsBtn); + persistentButtons->add(*scopeVectHcBtn); + persistentButtons->add(*separator); + persistentButtons->add(*scopeOptions); // Put the button vbox next to the window's border to be less disturbing if (options.histogramPosition == 1) { buttonGrid->add(*persistentButtons); - buttonGrid->add(*scopeButtons); + buttonGrid->add(*optionButtons); add (*buttonGrid); add (*gfxGrid); } else { - buttonGrid->add(*scopeButtons); + buttonGrid->add(*optionButtons); buttonGrid->add(*persistentButtons); add (*gfxGrid); @@ -355,8 +347,14 @@ HistogramPanel::HistogramPanel () : } show_all (); - scopeButtons->set_no_show_all(); - scopeButtons->set_visible(options.histogramShowScopeButtons); + optionButtons->set_no_show_all(); + optionButtons->set_visible(options.histogramShowOptionButtons); + + type_changed(); + updateHistAreaOptions(); + if (histogramRGBArea) { + updateHistRGBAreaOptions(); + } rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); } @@ -469,10 +467,10 @@ void HistogramPanel::mode_released () rgbv_toggled(); } -void HistogramPanel::type_pressed() +void HistogramPanel::scopeOptionsToggled() { - options.histogramShowScopeButtons = scopeType->get_active(); - scopeButtons->set_visible(scopeType->get_active()); + options.histogramShowOptionButtons = scopeOptions->get_active(); + optionButtons->set_visible(scopeOptions->get_active()); } void HistogramPanel::type_selected(Gtk::RadioButton* button) @@ -561,53 +559,48 @@ void HistogramPanel::type_changed() switch (options.histogramScopeType) { case ScopeType::HISTOGRAM: - showRed->set_sensitive(); - showGreen->set_sensitive(); - showBlue->set_sensitive(); - showValue->set_sensitive(); - showChro->set_sensitive(); - showMode->set_sensitive(); - scopeType->set_image(*histImage); + showRed->show(); + showGreen->show(); + showBlue->show(); + showValue->show(); + showChro->show(); + showMode->show(); + showBAR->show(); + showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_BAR")); histogramRGBArea = histogramRGBAreaHori.get(); break; case ScopeType::HISTOGRAM_RAW: - showRed->set_sensitive(); - showGreen->set_sensitive(); - showBlue->set_sensitive(); - showValue->set_sensitive(false); - showChro->set_sensitive(false); - showMode->set_sensitive(); - scopeType->set_image(*histRawImage); + showRed->show(); + showGreen->show(); + showBlue->show(); + showValue->hide(); + showChro->hide(); + showMode->show(); + showBAR->hide(); histogramRGBArea = nullptr; break; case ScopeType::PARADE: case ScopeType::WAVEFORM: - showRed->set_sensitive(); - showGreen->set_sensitive(); - showBlue->set_sensitive(); - showValue->set_sensitive(); - showChro->set_sensitive(false); - showMode->set_sensitive(false); - if (options.histogramScopeType == ScopeType::PARADE) { - scopeType->set_image(*paradeImage); - } else { - scopeType->set_image(*waveImage); - } + showRed->show(); + showGreen->show(); + showBlue->show(); + showValue->show(); + showChro->hide(); + showMode->hide(); + showBAR->show(); + showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_BAR")); histogramRGBArea = histogramRGBAreaVert.get(); break; case ScopeType::VECTORSCOPE_HC: case ScopeType::VECTORSCOPE_HS: - showRed->set_sensitive(false); - showGreen->set_sensitive(false); - showBlue->set_sensitive(false); - showValue->set_sensitive(false); - showChro->set_sensitive(false); - showMode->set_sensitive(false); - if (options.histogramScopeType == ScopeType::VECTORSCOPE_HC) { - scopeType->set_image(*vectHcImage); - } else { - scopeType->set_image(*vectHsImage); - } + showRed->hide(); + showGreen->hide(); + showBlue->hide(); + showValue->hide(); + showChro->hide(); + showMode->hide(); + showBAR->show(); + showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_CROSSHAIR")); histogramRGBArea = nullptr; break; case ScopeType::NONE: @@ -679,10 +672,10 @@ void HistogramPanel::reorder (Gtk::PositionType align) gfxGrid->add(*histogramRGBArea); } - scopeButtons->reference(); - removeIfThere(buttonGrid, scopeButtons, false); - buttonGrid->add(*scopeButtons); - scopeButtons->unreference(); + optionButtons->reference(); + removeIfThere(buttonGrid, optionButtons, false); + buttonGrid->add(*optionButtons); + optionButtons->unreference(); } else { buttonGrid->reference(); removeIfThere(this, buttonGrid, false); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index fdce93d00..5ecf378b8 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -257,7 +257,7 @@ protected: Gtk::Grid* gfxGrid; Gtk::Grid* buttonGrid; Gtk::Box* persistentButtons; - Gtk::Box* scopeButtons; + Gtk::Box* optionButtons; HistogramArea* histogramArea; HistogramRGBArea* histogramRGBArea; std::unique_ptr histogramRGBAreaHori; @@ -269,7 +269,7 @@ protected: Gtk::ToggleButton* showBAR; Gtk::ToggleButton* showChro; Gtk::Button* showMode; - Gtk::ToggleButton* scopeType; + Gtk::ToggleButton* scopeOptions; Gtk::RadioButton* scopeHistBtn; Gtk::RadioButton* scopeHistRawBtn; @@ -292,13 +292,6 @@ protected: Gtk::Image *barImage_g; Gtk::Image *chroImage_g; - std::unique_ptr histImage; - std::unique_ptr histRawImage; - std::unique_ptr paradeImage; - std::unique_ptr waveImage; - std::unique_ptr vectHcImage; - std::unique_ptr vectHsImage; - std::unique_ptr histImageOn; std::unique_ptr histRawImageOn; std::unique_ptr paradeImageOn; @@ -364,7 +357,7 @@ public: void chro_toggled (); void bar_toggled (); void mode_released (); - void type_pressed (); + void scopeOptionsToggled(); void type_selected(Gtk::RadioButton* button); void type_changed (); void rgbv_toggled (); diff --git a/rtgui/options.cc b/rtgui/options.cc index d71fcc57d..494a1ec3f 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -450,7 +450,7 @@ void Options::setDefaults() histogramHeight = 200; histogramDrawMode = 0; histogramScopeType = ScopeType::HISTOGRAM; - histogramShowScopeButtons = false; + histogramShowOptionButtons = false; curvebboxpos = 1; complexity = 2; prevdemo = PD_Sidecar; @@ -1440,8 +1440,8 @@ void Options::readFromFile(Glib::ustring fname) histogramScopeType = static_cast(keyFile.get_integer("GUI", "HistogramScopeType")); } - if (keyFile.has_key("GUI", "HistogramShowScopeButtons")) { - histogramShowScopeButtons = keyFile.get_boolean("GUI", "HistogramShowScopeButtons"); + if (keyFile.has_key("GUI", "HistogramShowOptionButtons")) { + histogramShowOptionButtons = keyFile.get_boolean("GUI", "HistogramShowOptionButtons"); } if (keyFile.has_key("GUI", "NavigatorRGBUnit")) { @@ -2267,7 +2267,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("GUI", "HistogramHeight", histogramHeight); keyFile.set_integer("GUI", "HistogramDrawMode", histogramDrawMode); keyFile.set_integer("GUI", "HistogramScopeType", rtengine::toUnderlying(histogramScopeType)); - keyFile.set_boolean("GUI", "HistogramShowScopeButtons", histogramShowScopeButtons); + keyFile.set_boolean("GUI", "HistogramShowOptionButtons", histogramShowOptionButtons); keyFile.set_integer("GUI", "NavigatorRGBUnit", (int)navRGBUnit); keyFile.set_integer("GUI", "NavigatorHSVUnit", (int)navHSVUnit); keyFile.set_boolean("GUI", "ShowFilmStripToolBar", showFilmStripToolBar); diff --git a/rtgui/options.h b/rtgui/options.h index aa5cff373..476af79ec 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -323,7 +323,7 @@ public: int histogramHeight; int histogramDrawMode; ScopeType histogramScopeType; - bool histogramShowScopeButtons; + bool histogramShowOptionButtons; bool FileBrowserToolbarSingleRow; bool hideTPVScrollbar; int whiteBalanceSpotSize; From 04524b6332564d9b9771607d3f9ce6142c49f1f5 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Fri, 2 Oct 2020 22:19:33 -0700 Subject: [PATCH 48/56] Change vectorscope crosshair style The original crosshair used dashed lines extending across the vectorscope area. The new crosshair uses solid lines with a small length. --- rtgui/histogrampanel.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 66b322085..480a80c92 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1817,14 +1817,13 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in cx = w / 2.f + scope_size * pointer_a * ab_factor; cy = h / 2.f - scope_size * pointer_b * ab_factor; } + const float crosshair_size = 20.f * s; cr->set_source_rgba(1, 1, 1, 0.5); - cr->set_dash(ch_ds, 0); - cr->move_to(0, cy); - cr->line_to(w, cy); - cr->move_to(cx, 0); - cr->line_to(cx, h); + cr->move_to(cx - crosshair_size, cy); + cr->line_to(cx + crosshair_size, cy); + cr->move_to(cx, cy - crosshair_size); + cr->line_to(cx, cy + crosshair_size); cr->stroke(); - cr->unset_dash(); cr->arc(cx, cy, 3 * s, 0, 2 * RT_PI); cr->set_source_rgb(1, 1, 1); cr->fill_preserve(); From edbf701264961d04e3b3cbb1fa5d715856a9f056 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 3 Oct 2020 22:37:13 -0700 Subject: [PATCH 49/56] Improve style of scope buttons Keep all buttons at the same place and use darkened button background instead of tiny icons to indicate which scope type is active. --- .../images/svg/histogram-bayer-off-small.svg | 139 ------------------ .../histogram-type-histogram-off-small.svg | 122 --------------- ...=> histogram-type-histogram-raw-small.svg} | 0 .../svg/histogram-type-parade-off-small.svg | 132 ----------------- ...istogram-type-vectorscope-hc-off-small.svg | 131 ----------------- ...istogram-type-vectorscope-hs-off-small.svg | 135 ----------------- .../svg/histogram-type-waveform-off-small.svg | 122 --------------- rtdata/themes/RawTherapee-GTK3-20_.css | 13 ++ rtdata/themes/TooWaBlue-GTK3-20_.css | 20 +++ rtgui/histogrampanel.cc | 91 +++--------- rtgui/histogrampanel.h | 13 -- 11 files changed, 53 insertions(+), 865 deletions(-) delete mode 100644 rtdata/images/svg/histogram-bayer-off-small.svg delete mode 100644 rtdata/images/svg/histogram-type-histogram-off-small.svg rename rtdata/images/svg/{histogram-bayer-on-small.svg => histogram-type-histogram-raw-small.svg} (100%) delete mode 100644 rtdata/images/svg/histogram-type-parade-off-small.svg delete mode 100644 rtdata/images/svg/histogram-type-vectorscope-hc-off-small.svg delete mode 100644 rtdata/images/svg/histogram-type-vectorscope-hs-off-small.svg delete mode 100644 rtdata/images/svg/histogram-type-waveform-off-small.svg diff --git a/rtdata/images/svg/histogram-bayer-off-small.svg b/rtdata/images/svg/histogram-bayer-off-small.svg deleted file mode 100644 index 5d6c439fb..000000000 --- a/rtdata/images/svg/histogram-bayer-off-small.svg +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - Maciej Dworak - - - - - - - - RawTherapee icon. - - - - - - - - - - - - - - - - - - - - diff --git a/rtdata/images/svg/histogram-type-histogram-off-small.svg b/rtdata/images/svg/histogram-type-histogram-off-small.svg deleted file mode 100644 index 456ead7e2..000000000 --- a/rtdata/images/svg/histogram-type-histogram-off-small.svg +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - Lawrence Lee - - - - - - - - RawTherapee icon. - - - - - - - - - - - - - - - - - - diff --git a/rtdata/images/svg/histogram-bayer-on-small.svg b/rtdata/images/svg/histogram-type-histogram-raw-small.svg similarity index 100% rename from rtdata/images/svg/histogram-bayer-on-small.svg rename to rtdata/images/svg/histogram-type-histogram-raw-small.svg diff --git a/rtdata/images/svg/histogram-type-parade-off-small.svg b/rtdata/images/svg/histogram-type-parade-off-small.svg deleted file mode 100644 index 015960fcc..000000000 --- a/rtdata/images/svg/histogram-type-parade-off-small.svg +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - Lawrence Lee - - - - - - - - RawTherapee icon. - - - - - - - - - - - - - - - - - - - - diff --git a/rtdata/images/svg/histogram-type-vectorscope-hc-off-small.svg b/rtdata/images/svg/histogram-type-vectorscope-hc-off-small.svg deleted file mode 100644 index 3a105a671..000000000 --- a/rtdata/images/svg/histogram-type-vectorscope-hc-off-small.svg +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - Lawrence Lee - - - - - - - - RawTherapee icon. - - - - - - - - - - - - - - - - - - - - diff --git a/rtdata/images/svg/histogram-type-vectorscope-hs-off-small.svg b/rtdata/images/svg/histogram-type-vectorscope-hs-off-small.svg deleted file mode 100644 index 253d2d9c3..000000000 --- a/rtdata/images/svg/histogram-type-vectorscope-hs-off-small.svg +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - Lawrence Lee - - - - - - - - RawTherapee icon. - - - - - - - - - - - - - - - - - - - - - diff --git a/rtdata/images/svg/histogram-type-waveform-off-small.svg b/rtdata/images/svg/histogram-type-waveform-off-small.svg deleted file mode 100644 index 787d6fe09..000000000 --- a/rtdata/images/svg/histogram-type-waveform-off-small.svg +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - Lawrence Lee - - - - - - - - RawTherapee icon. - - - - - - - - - - - - - - - - - - diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index 76f0004ee..07877c33f 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -720,6 +720,19 @@ flowboxchild:selected { margin: 0; } +/* Copied from button.flat style. */ +button.radio#histButton { + background-image: none; +} + +button.radio#histButton:checked { + background-image: linear-gradient(#343434, #2E2E2E, #292929); +} + +button.radio#histButton:hover { + background-image: linear-gradient(shade(#343434,1.3), shade(#2E2E2E,1.3), shade(#292929,1.3)); +} + /*** end ***************************************************************************************/ #MyExpander { diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css index ce4bb8d28..af3445650 100644 --- a/rtdata/themes/TooWaBlue-GTK3-20_.css +++ b/rtdata/themes/TooWaBlue-GTK3-20_.css @@ -453,6 +453,26 @@ filechooser placessidebar list row:selected { padding-bottom: 0.25em; margin: 0; } +/* Copied from button.flat style. */ +button.radio#histButton { + border: 0.083333333333333333em solid transparent; + box-shadow: none; + background-image: none; + background-color: transparent; +} +button.radio#histButton:hover { + border-color: @bg-button-border; + box-shadow: inset 0 0.083333333333333333em rgba(242, 242, 242, 0.1); + background-image: linear-gradient(to bottom, rgba(100,100,100,.3), rgba(30,30,30,.3)); + background-color: @bg-button-hover; +} +button.radio#histButton:active, +button.radio#histButton:checked { + border-color: @bg-button-border; + box-shadow: inset 0 0.1em rgba(242, 242, 242, 0.08); + background-image: linear-gradient(to bottom, rgba(100,100,100,.3), rgba(30,30,30,.3)); + background-color: @bg-button-active; +} /*** end ***************************************************************************************/ diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 480a80c92..8946a5e35 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -128,18 +128,12 @@ HistogramPanel::HistogramPanel () : mode1Image = new RTImage ("histogram-mode-logx-small.png"); mode2Image = new RTImage ("histogram-mode-logxy-small.png"); - histImageOn.reset(new RTImage("histogram-type-histogram-small.png")); - histRawImageOn.reset(new RTImage("histogram-bayer-on-small.png")); - paradeImageOn.reset(new RTImage("histogram-type-parade-small.png")); - waveImageOn.reset(new RTImage("histogram-type-waveform-small.png")); - vectHcImageOn.reset(new RTImage("histogram-type-vectorscope-hc-small.png")); - vectHsImageOn.reset(new RTImage("histogram-type-vectorscope-hs-small.png")); - histImageOff.reset(new RTImage("histogram-type-histogram-off-small.png")); - histRawImageOff.reset(new RTImage("histogram-bayer-off-small.png")); - paradeImageOff.reset(new RTImage("histogram-type-parade-off-small.png")); - waveImageOff.reset(new RTImage("histogram-type-waveform-off-small.png")); - vectHcImageOff.reset(new RTImage("histogram-type-vectorscope-hc-off-small.png")); - vectHsImageOff.reset(new RTImage("histogram-type-vectorscope-hs-off-small.png")); + Gtk::Image* histImage = Gtk::manage(new RTImage("histogram-type-histogram-small.png")); + Gtk::Image* histRawImage = Gtk::manage(new RTImage("histogram-type-histogram-raw-small.png")); + Gtk::Image* paradeImage = Gtk::manage(new RTImage("histogram-type-parade-small.png")); + Gtk::Image* waveImage = Gtk::manage(new RTImage("histogram-type-waveform-small.png")); + Gtk::Image* vectHcImage = Gtk::manage(new RTImage("histogram-type-vectorscope-hc-small.png")); + Gtk::Image* vectHsImage = Gtk::manage(new RTImage("histogram-type-vectorscope-hs-small.png")); showRed = Gtk::manage (new Gtk::ToggleButton ()); showGreen = Gtk::manage (new Gtk::ToggleButton ()); @@ -249,36 +243,30 @@ HistogramPanel::HistogramPanel () : showMode->set_image(*mode1Image); else showMode->set_image(*mode2Image); - scopeHistBtn->set_image(*histImageOff); - scopeHistRawBtn->set_image(*histRawImageOff); - scopeParadeBtn->set_image(*paradeImageOff); - scopeWaveBtn->set_image(*waveImageOff); - scopeVectHcBtn->set_image(*vectHcImageOff); - scopeVectHsBtn->set_image(*vectHsImageOff); + scopeHistBtn->set_image(*histImage); + scopeHistRawBtn->set_image(*histRawImage); + scopeParadeBtn->set_image(*paradeImage); + scopeWaveBtn->set_image(*waveImage); + scopeVectHcBtn->set_image(*vectHcImage); + scopeVectHsBtn->set_image(*vectHsImage); switch(options.histogramScopeType) { case ScopeType::HISTOGRAM: scopeHistBtn->set_active(); - scopeHistBtn->set_image(*histImageOn); break; case ScopeType::HISTOGRAM_RAW: scopeHistRawBtn->set_active(); - scopeHistRawBtn->set_image(*histRawImageOn); break; case ScopeType::PARADE: scopeParadeBtn->set_active(); - scopeParadeBtn->set_image(*paradeImageOn); break; case ScopeType::WAVEFORM: scopeWaveBtn->set_active(); - scopeWaveBtn->set_image(*waveImageOn); break; case ScopeType::VECTORSCOPE_HS: scopeVectHsBtn->set_active(); - scopeVectHsBtn->set_image(*vectHsImageOn); break; case ScopeType::VECTORSCOPE_HC: scopeVectHcBtn->set_active(); - scopeVectHcBtn->set_image(*vectHcImageOn); break; case ScopeType::NONE: break; @@ -294,6 +282,13 @@ HistogramPanel::HistogramPanel () : setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(scopeOptions, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(scopeOptions, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeHistBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeHistRawBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeParadeBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeWaveBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeVectHcBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeVectHsBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); setExpandAlignProperties(persistentButtons, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); setExpandAlignProperties(optionButtons, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); @@ -321,7 +316,7 @@ HistogramPanel::HistogramPanel () : optionButtons->add(*showBAR); Gtk::VSeparator* separator = Gtk::manage(new Gtk::VSeparator()); - setExpandAlignProperties(separator, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_END); + setExpandAlignProperties(separator, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); persistentButtons->add(*scopeHistBtn); persistentButtons->add(*scopeHistRawBtn); persistentButtons->add(*scopeParadeBtn); @@ -495,52 +490,6 @@ void HistogramPanel::type_selected(Gtk::RadioButton* button) return; } - switch (options.histogramScopeType) { - case ScopeType::HISTOGRAM: - scopeHistBtn->set_image(*histImageOff); - break; - case ScopeType::HISTOGRAM_RAW: - scopeHistRawBtn->set_image(*histRawImageOff); - break; - case ScopeType::PARADE: - scopeParadeBtn->set_image(*paradeImageOff); - break; - case ScopeType::WAVEFORM: - scopeWaveBtn->set_image(*waveImageOff); - break; - case ScopeType::VECTORSCOPE_HC: - scopeVectHcBtn->set_image(*vectHcImageOff); - break; - case ScopeType::VECTORSCOPE_HS: - scopeVectHsBtn->set_image(*vectHsImageOff); - break; - case ScopeType::NONE: - break; - } - - switch (new_type) { - case ScopeType::HISTOGRAM: - scopeHistBtn->set_image(*histImageOn); - break; - case ScopeType::HISTOGRAM_RAW: - scopeHistRawBtn->set_image(*histRawImageOn); - break; - case ScopeType::PARADE: - scopeParadeBtn->set_image(*paradeImageOn); - break; - case ScopeType::WAVEFORM: - scopeWaveBtn->set_image(*waveImageOn); - break; - case ScopeType::VECTORSCOPE_HC: - scopeVectHcBtn->set_image(*vectHcImageOn); - break; - case ScopeType::VECTORSCOPE_HS: - scopeVectHsBtn->set_image(*vectHsImageOn); - break; - case ScopeType::NONE: - break; - } - options.histogramScopeType = new_type; type_changed(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 5ecf378b8..7cf1c5e6f 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -292,19 +292,6 @@ protected: Gtk::Image *barImage_g; Gtk::Image *chroImage_g; - std::unique_ptr histImageOn; - std::unique_ptr histRawImageOn; - std::unique_ptr paradeImageOn; - std::unique_ptr waveImageOn; - std::unique_ptr vectHcImageOn; - std::unique_ptr vectHsImageOn; - std::unique_ptr histImageOff; - std::unique_ptr histRawImageOff; - std::unique_ptr paradeImageOff; - std::unique_ptr waveImageOff; - std::unique_ptr vectHcImageOff; - std::unique_ptr vectHsImageOff; - Gtk::Image *mode0Image; Gtk::Image *mode1Image; Gtk::Image *mode2Image; From c335e7ba246b842c036fd7a18e7d83ceb153b0ba Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 10 Oct 2020 11:56:13 -0700 Subject: [PATCH 50/56] Fix bug with vectorscope not updating The scope would not redraw after switching from one vectorscope to another. This commit sets the drawing area dirty when the scope type changes. --- rtgui/histogrampanel.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 8946a5e35..63d299fa5 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -497,6 +497,8 @@ void HistogramPanel::type_selected(Gtk::RadioButton* button) if (histogramRGBArea) { updateHistRGBAreaOptions(); } + histogramArea->setDirty(true); + histogramArea->queue_draw(); } void HistogramPanel::type_changed() From ee1c85879d1ac6175a745e6cfe2d4e3f63fb9583 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 10 Oct 2020 12:11:59 -0700 Subject: [PATCH 51/56] Suppress unnecessary updates to scope back buffer Upon the resize signal, the scope back buffers were redrawn, even if there was no actual change to the size. This commit checks the size and only updates the back buffers if the size changed. --- rtgui/histogrampanel.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 63d299fa5..8742c8bb0 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -403,14 +403,19 @@ void HistogramPanel::showRGBBar() void HistogramPanel::resized (Gtk::Allocation& req) { + static int old_height = 0; + static int old_width = 0; - if (!histogramArea->updatePending()) { + bool size_changed = + old_height != req.get_height() || old_width != req.get_width(); + + if (!histogramArea->updatePending() && size_changed) { histogramArea->updateBackBuffer (); histogramArea->queue_draw (); } // set histogramRGBArea invalid; - if (histogramRGBArea) { + if (histogramRGBArea && size_changed) { histogramRGBArea->updateBackBuffer(-1, -1, -1); histogramRGBArea->queue_draw (); } @@ -418,6 +423,8 @@ void HistogramPanel::resized (Gtk::Allocation& req) // Store current height of the histogram options.histogramHeight = get_height(); + old_height = req.get_height(); + old_width = req.get_width(); } void HistogramPanel::red_toggled () @@ -589,7 +596,7 @@ void HistogramPanel::rgbv_toggled () if (histogramRGBArea) { updateHistRGBAreaOptions(); - histogramRGBArea->updateBackBuffer (0, 0, 0); + histogramRGBArea->updateBackBuffer(-1, -1, -1); histogramRGBArea->queue_draw (); } } From 992a5ad3d99e8786bdc1a4304723c8d48cd2383d Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 10 Oct 2020 15:15:28 -0700 Subject: [PATCH 52/56] Change how histogram RGB indicators are rendered Show/hide them instead of removing/adding and fix the width of the vertical indicator. --- rtgui/histogrampanel.cc | 71 ++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 47 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 8742c8bb0..1165881a5 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -73,11 +73,9 @@ HistogramPanel::HistogramPanel () : histogramRGBAreaHori.reset(new HistogramRGBAreaHori()); setExpandAlignProperties(histogramRGBAreaHori.get(), true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_END); - histogramRGBAreaHori->show(); histogramRGBAreaVert.reset(new HistogramRGBAreaVert()); setExpandAlignProperties(histogramRGBAreaVert.get(), false, true, Gtk::ALIGN_END, Gtk::ALIGN_FILL); - histogramRGBAreaVert->show(); switch (options.histogramScopeType) { case ScopeType::NONE: @@ -102,13 +100,14 @@ HistogramPanel::HistogramPanel () : gfxGrid = Gtk::manage (new Gtk::Grid ()); gfxGrid->set_row_spacing(1); gfxGrid->set_column_spacing(1); - histogramRGBAreaHori->setParent(gfxGrid); - histogramRGBAreaVert->setParent(gfxGrid); gfxGrid->add(*histogramArea); - - if (options.histogramBar) { - showRGBBar(); - } + gfxGrid->attach_next_to( + *histogramRGBAreaVert, *histogramArea, + options.histogramPosition == 1 ? Gtk::POS_RIGHT : Gtk::POS_LEFT + ); + gfxGrid->attach_next_to(*histogramRGBAreaHori, *histogramArea, Gtk::POS_BOTTOM); + histogramRGBAreaHori->set_no_show_all(); + histogramRGBAreaVert->set_no_show_all(); redImage = new RTImage ("histogram-red-on-small.png"); greenImage = new RTImage ("histogram-green-on-small.png"); @@ -379,26 +378,19 @@ HistogramPanel::~HistogramPanel () void HistogramPanel::showRGBBar() { - Gtk::PositionType pos; + histogramRGBAreaHori->set_visible( + histogramRGBArea == histogramRGBAreaHori.get() && showBAR->get_active()); + histogramRGBAreaVert->set_visible( + histogramRGBArea == histogramRGBAreaVert.get() && showBAR->get_active()); + histogramRGBAreaHori->setShow(false); + histogramRGBAreaVert->setShow(false); - if (histogramRGBArea == histogramRGBAreaHori.get()) { - pos = Gtk::POS_BOTTOM; - } else if (histogramRGBArea == nullptr) { + if (!histogramRGBArea) { return; - } else { - if (options.histogramPosition == 1) { - pos = Gtk::POS_RIGHT; - } else { - pos = Gtk::POS_LEFT; - } } - gfxGrid->attach_next_to(*histogramRGBArea, *histogramArea, pos); setHistRGBInvalid(); - histogramRGBArea->setShow( - options.histogramScopeType == ScopeType::HISTOGRAM - || options.histogramScopeType == ScopeType::WAVEFORM - ); + histogramRGBArea->setShow(showBAR->get_active()); } void HistogramPanel::resized (Gtk::Allocation& req) @@ -510,11 +502,6 @@ void HistogramPanel::type_selected(Gtk::RadioButton* button) void HistogramPanel::type_changed() { - if (showBAR->get_active() && histogramRGBArea) { - histogramRGBArea->setShow(false); - gfxGrid->remove(*histogramRGBArea); - } - switch (options.histogramScopeType) { case ScopeType::HISTOGRAM: showRed->show(); @@ -570,21 +557,14 @@ void HistogramPanel::type_changed() panel_listener->scopeTypeChanged(options.histogramScopeType); } - if (showBAR->get_active()) { - showRGBBar(); - } + showRGBBar(); } void HistogramPanel::bar_toggled () { showBAR->set_image(showBAR->get_active() ? *barImage : *barImage_g); rgbv_toggled(); - - if (showBAR->get_active()) { - showRGBBar(); - } else if (histogramRGBArea) { - gfxGrid->remove(*histogramRGBArea); - } + showRGBBar(); } void HistogramPanel::rgbv_toggled () @@ -625,10 +605,8 @@ void HistogramPanel::reorder (Gtk::PositionType align) add (*gfxGrid); gfxGrid->unreference(); - if (histogramRGBArea == histogramRGBAreaVert.get()) { - gfxGrid->remove(*histogramRGBArea); - gfxGrid->add(*histogramRGBArea); - } + gfxGrid->remove(*histogramRGBAreaVert); + gfxGrid->add(*histogramRGBAreaVert); optionButtons->reference(); removeIfThere(buttonGrid, optionButtons, false); @@ -640,10 +618,8 @@ void HistogramPanel::reorder (Gtk::PositionType align) add (*buttonGrid); buttonGrid->unreference(); - if (histogramRGBArea == histogramRGBAreaVert.get()) { - gfxGrid->remove(*histogramArea); - gfxGrid->add(*histogramArea); - } + gfxGrid->remove(*histogramRGBAreaVert); + gfxGrid->attach_next_to(*histogramRGBAreaVert, *histogramArea, Gtk::POS_LEFT); persistentButtons->reference(); removeIfThere(buttonGrid, persistentButtons, false); @@ -1021,7 +997,8 @@ void HistogramRGBAreaVert::get_preferred_height_vfunc (int &minimum_height, int void HistogramRGBAreaVert::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const { - getPreferredThickness(minimum_width, natural_width); + minimum_width = 10 * RTScalable::getScale(); + natural_width = minimum_width; } void HistogramRGBAreaVert::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const @@ -1031,7 +1008,7 @@ void HistogramRGBAreaVert::get_preferred_height_for_width_vfunc (int width, int void HistogramRGBAreaVert::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const { - getPreferredThicknessForLength(height, minimum_width, natural_width); + get_preferred_width_vfunc(minimum_width, natural_width); } // From e93c4f6ed4bc10457961cb86a773b932646881e9 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 11 Oct 2020 12:29:47 -0700 Subject: [PATCH 53/56] Add slider for adjusting scope trace brightness This makes it easier for users to discover the feature and see the current brightness. --- rtdata/languages/default | 1 + rtdata/themes/RawTherapee-GTK3-20_.css | 17 ++++++ rtdata/themes/TooWaBlue-GTK3-20_.css | 21 ++++++++ rtgui/histogrampanel.cc | 72 ++++++++++++++++++++------ rtgui/histogrampanel.h | 13 +++++ 5 files changed, 109 insertions(+), 15 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index d7f5734ae..e7c47e50d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -251,6 +251,7 @@ HISTOGRAM_TOOLTIP_MODE;Toggle between linear, log-linear and log-log scaling of HISTOGRAM_TOOLTIP_R;Show/Hide red histogram. HISTOGRAM_TOOLTIP_RAW;Show/Hide raw histogram. HISTOGRAM_TOOLTIP_SHOW_OPTIONS;Toggle visibility of the scope option buttons. +HISTOGRAM_TOOLTIP_TRACE_BRIGHTNESS;Adjust scope brightness. HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM;Histogram HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW;Raw Histogram HISTOGRAM_TOOLTIP_TYPE_PARADE;RGB Parade diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index 07877c33f..f4f9ddb7f 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -720,6 +720,23 @@ flowboxchild:selected { margin: 0; } +/* Vertical version of slider. */ +#histScale { + min-height: 4em; + min-width: 0.4166666666666666em; + margin: 0.5833333333333333em 0 0 0; +} +#histScale trough { + padding: 0.583333333333333333em 0; +} +#histScale trough highlight { + margin: -0.583333333333333333em 0; + padding: 0.1em 0 0 0.1em; +} +#histScale.fine-tune trough highlight { + padding: 0.5em 0 0 0.5em; +} + /* Copied from button.flat style. */ button.radio#histButton { background-image: none; diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css index af3445650..c4300413e 100644 --- a/rtdata/themes/TooWaBlue-GTK3-20_.css +++ b/rtdata/themes/TooWaBlue-GTK3-20_.css @@ -453,6 +453,27 @@ filechooser placessidebar list row:selected { padding-bottom: 0.25em; margin: 0; } + +/* Vertical version of slider. */ +#histScale { + min-height: 4em; + min-width: 1.833333333333333333em; + margin: -0.333333333333333333em 0; +} +#histScale trough { + padding: 0.583333333333333333em 0; +} +#histScale highlight { + background-image: linear-gradient(to right, shade (@accent-color2,1.22), shade(@accent-color2,.88)); + margin: -0.583333333333333333em 0; + padding: 0.333333333333333333em 0 0 0.333333333333333333em; +} +#histScale slider { +} +#histScale.fine-tune highlight { + padding: 0.5em 0 0 0.5em; +} + /* Copied from button.flat style. */ button.radio#histButton { border: 0.083333333333333333em solid transparent; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 1165881a5..3c7a3e631 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -273,14 +273,14 @@ HistogramPanel::HistogramPanel () : scopeOptions->set_image(*Gtk::manage(new RTImage("histogram-ellipsis-small.png"))); showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); - setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showBlue , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showValue, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showBlue , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showValue, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); setExpandAlignProperties(scopeOptions, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); setExpandAlignProperties(scopeOptions, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); setExpandAlignProperties(scopeHistBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); setExpandAlignProperties(scopeHistRawBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); @@ -306,6 +306,15 @@ HistogramPanel::HistogramPanel () : scopeVectHcBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHcBtn)); scopeVectHsBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHsBtn)); + brightnessWidget = Gtk::manage(new Gtk::Scale(Gtk::ORIENTATION_VERTICAL)); + brightnessWidget->set_inverted(); + brightnessWidget->set_range(log(HistogramArea::MIN_BRIGHT), log(HistogramArea::MAX_BRIGHT)); + brightnessWidget->set_draw_value(false); + brightnessWidget->signal_value_changed().connect(sigc::mem_fun(*this, &HistogramPanel::brightnessWidgetValueChanged)); + brightnessWidget->set_name("histScale"); + brightnessWidget->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TRACE_BRIGHTNESS")); + setExpandAlignProperties(brightnessWidget, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + optionButtons->add(*showRed); optionButtons->add(*showGreen); optionButtons->add(*showBlue); @@ -313,6 +322,7 @@ HistogramPanel::HistogramPanel () : optionButtons->add(*showChro); optionButtons->add(*showMode); optionButtons->add(*showBAR); + optionButtons->add(*brightnessWidget); Gtk::VSeparator* separator = Gtk::manage(new Gtk::VSeparator()); setExpandAlignProperties(separator, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); @@ -350,6 +360,7 @@ HistogramPanel::HistogramPanel () : updateHistRGBAreaOptions(); } + brightness_changed_connection = histogramArea->getBrighnessChangedSignal().connect(sigc::mem_fun(*this, &HistogramPanel::brightnessUpdated)); rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); } @@ -461,6 +472,17 @@ void HistogramPanel::mode_released () rgbv_toggled(); } +void HistogramPanel::brightnessWidgetValueChanged(void) +{ + ConnectionBlocker blocker(brightness_changed_connection); + histogramArea->setBrightness(exp(brightnessWidget->get_value())); +} + +void HistogramPanel::brightnessUpdated(float brightness) +{ + brightnessWidget->set_value(log(brightness)); +} + void HistogramPanel::scopeOptionsToggled() { options.histogramShowOptionButtons = scopeOptions->get_active(); @@ -512,6 +534,7 @@ void HistogramPanel::type_changed() showMode->show(); showBAR->show(); showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_BAR")); + brightnessWidget->hide(); histogramRGBArea = histogramRGBAreaHori.get(); break; case ScopeType::HISTOGRAM_RAW: @@ -522,6 +545,7 @@ void HistogramPanel::type_changed() showChro->hide(); showMode->show(); showBAR->hide(); + brightnessWidget->hide(); histogramRGBArea = nullptr; break; case ScopeType::PARADE: @@ -534,6 +558,7 @@ void HistogramPanel::type_changed() showMode->hide(); showBAR->show(); showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_BAR")); + brightnessWidget->show(); histogramRGBArea = histogramRGBAreaVert.get(); break; case ScopeType::VECTORSCOPE_HC: @@ -546,6 +571,7 @@ void HistogramPanel::type_changed() showMode->hide(); showBAR->show(); showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_CROSSHAIR")); + brightnessWidget->show(); histogramRGBArea = nullptr; break; case ScopeType::NONE: @@ -1921,23 +1947,39 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) || scopeType == ScopeType::VECTORSCOPE_HC || scopeType == ScopeType::VECTORSCOPE_HS ) { // Adjust brightness. - constexpr float MIN_BRIGHT = 0.1; - constexpr float MAX_BRIGHT = 3; constexpr float RANGE = MAX_BRIGHT / MIN_BRIGHT; double dx = (event->x - movingPosition) / get_width(); float new_brightness = LIM(trace_brightness * pow(RANGE, dx), MIN_BRIGHT, MAX_BRIGHT); - if (new_brightness != trace_brightness) { - parade_buffer_r_dirty = parade_buffer_g_dirty = parade_buffer_b_dirty = wave_buffer_dirty = wave_buffer_luma_dirty = vect_hc_buffer_dirty = vect_hs_buffer_dirty = true; - trace_brightness = new_brightness; - setDirty(true); - queue_draw(); - } + setBrightness(new_brightness); movingPosition = event->x; } return true; } +float HistogramArea::getBrightness(void) +{ + return trace_brightness; +} + +void HistogramArea::setBrightness(float brightness) +{ + brightness = LIM(brightness, MIN_BRIGHT, MAX_BRIGHT); + if (brightness != trace_brightness) { + parade_buffer_r_dirty = parade_buffer_g_dirty = parade_buffer_b_dirty = wave_buffer_dirty = wave_buffer_luma_dirty = vect_hc_buffer_dirty = vect_hs_buffer_dirty = true; + trace_brightness = brightness; + setDirty(true); + queue_draw(); + + signal_brightness_changed.emit(trace_brightness); + } +} + +HistogramArea::SignalBrightnessChanged HistogramArea::getBrighnessChangedSignal(void) +{ + return signal_brightness_changed; +} + HistogramArea::type_signal_factor_changed HistogramArea::signal_factor_changed() { return sigFactorChanged; diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 7cf1c5e6f..393df51a5 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -152,7 +152,10 @@ class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private { public: typedef sigc::signal type_signal_factor_changed; + typedef sigc::signal SignalBrightnessChanged; + static constexpr float MIN_BRIGHT = 0.1; + static constexpr float MAX_BRIGHT = 3; private: IdleRegister idle_register; type_signal_factor_changed sigFactorChanged; @@ -194,6 +197,8 @@ protected: int pointer_red, pointer_green, pointer_blue; float pointer_a, pointer_b; + SignalBrightnessChanged signal_brightness_changed; + public: explicit HistogramArea(DrawModeListener *fml = nullptr); ~HistogramArea() override; @@ -226,6 +231,10 @@ public: bool on_button_press_event (GdkEventButton* event) override; bool on_button_release_event (GdkEventButton* event) override; bool on_motion_notify_event (GdkEventMotion* event) override; + float getBrightness(void); + /** Set the trace brightness, with 1 being normal. */ + void setBrightness(float brightness); + SignalBrightnessChanged getBrighnessChangedSignal(void); type_signal_factor_changed signal_factor_changed(); private: @@ -270,6 +279,7 @@ protected: Gtk::ToggleButton* showChro; Gtk::Button* showMode; Gtk::ToggleButton* scopeOptions; + Gtk::Scale* brightnessWidget; Gtk::RadioButton* scopeHistBtn; Gtk::RadioButton* scopeHistRawBtn; @@ -298,6 +308,7 @@ protected: HistogramPanelListener* panel_listener; + sigc::connection brightness_changed_connection; sigc::connection rconn; void setHistInvalid (); void showRGBBar(); @@ -344,6 +355,8 @@ public: void chro_toggled (); void bar_toggled (); void mode_released (); + void brightnessWidgetValueChanged(); + void brightnessUpdated(float brightness); void scopeOptionsToggled(); void type_selected(Gtk::RadioButton* button); void type_changed (); From 01ad249718933ea4797462b4c0f9ff52c79724d3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Thu, 15 Oct 2020 21:09:13 -0700 Subject: [PATCH 54/56] Make scope trace brightness persistent --- rtgui/histogrampanel.cc | 4 ++++ rtgui/options.cc | 6 ++++++ rtgui/options.h | 1 + 3 files changed, 11 insertions(+) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 3c7a3e631..2655897e3 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -362,6 +362,8 @@ HistogramPanel::HistogramPanel () : brightness_changed_connection = histogramArea->getBrighnessChangedSignal().connect(sigc::mem_fun(*this, &HistogramPanel::brightnessUpdated)); rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); + + histogramArea->setBrightness(options.histogramTraceBrightness); } HistogramPanel::~HistogramPanel () @@ -476,11 +478,13 @@ void HistogramPanel::brightnessWidgetValueChanged(void) { ConnectionBlocker blocker(brightness_changed_connection); histogramArea->setBrightness(exp(brightnessWidget->get_value())); + options.histogramTraceBrightness = histogramArea->getBrightness(); } void HistogramPanel::brightnessUpdated(float brightness) { brightnessWidget->set_value(log(brightness)); + options.histogramTraceBrightness = histogramArea->getBrightness(); } void HistogramPanel::scopeOptionsToggled() diff --git a/rtgui/options.cc b/rtgui/options.cc index 494a1ec3f..46d9b9ca5 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -451,6 +451,7 @@ void Options::setDefaults() histogramDrawMode = 0; histogramScopeType = ScopeType::HISTOGRAM; histogramShowOptionButtons = false; + histogramTraceBrightness = 1; curvebboxpos = 1; complexity = 2; prevdemo = PD_Sidecar; @@ -1444,6 +1445,10 @@ void Options::readFromFile(Glib::ustring fname) histogramShowOptionButtons = keyFile.get_boolean("GUI", "HistogramShowOptionButtons"); } + if (keyFile.has_key("GUI", "HistogramTraceBrightness")) { + histogramTraceBrightness = keyFile.get_double("GUI", "HistogramTraceBrightness"); + } + if (keyFile.has_key("GUI", "NavigatorRGBUnit")) { navRGBUnit = (NavigatorUnit)keyFile.get_integer("GUI", "NavigatorRGBUnit"); } @@ -2268,6 +2273,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("GUI", "HistogramDrawMode", histogramDrawMode); keyFile.set_integer("GUI", "HistogramScopeType", rtengine::toUnderlying(histogramScopeType)); keyFile.set_boolean("GUI", "HistogramShowOptionButtons", histogramShowOptionButtons); + keyFile.set_double("GUI", "HistogramTraceBrightness", histogramTraceBrightness); keyFile.set_integer("GUI", "NavigatorRGBUnit", (int)navRGBUnit); keyFile.set_integer("GUI", "NavigatorHSVUnit", (int)navHSVUnit); keyFile.set_boolean("GUI", "ShowFilmStripToolBar", showFilmStripToolBar); diff --git a/rtgui/options.h b/rtgui/options.h index 476af79ec..d2e0c0543 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -324,6 +324,7 @@ public: int histogramDrawMode; ScopeType histogramScopeType; bool histogramShowOptionButtons; + float histogramTraceBrightness; bool FileBrowserToolbarSingleRow; bool hideTPVScrollbar; int whiteBalanceSpotSize; From cfb22d555022884f9cade07eded320f644e5a794 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Thu, 15 Oct 2020 21:13:01 -0700 Subject: [PATCH 55/56] Fix signed comparison compiler warning --- rtgui/histogrampanel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 2655897e3..bbad4ecf3 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1604,7 +1604,7 @@ void HistogramArea::drawParade(Cairo::RefPtr &cr, int w, int h) auto orig_matrix = cr->get_matrix(); const double display_wave_width = static_cast(w) / buffers.size(); - for (int i = 0; i < buffers.size(); i++) { + for (unsigned i = 0; i < buffers.size(); i++) { Cairo::RefPtr surface; cr->translate(i * display_wave_width, padding); cr->scale(display_wave_width / wave_width, (h - 2 * padding) / wave_height); From 044d16503c55f3b310307c324960efa207122225 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Fri, 16 Oct 2020 17:15:03 -0700 Subject: [PATCH 56/56] Fix undefined reference compilation error The debug build failed to compile due to undefined reference to HistogramArea::MAX_BRIGHT and HistogramArea::MIN_BRIGHT. Co-authored-by: Ingo Weyrich --- rtgui/histogrampanel.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index bbad4ecf3..d7e9bbc69 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -29,6 +29,9 @@ using namespace rtengine; +constexpr float HistogramArea::MAX_BRIGHT; +constexpr float HistogramArea::MIN_BRIGHT; + using ScopeType = Options::ScopeType; //