diff --git a/toonz/sources/include/tools/tool.h b/toonz/sources/include/tools/tool.h index 39af9a4..28f5e16 100644 --- a/toonz/sources/include/tools/tool.h +++ b/toonz/sources/include/tools/tool.h @@ -59,9 +59,6 @@ class ToolOptionsBox; class QMenu; -// iwsw commented out -// class Ghibli3DLutUtil; - //=================================================================== //***************************************************************************************** @@ -655,8 +652,8 @@ public: /*-- Toolで画面の内外を判断するため --*/ virtual TRectD getGeometry() const = 0; - // iwsw commented out - // virtual Ghibli3DLutUtil* get3DLutUtil(){ return 0; } + virtual void bindFBO() {} + virtual void releaseFBO() {} }; #endif diff --git a/toonz/sources/include/toonz/preferences.h b/toonz/sources/include/toonz/preferences.h index 801ca00..69dbf6d 100644 --- a/toonz/sources/include/toonz/preferences.h +++ b/toonz/sources/include/toonz/preferences.h @@ -235,6 +235,15 @@ public: void setInterfaceFontWeight(int weight); int getInterfaceFontWeight() { return m_interfaceFontWeight; } + // color calibration using 3DLUT + void enableColorCalibration(bool on); + bool isColorCalibrationEnabled() const { return m_colorCalibrationEnabled; } + void setColorCalibrationLutPath(QString monitorName, QString path); + QMap &getColorCalibrationLutPathMap() { + return m_colorCalibrationLutPaths; + } + QString getColorCalibrationLutPath(QString &monitorName) const; + // Visualization tab void setShow0ThickLines(bool on); @@ -652,6 +661,12 @@ private: bool m_currentTimelineEnabled; + // color calibration using 3DLUT + bool m_colorCalibrationEnabled = true; //とりあえず + // map of [monitor name]-[path to the lut file]. + // for now non-Windows accepts only one lut path for all kinds of monitors + QMap m_colorCalibrationLutPaths; + private: Preferences(); ~Preferences(); diff --git a/toonz/sources/include/toonzqt/lutcalibrator.h b/toonz/sources/include/toonzqt/lutcalibrator.h new file mode 100644 index 0000000..f70981b --- /dev/null +++ b/toonz/sources/include/toonzqt/lutcalibrator.h @@ -0,0 +1,78 @@ +#pragma once + +#ifndef LUT_CALIBRATOR_H +#define LUT_CALIBRATOR_H + +#include "tcommon.h" +#include "tpixelutils.h" + +#include +#include +#include + +#undef DVAPI +#undef DVVAR +#ifdef TOONZQT_EXPORTS +#define DVAPI DV_EXPORT_API +#define DVVAR DV_EXPORT_VAR +#else +#define DVAPI DV_IMPORT_API +#define DVVAR DV_IMPORT_VAR +#endif + +class QOpenGLShader; +class QOpenGLShaderProgram; +class QOpenGLFramebufferObject; +class QOpenGLTexture; + +class QColor; + +class DVAPI LutCalibrator : public QOpenGLFunctions // sigleton +{ + bool m_isValid = false; + + struct LutTextureShader { + QOpenGLShader* vert = nullptr; + QOpenGLShader* frag = nullptr; + QOpenGLShaderProgram* program = nullptr; + int texUniform = -1; + int lutUniform = -1; + int lutSizeUniform = -1; + int vertexAttrib = -1; + int texCoordAttrib = -1; + } m_shader; + + struct Lut { + int meshSize; + float* data = NULL; + QOpenGLTexture* tex = NULL; + } m_lut; + + QOpenGLBuffer m_viewerVBO; + LutCalibrator() {} + + bool initializeLutTextureShader(); + void createViewerVBO(); + bool loadLutFile(const QString& path); + void assignLutTexture(); + +public: + static LutCalibrator* instance(); + + // to be computed once through the software + void initialize(); + void finalize(); + bool isValid() { return m_isValid; } + + ~LutCalibrator() { finalize(); } + + void onEndDraw(QOpenGLFramebufferObject*); + + QString& getMonitorName() const; + + void convert(float&, float&, float&); + void convert(QColor&); + void convert(TPixel32&); +}; + +#endif \ No newline at end of file diff --git a/toonz/sources/include/toonzqt/styleeditor.h b/toonz/sources/include/toonzqt/styleeditor.h index 8a40c05..040dee9 100644 --- a/toonz/sources/include/toonzqt/styleeditor.h +++ b/toonz/sources/include/toonzqt/styleeditor.h @@ -14,7 +14,6 @@ #include "toonz/tpalettehandle.h" #include "toonz/txshlevelhandle.h" #include "toonz/txshlevel.h" -//#include "toonz/preferences.h" //iwsw commented out temporarily // TnzQt includes #include "toonzqt/checkbox.h" @@ -24,9 +23,6 @@ #include "toonzqt/tabbar.h" #include "toonzqt/glwidget_for_highdpi.h" -// Toonz includes -//#include "../toonz/tapp.h" //iwsw commented out temporarily - // Qt includes #include #include @@ -39,9 +35,6 @@ #include #include -// iwsw commented out temporarily -//#include "ghibli_3dlut_util.h" - #undef DVAPI #undef DVVAR #ifdef TOONZQT_EXPORTS @@ -71,6 +64,7 @@ class QButtonGroup; class QPushButton; class QTabWidget; class QToolBar; +class QOpenGLFramebufferObject; class ColorSquaredWheel; class TabBarContainter; @@ -153,8 +147,8 @@ class DVAPI HexagonalColorWheel final : public GLWidgetForHighDpi { CurrentWheel m_currentWheel; - // iwsw commented out temporarily about 3DLUT - // Ghibli3DLutUtil * m_ghibli3DLutUtil; + // used for color calibration with 3DLUT + QOpenGLFramebufferObject *m_fbo = NULL; private: void drawCurrentColorMark(); diff --git a/toonz/sources/tnztools/brushtool.cpp b/toonz/sources/tnztools/brushtool.cpp index 9c9a7d8..c3a461a 100644 --- a/toonz/sources/tnztools/brushtool.cpp +++ b/toonz/sources/tnztools/brushtool.cpp @@ -2087,8 +2087,8 @@ void BrushTool::checkGuideSnapping(bool beforeMousePress) { snapPoint.x = hGuide; } beforeMousePress ? m_foundFirstSnap = true : m_foundLastSnap = true; - beforeMousePress ? m_firstSnapPoint = snapPoint : m_lastSnapPoint = - snapPoint; + beforeMousePress ? m_firstSnapPoint = snapPoint + : m_lastSnapPoint = snapPoint; } } } diff --git a/toonz/sources/tnztools/rgbpickertool.cpp b/toonz/sources/tnztools/rgbpickertool.cpp index 72b5092..a1c3ebf 100644 --- a/toonz/sources/tnztools/rgbpickertool.cpp +++ b/toonz/sources/tnztools/rgbpickertool.cpp @@ -22,15 +22,13 @@ #include "toonzqt/icongenerator.h" #include "toonzqt/dvdialog.h" +#include "toonzqt/lutcalibrator.h" #include "tools/toolhandle.h" #include "tools/stylepicker.h" #include "tools/toolutils.h" #include "tools/RGBpicker.h" -// iwsw commented out temporarily -//#include "toonzqt/ghibli_3dlut_util.h" - #define NORMAL_PICK L"Normal" #define RECT_PICK L"Rectangular" #define FREEHAND_PICK L"Freehand" @@ -420,8 +418,12 @@ void RGBPickerTool::passivePick() { StylePicker picker(image); + if (LutCalibrator::instance()->isValid()) m_viewer->bindFBO(); + TPixel32 pix = picker.pickColor(area); + if (LutCalibrator::instance()->isValid()) m_viewer->releaseFBO(); + QColor col((int)pix.r, (int)pix.g, (int)pix.b); PaletteController *controller = @@ -444,8 +446,12 @@ void RGBPickerTool::pick() { m_mousePixelPosition.x + 1, m_mousePixelPosition.y + 1); StylePicker picker(image, palette); + if (LutCalibrator::instance()->isValid()) m_viewer->bindFBO(); + m_currentValue = picker.pickColor(area); + if (LutCalibrator::instance()->isValid()) m_viewer->releaseFBO(); + TXshSimpleLevel *level = app->getCurrentLevel()->getSimpleLevel(); UndoPickRGBM *cmd = new UndoPickRGBM(palette, styleId, m_currentValue, level); TUndoManager::manager()->add(cmd); @@ -485,7 +491,11 @@ void RGBPickerTool::pickRect() { if (area.getLx() <= 1 || area.getLy() <= 1) return; StylePicker picker(image, palette); + if (LutCalibrator::instance()->isValid()) m_viewer->bindFBO(); + m_currentValue = picker.pickColor(area); + + if (LutCalibrator::instance()->isValid()) m_viewer->releaseFBO(); } //--------------------------------------------------------- @@ -502,8 +512,12 @@ void RGBPickerTool::pickStroke() { StylePicker picker(image, palette); TStroke *stroke = new TStroke(*m_stroke); + if (LutCalibrator::instance()->isValid()) m_viewer->bindFBO(); + m_currentValue = picker.pickColor(stroke); + if (LutCalibrator::instance()->isValid()) m_viewer->releaseFBO(); + if (!(m_pickType.getValue() == POLYLINE_PICK)) { TXshSimpleLevel *level = app->getCurrentLevel()->getSimpleLevel(); TUndoManager::manager()->add( diff --git a/toonz/sources/tnztools/tooloptions.cpp b/toonz/sources/tnztools/tooloptions.cpp index fdbc903..d67580d 100644 --- a/toonz/sources/tnztools/tooloptions.cpp +++ b/toonz/sources/tnztools/tooloptions.cpp @@ -22,8 +22,7 @@ #include "toonzqt/menubarcommand.h" #include "toonzqt/gutil.h" #include "toonzqt/dvscrollwidget.h" -// iwsw commented out temporarily -//#include "toonzqt/ghibli_3dlut_converter.h" +#include "toonzqt/lutcalibrator.h" // TnzLib includes #include "toonz/tobjecthandle.h" @@ -2279,18 +2278,12 @@ protected: QPainter p(this); p.setPen(Qt::NoPen); - // iwsw commented out temporarily - /* - if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - { - QColor convertedColor(m_color); - Ghibli3DLutConverter::instance()->convert(convertedColor); - p.setBrush(convertedColor); - } - else - */ - p.setBrush(m_color); - p.setBrush(m_color); + if (LutCalibrator::instance()->isValid()) { + QColor convertedColor(m_color); + LutCalibrator::instance()->convert(convertedColor); + p.setBrush(convertedColor); + } else + p.setBrush(m_color); p.drawRect(rect()); diff --git a/toonz/sources/toonz/imageviewer.cpp b/toonz/sources/toonz/imageviewer.cpp index f4abded..77ec6c9 100644 --- a/toonz/sources/toonz/imageviewer.cpp +++ b/toonz/sources/toonz/imageviewer.cpp @@ -20,6 +20,7 @@ #include "toonzqt/menubarcommand.h" #include "toonzqt/viewcommandids.h" #include "toonzqt/imageutils.h" +#include "toonzqt/lutcalibrator.h" // TnzLib includes #include "toonz/tscenehandle.h" @@ -36,6 +37,7 @@ #include #include #include +#include //=================================================================================== @@ -226,11 +228,6 @@ ImageViewer::ImageViewer(QWidget *parent, FlipBook *flipbook, if (m_isHistogramEnable) m_histogramPopup = new HistogramPopup(tr("Flipbook Histogram")); - - // iwsw commented out 2 lines temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // Ghibli3DLutUtil::m_isValid) - // m_ghibli3DLutUtil = new Ghibli3DLutUtil(); } //----------------------------------------------------------------------------- @@ -365,6 +362,7 @@ ImageViewer::~ImageViewer() { delete m_ghibli3DLutUtil; } */ + if (m_fbo) delete m_fbo; } //----------------------------------------------------------------------------- @@ -413,13 +411,12 @@ void ImageViewer::hideHistogram() { void ImageViewer::initializeGL() { initializeOpenGLFunctions(); + + // to be computed once through the software + LutCalibrator::instance()->initialize(); + // glClearColor(1.0,1.0,1.0,1); glClear(GL_COLOR_BUFFER_BIT); - - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->onInit(); } //----------------------------------------------------------------------------- @@ -439,19 +436,17 @@ void ImageViewer::resizeGL(int w, int h) { glTranslatef(0.375, 0.375, 0.0); glTranslated(w * 0.5, h * 0.5, 0); - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->onResize(w, h); + // remake fbo with new size + if (LutCalibrator::instance()->isValid()) { + if (m_fbo) delete m_fbo; + m_fbo = new QOpenGLFramebufferObject(w, h); + } } //----------------------------------------------------------------------------- void ImageViewer::paintGL() { - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->startDraw(); + if (LutCalibrator::instance()->isValid()) m_fbo->bind(); TDimension viewerSize(width(), height()); TAffine aff = m_viewAff; @@ -508,11 +503,8 @@ void ImageViewer::paintGL() { } if (!m_image) { - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->endDraw(); - + if (LutCalibrator::instance()->isValid()) + LutCalibrator::instance()->onEndDraw(m_fbo); return; } @@ -590,10 +582,8 @@ void ImageViewer::paintGL() { } } - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->endDraw(); + if (LutCalibrator::instance()->isValid()) + LutCalibrator::instance()->onEndDraw(m_fbo); } //------------------------------------------------------------------------------ @@ -851,17 +841,11 @@ void ImageViewer::pickColor(QMouseEvent *event, bool putValueToStyleEditor) { TPoint mousePos = TPoint(curPos.x(), height() - 1 - curPos.y()); TRectD area = TRectD(mousePos.x, mousePos.y, mousePos.x, mousePos.y); - // iwsw commented out temporarily - // if (get3DLutUtil() && - // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - // get3DLutUtil()->bindFBO(); + if (LutCalibrator::instance()->isValid()) m_fbo->bind(); const TPixel32 pix = picker.pickColor(area); - // iwsw commented out temporarily - // if (get3DLutUtil() && - // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - // get3DLutUtil()->releaseFBO(); + if (LutCalibrator::instance()->isValid()) m_fbo->release(); QPoint viewP = mapFrom(this, curPos); TPointD pos = getViewAff().inv() * @@ -899,17 +883,11 @@ void ImageViewer::rectPickColor(bool putValueToStyleEditor) { return; } - // iwsw commented out temporarily - // if (get3DLutUtil() && - // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - // get3DLutUtil()->bindFBO(); + if (LutCalibrator::instance()->isValid() && m_fbo) m_fbo->bind(); const TPixel32 pix = picker.pickColor(area.enlarge(-1, -1)); - // iwsw commented out temporarily - // if (get3DLutUtil() && - // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - // get3DLutUtil()->releaseFBO(); + if (LutCalibrator::instance()->isValid() && m_fbo) m_fbo->release(); // throw the picked color to the histogram m_histogramPopup->updateAverageColor(pix); diff --git a/toonz/sources/toonz/imageviewer.h b/toonz/sources/toonz/imageviewer.h index d8c905b..857e59a 100644 --- a/toonz/sources/toonz/imageviewer.h +++ b/toonz/sources/toonz/imageviewer.h @@ -3,9 +3,6 @@ #ifndef IMAGEVIEWER_INCLUDE #define IMAGEVIEWER_INCLUDE -// iwsw commented out temporarily -//#include "toonzqt/ghibli_3dlut_util.h" - #include "toonz/imagepainter.h" #include "toonzqt/glwidget_for_highdpi.h" @@ -14,6 +11,7 @@ // Forward declarations class FlipBook; class HistogramPopup; +class QOpenGLFramebufferObject; //----------------------------------------------------------------------------- @@ -57,8 +55,8 @@ class ImageViewer final : public GLWidgetForHighDpi { // a flipbook shows a red border line before the rendered result is shown. bool m_isRemakingPreviewFx; - // iwsw commented out temporarily - // Ghibli3DLutUtil * m_ghibli3DLutUtil; + // used for color calibration with 3DLUT + QOpenGLFramebufferObject *m_fbo = NULL; int getDragType(const TPoint &pos, const TRect &loadBox); void updateLoadbox(const TPoint &curPos); @@ -109,9 +107,6 @@ public: void doSwapBuffers(); void changeSwapBehavior(bool enable); - // iwsw commented out temporarily - // Ghibli3DLutUtil* get3DLutUtil(){ return m_ghibli3DLutUtil; } - protected: void contextMenuEvent(QContextMenuEvent *event) override; void initializeGL() override; diff --git a/toonz/sources/toonz/main.cpp b/toonz/sources/toonz/main.cpp index 7fa0819..3619742 100644 --- a/toonz/sources/toonz/main.cpp +++ b/toonz/sources/toonz/main.cpp @@ -25,8 +25,6 @@ #include "toonzqt/icongenerator.h" #include "toonzqt/gutil.h" #include "toonzqt/pluginloader.h" -// iwsw commented out temporarily -//#include "toonzqt/ghibli_3dlut_util.h" // TnzStdfx includes #include "stdfx/shaderfx.h" @@ -532,32 +530,6 @@ int main(int argc, char *argv[]) { TTool::setApplication(TApp::instance()); TApp::instance()->init(); -// iwsw commented out temporarily -#if 0 - QStringList monitorNames; - /*-- 接続モニタがPVM-2541の場合のみLUTを読み込む --*/ - if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - { - /*-- 接続モニタがPVM-2541の場合のみLUTを読み込む --*/ - monitorNames = Ghibli3DLutUtil::getMonitorName(); - if (monitorNames.contains(QString::fromStdWString(L"PVM-2541"))) - /*-- 3DLUTファイルを読み込む --*/ - Ghibli3DLutUtil::loadLutFile(Preferences::instance()->get3DLutPath()); - } - /*-- 接続モニタをスプラッシュ画面にも表示 --*/ - if (!monitorNames.isEmpty()) - { - lastUpdateStr += QString("Monitor Name : "); - for (int mn = 0; mn < monitorNames.size(); mn++) - { - if (mn != 0) - lastUpdateStr += QString(", "); - lastUpdateStr += monitorNames.at(mn); - } - lastUpdateStr += QString("\n"); - } -#endif - splash.showMessage(offsetStr + "Loading Plugins...", Qt::AlignCenter, Qt::white); a.processEvents(); diff --git a/toonz/sources/toonz/preferencespopup.cpp b/toonz/sources/toonz/preferencespopup.cpp index 1c04676..de2dbd4 100644 --- a/toonz/sources/toonz/preferencespopup.cpp +++ b/toonz/sources/toonz/preferencespopup.cpp @@ -17,6 +17,7 @@ #include "toonzqt/doublefield.h" #include "toonzqt/dvdialog.h" #include "toonzqt/filefield.h" +#include "toonzqt/lutcalibrator.h" // TnzLib includes #include "toonz/txsheethandle.h" @@ -1145,6 +1146,20 @@ void PreferencesPopup::onShowCurrentTimelineChanged(int index) { m_pref->enableCurrentTimelineIndicator(index == Qt::Checked); } +//----------------------------------------------------------------------------- + +void PreferencesPopup::onColorCalibrationChanged(bool on) { + m_pref->enableColorCalibration(on); +} + +//----------------------------------------------------------------------------- + +void PreferencesPopup::onLutPathChanged() { + m_pref->setColorCalibrationLutPath( + LutCalibrator::instance()->getMonitorName(), + m_lutPathFileField->getPath()); +} + //********************************************************************************** // PrefencesPopup's constructor //********************************************************************************** @@ -1259,6 +1274,11 @@ PreferencesPopup::PreferencesPopup() m_interfaceFont = new QComboBox(this); m_interfaceFontWeight = new QComboBox(this); + m_colorCalibration = + new QGroupBox(tr("Color Calibration using 3D Look-up Table *")); + m_lutPathFileField = new DVGui::FileField( + this, QString("- Please specify 3DLUT file (.3dl) -"), false, true); + //--- Visualization ------------------------------ categoryList->addItem(tr("Visualization")); CheckBox *show0ThickLinesCB = @@ -1583,6 +1603,16 @@ PreferencesPopup::PreferencesPopup() m_interfaceFontWeight->addItems(fontStyles); m_interfaceFontWeight->setCurrentIndex(m_pref->getInterfaceFontWeight()); + m_colorCalibration->setCheckable(true); + m_colorCalibration->setChecked(m_pref->isColorCalibrationEnabled()); + QString lutPath = m_pref->getColorCalibrationLutPath( + LutCalibrator::instance()->getMonitorName()); + if (!lutPath.isEmpty()) m_lutPathFileField->setPath(lutPath); + m_lutPathFileField->setFileMode(QFileDialog::ExistingFile); + QStringList lutFileTypes; + lutFileTypes << "3dl"; + m_lutPathFileField->setFilters(lutFileTypes); + //--- Visualization ------------------------------ show0ThickLinesCB->setChecked(m_pref->getShow0ThickLines()); regionAntialiasCB->setChecked(m_pref->getRegionAntialias()); @@ -1985,6 +2015,20 @@ PreferencesPopup::PreferencesPopup() interfaceBottomLay->setColumnStretch(5, 1); userInterfaceFrameLay->addLayout(interfaceBottomLay, 0); + QHBoxLayout *lutLayout = new QHBoxLayout(); + lutLayout->setMargin(10); + lutLayout->setSpacing(5); + { + lutLayout->addWidget( + new QLabel(tr("3DLUT File for [%1] *:") + .arg(LutCalibrator::instance()->getMonitorName()), + this), + 0); + lutLayout->addWidget(m_lutPathFileField, 1); + } + m_colorCalibration->setLayout(lutLayout); + userInterfaceFrameLay->addWidget(m_colorCalibration); + userInterfaceFrameLay->addStretch(1); userInterfaceFrameLay->addWidget(note_interface, 0); @@ -2562,6 +2606,11 @@ PreferencesPopup::PreferencesPopup() ret = ret && connect(levelNameOnEachMarkerCB, SIGNAL(stateChanged(int)), SLOT(onLevelNameOnEachMarkerChanged(int))); + ret = ret && connect(m_colorCalibration, SIGNAL(clicked(bool)), this, + SLOT(onColorCalibrationChanged(bool))); + ret = ret && connect(m_lutPathFileField, SIGNAL(pathChanged()), this, + SLOT(onLutPathChanged())); + //--- Visualization --------------------- ret = ret && connect(show0ThickLinesCB, SIGNAL(stateChanged(int)), this, SLOT(onShow0ThickLinesChanged(int))); diff --git a/toonz/sources/toonz/preferencespopup.h b/toonz/sources/toonz/preferencespopup.h index 231b107..30e52f8 100644 --- a/toonz/sources/toonz/preferencespopup.h +++ b/toonz/sources/toonz/preferencespopup.h @@ -81,9 +81,10 @@ private: DVGui::FileField *m_customProjectRootFileField; - DVGui::FileField *m_ffmpegPathFileFld, *m_fastRenderPathFileField; + DVGui::FileField *m_ffmpegPathFileFld, *m_fastRenderPathFileField, + *m_lutPathFileField; - QGroupBox *m_autoSaveGroup, *m_showXSheetToolbar; + QGroupBox *m_autoSaveGroup, *m_showXSheetToolbar, *m_colorCalibration; private: // QWidget* create(const QString& lbl, bool def, const char* slot); @@ -200,6 +201,8 @@ private slots: void onXsheetLayoutChanged(const QString &text); void onPathAliasPriorityChanged(int index); void onShowCurrentTimelineChanged(int); + void onColorCalibrationChanged(bool); + void onLutPathChanged(); }; //********************************************************************************** diff --git a/toonz/sources/toonz/sceneviewer.cpp b/toonz/sources/toonz/sceneviewer.cpp index ab1c453..a9ea660 100644 --- a/toonz/sources/toonz/sceneviewer.cpp +++ b/toonz/sources/toonz/sceneviewer.cpp @@ -23,6 +23,7 @@ #include "toonzqt/icongenerator.h" #include "toonzqt/gutil.h" #include "toonzqt/imageutils.h" +#include "toonzqt/lutcalibrator.h" // TnzLib includes #include "toonz/tscenehandle.h" @@ -81,6 +82,7 @@ #include #endif #include +#include #include "sceneviewer.h" @@ -500,10 +502,6 @@ SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent) m_3DSideL = rasterFromQPixmap(svgToPixmap(":Resources/3Dside_l.svg")); m_3DTop = rasterFromQPixmap(svgToPixmap(":Resources/3Dtop.svg")); - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // Ghibli3DLutUtil::m_isValid) - // m_ghibli3DLutUtil = new Ghibli3DLutUtil(); setAttribute(Qt::WA_AcceptTouchEvents); grabGesture(Qt::SwipeGesture); grabGesture(Qt::PanGesture); @@ -525,14 +523,7 @@ void SceneViewer::setVisual(const ImagePainter::VisualSettings &settings) { //----------------------------------------------------------------------------- SceneViewer::~SceneViewer() { - // iwsw commented out temporarily - /* -if (m_ghibli3DLutUtil) -{ - m_ghibli3DLutUtil->onEnd(); - delete m_ghibli3DLutUtil; -} -*/ + if (m_fbo) delete m_fbo; } //------------------------------------------------------------------------------- @@ -825,13 +816,12 @@ double SceneViewer::getHGuide(int index) { return m_hRuler->getGuide(index); } void SceneViewer::initializeGL() { initializeOpenGLFunctions(); + + // to be computed once through the software + LutCalibrator::instance()->initialize(); + // glClearColor(1.0,1.0,1.0,1); glClear(GL_COLOR_BUFFER_BIT); - - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->onInit(); } //----------------------------------------------------------------------------- @@ -856,12 +846,14 @@ void SceneViewer::resizeGL(int w, int h) { if (m_previewMode != NO_PREVIEW) requestTimedRefresh(); + // remake fbo with new size + if (LutCalibrator::instance()->isValid()) { + if (m_fbo) delete m_fbo; + m_fbo = new QOpenGLFramebufferObject(w, h); + } + // for updating the navigator in levelstrip emit refreshNavi(); - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->onResize(w, h); } //----------------------------------------------------------------------------- @@ -1381,11 +1373,7 @@ void SceneViewer::paintGL() { time.start(); #endif - // iwsw commented out temporarily - // if (!m_isPicking && - // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->startDraw(); + if (!m_isPicking && LutCalibrator::instance()->isValid()) m_fbo->bind(); if (m_hRuler && m_vRuler) { if (!viewRulerToggle.getStatus() && @@ -1415,11 +1403,8 @@ void SceneViewer::paintGL() { glPopMatrix(); m_viewGrabImage->unlock(); - // iwsw commented out temporarily - // if (!m_isPicking && - // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->endDraw(); + if (!m_isPicking && LutCalibrator::instance()->isValid()) + LutCalibrator::instance()->onEndDraw(m_fbo); return; } @@ -1427,11 +1412,8 @@ void SceneViewer::paintGL() { drawBuildVars(); check_framebuffer_status(); - // iwsw commented out temporarily - // if (!m_isPicking && - // !Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() || - //! m_ghibli3DLutUtil) copyFrontBufferToBackBuffer(); + check_framebuffer_status(); drawEnableScissor(); check_framebuffer_status(); @@ -1465,11 +1447,8 @@ void SceneViewer::paintGL() { #endif // TOfflineGL::setContextManager(0); - // iwsw commented out temporarily - // if (!m_isPicking && - // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - // m_ghibli3DLutUtil) - // m_ghibli3DLutUtil->endDraw(); + if (!m_isPicking && LutCalibrator::instance()->isValid()) + LutCalibrator::instance()->onEndDraw(m_fbo); } //----------------------------------------------------------------------------- @@ -2556,3 +2535,15 @@ TRectD SceneViewer::getGeometry() const { void SceneViewer::doDeleteSubCamera() { PreviewSubCameraManager::instance()->deleteSubCamera(this); } + +//----------------------------------------------------------------------------- + +void SceneViewer::bindFBO() { + if (m_fbo) m_fbo->bind(); +} + +//----------------------------------------------------------------------------- + +void SceneViewer::releaseFBO() { + if (m_fbo) m_fbo->release(); +} diff --git a/toonz/sources/toonz/sceneviewer.h b/toonz/sources/toonz/sceneviewer.h index 4b456b1..d5e6824 100644 --- a/toonz/sources/toonz/sceneviewer.h +++ b/toonz/sources/toonz/sceneviewer.h @@ -14,8 +14,6 @@ #include "toonzqt/menubarcommand.h" #include "toonzqt/flipconsole.h" #include "toonzqt/glwidget_for_highdpi.h" -// iwsw commented out temporarily -//#include "toonzqt/ghibli_3dlut_util.h" // TnzTools includes #include "tools/tool.h" @@ -36,6 +34,7 @@ class SceneViewer; class LocatorPopup; class QGestureEvent; class QTouchEvent; +class QOpenGLFramebufferObject; namespace ImageUtils { class FullScreenWidget; @@ -145,6 +144,9 @@ class SceneViewer final : public GLWidgetForHighDpi, bool m_editPreviewSubCamera; + // used for color calibration with 3DLUT + QOpenGLFramebufferObject *m_fbo = NULL; + enum Device3D { NONE, SIDE_LEFT_3D, @@ -160,8 +162,6 @@ class SceneViewer final : public GLWidgetForHighDpi, QMatrix4x4 m_projectionMatrix; - // iwsw commented out temporarily - // Ghibli3DLutUtil * m_ghibli3DLutUtil; public: // iwsw commented out temporarily // Ghibli3DLutUtil* get3DLutUtil(){ return m_ghibli3DLutUtil; } @@ -262,6 +262,9 @@ public: double getVGuide(int index); double getHGuide(int index); + void bindFBO() override; + void releaseFBO() override; + public: // SceneViewer's gadget public functions TPointD winToWorld(const QPointF &pos) const; diff --git a/toonz/sources/toonzlib/preferences.cpp b/toonz/sources/toonzlib/preferences.cpp index ed297d5..3eee622 100644 --- a/toonz/sources/toonzlib/preferences.cpp +++ b/toonz/sources/toonzlib/preferences.cpp @@ -666,6 +666,18 @@ Preferences::Preferences() m_loadedXsheetLayout = m_xsheetLayoutPreference; getValue(*m_settings, "currentTimelineEnabled", m_currentTimelineEnabled); + + getValue(*m_settings, "colorCalibrationEnabled", m_colorCalibrationEnabled); + QVariant val = m_settings->value("colorCalibrationLutPaths"); + if (val.canConvert()) { + QAssociativeIterable iterable = val.value(); + QAssociativeIterable::const_iterator it = iterable.begin(); + const QAssociativeIterable::const_iterator end = iterable.end(); + for (; it != end; ++it) { + m_colorCalibrationLutPaths.insert(it.key().toString(), + it.value().toString()); + } + } } //----------------------------------------------------------------- @@ -1617,3 +1629,30 @@ void Preferences::enableCurrentTimelineIndicator(bool on) { m_currentTimelineEnabled = on; m_settings->setValue("currentTimelineEnabled", on ? "1" : "0"); } + +//----------------------------------------------------------------- +// color calibration using 3DLUT + +void Preferences::enableColorCalibration(bool on) { + m_colorCalibrationEnabled = on; + m_settings->setValue("colorCalibrationEnabled", on ? "1" : "0"); +} + +void Preferences::setColorCalibrationLutPath(QString monitorName, + QString path) { + m_colorCalibrationLutPaths.insert(monitorName, path); + QMap map; + QMap::const_iterator i = + m_colorCalibrationLutPaths.constBegin(); + while (i != m_colorCalibrationLutPaths.constEnd()) { + map.insert(i.key(), i.value()); + i++; + } + m_settings->setValue("colorCalibrationLutPaths", map); +} + +QString Preferences::getColorCalibrationLutPath(QString &monitorName) const { + return m_colorCalibrationLutPaths.value(monitorName); +} + +//----------------------------------------------------------------- \ No newline at end of file diff --git a/toonz/sources/toonzqt/CMakeLists.txt b/toonz/sources/toonzqt/CMakeLists.txt index bed4735..513b5f1 100644 --- a/toonz/sources/toonzqt/CMakeLists.txt +++ b/toonz/sources/toonzqt/CMakeLists.txt @@ -87,6 +87,7 @@ set(MOC_HEADERS ../include/toonzqt/combohistogram.h ../include/toonzqt/fxiconmanager.h ../include/toonzqt/glwidget_for_highdpi.h + ../include/toonzqt/lutcalibrator.h pluginhost.h ) @@ -193,6 +194,7 @@ set(SOURCES plugin_param_view_interface.cpp plugin_ui_page_interface.cpp toonz_params.cpp + lutcalibrator.cpp ) set(RESOURCES toonzqt.qrc) diff --git a/toonz/sources/toonzqt/colorfield.cpp b/toonz/sources/toonzqt/colorfield.cpp index a052eaa..3396785 100644 --- a/toonz/sources/toonzqt/colorfield.cpp +++ b/toonz/sources/toonzqt/colorfield.cpp @@ -9,6 +9,7 @@ #include "tconvert.h" #include "tcolorstyles.h" #include "trop.h" +#include "toonzqt/lutcalibrator.h" #include #include @@ -95,9 +96,9 @@ void StyleSample::setStyle(TColorStyle &style) { */ void StyleSample::setColor(const TPixel32 &pixel) { QColor color(pixel.r, pixel.g, pixel.b, pixel.m); - // iwsw commented out temporarily - // if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - // Ghibli3DLutConverter::instance()->convert(color); + if (LutCalibrator::instance()->isValid()) + LutCalibrator::instance()->convert(color); + m_samplePixmap.fill(color.rgba()); update(); } diff --git a/toonz/sources/toonzqt/combohistogram.cpp b/toonz/sources/toonzqt/combohistogram.cpp index ecd3d2d..14f35e5 100644 --- a/toonz/sources/toonzqt/combohistogram.cpp +++ b/toonz/sources/toonzqt/combohistogram.cpp @@ -10,8 +10,7 @@ #include #include "toonz/preferences.h" -// iwsw commented out temporarily -//#include "toonzqt/ghibli_3dlut_converter.h" +#include "toonzqt/lutcalibrator.h" #include #include @@ -323,17 +322,12 @@ void ComboHistoRGBLabel::paintEvent(QPaintEvent *pe) { return; } - // iwsw commented out temporarily - /* - if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - { - QColor convertedColor(m_color); - Ghibli3DLutConverter::instance()->convert(convertedColor); - p.setBrush(convertedColor); - } - else - */ - p.setBrush(m_color); + if (LutCalibrator::instance()->isValid()) { + QColor convertedColor(m_color); + LutCalibrator::instance()->convert(convertedColor); + p.setBrush(convertedColor); + } else + p.setBrush(m_color); p.drawRect(bgRect); diff --git a/toonz/sources/toonzqt/lutcalibrator.cpp b/toonz/sources/toonzqt/lutcalibrator.cpp new file mode 100644 index 0000000..226f796 --- /dev/null +++ b/toonz/sources/toonzqt/lutcalibrator.cpp @@ -0,0 +1,589 @@ +#include "toonzqt/lutcalibrator.h" + +// Tnzlib includes +#include "toonz/preferences.h" + +// TnzCore includes +#include "tmsgcore.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +inline bool execWarning(const QString& s) { + DVGui::MsgBox(DVGui::WARNING, s); + return false; +} +}; + +#ifdef WIN32 + +#include +#include +#include + +namespace { +// obtain monitor information from registry +QStringList getMonitorNames() { + QStringList subPathSet; + // QSettings regSys("SYSTEM\\CurrentControlSet\\Enum\\DISPLAY", + // QSettings::NativeFormat); + QSettings regSys( + "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\DISPLAY", + QSettings::NativeFormat); + QStringList children = regSys.childGroups(); + // return value + QStringList nameList; + + if (children.isEmpty()) { + std::cout << "getMonitorNames : Failed to Open Registry" << std::endl; + return nameList; + } + + for (int c = 0; c < children.size(); c++) { + // Parent Key : DISPLAY + // Child Keys : AVO0000, ENC2174, etc. + // Grandchild Key : 5&388.. + // Find grandchild key which contains a great-grandchild key named "Control" + + regSys.beginGroup(children.at(c)); // Child keys : AVO0000, ENC2174, etc. + QStringList grandChildren = regSys.childGroups(); + for (int gc = 0; gc < grandChildren.size(); gc++) { + regSys.beginGroup(grandChildren.at(gc)); // Grandchild key : 5&388.. + + QStringList greatGrandChildren = regSys.childGroups(); + + if (greatGrandChildren.contains( + "Control")) // If the key "Control" is found + { + // Obtain variable "EDID" from the key "Device Parameters" + regSys.beginGroup("Device Parameters"); + + // the key may be not "EDID", but "BAD_EDID" + if (regSys.contains("EDID")) { + QString subPath = regSys.group().replace("/", "\\").prepend( + "SYSTEM\\CurrentControlSet\\Enum\\DISPLAY\\"); + subPathSet.push_back(subPath); + } + regSys.endGroup(); + } + regSys.endGroup(); + } + // subPath may not be one...? + // if(!subPath.isEmpty()) + // break; + regSys.endGroup(); + } + + if (subPathSet.isEmpty()) { + std::cout << "getMonitorNames : Failed to Find Current EDID" << std::endl; + return nameList; + } + + // for each subPath ( it may become more than one when using submonitor ) + for (int sp = 0; sp < subPathSet.size(); sp++) { + QString subPath = subPathSet.at(sp); + + HKEY handle = 0; + + LONG res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + reinterpret_cast(subPath.utf16()), + 0, KEY_READ, &handle); + + if (res == ERROR_SUCCESS && handle) { + QString keyStr("EDID"); + + // get the size and type of the value + DWORD dataType; + DWORD dataSize; + LONG res = RegQueryValueExW( + handle, reinterpret_cast(keyStr.utf16()), 0, + &dataType, 0, &dataSize); + + if (res != ERROR_SUCCESS) { + RegCloseKey(handle); + continue; + } + + // get the value + QByteArray ba(dataSize, 0); + res = RegQueryValueExW( + handle, reinterpret_cast(keyStr.utf16()), 0, 0, + reinterpret_cast(ba.data()), &dataSize); + + if (res != ERROR_SUCCESS) { + RegCloseKey(handle); + continue; + } + + QString s; + if (dataSize) { + s = QString::fromUtf16((const ushort*)ba.constData(), ba.size() / 2); + } + + QString valStr; + QList valArray; + for (int b = 0; b < s.length(); b++) { + QChar c1((int)s[b].unicode() % 256); + QChar c2((int)s[b].unicode() / 256); + valStr.append(c1.toLatin1()); + valStr.append(c2.toLatin1()); + valArray.append((int)s[b].unicode() % 256); + valArray.append((int)s[b].unicode() / 256); + } + + // machine name starts from "FC 00", end with "0A" + int index1 = valArray.indexOf(252); // FC + int index2 = valArray.indexOf(10, index1); // 0A + + if (index1 > 0 && index2 > 0) { + QString machineName = valStr.mid(index1 + 2, index2 - index1 - 2); + nameList.push_back(machineName); + // std::wcout << "machine name = " << machineName.toStdWString() << + // std::endl; + } + RegCloseKey(handle); + + } else { + std::cout << "getMonitorNames : failed to get handle" << std::endl; + continue; + } + } + + if (nameList.isEmpty()) + std::cout << "getMonitorNames : No Monitor Name Found" << std::endl; + + return nameList; +} +}; +#endif + +//----------------------------------------------------------------------------- + +LutCalibrator* LutCalibrator::instance() { + static LutCalibrator _instance; + return &_instance; +} + +//----------------------------------------------------------------------------- + +void LutCalibrator::initialize() { + static bool hasInitialized = false; + if (hasInitialized) return; + hasInitialized = true; + + initializeOpenGLFunctions(); + + // check whether preference enables color calibration + if (!Preferences::instance()->isColorCalibrationEnabled()) return; + + // obtain current monitor name + QString monitorName = getMonitorName(); + + // obtain 3dlut path associated to the monitor name + QString lutPath = + Preferences::instance()->getColorCalibrationLutPath(monitorName); + + if (lutPath.isEmpty()) return; + + // check existence of the 3dlut file + // load 3dlut data + if (!loadLutFile(lutPath)) return; + + // create shader + if (!initializeLutTextureShader()) { + if (m_shader.program) delete m_shader.program; + if (m_shader.vert) delete m_shader.vert; + if (m_shader.frag) delete m_shader.frag; + return; + } + createViewerVBO(); + + // input 3dlut data to the shader + assignLutTexture(); + + m_isValid = true; + return; +} + +//----------------------------------------------------------------------------- + +void LutCalibrator::finalize() { + if (!m_isValid) return; + // release shader + if (m_shader.program) delete m_shader.program; + if (m_shader.vert) delete m_shader.vert; + if (m_shader.frag) delete m_shader.frag; + // release VBO + if (m_viewerVBO.isCreated()) m_viewerVBO.destroy(); + // release LUT texture + if (m_lut.tex && m_lut.tex->isCreated()) { + m_lut.tex->destroy(); + delete m_lut.tex; + } + if (m_lut.data) delete[] m_lut.data; +} + +//----------------------------------------------------------------------------- + +bool LutCalibrator::initializeLutTextureShader() { + m_shader.vert = new QOpenGLShader(QOpenGLShader::Vertex); + const char* simple_vsrc = + "#version 330 core\n" + "// Input vertex data, different for all executions of this shader.\n" + "layout(location = 0) in vec3 vertexPosition;\n" + "layout(location = 1) in vec2 texCoord;\n" + "// Output data ; will be interpolated for each fragment.\n" + "out vec2 UV;\n" + "// Values that stay constant for the whole mesh.\n" + "void main() {\n" + " // Output position of the vertex, in clip space : MVP * position\n" + " gl_Position = vec4(vertexPosition, 1);\n" + " // UV of the vertex. No special space for this one.\n" + " UV = texCoord;\n" + "}\n"; + bool ret = m_shader.vert->compileSourceCode(simple_vsrc); + if (!ret) + return execWarning( + QObject::tr("Failed to compile m_textureShader.vert.", "gl")); + + m_shader.frag = new QOpenGLShader(QOpenGLShader::Fragment); + const char* simple_fsrc = + "#version 330 core \n" + "// Interpolated values from the vertex shaders \n" + "in vec2 UV; \n" + "// Ouput data \n" + "out vec4 color; \n" + "// Values that stay constant for the whole mesh. \n" + "uniform sampler2D tex; \n" + "uniform sampler3D lut; \n" + "uniform vec3 lutSize; \n" + "void main() { \n" + " vec3 rawColor = texture(tex,UV).rgb; \n" + " vec3 scale = (lutSize - 1.0) / lutSize; \n" + " vec3 offset = 1.0 / (2.0 * lutSize); \n" + " color = vec4(texture(lut, scale * rawColor + offset).rgb, 1.0); \n" + "} \n"; + ret = m_shader.frag->compileSourceCode(simple_fsrc); + if (!ret) + return execWarning(QObject::tr("Failed to compile m_shader.frag.", "gl")); + + m_shader.program = new QOpenGLShaderProgram(); + // add shaders + ret = m_shader.program->addShader(m_shader.vert); + if (!ret) + return execWarning(QObject::tr("Failed to add m_shader.vert.", "gl")); + ret = m_shader.program->addShader(m_shader.frag); + if (!ret) + return execWarning(QObject::tr("Failed to add m_shader.frag.", "gl")); + // link shaders + ret = m_shader.program->link(); + if (!ret) + return execWarning(QObject::tr("Failed to link simple shader: %1", "gl") + .arg(m_shader.program->log())); + // obtain parameter locations + m_shader.vertexAttrib = m_shader.program->attributeLocation("vertexPosition"); + if (m_shader.vertexAttrib == -1) + return execWarning( + QObject::tr("Failed to get attribute location of %1", "gl") + .arg("vertexPosition")); + m_shader.texCoordAttrib = m_shader.program->attributeLocation("texCoord"); + if (m_shader.texCoordAttrib == -1) + return execWarning( + QObject::tr("Failed to get attribute location of %1", "gl") + .arg("texCoord")); + m_shader.texUniform = m_shader.program->uniformLocation("tex"); + if (m_shader.texUniform == -1) + return execWarning( + QObject::tr("Failed to get uniform location of %1", "gl").arg("tex")); + m_shader.lutUniform = m_shader.program->uniformLocation("lut"); + if (m_shader.lutUniform == -1) + return execWarning( + QObject::tr("Failed to get uniform location of %1", "gl").arg("lut")); + m_shader.lutSizeUniform = m_shader.program->uniformLocation("lutSize"); + if (m_shader.lutSizeUniform == -1) + return execWarning(QObject::tr("Failed to get uniform location of %1", "gl") + .arg("lutSize")); + + return true; +} + +//----------------------------------------------------------------------------- + +void LutCalibrator::createViewerVBO() { + GLfloat vertex[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f}; + GLfloat texCoord[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; + + m_viewerVBO.create(); + m_viewerVBO.bind(); + m_viewerVBO.allocate(4 * 4 * sizeof(GLfloat)); + m_viewerVBO.write(0, vertex, sizeof(vertex)); + m_viewerVBO.write(sizeof(vertex), texCoord, sizeof(texCoord)); + m_viewerVBO.release(); +} + +//----------------------------------------------------------------------------- + +void LutCalibrator::onEndDraw(QOpenGLFramebufferObject* fbo) { + assert((glGetError()) == GL_NO_ERROR); + fbo->release(); + GLuint textureId = fbo->texture(); + + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE4); + glBindTexture(GL_TEXTURE_2D, textureId); + + glActiveTexture(GL_TEXTURE5); + m_lut.tex->bind(); + + glPushMatrix(); + glLoadIdentity(); + + m_shader.program->bind(); + m_shader.program->setUniformValue(m_shader.texUniform, + 4); // use texture unit 4 + m_shader.program->setUniformValue(m_shader.lutUniform, + 5); // use texture unit 5 + GLfloat size = (GLfloat)m_lut.meshSize; + m_shader.program->setUniformValue(m_shader.lutSizeUniform, size, size, size); + + m_shader.program->enableAttributeArray(m_shader.vertexAttrib); + m_shader.program->enableAttributeArray(m_shader.texCoordAttrib); + + m_viewerVBO.bind(); + m_shader.program->setAttributeBuffer(m_shader.vertexAttrib, GL_FLOAT, 0, 2); + m_shader.program->setAttributeBuffer(m_shader.texCoordAttrib, GL_FLOAT, + 4 * 2 * sizeof(GLfloat), 2); + m_viewerVBO.release(); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + m_shader.program->disableAttributeArray(m_shader.vertexAttrib); + m_shader.program->disableAttributeArray(m_shader.texCoordAttrib); + + m_shader.program->release(); + + glPopMatrix(); + glDisable(GL_TEXTURE_2D); + + assert((glGetError()) == GL_NO_ERROR); +} + +//----------------------------------------------------------------------------- + +QString& LutCalibrator::getMonitorName() const { + static QString monitorName; + if (!monitorName.isEmpty()) return monitorName; + +#ifdef WIN32 + QStringList list = getMonitorNames(); + if (list.isEmpty()) + monitorName = "Any Monitor"; // this should not be translated + else + monitorName = list.at(0); // for now only the first monitor is handled +#else + monitorName = "Any Monitor"; // this should not be translated +#endif + + return monitorName; +} + +//----------------------------------------------------------------------------- + +bool LutCalibrator::loadLutFile(const QString& fp) { + struct locals { + // skip empty or comment lines + static inline QString readDataLine(QTextStream& stream) { + while (1) { + if (stream.atEnd()) return QString(); + QString ret = stream.readLine(); + if (!ret.isEmpty() && ret[0] != QChar('#')) return ret; + } + } + + static inline int lutCoords(int r, int g, int b, int meshSize) { + return b * meshSize * meshSize * 3 + g * meshSize * 3 + r * 3; + } + }; + + QFile file(fp); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return execWarning(QObject::tr("Failed to Open 3DLUT File.")); + + QTextStream stream(&file); + QString line; + + //---- read the 3DLUT files + + // The first line shoud start from "3DMESH" keyword (case sensitive) + line = locals::readDataLine(stream); + if (line != "3DMESH") { + file.close(); + return execWarning( + QObject::tr("Failed to Load 3DLUT File.\nIt should start with " + "\"3DMESH\" keyword.")); + } + + // The second line is "Mesh [Input bit depth] [Output bit depth]" + // "Mesh" is a keyword (case sensitive)  + line = locals::readDataLine(stream); + QStringList list = line.split(" "); + if (list.size() != 3 || list.at(0) != "Mesh") { + file.close(); + return execWarning( + QObject::tr("Failed to Load 3DLUT File.\nThe second line should be " + "\"Mesh [Input bit depth] [Output bit depth]\"")); + } + + int inputBitDepth = list.at(1).toInt(); + int outputBitDepth = list.at(2).toInt(); + + m_lut.meshSize = (int)pow(2.0, inputBitDepth) + 1; + + float maxValue = pow(2.0, outputBitDepth) - 1.0f; + + // The third line is corrections of values at each LUT grid + line = locals::readDataLine(stream); + list = line.split(" ", QString::SkipEmptyParts); + if (list.size() != m_lut.meshSize) { + file.close(); + return execWarning(QObject::tr("Failed to Load 3DLUT File.")); + } + + m_lut.data = new float[m_lut.meshSize * m_lut.meshSize * m_lut.meshSize * 3]; + + for (int k = 0; k < m_lut.meshSize; ++k) // r + { + for (int j = 0; j < m_lut.meshSize; ++j) // g + { + for (int i = 0; i < m_lut.meshSize; ++i) // b + { + line = locals::readDataLine(stream); + list = line.split(" ", QString::SkipEmptyParts); + if (list.size() != 3) { + file.close(); + delete[] m_lut.data; + return execWarning(QObject::tr("Failed to Load 3DLUT File.")); + } + float* lut = m_lut.data + locals::lutCoords(k, j, i, m_lut.meshSize); + *lut = (float)(list.at(0).toInt()) / maxValue; + lut++; + *lut = (float)(list.at(1).toInt()) / maxValue; + lut++; + *lut = (float)(list.at(2).toInt()) / maxValue; + } + } + } + + file.close(); + return true; +} + +//----------------------------------------------------------------------------- + +void LutCalibrator::assignLutTexture() { + assert(glGetError() == GL_NO_ERROR); + + m_lut.tex = new QOpenGLTexture(QOpenGLTexture::Target3D); + m_lut.tex->setSize(m_lut.meshSize, m_lut.meshSize, m_lut.meshSize); + m_lut.tex->setFormat(QOpenGLTexture::RGB32F); + m_lut.tex->setLayers(1); + m_lut.tex->setMipLevels(1); + m_lut.tex->allocateStorage(); + m_lut.tex->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + m_lut.tex->setWrapMode(QOpenGLTexture::ClampToEdge); + + m_lut.tex->setData(QOpenGLTexture::RGB, QOpenGLTexture::Float32, m_lut.data); + + assert(glGetError() == GL_NO_ERROR); +} + +//----------------------------------------------------------------------------- + +// input : 0-1 +void LutCalibrator::convert(float& r, float& g, float& b) { + struct locals { + static inline float lerp(float val1, float val2, float ratio) { + return val1 * (1.0f - ratio) + val2 * ratio; + } + static inline int getCoord(int r, int g, int b, int meshSize) { + return b * meshSize * meshSize * 3 + g * meshSize * 3 + r * 3; + } + }; + + if (!m_isValid) return; + + float ratio[3]; // RGB軸 + int index[3][2]; // rgb インデックス + float rawVal[3] = {r, g, b}; + + float vertex_color[2][2][2][3]; //補間用の1ボクセルの頂点色 + + for (int c = 0; c < 3; c++) { + float val = rawVal[c] * (float)(m_lut.meshSize - 1); + index[c][0] = (int)val; + // boundary condition: if rawVal == 1 the value will not be interporated + index[c][1] = (rawVal[c] >= 1.0f) ? index[c][0] : index[c][0] + 1; + ratio[c] = val - (float)index[c][0]; + } + + for (int rr = 0; rr < 2; rr++) + for (int gg = 0; gg < 2; gg++) + for (int bb = 0; bb < 2; bb++) { + float* val = &m_lut.data[locals::getCoord( + index[0][rr], index[1][gg], index[2][bb], m_lut.meshSize)]; + for (int chan = 0; chan < 3; chan++, val++) + vertex_color[rr][gg][bb][chan] = *val; + } + float result[3]; + + for (int chan = 0; chan < 3; chan++) { + result[chan] = locals::lerp( + locals::lerp(locals::lerp(vertex_color[0][0][0][chan], + vertex_color[0][0][1][chan], ratio[2]), + locals::lerp(vertex_color[0][1][0][chan], + vertex_color[0][1][1][chan], ratio[2]), + ratio[1]), + locals::lerp(locals::lerp(vertex_color[1][0][0][chan], + vertex_color[1][0][1][chan], ratio[2]), + locals::lerp(vertex_color[1][1][0][chan], + vertex_color[1][1][1][chan], ratio[2]), + ratio[1]), + ratio[0]); + } + + r = result[0]; + g = result[1]; + b = result[2]; +} + +//----------------------------------------------------------------------------- + +void LutCalibrator::convert(QColor& col) { + if (!m_isValid) return; + float r = col.redF(); + float g = col.greenF(); + float b = col.blueF(); + convert(r, g, b); + // 0.5 offset is necessary for converting to 255 grading + col = QColor((int)(r * 255.0 + 0.5), (int)(g * 255.0 + 0.5), + (int)(b * 255.0 + 0.5), col.alpha()); +} + +//----------------------------------------------------------------------------- + +void LutCalibrator::convert(TPixel32& col) { + if (!m_isValid) return; + float r = (float)col.r / 255.0; + float g = (float)col.g / 255.0; + float b = (float)col.b / 255.0; + convert(r, g, b); + col = TPixel32((int)(r * 255.0 + 0.5), (int)(g * 255.0 + 0.5), + (int)(b * 255.0 + 0.5), col.m); +} \ No newline at end of file diff --git a/toonz/sources/toonzqt/paletteviewergui.cpp b/toonz/sources/toonzqt/paletteviewergui.cpp index 7b20ad9..8ee8126 100644 --- a/toonz/sources/toonzqt/paletteviewergui.cpp +++ b/toonz/sources/toonzqt/paletteviewergui.cpp @@ -11,6 +11,7 @@ #include "toonzqt/stylenameeditor.h" #include "toonzqt/viewcommandids.h" #include "palettedata.h" +#include "toonzqt/lutcalibrator.h" // TnzLib includes #include "toonz/palettecmd.h" @@ -681,10 +682,8 @@ void PageViewer::paintEvent(QPaintEvent *e) { // and TBlackCleanupStyle(2002) if (style->getTagId() == 3 || style->getTagId() == 2001 || style->getTagId() == 2002) { - // iwsw commented out temporaly - // if - // (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled()) - // Ghibli3DLutConverter::instance()->convert(styleColor); + if (LutCalibrator::instance()->isValid()) + LutCalibrator::instance()->convert(styleColor); p.fillRect(chipRect, QBrush(styleColor)); diff --git a/toonz/sources/toonzqt/styleeditor.cpp b/toonz/sources/toonzqt/styleeditor.cpp index 8950103..ee430ab 100644 --- a/toonz/sources/toonzqt/styleeditor.cpp +++ b/toonz/sources/toonzqt/styleeditor.cpp @@ -6,6 +6,7 @@ #include "toonzqt/gutil.h" #include "toonzqt/filefield.h" #include "historytypes.h" +#include "toonzqt/lutcalibrator.h" // TnzLib includes #include "toonz/txshlevel.h" @@ -53,6 +54,7 @@ #include #include #include +#include using namespace StyleEditorGUI; @@ -557,44 +559,24 @@ HexagonalColorWheel::HexagonalColorWheel(QWidget *parent) setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setFocusPolicy(Qt::NoFocus); m_currentWheel = none; - - // iwsw commented out temporarily - /* - if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - Ghibli3DLutUtil::m_isValid) - { - m_ghibli3DLutUtil = new Ghibli3DLutUtil(); - m_ghibli3DLutUtil->setInvert(); - } - */ } //----------------------------------------------------------------------------- HexagonalColorWheel::~HexagonalColorWheel() { - // iwsw commented out temporarily - /* - if(m_ghibli3DLutUtil) - { - m_ghibli3DLutUtil->onEnd(); - delete m_ghibli3DLutUtil; - } - */ + if (m_fbo) delete m_fbo; } //----------------------------------------------------------------------------- void HexagonalColorWheel::initializeGL() { initializeOpenGLFunctions(); + + // to be computed once through the software + LutCalibrator::instance()->initialize(); + QColor const color = getBGColor(); glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF()); - - // iwsw commented out temporarily - /* - if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - m_ghibli3DLutUtil) - m_ghibli3DLutUtil->onInit(); - */ } //----------------------------------------------------------------------------- @@ -646,12 +628,11 @@ void HexagonalColorWheel::resizeGL(int w, int h) { glLoadIdentity(); glOrtho(0.0, (GLdouble)w, (GLdouble)h, 0.0, 1.0, -1.0); - // iwsw commented out temporarily - /* - if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - m_ghibli3DLutUtil) - m_ghibli3DLutUtil->onResize(w,h); - */ + // remake fbo with new size + if (LutCalibrator::instance()->isValid()) { + if (m_fbo) delete m_fbo; + m_fbo = new QOpenGLFramebufferObject(w, h); + } } //----------------------------------------------------------------------------- @@ -664,12 +645,7 @@ void HexagonalColorWheel::paintGL() { glMatrixMode(GL_MODELVIEW); - // iwsw commented out temporarily - /* - if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - m_ghibli3DLutUtil) - m_ghibli3DLutUtil->startDraw(); - */ + if (LutCalibrator::instance()->isValid()) m_fbo->bind(); glClear(GL_COLOR_BUFFER_BIT); @@ -716,12 +692,8 @@ void HexagonalColorWheel::paintGL() { glPopMatrix(); - // iwsw commented out temporarily - /* - if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && - m_ghibli3DLutUtil) - m_ghibli3DLutUtil->endDraw(); - */ + if (LutCalibrator::instance()->isValid()) + LutCalibrator::instance()->onEndDraw(m_fbo); } //-----------------------------------------------------------------------------