aboutsummaryrefslogtreecommitdiff
path: root/NvBlast/tools/CurveEditor/source
diff options
context:
space:
mode:
authorBryan Galdrikian <[email protected]>2017-02-21 12:07:59 -0800
committerBryan Galdrikian <[email protected]>2017-02-21 12:07:59 -0800
commit446ce137c6823ba9eff273bdafdaf266287c7c98 (patch)
treed20aab3e2ed08d7b3ca71c2f40db6a93ea00c459 /NvBlast/tools/CurveEditor/source
downloadblast-1.0.0-beta.tar.xz
blast-1.0.0-beta.zip
first commitv1.0.0-beta
Diffstat (limited to 'NvBlast/tools/CurveEditor/source')
-rw-r--r--NvBlast/tools/CurveEditor/source/Attribute.h109
-rw-r--r--NvBlast/tools/CurveEditor/source/Common.h10
-rw-r--r--NvBlast/tools/CurveEditor/source/Curve.h204
-rw-r--r--NvBlast/tools/CurveEditor/source/CurveEditorMainWindow.h217
-rw-r--r--NvBlast/tools/CurveEditor/source/GraphEditorTestApp/CurveEditorTestApp.cpp342
-rw-r--r--NvBlast/tools/CurveEditor/source/GraphEditorTestApp/CurveEditorTestApp.h49
-rw-r--r--NvBlast/tools/CurveEditor/source/GraphEditorTestApp/main.cpp10
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Curve/BezierSpline.cpp143
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Curve/BezierSpline.h57
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Curve/CatmullRomSpline.cpp205
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Curve/CatmullRomSpline.h44
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Curve/Curve.cpp1114
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Curve/Spline.cpp151
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Curve/Spline.h43
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Window/AlphaDialog.cpp181
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Window/AlphaDialog.h47
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Window/ColorWidget.cpp1724
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Window/ColorWidget.h126
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Window/CurveEditorMainWindow.cpp1530
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Window/CurveWidget.cpp1229
-rw-r--r--NvBlast/tools/CurveEditor/source/Internal/Window/CurveWidget.h158
21 files changed, 7693 insertions, 0 deletions
diff --git a/NvBlast/tools/CurveEditor/source/Attribute.h b/NvBlast/tools/CurveEditor/source/Attribute.h
new file mode 100644
index 0000000..c8af7f7
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Attribute.h
@@ -0,0 +1,109 @@
+#ifndef ATTRIBUTE_H__
+#define ATTRIBUTE_H__
+
+#include "Curve.h"
+#include <vector>
+
+namespace nvidia {
+namespace CurveEditor {
+
+class CurveEditorMainWindow;
+
+enum CurveAttributeType
+{
+ eSingleAttr,
+ eGroupAttr,
+ eColorAttr,
+};
+
+class CURVEEDITOR_EXPORT CurveAttributeBase
+{
+ friend class CurveEditorMainWindow;
+public:
+ std::string getName() const { return _name; }
+ CurveAttributeType getType() const { return _type; }
+
+ inline bool canMoveControlPointHorizontally() { return _canMoveControlPointHorizontally; }
+ inline bool canAddRemoveControlPoint() { return _canAddRemoveControlPoint; }
+ inline bool canChangeTangentType() { return _canChangeTangentType; }
+
+protected:
+ CurveAttributeBase(const std::string& name, CurveAttributeType type, bool canMoveControlPointHorizontally = false, bool canAddRemoveControlPoint = false, bool canChangeTangentType = false)
+ : _name(name)
+ , _type(type)
+ , _canMoveControlPointHorizontally(canMoveControlPointHorizontally)
+ , _canAddRemoveControlPoint(canAddRemoveControlPoint)
+ , _canChangeTangentType(canChangeTangentType)
+ {
+ }
+
+protected:
+ std::string _name;
+ CurveAttributeType _type;
+ bool _canMoveControlPointHorizontally;
+ bool _canAddRemoveControlPoint;
+ bool _canChangeTangentType;
+};
+
+class CURVEEDITOR_EXPORT CurveAttribute : public CurveAttributeBase
+{
+public:
+ CurveAttribute()
+ : CurveAttributeBase("", eSingleAttr)
+ {
+ }
+
+ CurveAttribute(const std::string& name, bool canMoveControlPointHorizontally = false, bool canAddRemoveControlPoint = false, bool canChangeTangentType = false)
+ : CurveAttributeBase(name, eSingleAttr, canMoveControlPointHorizontally, canAddRemoveControlPoint, canChangeTangentType)
+ {
+ }
+
+ CurveAttribute(const CurveAttribute& attr)
+ : CurveAttributeBase(attr._name, eSingleAttr)
+ {
+ }
+
+ ~CurveAttribute()
+ {
+ }
+
+ QColor color;
+ Curve curve;
+};
+
+class CURVEEDITOR_EXPORT CurveAttributeGroup : public CurveAttributeBase
+{
+public:
+ CurveAttributeGroup(std::string name, bool canMoveControlPointHorizontally = false, bool canAddRemoveControlPoint = false, bool canChangeTangentType = false)
+ : CurveAttributeBase(name, eGroupAttr, canMoveControlPointHorizontally, canAddRemoveControlPoint, canChangeTangentType)
+ {
+ }
+
+ std::vector<CurveAttribute*> attributes;
+};
+
+class CURVEEDITOR_EXPORT ColorAttribute : public CurveAttributeBase
+{
+ friend class CurveEditor;
+public:
+ ColorAttribute()
+ : CurveAttributeBase("", eSingleAttr)
+ , useAlphaFromColor(false)
+ {
+ }
+
+ ColorAttribute(const std::string& name, bool canMoveControlPointHorizontally = false, bool canAddRemoveControlPoint = false, bool canChangeTangentType = false)
+ : CurveAttributeBase(name, eColorAttr, canMoveControlPointHorizontally, canAddRemoveControlPoint, canChangeTangentType)
+ , useAlphaFromColor(false)
+ {
+ }
+
+ ColorCurve colorCurve;
+ ColorCurve alphaCurve;
+ bool useAlphaFromColor;
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // ATTRIBUTE_H__
diff --git a/NvBlast/tools/CurveEditor/source/Common.h b/NvBlast/tools/CurveEditor/source/Common.h
new file mode 100644
index 0000000..43038fd
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Common.h
@@ -0,0 +1,10 @@
+#ifndef CURVEEDITOR_COMMON_H
+#define CURVEEDITOR_COMMON_H
+
+#ifdef CURVEEDITOR_LIB
+# define CURVEEDITOR_EXPORT Q_DECL_EXPORT
+#else
+# define CURVEEDITOR_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif
diff --git a/NvBlast/tools/CurveEditor/source/Curve.h b/NvBlast/tools/CurveEditor/source/Curve.h
new file mode 100644
index 0000000..a070fb5
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Curve.h
@@ -0,0 +1,204 @@
+#ifndef CURVE_H
+#define CURVE_H
+#include <QtCore/QPointF>
+#include <QtGui/QColor>
+#include <vector>
+#include "Common.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+enum InterpolateMode
+{
+ eDiscret,
+ eLinear,
+ eBezierSpline,
+ eCatmullRomSpline,
+};
+
+struct BezierSplineData
+{
+ float inTan;
+ float inLen;
+ float outTan;
+ float outLen;
+};
+
+struct ControlPoint
+{
+ ControlPoint()
+ : value(0, 0)
+ , mode (eDiscret)
+ {
+ memset( &splineData, 0, sizeof(BezierSplineData));
+ }
+
+ ControlPoint(float inX, float inY, InterpolateMode inMode)
+ : value(inX, inY)
+ , mode(inMode)
+ {
+ memset( &splineData, 0, sizeof(BezierSplineData));
+ }
+
+ ControlPoint(float inX, float inY, InterpolateMode inMode, BezierSplineData& inSplineData)
+ : value(inX, inY)
+ , mode(inMode)
+ , splineData(inSplineData)
+ {
+
+ }
+
+ QPointF value;
+ InterpolateMode mode;
+ BezierSplineData splineData;
+};
+
+class CURVEEDITOR_EXPORT Curve
+{
+ friend class CurveWidget;
+ friend class CurveEntity;
+public:
+ Curve(long segmentCount = 100);
+
+ void initValueRange(const QPointF& min, const QPointF& max);
+ QPointF getMinValue();
+ QPointF getMaxValue();
+
+ int getControlPointCount() { return (int) _controlPoints.size(); }
+ const ControlPoint& getControlPoint(int index) { return _controlPoints[index]; }
+ void appendControlPoint(ControlPoint& controlPoint, bool asDefaultToo = true);
+ int appendControlPoint(float x);
+ void setControlPoint(int index, const ControlPoint& point);
+ void reset(void);
+ void insertControlPointAt(int index);
+ void removeControlPoint(int index);
+ void removeControlPoints(std::vector<int>& indexes);
+
+ QPointF getPointByX(float x);
+ std::vector<QPointF> getSamplePoints();
+ Curve resampleCurve(int resamplePnts, long segmentCount = 100);
+
+ Curve& operator = (const Curve& right);
+
+private:
+ void _sample();
+ ControlPoint& _getNearCtrlPnt(float x);
+
+private:
+ bool _needSample;
+ bool _initValueRange;
+ QPointF _minValue;
+ QPointF _maxValue;
+ long _segmentCount;
+ std::vector<QPointF> _samplePoints;
+ std::vector<ControlPoint> _controlPoints;
+ std::vector<ControlPoint> _defaultControlPoints;
+};
+
+struct ColorControlPoint
+{
+ ColorControlPoint()
+ : x(0.0)
+ , color()
+ , mode (eDiscret)
+ , weight(0.5f)
+ , fallOff(0.5f)
+ , texturePath()
+ {
+ memset( &splineData, 0, sizeof(BezierSplineData));
+ }
+
+ ColorControlPoint(float inX, const QColor& inColor, InterpolateMode inMode, float inWeight = 0.5f, float inFallOff = 0.5f)
+ : x(inX)
+ , color(inColor)
+ , mode(inMode)
+ , weight(inWeight)
+ , fallOff(inFallOff)
+ , texturePath()
+ {
+ memset( &splineData, 0, sizeof(BezierSplineData));
+ }
+
+ ColorControlPoint(float inX, const QColor& inColor, InterpolateMode inMode, const BezierSplineData& inSplineData, float inWeight = 0.5f, float inFallOff = 0.5f)
+ : x(inX)
+ , color(inColor)
+ , mode(inMode)
+ , splineData(inSplineData)
+ , weight(inWeight)
+ , fallOff(inFallOff)
+ , texturePath()
+ {
+
+ }
+
+ float x;
+ QColor color;
+ InterpolateMode mode;
+ BezierSplineData splineData;
+ float weight; // if it's less than 0, the segememnt between this control point and next control point won't use weight algorithm
+ float fallOff;
+ std::string texturePath;
+ QColor textureAverageColor;
+};
+
+struct ColorPoint
+{
+ ColorPoint()
+ : x(0.0)
+ , color()
+ {
+ }
+
+ ColorPoint(float inX, const QColor& inColor)
+ : x(inX)
+ , color(inColor)
+ {
+ }
+
+ float x;
+ QColor color;
+};
+
+class ColorWidget;
+class CURVEEDITOR_EXPORT ColorCurve
+{
+ friend class ColorWidget;
+public:
+ ColorCurve(long segmentCount = 100);
+
+ void initValueRange(float min, float max);
+ float getMinValue();
+ float getMaxValue();
+
+ int getControlPointCount() { return (int) _controlPoints.size(); }
+ const ColorControlPoint& getControlPoint(int index) { return _controlPoints[index]; }
+ void appendControlPoint(ColorControlPoint& controlPoint, bool asDefaultToo = true);
+ void setControlPoint(int index, const ColorControlPoint& point);
+ void reset(void);
+ void insertControlPointAt(int index);
+ void removeControlPoint(int index);
+
+ QColor getColorByX(float x);
+
+ ColorCurve& operator = (const ColorCurve& right);
+
+private:
+ void _doSamplePoints();
+ void _reOrderControlPoints(int& pickedPoint);
+ QColor _calcTextureAverageColor(const char* texturePath);
+
+private:
+ bool _needSample;
+ bool _initValueRange;
+ float _minValue;
+ float _maxValue;
+ long _segmentCount;
+ std::vector<ColorPoint> _colorSamplePnts;
+ std::vector<ColorControlPoint> _controlPoints;
+ std::vector<ColorControlPoint> _defaultControlPoints;
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // CURVE_H
diff --git a/NvBlast/tools/CurveEditor/source/CurveEditorMainWindow.h b/NvBlast/tools/CurveEditor/source/CurveEditorMainWindow.h
new file mode 100644
index 0000000..1ae9092
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/CurveEditorMainWindow.h
@@ -0,0 +1,217 @@
+#ifndef CURVEEDITOR_H
+#define CURVEEDITOR_H
+
+#include <QtWidgets/QMainWindow>
+#include <QtWidgets/QTreeWidget>
+#include <QtXml\QtXml>
+#include "Attribute.h"
+
+namespace Ui {
+ class CurveEditorMainWindow;
+}
+
+namespace nvidia {
+namespace CurveEditor {
+
+class CurveWidget;
+class CurveEntity;
+class ColorWidget;
+
+class CURVEEDITOR_EXPORT CurveEditorMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+ friend class CurveWidget;
+ friend class CurveEntity;
+ friend class ColorWidget;
+
+public:
+ explicit CurveEditorMainWindow(QWidget *parent = 0);
+ ~CurveEditorMainWindow();
+
+ void setCurveAttributes(const std::vector<CurveAttributeBase*>& attributes);
+ void setColorCurveAttributes(const std::vector<ColorAttribute*>& attributes);
+ // if this method is called, tab widget switch to curve attribute tab
+ void setSelectedCurveAttributes(const std::vector<CurveAttributeBase*>& attributes);
+ // if this method is called, tab widget switch to color attribute tab
+ void setSelectedColorAttribute(const ColorAttribute* attribute);
+ void setResampleEnabled(bool enable);
+
+signals:
+ void CurveAttributeChanged(nvidia::CurveEditor::CurveAttribute* attribute);
+ void ColorAttributeChanged(nvidia::CurveEditor::ColorAttribute* attribute);
+ // if reloadColorTex is true, reload texture of the selected control point of the color curve of the color attribute
+ // if reloadColorTex is false, reload texture of the selected control point of the alpha curve of the color attribute
+ // selectedCtrlPntIndex index of the selected control point
+ void ReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute* attribute, bool reloadColorTex, int selectedCtrlPntIndex);
+
+private slots:
+ /////////////////////////slots for signals of standard QT controls//////////////////////////////////////////////////////
+ void on_actionCopy_triggered();
+
+ void on_actionPaste_triggered();
+
+ void on_actionSave_Selected_as_Preset_triggered();
+
+ void on_actionLoad_Preset_to_Copy_Buffer_triggered();
+
+ void on_actionImport_Preset_onto_Selected_triggered();
+
+ void on_actionReset_Curve_triggered();
+
+ void on_actionAdd_Before_Selected_triggered();
+
+ void on_actionAdd_After_Selected_triggered();
+
+ void on_actionRemove_Selected_triggered();
+
+ void on_actionTangent_Stepped_triggered();
+
+ void on_actionTangent_Linear_triggered();
+
+ void on_actionTangent_Smooth_triggered();
+
+ void on_actionTangent_Ease_Out_triggered();
+
+ void on_actionTangent_Ease_In_triggered();
+
+ void on_actionTangent_Spline_triggered();
+
+ void on_actionSnap_All_triggered();
+
+ void on_actionSnap_Horizontal_triggered();
+
+ void on_actionSnap_Vertical_triggered();
+
+ void on_actionContract_Horizontally_triggered();
+
+ void on_actionExpand_Horizontally_triggered();
+
+ void on_actionContract_Vertically_triggered();
+
+ void on_actionExpand_Vertically_triggered();
+
+ void on_actionFrame_Horizontally_triggered();
+
+ void on_actionFrame_Vertically_triggered();
+
+ void on_actionFrame_All_triggered();
+
+ void on_spinBoxLocation_valueChanged(double value);
+
+ void on_spinBoxValue_valueChanged(double value);
+
+ void on_btnColor_clicked();
+
+ void on_btnColorTex_clicked();
+
+ void on_btnColorReload_clicked();
+
+ void on_btnColorClear_clicked();
+
+ void on_btnAlpha_clicked();
+
+ void on_btnAlphaTex_clicked();
+
+ void on_btnAlphaReload_clicked();
+
+ void on_btnAlphaClear_clicked();
+
+ void on_checkBoxUseAlphaChannellFromColor_stateChanged(int val);
+
+ void on_treeWidgetCurveAttributes_itemSelectionChanged();
+
+ void on_treeWidgetColorAttributes_itemSelectionChanged();
+
+ void on_tabWidgetAttributes_currentChanged(int index);
+
+ void on_sliderColorFallOff_sliderMoved(int value);
+
+ void on_sliderAlphaFallOff_sliderMoved(int value);
+
+ void on_actionAdd_Control_Point_By_Click_triggered(bool val);
+
+ void on_actionRemove_Control_Point_By_Click_triggered(bool val);
+
+ /////////////////////////slots for inside signals//////////////////////////////////////////////////////
+ void onCurvePickedControlPointChanged(const std::vector<CurveEntity*>& pickedCurves);
+
+ void onCurvePickedControlPointValueChanged(QPointF& value);
+
+ void onColorPickedControlPointChanged(bool isColorCtrlPnt);
+
+private:
+ class CurveAttributeTreeItem : public QTreeWidgetItem
+ {
+ public:
+ explicit CurveAttributeTreeItem(QTreeWidget *view, CurveAttributeBase* attribute)
+ : QTreeWidgetItem(view)
+ , _attribute(attribute)
+ {
+
+ }
+ explicit CurveAttributeTreeItem(QTreeWidgetItem *parent, CurveAttributeBase* attribute)
+ : QTreeWidgetItem(parent)
+ , _attribute(attribute)
+ {
+
+ }
+
+ CurveAttributeBase* _attribute;
+ };
+
+ class ColorAttributeTreeItem : public QTreeWidgetItem
+ {
+ public:
+ explicit ColorAttributeTreeItem(QTreeWidget *view, ColorAttribute* attribute)
+ : QTreeWidgetItem(view)
+ , _attribute(attribute)
+ {
+
+ }
+
+ ColorAttribute* _attribute;
+ };
+
+private:
+ void _fillCurveAttributesTree();
+ void _fillColorAttributesTree();
+ void _syncUIStatusWithSelectedAttribute(bool canAddRemoveControlPoint, bool canChangeTangentType);
+ void _setCurveExclusiveUIEnable(bool enable);
+ void _setColorUIEnable(bool enable);
+ void _setAlphaUIEnable(bool enable);
+ void _saveAttributeGroup(QDomElement& parentElm, CurveAttributeGroup* attributeGroup);
+ void _saveAttribute(QDomElement& parentElm, CurveAttribute* attribute);
+ void _saveAttribute(QDomElement& parentElm, ColorAttribute* attribute);
+ void _saveCurve(QDomElement& parentElm, Curve& curve);
+ void _saveCurve(QDomElement& parentElm, ColorCurve& curve, const QString& curveName);
+ void _saveCtrlPnt(QDomElement& parentElm, const ControlPoint& ctrlPnt);
+ void _saveCtrlPnt(QDomElement& parentElm, const ColorControlPoint& ctrlPnt);
+ CurveAttributeBase* _loadAttribute(QDomElement& elm);
+ void _loadCurve(QDomElement& elm, Curve& curve);
+ void _loadCurve(QDomElement& elm, ColorCurve& curve);
+ void _loadCtrlPnt(QDomElement& elm, ControlPoint& ctrlPnt);
+ void _loadCtrlPnt(QDomElement& elm, ColorControlPoint& ctrlPnt);
+
+ void _setTangentTypeUIStatus(bool enable);
+ void _setAddRemoveCtrlPntUIStatus(bool enable);
+
+ Ui::CurveEditorMainWindow* ui;
+ std::vector<CurveAttributeBase*> _curveAttributes;
+ std::vector<ColorAttribute*> _colorAttributes;
+ CurveWidget* _curveWidget;
+ ColorWidget* _colorWidget;
+ CurveAttribute* _curveAttributeCache; // for copy operation of curve attribute
+ ColorAttribute* _colorAttributeCache; // for copy operation of color attribute
+ bool _updateUIFromData;
+ bool _canMoveCurveControlPointHorizontally;
+ bool _canAddRemoveCurveControlPoint;
+ bool _canChangeCurveTangentType;
+ QString _lastFilePath;
+ QString _presetPath;
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // CURVEEDITOR_H
diff --git a/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/CurveEditorTestApp.cpp b/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/CurveEditorTestApp.cpp
new file mode 100644
index 0000000..9aa42bd
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/CurveEditorTestApp.cpp
@@ -0,0 +1,342 @@
+#include "CurveEditorTestApp.h"
+#include "ui_CurveEditorTestApp.h"
+#include "CurveEditorMainWindow.h"
+#include <QtCore/QDebug>
+
+CurveEditorTestApp::CurveEditorTestApp(QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(parent, flags)
+ , ui(new Ui::CurveEditorTestAppClass())
+ , _curveEditor(new CurveEditorMainWindow(this))
+{
+ ui->setupUi(this);
+
+ bool val = connect(_curveEditor, SIGNAL(CurveAttributeChanged(nvidia::CurveEditor::CurveAttribute*)), this, SLOT(onCurveAttributeChanged(nvidia::CurveEditor::CurveAttribute*)));
+ val = connect(_curveEditor, SIGNAL(ColorAttributeChanged(nvidia::CurveEditor::ColorAttribute*)), this, SLOT(onColorAttributeChanged(nvidia::CurveEditor::ColorAttribute*)) );
+ val = connect(_curveEditor, SIGNAL(ReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute*, bool, int)), this, SLOT(onReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute*, bool, int)) );
+
+ _curveEditor->hide();
+
+ _fillCurveAttributes();
+ _fillColorAttributes();
+}
+
+CurveEditorTestApp::~CurveEditorTestApp()
+{
+
+}
+
+void CurveEditorTestApp::on_btnCurveEditor_clicked(void)
+{
+ _curveEditor->show();
+}
+
+void CurveEditorTestApp::onCurveAttributeChanged(CurveAttribute* attribute)
+{
+ if (attribute)
+ {
+ qDebug()<<"-------------------------onCurveAttributeChanged---------------------------------";
+ qDebug()<< attribute->getName().c_str() <<": changed";
+
+ size_t count = attribute->curve.getControlPointCount();
+ for (int i = 0; i < count; ++i)
+ {
+ const ControlPoint& ctrlPnt = attribute->curve.getControlPoint(i);
+ if (attribute->getName() == "Y" && i == 9 && ctrlPnt.value.y() > 2.5)
+ {
+ int j = 0;
+ ++j;
+ }
+ qDebug()<< ctrlPnt.value;
+ }
+ }
+}
+
+void CurveEditorTestApp::onColorAttributeChanged(ColorAttribute* attribute)
+{
+ if (attribute)
+ {
+ qDebug()<<"----------------------------------------------------------";
+ qDebug()<< attribute->getName().c_str() <<": changed";
+ }
+}
+
+void CurveEditorTestApp::onReloadColorAttributeTexture(ColorAttribute* attribute, bool reloadColorTex, int selectedCtrlPntIndex)
+{
+ if (attribute)
+ {
+ qDebug()<<"----------------------------------------------------------";
+ qDebug()<< attribute->getName().c_str() <<": reloadColorTex" << reloadColorTex<< " selectedCtrlPntIndex: "<< selectedCtrlPntIndex;
+ }
+}
+
+void CurveEditorTestApp::_fillCurveAttributes()
+{
+ {
+ std::vector<CurveAttributeBase*> attributes;
+
+ CurveAttributeGroup* attrGroup = new CurveAttributeGroup("Position");
+ attributes.push_back(attrGroup);
+
+ CurveAttribute* attribute = new CurveAttribute("X", false, true, true);
+ //attribute->color = QColor(0x11, 0x22, 0x33, 0x44);//
+ attribute->color = QColor("#FF0000");
+ attrGroup->attributes.push_back(attribute);
+
+ {
+ Curve& curve = attribute->curve;
+ curve.initValueRange(QPointF(-1, 0), QPointF(6, 1));
+ curve.appendControlPoint(ControlPoint(-1, 1, eDiscret));
+ curve.appendControlPoint(ControlPoint(0, 0, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(0.25, 0.5, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(0.5, 0, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(0.75, 0.5, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(1, 0, eCatmullRomSpline));
+ {
+ BezierSplineData splineData;
+ splineData.inLen = 0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(2, 1, eBezierSpline, splineData));
+ splineData.inLen = 0.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(3, 0, eBezierSpline, splineData));
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(4, 1, eBezierSpline, splineData));
+ }
+ curve.appendControlPoint(ControlPoint(5, 0, eLinear));
+ curve.appendControlPoint(ControlPoint(6, 1, eLinear));
+ }
+
+ attribute = new CurveAttribute("Y", true);
+ attribute->color = QColor("#FFFF00");
+ attrGroup->attributes.push_back(attribute);
+ {
+ Curve& curve = attribute->curve;
+ curve.initValueRange(QPointF(-2, 0), QPointF(8, 2));
+ curve.appendControlPoint(ControlPoint(-2, 2, eDiscret));
+ curve.appendControlPoint(ControlPoint(1, 0, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(1.25, 0.5, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(1.5, 0, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(1.75, 0.5, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(2, 0, eCatmullRomSpline));
+ {
+ BezierSplineData splineData;
+ splineData.inLen = 0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(3, 1, eBezierSpline, splineData));
+ splineData.inLen = 0.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(4, 0, eBezierSpline, splineData));
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(5, 1, eBezierSpline, splineData));
+ }
+ curve.appendControlPoint(ControlPoint(6, 0, eLinear));
+ curve.appendControlPoint(ControlPoint(8, 2, eLinear));
+ }
+
+ attribute = new CurveAttribute("Z", true);
+ attribute->color = QColor("#00FF00");
+ attrGroup->attributes.push_back(attribute);
+ {
+ Curve& curve = attribute->curve;
+ curve.initValueRange(QPointF(-2, 0), QPointF(8, 4));
+ curve.appendControlPoint(ControlPoint(-2, 2, eDiscret));
+ curve.appendControlPoint(ControlPoint(1, 0, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(1.5, 4, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(1.75, 0.5, eCatmullRomSpline));
+ curve.appendControlPoint(ControlPoint(2, 1, eCatmullRomSpline));
+ {
+ BezierSplineData splineData;
+ splineData.inLen = 0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(3, 3, eBezierSpline, splineData));
+ splineData.inLen = 0.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(4, 0, eBezierSpline, splineData));
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(5, 2, eBezierSpline, splineData));
+ }
+ curve.appendControlPoint(ControlPoint(6, 0, eLinear));
+ curve.appendControlPoint(ControlPoint(8, 4, eLinear));
+ }
+
+ attribute = new CurveAttribute("AddRemove_ChangeTangent", true, true, true);
+
+ attributes.push_back(attribute);
+
+ {
+ Curve& curve = attribute->curve;
+ curve.initValueRange(QPointF(-1, 0), QPointF(4, 255));
+ curve.appendControlPoint(ControlPoint(-1, 0, eLinear));
+ {
+ BezierSplineData splineData;
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ControlPoint(4, 255, eBezierSpline, splineData));
+ }
+ }
+
+
+ _curveAttributes = attributes;
+ _curveEditor->setCurveAttributes(_curveAttributes);
+ }
+}
+
+void CurveEditorTestApp::_fillColorAttributes()
+{
+ {
+ std::vector<ColorAttribute*> attributes;
+
+ ColorAttribute* attribute = new ColorAttribute("Hair Color");
+ attributes.push_back(attribute);
+
+ {
+ ColorCurve& colorCurve = attribute->colorCurve;
+ colorCurve.initValueRange(0, 1);
+ ColorCurve& alphaCurve = attribute->alphaCurve;
+ alphaCurve.initValueRange(0, 1);
+
+ colorCurve.appendControlPoint(ColorControlPoint(0, QColor(255, 0, 0, 255), eLinear));
+ colorCurve.appendControlPoint(ColorControlPoint(1, QColor(0, 255, 0, 255), eLinear));
+
+ alphaCurve.appendControlPoint(ColorControlPoint(0, QColor(0, 0, 0, 0), eLinear));
+ alphaCurve.appendControlPoint(ColorControlPoint(1, QColor(0, 0, 0, 255), eLinear));
+ }
+
+ attribute = new ColorAttribute("XColor", true, true, true);
+ //attribute->color = QColor(0x11, 0x22, 0x33, 0x44);//
+ attributes.push_back(attribute);
+
+ {
+ ColorCurve& curve = attribute->colorCurve;
+ curve.initValueRange(-1, 6);
+ curve.appendControlPoint(ColorControlPoint(-1, QColor(255, 0, 0, 0), eDiscret));
+ curve.appendControlPoint(ColorControlPoint(0, QColor(0, 255, 0, 255), eCatmullRomSpline));
+ curve.appendControlPoint(ColorControlPoint(0.25, QColor(128, 0, 255, 128), eCatmullRomSpline));
+ curve.appendControlPoint(ColorControlPoint(0.5, QColor(255, 0, 0, 255), eCatmullRomSpline));
+ curve.appendControlPoint(ColorControlPoint(0.75, QColor(0, 255, 0, 128), eCatmullRomSpline));
+ curve.appendControlPoint(ColorControlPoint(1, QColor(0, 0, 255, 0), eCatmullRomSpline));
+ {
+ BezierSplineData splineData;
+ splineData.inLen = 0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ColorControlPoint(2, QColor(255, 0, 0, 255), eBezierSpline, splineData));
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ColorControlPoint(3, QColor(0, 255, 0, 128), eBezierSpline, splineData));
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ curve.appendControlPoint(ColorControlPoint(4, QColor(0, 0, 255, 0), eBezierSpline, splineData));
+ }
+ curve.appendControlPoint(ColorControlPoint(5, QColor(255, 0, 0, 255), eLinear));
+ curve.appendControlPoint(ColorControlPoint(6, QColor(0, 255, 0, 128), eLinear));
+ }
+
+ attribute = new ColorAttribute("Color_NoAddRemove_NotChangeTangent", true, false, false);
+
+ attributes.push_back(attribute);
+
+ {
+ ColorCurve& colorCurve = attribute->colorCurve;
+ colorCurve.initValueRange(-1, 4);
+ colorCurve.appendControlPoint(ColorControlPoint(-1, QColor(255, 0, 0, 0), eLinear));
+ colorCurve.appendControlPoint(ColorControlPoint(0, QColor(0, 255, 0, 255), eLinear));
+ colorCurve.appendControlPoint(ColorControlPoint(0.5, QColor(0, 0, 255, 255), eLinear));
+ colorCurve.appendControlPoint(ColorControlPoint(1, QColor(255, 0, 0, 0), eLinear));
+ {
+ BezierSplineData splineData;
+ splineData.inLen = 0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ colorCurve.appendControlPoint(ColorControlPoint(2, QColor(0, 255, 0, 255), eBezierSpline, splineData));
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ colorCurve.appendControlPoint(ColorControlPoint(3, QColor(0, 0, 255, 128), eBezierSpline, splineData));
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ colorCurve.appendControlPoint(ColorControlPoint(4, QColor(255, 0, 0, 0), eBezierSpline, splineData));
+ }
+
+ ColorCurve& alphaCurve = attribute->alphaCurve;
+ alphaCurve.initValueRange(-1, 4);
+ alphaCurve.appendControlPoint(ColorControlPoint(-1, QColor(0, 0, 0, 0), eDiscret));
+ alphaCurve.appendControlPoint(ColorControlPoint(1, QColor(0, 0, 0, 255), eLinear));
+ alphaCurve.appendControlPoint(ColorControlPoint(2, QColor(0, 0, 0, 80), eLinear));
+ alphaCurve.appendControlPoint(ColorControlPoint(4, QColor(0, 0, 0, 255), eLinear));
+ }
+
+ attribute = new ColorAttribute("Color_AddRemove_ChangeTangent", true, true, true);
+
+ attributes.push_back(attribute);
+
+ {
+ ColorCurve& colorCurve = attribute->colorCurve;
+ colorCurve.initValueRange(-1, 4);
+ colorCurve.appendControlPoint(ColorControlPoint(-1, QColor(255, 0, 0, 0), eLinear));
+ //colorCurve.appendControlPoint(ColorControlPoint(0, QColor(0, 255, 0, 255), eLinear));
+ //colorCurve.appendControlPoint(ColorControlPoint(0.5, QColor(0, 0, 255, 255), eLinear));
+ //colorCurve.appendControlPoint(ColorControlPoint(1, QColor(255, 0, 0, 0), eLinear));
+ {
+ BezierSplineData splineData;
+ //splineData.inLen = 0;
+ //splineData.inTan = 0;
+ //splineData.outLen = 1.0;
+ //splineData.outTan = 0;
+ //colorCurve.appendControlPoint(ColorControlPoint(2, QColor(0, 255, 0, 255), eBezierSpline, splineData));
+ //splineData.inLen = 1.0;
+ //splineData.inTan = 0;
+ //splineData.outLen = 1.0;
+ //splineData.outTan = 0;
+ //colorCurve.appendControlPoint(ColorControlPoint(3, QColor(0, 0, 255, 128), eBezierSpline, splineData));
+ splineData.inLen = 1.0;
+ splineData.inTan = 0;
+ splineData.outLen = 1.0;
+ splineData.outTan = 0;
+ colorCurve.appendControlPoint(ColorControlPoint(4, QColor(0, 255, 0, 0), eBezierSpline, splineData));
+ }
+
+ ColorCurve& alphaCurve = attribute->alphaCurve;
+ alphaCurve.initValueRange(-1, 4);
+ alphaCurve.appendControlPoint(ColorControlPoint(-1, QColor(0, 0, 0, 0), eDiscret));
+ //alphaCurve.appendControlPoint(ColorControlPoint(1, QColor(0, 0, 0, 255), eLinear));
+ //alphaCurve.appendControlPoint(ColorControlPoint(2, QColor(0, 0, 0, 80), eLinear));
+ alphaCurve.appendControlPoint(ColorControlPoint(4, QColor(0, 0, 0, 255), eLinear));
+ }
+
+ _colorAttributes = attributes;
+ _curveEditor->setColorCurveAttributes(_colorAttributes);
+ }
+}
diff --git a/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/CurveEditorTestApp.h b/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/CurveEditorTestApp.h
new file mode 100644
index 0000000..ed68141
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/CurveEditorTestApp.h
@@ -0,0 +1,49 @@
+#ifndef GRAPHEDITORTESTAPP_H
+#define GRAPHEDITORTESTAPP_H
+
+#include <QtWidgets/QWidget>
+
+namespace nvidia {
+namespace CurveEditor {
+
+class CurveEditorMainWindow;
+class CurveAttributeBase;
+class CurveAttribute;
+class ColorAttribute;
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+using namespace nvidia::CurveEditor;
+
+namespace Ui
+{
+ class CurveEditorTestAppClass;
+}
+
+class CurveEditorTestApp : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CurveEditorTestApp(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~CurveEditorTestApp();
+
+private slots:
+ void on_btnCurveEditor_clicked(void);
+ void onCurveAttributeChanged(nvidia::CurveEditor::CurveAttribute* attribute);
+ void onColorAttributeChanged(nvidia::CurveEditor::ColorAttribute* attribute);
+ void onReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute* attribute, bool reloadColorTex, int selectedCtrlPntIndex);
+
+private:
+ void _fillCurveAttributes();
+ void _fillColorAttributes();
+
+private:
+ Ui::CurveEditorTestAppClass* ui;
+ CurveEditorMainWindow* _curveEditor;
+ std::vector<CurveAttributeBase*> _curveAttributes;
+ std::vector<ColorAttribute*> _colorAttributes;
+};
+
+#endif // GRAPHEDITORTESTAPP_H
diff --git a/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/main.cpp b/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/main.cpp
new file mode 100644
index 0000000..ecc3a75
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/GraphEditorTestApp/main.cpp
@@ -0,0 +1,10 @@
+#include "CurveEditorTestApp.h"
+#include <QtWidgets/QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ CurveEditorTestApp w;
+ w.show();
+ return a.exec();
+}
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Curve/BezierSpline.cpp b/NvBlast/tools/CurveEditor/source/Internal/Curve/BezierSpline.cpp
new file mode 100644
index 0000000..03ab848
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Curve/BezierSpline.cpp
@@ -0,0 +1,143 @@
+#include "BezierSpline.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+std::vector<QPointF> BezierSpline::sample(const std::vector<BezierSplinePoint>& splinePoints, long segmentCount)
+{
+ std::vector<QPointF> samplePoints;
+
+ if (segmentCount < 1)
+ return samplePoints;
+
+ long lPointCount = (long)splinePoints.size();
+ float fLengthStep = 1.0 / segmentCount;
+ float ft;
+ QPointF p0;
+ QPointF p1;
+ QPointF p2;
+ QPointF p3;
+ QPointF p01;
+ QPointF p11;
+ QPointF p21;
+ QPointF p02;
+ QPointF p12;
+ QPointF p03;
+
+ for (int i = 1; i < lPointCount; i++)
+ {
+ const BezierSplinePoint& pt1 = splinePoints[i - 1];
+ const BezierSplinePoint& pt2 = splinePoints[i];
+
+ // start point of each Bezier curve segment
+ samplePoints.push_back(pt1.valuePoint);
+
+ // sample each point on each Bezier curve segment by percent value and De Casteljau algorithm
+ // the sample points are not including start point and end poit of the Bezier curve segement
+ for (int j = 1; j < segmentCount; j++)
+ {
+ ft = fLengthStep * j;
+
+ p0 = pt1.valuePoint;
+ p1 = pt1.ctrlPoint1;
+ p2 = pt2.ctrlPoint0;
+ p3 = pt2.valuePoint;
+
+ p01 = p0 + (p1 - p0) * ft;
+ p11 = p1 + (p2 - p1) * ft;
+ p21 = p2 + (p3 - p2) * ft;
+
+ p02 = p01 + (p11 - p01) * ft;\
+ p12 = p11 + (p21 - p11) * ft;
+ p03 = p02 + (p12 - p02) * ft;
+
+ samplePoints.push_back(p03);
+ }
+
+ if (i == lPointCount - 1)
+ {// end point of last Bezier curve segment
+ samplePoints.push_back(pt2.valuePoint);
+ }
+ }
+ return samplePoints;
+}
+
+BezierSpline::BezierSpline(long segmentCount)
+ : Spline(segmentCount)
+ , _controlPoints()
+{
+}
+
+bool BezierSpline::getControlPoint(int index, BezierSplinePoint &pt)
+{
+ long lPointCount = (long)_controlPoints.size();
+
+ if (lPointCount == 0)
+ {
+ return false;
+ }
+
+ index = index < 0 ? 0 : (index >= lPointCount ? lPointCount - 1: index);
+
+ pt = _controlPoints[index];
+
+ return true;
+}
+
+void BezierSpline::appendControlPoint(BezierSplinePoint pt)
+{
+ _controlPoints.push_back(pt);
+
+ _needSample = true;
+}
+
+void BezierSpline::insertControlPoint(int index, BezierSplinePoint pt)
+{
+ long lPointCount = (long)_controlPoints.size();
+
+ index = index < 0 ? 0 : (index >= lPointCount ? lPointCount: index);
+
+ _controlPoints.insert(_controlPoints.begin() + index, pt);
+
+ _needSample = true;
+}
+
+bool BezierSpline::setControlPoint(int index, BezierSplinePoint pt)
+{
+ long lPointCount = (long)_controlPoints.size();
+
+ if (0 <= index && index < lPointCount)
+ {
+ _controlPoints[index] = pt;
+ _needSample = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool BezierSpline::removeControlPoint(int index)
+{
+ long lPointCount = (long)_controlPoints.size();
+
+ if (0 <= index && index < lPointCount)
+ {
+ _controlPoints.erase(_controlPoints.begin() + index);
+ _needSample = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void BezierSpline::_doSample()
+{
+ _samplePoints = sample(_controlPoints, _segmentCount);
+}
+
+} // namespace CurveEditor
+} // namespace nvidia \ No newline at end of file
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Curve/BezierSpline.h b/NvBlast/tools/CurveEditor/source/Internal/Curve/BezierSpline.h
new file mode 100644
index 0000000..ba5da46
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Curve/BezierSpline.h
@@ -0,0 +1,57 @@
+#ifndef BEZIERSPLINE_H
+#define BEZIERSPLINE_H
+#include <vector>
+#include <QtCore/QPointF>
+#include "Spline.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+class BezierSplinePoint
+{
+public:
+ QPointF ctrlPoint0;
+ QPointF valuePoint;
+ QPointF ctrlPoint1;
+};
+
+class BezierSpline : public Spline
+{
+public:
+ static std::vector<QPointF> sample(const std::vector<BezierSplinePoint>& splinePoints, long segmentCount = 100);
+
+ BezierSpline(long segmentCount = 100);
+
+ virtual ~BezierSpline() {}
+
+ inline long getControlPointCount() { return (long)_controlPoints.size(); }
+
+ // index <= 0, return the first point;
+ // index >= point count, return the last point.
+ bool getControlPoint(int index, BezierSplinePoint &pt);
+
+ // add a spline point to last
+ void appendControlPoint(BezierSplinePoint pt);
+
+ // insert a spline point at the identified position.
+ // index <= 0, inert to fisrt;
+ // index >= point count, insert to last.
+ void insertControlPoint(int index, BezierSplinePoint pt);
+
+ // change a spline point value at the identified position.
+ bool setControlPoint(int index, BezierSplinePoint pt);
+
+ // remove the identified spline point.
+ bool removeControlPoint(int index);
+
+private:
+ virtual void _doSample();
+
+private:
+ std::vector<BezierSplinePoint> _controlPoints;
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // BEZIERSPLINE_H
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Curve/CatmullRomSpline.cpp b/NvBlast/tools/CurveEditor/source/Internal/Curve/CatmullRomSpline.cpp
new file mode 100644
index 0000000..abe80bb
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Curve/CatmullRomSpline.cpp
@@ -0,0 +1,205 @@
+#include "CatmullRomSpline.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+float CatmullRomSpline::splineInterpolate(float v0, float v1, float v2, float v3, float u)
+{
+ float basis[4];
+
+ {
+ _computeSplineBasis(u, basis);
+ return
+ basis[0] * v0 +
+ basis[1] * v1 +
+ basis[2] * v2 +
+ basis[3] * v3;
+ }
+}
+
+QPointF CatmullRomSpline::splineInterpolate(const QPointF& p0, const QPointF& p1, const QPointF& p2, const QPointF& p3, float u)
+{
+ float basis[4];
+
+ {
+ _computeSplineBasis(u, basis);
+ return
+ QPointF(basis[0] * p0.x() +
+ basis[1] * p1.x() +
+ basis[2] * p2.x() +
+ basis[3] * p3.x(),
+ basis[0] * p0.y() +
+ basis[1] * p1.y() +
+ basis[2] * p2.y() +
+ basis[3] * p3.y());
+ }
+}
+
+std::vector<QPointF> CatmullRomSpline::sample(const std::vector<QPointF>& inControlPoints, int numSegments)
+{
+ std::vector<QPointF> samplePoints;
+ int numPoints = (int)inControlPoints.size();
+
+ for (int i = 0; i < numPoints - 1; i++)
+ {
+ QPointF p0, p1, p2, p3;
+
+ if (i == 0)
+ {
+ p0 = inControlPoints[0], p1 = inControlPoints[0], p2 = inControlPoints[1];
+ if (2 < numPoints)
+ p3 = inControlPoints[2];
+ else
+ p3 = inControlPoints[1];
+
+ }
+ else if (0 < i && i < numPoints - 2)
+ {
+ p0 = inControlPoints[i-1], p1 = inControlPoints[i], p2 = inControlPoints[i+1], p3 = inControlPoints[i+2];
+ }
+ else
+ {
+ if (2 < numPoints)
+ p0 = inControlPoints[i-1];
+ else
+ p0 = inControlPoints[i];
+ p1 = inControlPoints[i], p2 = inControlPoints[i+1], p3 = inControlPoints[i+1];
+ }
+
+ for (int j = 0; j <= numSegments; j++)
+ {
+ float u = j / float(numSegments);
+
+ samplePoints.push_back(splineInterpolate(p0, p1, p2, p3, u));
+ }
+ }
+
+ return samplePoints;
+}
+
+void CatmullRomSpline::_computeSplineBasis(float u, float* basis)
+{
+ float u2 = u * u;
+ float u3 = u2 * u;
+
+ basis[0] = -0.5f * u3 + 1.0f * u2 - 0.5f * u + 0.0f;
+ basis[1] = 1.5f * u3 - 2.5f * u2 + 0.0f * u + 1.0f;
+ basis[2] = -1.5f * u3 + 2.0f * u2 + 0.5f * u + 0.0f;
+ basis[3] = 0.5f * u3 - 0.5f * u2 + 0.0f * u + 0.0f;
+}
+
+CatmullRomSpline::CatmullRomSpline(long segmentCount)
+ : Spline(segmentCount)
+ , _controlPoints()
+{
+ _segmentCount = segmentCount < 1 ? 1 : segmentCount;
+}
+
+CatmullRomSpline::CatmullRomSpline(int numControlPoints, long segmentCount)
+ : Spline(segmentCount)
+ , _controlPoints()
+{
+ for (int i = 0; i < numControlPoints; ++i)
+ {
+ _controlPoints.push_back(QPointF(i / float(numControlPoints - 1), 1.0f));
+ }
+}
+
+CatmullRomSpline::~CatmullRomSpline(void)
+{
+}
+
+void CatmullRomSpline::setControlPoint(int index, const QPointF& point)
+{
+ std::vector<QPointF>::iterator itr = _controlPoints.begin();
+ std::advance(itr, index);
+ *itr = point;
+}
+
+QPointF CatmullRomSpline::getControlPoint(int index)
+{
+ std::vector<QPointF>::iterator itr = _controlPoints.begin();
+ std::advance(itr, index);
+ return *itr;
+}
+
+std::vector<QPointF> CatmullRomSpline::getControlPoints()
+{
+ return _controlPoints;
+}
+
+void CatmullRomSpline::reset(void)
+{
+ int i = 0;
+ for (std::vector<QPointF>::iterator itr = _controlPoints.begin(); itr != _controlPoints.end(); ++itr, ++i)
+ {
+ itr->setX(i / float(_controlPoints.size() - 1));
+ itr->setY(1.0f);
+ }
+}
+
+void CatmullRomSpline::insertControlPointAt(int index)
+{
+ QPointF p0, p1, p2, p3;
+
+ QPointF newPoint;
+ std::vector<QPointF>::iterator itr = _controlPoints.begin();
+
+ if (index == 0)
+ {
+ return;
+ }
+ else if (index == 1)
+ {
+ p0 = _controlPoints[0], p1 = _controlPoints[0], p2 = _controlPoints[1];
+ if (_controlPoints.size() > 2)
+ p3 = _controlPoints[2];
+ else
+ p3 = _controlPoints[1];
+ newPoint = splineInterpolate(p0, p1, p2, p3, 0.5);
+ }
+ else if (index > (int)(_controlPoints.size() - 1))
+ {
+ return;
+ }
+ else if (index == (_controlPoints.size() - 1))
+ {
+ if (_controlPoints.size() > 2)
+ p0 = _controlPoints[index-2];
+ else
+ p0 = _controlPoints[index-1];
+ p1 = _controlPoints[index-1], p2 = _controlPoints[index], p3 = _controlPoints[index];
+ newPoint = splineInterpolate(p0, p1, p2, p3, 0.5);
+ }
+ else
+ {
+ p0 = _controlPoints[index - 2], p1 = _controlPoints[index - 1], p2 = _controlPoints[index], p3 = _controlPoints[index + 1];
+ newPoint = splineInterpolate(p0, p1, p2, p3, 0.5);
+ }
+
+ std::advance(itr, index);
+ _controlPoints.insert(itr, newPoint);
+}
+
+void CatmullRomSpline::removeControlPoints(std::vector<int>& points)
+{
+ for (std::vector<int>::iterator itr = points.begin(); itr != points.end(); ++itr)
+ {
+ std::vector<QPointF>::iterator itrToRemove = _controlPoints.begin();
+ std::advance(itrToRemove, *itr);
+ _controlPoints.erase(itrToRemove);
+
+ for (std::vector<int>::iterator itrRight = itr + 1; itrRight != points.end(); ++itrRight)
+ {
+ --(*itrRight);
+ }
+ }
+}
+
+void CatmullRomSpline::_doSample()
+{
+ _samplePoints = sample(_controlPoints, _segmentCount);
+}
+
+} // namespace CurveEditor
+} // namespace nvidia \ No newline at end of file
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Curve/CatmullRomSpline.h b/NvBlast/tools/CurveEditor/source/Internal/Curve/CatmullRomSpline.h
new file mode 100644
index 0000000..71573a9
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Curve/CatmullRomSpline.h
@@ -0,0 +1,44 @@
+#ifndef CatmullRomSpline_h__
+#define CatmullRomSpline_h__
+
+#include <QtCore/QPoint>
+#include <vector>
+#include "Spline.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+class CatmullRomSpline : public Spline
+{
+public:
+ static float splineInterpolate(float v0, float v1, float v2, float v3, float u);
+ static QPointF splineInterpolate(const QPointF& p0, const QPointF& p1, const QPointF& p2, const QPointF& p3, float u);
+ static std::vector<QPointF> sample(const std::vector<QPointF>& inControlPoints, int numSegments = 100);
+private:
+ static void _computeSplineBasis(float u, float* basis);
+
+public:
+ CatmullRomSpline(long segmentCount = 100);
+ CatmullRomSpline(int numControlPoints, long segmentCount = 100);
+ virtual ~CatmullRomSpline(void);
+
+ int getControlPointCount() { return (int)_controlPoints.size(); }
+ // add a spline point to last
+ void appendControlPoint(QPointF point) { _controlPoints.push_back(point); }
+ void setControlPoint(int index, const QPointF& point);
+ QPointF getControlPoint(int index);
+ std::vector<QPointF> getControlPoints();
+ void reset(void);
+ void insertControlPointAt(int index);
+ void removeControlPoints(std::vector<int>& points);
+
+private:
+ virtual void _doSample();
+private:
+ std::vector<QPointF> _controlPoints;
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // CatmullRomSpline_h__
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Curve/Curve.cpp b/NvBlast/tools/CurveEditor/source/Internal/Curve/Curve.cpp
new file mode 100644
index 0000000..01d6351
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Curve/Curve.cpp
@@ -0,0 +1,1114 @@
+#include "Curve.h"
+#include "BezierSpline.h"
+#include "CatmullRomSpline.h"
+#include <QtCore/QDebug>
+#include <QtWidgets/QMessageBox>
+#include <QtGui/QImage>
+#pragma warning( disable : 4312 )
+#pragma warning( disable : 4996 )
+#include "../../../external/stb_image/stb_image.c"
+
+namespace nvidia {
+namespace CurveEditor {
+
+Curve::Curve(long segmentCount)
+ : _needSample(true)
+ , _initValueRange(false)
+ , _minValue()
+ , _maxValue(1.0f, 1.0f)
+ , _segmentCount(1)
+ , _samplePoints()
+ , _controlPoints()
+ , _defaultControlPoints()
+{
+ _segmentCount = segmentCount < 1 ? 1 : segmentCount;
+}
+
+void Curve::initValueRange(const QPointF& min, const QPointF& max)
+{
+ if (min.x() >= max.x() || min.y() >max.y())
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Max value must be larger than min value when initilize value range of curve"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return ;
+ }
+
+ _minValue = min;
+ _maxValue = max;
+ _initValueRange = true;
+}
+
+QPointF Curve::getMinValue()
+{
+ return _minValue;
+}
+
+QPointF Curve::getMaxValue()
+{
+ return _maxValue;
+}
+
+void Curve::appendControlPoint(ControlPoint& controlPoint, bool asDefaultToo)
+{
+ if (!_initValueRange)
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Curve must be initilized its value range before being used!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return;
+ }
+
+ if (controlPoint.value.x() < _minValue.x()
+ || controlPoint.value.x() > _maxValue.x()
+ || controlPoint.value.y() < _minValue.y()
+ || controlPoint.value.y() > _maxValue.y())
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("The value of the control point to add isn't in value range of the curve to add!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return;
+ }
+
+ _controlPoints.push_back(controlPoint);
+
+ if (asDefaultToo)
+ {
+ _defaultControlPoints.push_back(controlPoint);
+ }
+
+ _needSample = true;
+}
+
+int Curve::appendControlPoint(float x)
+{
+ size_t count = _controlPoints.size();
+ for (int i = 0; i < count - 1; ++i)
+ {
+ ControlPoint& ctrlPntLeft = _controlPoints[i];
+ ControlPoint& ctrlPntRight = _controlPoints[i + 1];
+ if (ctrlPntLeft.value.x() <= x && x <= ctrlPntRight.value.x())
+ {
+ std::vector<ControlPoint>::iterator itr = _controlPoints.begin();
+ std::advance(itr, i+1);
+ ControlPoint pnt(x, getPointByX(x).y(), ctrlPntLeft.mode, ctrlPntLeft.splineData);
+ _controlPoints.insert(itr, pnt);
+ _needSample = true;
+ return i + 1;
+ }
+ }
+
+ return -1;
+}
+
+void Curve::setControlPoint(int index, const ControlPoint& point)
+{
+ if (index < 0 || index > (_controlPoints.size() - 1) )
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Meet invalid index when setting control point for curve!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return;
+ }
+
+ if (point.value.x() < _minValue.x()
+ || point.value.x() > _maxValue.x()
+ || point.value.y() < _minValue.y()
+ || point.value.y() > _maxValue.y())
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("The setting value isn't in value range of the curve!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return;
+ }
+ std::vector<ControlPoint>::iterator itr = _controlPoints.begin();
+ std::advance(itr, index);
+ *itr = point;
+ _needSample = true;
+}
+
+void Curve::reset(void)
+{
+ if (_defaultControlPoints.size() > 0)
+ {
+ _controlPoints = _defaultControlPoints;
+ _needSample = true;
+ }
+}
+
+void Curve::insertControlPointAt(int index)
+{
+ if (index < 0)
+ index = 0;
+ else if (index > (_controlPoints.size() - 1) )
+ index = (int)(_controlPoints.size() - 1);
+
+ std::vector<ControlPoint>::iterator itrToAdd = _controlPoints.begin();
+ std::advance(itrToAdd, index);
+
+ ControlPoint& ctrlPntFront = _controlPoints[index - 1];
+ ControlPoint& ctrlPntBehind = _controlPoints[index];
+
+ switch (ctrlPntFront.mode)
+ {
+ case eDiscret:
+ {
+ ControlPoint ctrlPntToAdd;
+ ctrlPntToAdd.mode = ctrlPntFront.mode;
+ ctrlPntToAdd.value.setX((ctrlPntFront.value.x() + ctrlPntBehind.value.x()) / 2);
+ ctrlPntToAdd.value.setY(ctrlPntFront.value.y());
+ _controlPoints.insert(itrToAdd, ctrlPntToAdd);
+ break;
+ }
+ case eLinear:
+ {
+ ControlPoint ctrlPntToAdd;
+ ctrlPntToAdd.mode = ctrlPntFront.mode;
+ ctrlPntToAdd.value.setX((ctrlPntFront.value.x() + ctrlPntBehind.value.x()) / 2);
+ ctrlPntToAdd.value.setY(ctrlPntFront.value.y() + (ctrlPntBehind.value.y() - ctrlPntFront.value.y()) / 2);
+ _controlPoints.insert(itrToAdd, ctrlPntToAdd);
+ break;
+ }
+ case eBezierSpline:
+ {
+ BezierSplinePoint bezierPnt0;
+ BezierSplinePoint bezierPnt1;
+
+ float xStride = ctrlPntBehind.value.x() - ctrlPntFront.value.x();
+ bezierPnt0.ctrlPoint0 = ctrlPntFront.value;
+ bezierPnt0.valuePoint = ctrlPntFront.value;
+ float xDelta = ctrlPntFront.splineData.outLen * xStride;
+ bezierPnt0.ctrlPoint1 = ctrlPntFront.value + QPointF(xDelta, xDelta * ctrlPntFront.splineData.outTan);
+
+ if (eBezierSpline == ctrlPntBehind.mode)
+ {
+ xDelta = ctrlPntBehind.splineData.inLen * xStride;
+ bezierPnt1.ctrlPoint0 = ctrlPntBehind.value - QPointF(xDelta, xDelta * ctrlPntBehind.splineData.inTan);
+ bezierPnt1.valuePoint = ctrlPntBehind.value;
+ bezierPnt1.ctrlPoint1 = ctrlPntBehind.value;
+ }
+ else
+ {
+ bezierPnt1.ctrlPoint0 = ctrlPntBehind.value;
+ bezierPnt1.valuePoint = ctrlPntBehind.value;
+ bezierPnt1.ctrlPoint1 = ctrlPntBehind.value;
+ }
+
+ BezierSpline spline(100);
+ spline.appendControlPoint(bezierPnt0);
+ spline.appendControlPoint(bezierPnt1);
+ QPointF pntOnSpline;
+ spline.getPointByX(ctrlPntFront.value.x() + xStride / 2, pntOnSpline);
+
+ ControlPoint ctrlPntToAdd;
+ ctrlPntToAdd.mode = eBezierSpline;
+ ctrlPntToAdd.value = pntOnSpline;
+ ctrlPntToAdd.splineData.inLen = 1.0;
+ ctrlPntToAdd.splineData.inTan = 0.0;
+ ctrlPntToAdd.splineData.outLen = 1.0;
+ ctrlPntToAdd.splineData.outTan = 0.0;
+ _controlPoints.insert(itrToAdd, ctrlPntToAdd);
+ break;
+ }
+ case eCatmullRomSpline:
+ {
+ CatmullRomSpline spline;
+
+ int i = index - 1;
+ for (; i >= 0; --i)
+ {
+ if (eCatmullRomSpline != _controlPoints[i].mode)
+ {
+ ++i;
+ break;
+ }
+ }
+
+ if (i < 0)
+ i = 0;
+
+ for (; i < (int)_controlPoints.size(); ++i)
+ {
+ spline.appendControlPoint(_controlPoints[i].value);
+ if (eCatmullRomSpline != _controlPoints[i].mode)
+ break;
+ }
+
+ QPointF pntOnSpline;
+ spline.getPointByX((ctrlPntFront.value.x() + ctrlPntBehind.value.x()) / 2, pntOnSpline);
+ ControlPoint ctrlPntToAdd;
+ ctrlPntToAdd.mode = eCatmullRomSpline;
+ ctrlPntToAdd.value = pntOnSpline;
+ _controlPoints.insert(itrToAdd, ctrlPntToAdd);
+ break;
+ }
+ default:
+ break;
+ }
+
+ _needSample = true;
+}
+
+void Curve::removeControlPoint(int index)
+{
+ std::vector<ControlPoint>::iterator itr = _controlPoints.begin();
+ std::advance(itr, index);
+ _controlPoints.erase(itr);
+ _needSample = true;
+}
+
+void Curve::removeControlPoints(std::vector<int>& indexes)
+{
+ for (std::vector<int>::iterator itr = indexes.begin(); itr != indexes.end(); ++itr)
+ {
+ std::vector<ControlPoint>::iterator itrToRemove = _controlPoints.begin();
+ std::advance(itrToRemove, *itr);
+ _controlPoints.erase(itrToRemove);
+
+ for (std::vector<int>::iterator itrRight = itr + 1; itrRight != indexes.end(); ++itrRight)
+ {
+ --(*itrRight);
+ }
+ }
+
+ _needSample = true;
+}
+
+QPointF Curve::getPointByX(float x)
+{
+ if (!_initValueRange)
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Curve must be initilized its value range before being used!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return QPointF(0, 0);
+ }
+
+ if (x < _controlPoints[0].value.x())
+ return _controlPoints[0].value;
+
+ if (x >= _controlPoints[_controlPoints.size() - 1].value.x())
+ return _controlPoints[_controlPoints.size() - 1].value;
+
+ long lPointCount = (long)_samplePoints.size();
+
+ if(lPointCount < 2)
+ {
+ return QPointF(0,0);
+ }
+
+ if (_needSample)
+ _sample();
+
+ QPointF point;
+
+ for (int i = 0; i < lPointCount - 1; i++)
+ {
+ if(_samplePoints[i].x() <= x && _samplePoints[i + 1].x() > x)
+ {
+ point.setX( x );
+ float fRate = (x - _samplePoints[i].x())/ (_samplePoints[i + 1].x() - _samplePoints[i].x());
+ point.setY(_samplePoints[i].y() + (_samplePoints[i+1].y() - _samplePoints[i].y()) * fRate);
+ return point;
+ }
+ }
+
+ return QPointF(0,0);
+}
+
+std::vector<QPointF> Curve::getSamplePoints()
+{
+ if (!_initValueRange)
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Curve must be initilized its value range before being used!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return std::vector<QPointF>();
+ }
+
+ if (_needSample)
+ _sample();
+
+ return _samplePoints;
+}
+
+Curve Curve::resampleCurve(int resamplePnts, long segmentCount)
+{
+ if (!_initValueRange)
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Curve must be initilized its value range before being used!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return Curve();
+ }
+
+ Curve resmapleCurve(segmentCount);
+ if (resamplePnts < 2)
+ return resmapleCurve;
+ else
+ {
+ int segment = resamplePnts - 1;
+ float xStart = _controlPoints[0].value.x();
+ float xEnd = _controlPoints[_controlPoints.size() - 1].value.x();
+ float strideX = (xEnd - xStart) / segment;
+ for (int i = 0; i <= segment; ++i)
+ {
+ float x = xStart + strideX * i;
+ QPointF pnt = getPointByX(x);
+ ControlPoint& ctrlPntNear = _getNearCtrlPnt(x);
+
+ ControlPoint ctrlPntNew(pnt.x(), pnt.y(), ctrlPntNear.mode);
+
+ if (eBezierSpline == ctrlPntNear.mode)
+ {
+ ctrlPntNew.splineData = ctrlPntNear.splineData;
+ }
+
+ resmapleCurve.appendControlPoint(ctrlPntNew);
+ }
+ }
+
+ return resmapleCurve;
+}
+
+Curve& Curve::operator = (const Curve& right)
+{
+ if (this == &right)
+ return *this;
+
+ _needSample = right._needSample;
+ _initValueRange = right._initValueRange;
+ _minValue = right._minValue;
+ _maxValue = right._maxValue;
+ _segmentCount = right._segmentCount;
+ _samplePoints = right._samplePoints;
+ _controlPoints = right._controlPoints;
+
+ return *this;
+}
+
+void Curve::_sample()
+{
+ _samplePoints.clear();
+
+ for (size_t i = 1; i < _controlPoints.size(); ++i)
+ {
+ ControlPoint& ctrlPntFront = _controlPoints[i-1];
+ ControlPoint& ctrlPntBehind = _controlPoints[i];
+
+ switch (ctrlPntFront.mode)
+ {
+ case eDiscret:
+ {
+ _samplePoints.push_back(ctrlPntFront.value);
+ _samplePoints.push_back(QPointF(ctrlPntBehind.value.x(), ctrlPntFront.value.y()));
+ break;
+ }
+ case eLinear:
+ {
+ _samplePoints.push_back(ctrlPntFront.value);
+ _samplePoints.push_back(ctrlPntBehind.value);
+ break;
+ }
+ case eBezierSpline:
+ {
+ BezierSplinePoint bezierPnt0;
+ BezierSplinePoint bezierPnt1;
+
+ float xStride = ctrlPntBehind.value.x() - ctrlPntFront.value.x();
+ bezierPnt0.ctrlPoint0 = ctrlPntFront.value;
+ bezierPnt0.valuePoint = ctrlPntFront.value;
+ float xDelta = ctrlPntFront.splineData.outLen * xStride;
+ bezierPnt0.ctrlPoint1 = ctrlPntFront.value + QPointF(xDelta, xDelta * ctrlPntFront.splineData.outTan);
+
+ if (eBezierSpline == ctrlPntBehind.mode)
+ {
+ xDelta = ctrlPntBehind.splineData.inLen * xStride;
+ bezierPnt1.ctrlPoint0 = ctrlPntBehind.value - QPointF(xDelta, xDelta * ctrlPntBehind.splineData.inTan);
+ bezierPnt1.valuePoint = ctrlPntBehind.value;
+ bezierPnt1.ctrlPoint1 = ctrlPntBehind.value;
+ }
+ else
+ {
+ bezierPnt1.ctrlPoint0 = ctrlPntBehind.value;
+ bezierPnt1.valuePoint = ctrlPntBehind.value;
+ bezierPnt1.ctrlPoint1 = ctrlPntBehind.value;
+ }
+
+ BezierSpline spline(_segmentCount);
+ spline.appendControlPoint(bezierPnt0);
+ spline.appendControlPoint(bezierPnt1);
+
+ std::vector<QPointF> pnts = spline.getSamplePoints();
+ _samplePoints.insert(_samplePoints.end(), pnts.begin(), pnts.end());
+ break;
+ }
+ case eCatmullRomSpline:
+ {
+ CatmullRomSpline spline(_segmentCount);
+
+ for (i = i - 1; i < _controlPoints.size(); ++i)
+ {
+ spline.appendControlPoint(_controlPoints[i].value);
+ if (eCatmullRomSpline != _controlPoints[i].mode)
+ {
+ break;
+ }
+ }
+
+ std::vector<QPointF> pnts = spline.getSamplePoints();
+ _samplePoints.insert(_samplePoints.end(), pnts.begin(), pnts.end());
+ break;
+ }
+ }
+ }
+
+ _needSample = false;
+}
+
+ControlPoint& Curve::_getNearCtrlPnt(float x)
+{
+ size_t count = _controlPoints.size();
+ for (int i = 0; i < count - 1; ++i)
+ {
+ ControlPoint& ctrlPntLeft = _controlPoints[i];
+ ControlPoint& ctrlPntRight = _controlPoints[i + 1];
+ if (x < ctrlPntLeft.value.x())
+ return ctrlPntLeft;
+ else if (ctrlPntLeft.value.x() <= x && x <= ctrlPntRight.value.x())
+ {
+ if (abs(x - ctrlPntLeft.value.x()) <= abs(x - ctrlPntRight.value.x()))
+ {
+ return ctrlPntLeft;
+ }
+ else
+ {
+ return ctrlPntRight;
+ }
+ }
+ }
+ return _controlPoints[0];
+}
+
+ColorCurve::ColorCurve(long segmentCount)
+ : _needSample(true)
+ , _initValueRange(false)
+ , _minValue(0.0f)
+ , _maxValue(1.0f)
+ , _colorSamplePnts()
+ , _controlPoints()
+ , _defaultControlPoints()
+{
+ _segmentCount = segmentCount < 1 ? 1 : segmentCount;
+}
+
+void ColorCurve::initValueRange(float min, float max)
+{
+ if (min >= max )
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Max x must be larger than min x when initilize value range of color curve"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return ;
+ }
+
+ _minValue = min;
+ _maxValue = max;
+ _initValueRange = true;
+}
+
+float ColorCurve::getMinValue()
+{
+ return _minValue;
+}
+
+float ColorCurve::getMaxValue()
+{
+ return _maxValue;
+}
+
+void ColorCurve::appendControlPoint(ColorControlPoint& controlPoint, bool asDefaultToo)
+{
+ if (!_initValueRange)
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Color curve must be initilized its value range before being used!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return;
+ }
+
+ if (controlPoint.x < _minValue
+ || controlPoint.x > _maxValue)
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("The x value of the control point to add isn't in x value range of the color curve to add!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return;
+ }
+
+ _controlPoints.push_back(controlPoint);
+
+ if (asDefaultToo)
+ {
+ _defaultControlPoints.push_back(controlPoint);
+ }
+
+ if (!controlPoint.texturePath.empty())
+ {
+ _controlPoints[_controlPoints.size() - 1].textureAverageColor = _calcTextureAverageColor(controlPoint.texturePath.c_str());
+ }
+
+ _needSample = true;
+}
+
+void ColorCurve::setControlPoint(int index, const ColorControlPoint& point)
+{
+ if (index < 0 || index > (_controlPoints.size() - 1) )
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Meet invalid index when setting control point for color curve!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return;
+ }
+
+ if (point.x < _minValue
+ || point.x > _maxValue)
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("The setting value isn't in x value range of the color curve!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return;
+ }
+ std::vector<ColorControlPoint>::iterator itr = _controlPoints.begin();
+ std::advance(itr, index);
+
+ if (!point.texturePath.empty() && point.texturePath != itr->texturePath)
+ {
+ *itr = point;
+ itr->textureAverageColor = _calcTextureAverageColor(point.texturePath.c_str());
+ }
+ else
+ *itr = point;
+
+ _needSample = true;
+}
+
+void ColorCurve::reset(void)
+{
+ if (_defaultControlPoints.size() > 0)
+ {
+ _controlPoints = _defaultControlPoints;
+ _needSample = true;
+ }
+}
+
+void rectifyColorValue(float& colorComponent)
+{
+ if (colorComponent < 0)
+ colorComponent = 0;
+ else if(colorComponent > 255)
+ {
+ colorComponent = 255;
+ }
+}
+
+void rectifyColorValue(QPointF& colorComponent)
+{
+ if (colorComponent.y() < 0)
+ colorComponent.setY(0);
+ else if(colorComponent.y() > 255)
+ {
+ colorComponent.setY(255);
+ }
+}
+
+float getBezierColorByX(ColorControlPoint& ctrlPntFront, ColorControlPoint& ctrlPntBehind, int component, float x)
+{
+ BezierSplinePoint bezierPnt0;
+ BezierSplinePoint bezierPnt1;
+
+ float y0 = 0.0f, y1 = 0.0f;
+ switch (component) {
+ case 0:
+ y0 = ctrlPntFront.color.red();
+ y1 = ctrlPntBehind.color.red();
+ break;
+ case 1:
+ y0 = ctrlPntFront.color.green();
+ y1 = ctrlPntBehind.color.green();
+ break;
+ case 2:
+ y0 = ctrlPntFront.color.blue();
+ y1 = ctrlPntBehind.color.blue();
+ break;
+ case 3:
+ y0 = ctrlPntFront.color.alpha();
+ y1 = ctrlPntBehind.color.alpha();
+ break;
+ default:
+ break;
+ }
+
+ QPointF pntFront = QPointF(ctrlPntFront.x, y0);
+ QPointF pntBehind = QPointF(ctrlPntBehind.x, y1);
+ float xStride = ctrlPntBehind.x - ctrlPntFront.x;
+ bezierPnt0.ctrlPoint0 = pntFront;
+ bezierPnt0.valuePoint = pntFront;
+ float xDelta = ctrlPntFront.splineData.outLen * xStride;
+ bezierPnt0.ctrlPoint1 = pntFront + QPointF(xDelta, xDelta * ctrlPntFront.splineData.outTan);
+
+ if (eBezierSpline == ctrlPntBehind.mode)
+ {
+ xDelta = ctrlPntBehind.splineData.inLen * xStride;
+ bezierPnt1.ctrlPoint0 = pntBehind - QPointF(xDelta, xDelta * ctrlPntBehind.splineData.inTan);
+ bezierPnt1.valuePoint = pntBehind;
+ bezierPnt1.ctrlPoint1 = pntBehind;
+ }
+ else
+ {
+ bezierPnt1.ctrlPoint0 = pntBehind;
+ bezierPnt1.valuePoint = pntBehind;
+ bezierPnt1.ctrlPoint1 = pntBehind;
+ }
+
+ BezierSpline spline(100);
+ spline.appendControlPoint(bezierPnt0);
+ spline.appendControlPoint(bezierPnt1);
+ QPointF pntOnSpline;
+ spline.getPointByX(x, pntOnSpline);
+
+ rectifyColorValue(pntOnSpline);
+ return pntOnSpline.y();
+}
+
+void ColorCurve::insertControlPointAt(int index)
+{
+ if (index < 0)
+ index = 0;
+ else if (index > (_controlPoints.size() - 1) )
+ index = (int)(_controlPoints.size() - 1);
+
+ std::vector<ColorControlPoint>::iterator itrToAdd = _controlPoints.begin();
+ std::advance(itrToAdd, index);
+
+ ColorControlPoint& ctrlPntFront = _controlPoints[index - 1];
+ ColorControlPoint& ctrlPntBehind = _controlPoints[index];
+
+ switch (ctrlPntFront.mode)
+ {
+ case eDiscret:
+ {
+ ColorControlPoint ctrlPntToAdd;
+ ctrlPntToAdd.mode = ctrlPntFront.mode;
+ ctrlPntToAdd.x = ((ctrlPntFront.x + ctrlPntBehind.x) / 2);
+ ctrlPntToAdd.color = ctrlPntFront.color;
+ _controlPoints.insert(itrToAdd, ctrlPntToAdd);
+ break;
+ }
+ case eLinear:
+ {
+ ColorControlPoint ctrlPntToAdd;
+ ctrlPntToAdd.mode = ctrlPntFront.mode;
+ ctrlPntToAdd.x = ((ctrlPntFront.x + ctrlPntBehind.x) / 2);
+ ctrlPntToAdd.color.setRed(ctrlPntFront.color.red() + (ctrlPntBehind.color.red() - ctrlPntFront.color.red()) / 2);
+ ctrlPntToAdd.color.setRed(ctrlPntFront.color.green() + (ctrlPntBehind.color.green() - ctrlPntFront.color.green()) / 2);
+ ctrlPntToAdd.color.setRed(ctrlPntFront.color.blue() + (ctrlPntBehind.color.blue() - ctrlPntFront.color.blue()) / 2);
+ ctrlPntToAdd.color.setRed(ctrlPntFront.color.alpha() + (ctrlPntBehind.color.alpha() - ctrlPntFront.color.alpha()) / 2);
+ _controlPoints.insert(itrToAdd, ctrlPntToAdd);
+ break;
+ }
+ case eBezierSpline:
+ {
+ ColorControlPoint ctrlPntToAdd;
+ ctrlPntToAdd.mode = eBezierSpline;
+ ctrlPntToAdd.x = (ctrlPntFront.x + ctrlPntBehind.x) / 2;
+ ctrlPntToAdd.color.setRed(getBezierColorByX(ctrlPntFront, ctrlPntBehind, 0, ctrlPntToAdd.x));
+ ctrlPntToAdd.color.setGreen(getBezierColorByX(ctrlPntFront, ctrlPntBehind, 1, ctrlPntToAdd.x));
+ ctrlPntToAdd.color.setBlue(getBezierColorByX(ctrlPntFront, ctrlPntBehind, 2, ctrlPntToAdd.x));
+ ctrlPntToAdd.color.setAlpha(getBezierColorByX(ctrlPntFront, ctrlPntBehind, 3, ctrlPntToAdd.x));
+ ctrlPntToAdd.splineData.inLen = 1.0;
+ ctrlPntToAdd.splineData.inTan = 0.0;
+ ctrlPntToAdd.splineData.outLen = 1.0;
+ ctrlPntToAdd.splineData.outTan = 0.0;
+ _controlPoints.insert(itrToAdd, ctrlPntToAdd);
+ break;
+ }
+ case eCatmullRomSpline:
+ {
+ CatmullRomSpline splineRed;
+ CatmullRomSpline splineGreen;
+ CatmullRomSpline splineBlue;
+ CatmullRomSpline splineAlpha;
+
+ int i = index - 1;
+ for (; i >= 0; --i)
+ {
+ if (eCatmullRomSpline != _controlPoints[i].mode)
+ {
+ ++i;
+ break;
+ }
+ }
+
+ for (; i < (int)_controlPoints.size(); ++i)
+ {
+ splineRed.appendControlPoint(QPointF(_controlPoints[i].x, _controlPoints[i].color.red()));
+ splineGreen.appendControlPoint(QPointF(_controlPoints[i].x, _controlPoints[i].color.green()));
+ splineBlue.appendControlPoint(QPointF(_controlPoints[i].x, _controlPoints[i].color.blue()));
+ splineAlpha.appendControlPoint(QPointF(_controlPoints[i].x, _controlPoints[i].color.alpha()));
+ if (eCatmullRomSpline != _controlPoints[i].mode)
+ break;
+ }
+
+ QPointF pntOnSpline;
+ ColorControlPoint ctrlPntToAdd;
+ ctrlPntToAdd.mode = eCatmullRomSpline;
+ ctrlPntToAdd.x = (ctrlPntFront.x + ctrlPntBehind.x) / 2;
+ splineRed.getPointByX(ctrlPntToAdd.x, pntOnSpline);
+ rectifyColorValue(pntOnSpline);
+ ctrlPntToAdd.color.setRed(pntOnSpline.y());
+ splineGreen.getPointByX(ctrlPntToAdd.x, pntOnSpline);
+ rectifyColorValue(pntOnSpline);
+ ctrlPntToAdd.color.setGreen(pntOnSpline.y());
+ splineBlue.getPointByX(ctrlPntToAdd.x, pntOnSpline);
+ rectifyColorValue(pntOnSpline);
+ ctrlPntToAdd.color.setBlue(pntOnSpline.y());
+ splineAlpha.getPointByX(ctrlPntToAdd.x, pntOnSpline);
+ rectifyColorValue(pntOnSpline);
+ ctrlPntToAdd.color.setAlpha(pntOnSpline.y());
+ _controlPoints.insert(itrToAdd, ctrlPntToAdd);
+ break;
+ }
+ default:
+ break;
+ }
+
+ _needSample = true;
+}
+
+void ColorCurve::removeControlPoint(int index)
+{
+ std::vector<ColorControlPoint>::iterator itrToRemove = _controlPoints.begin();
+ std::advance(itrToRemove, index);
+ _controlPoints.erase(itrToRemove);
+
+ _needSample = true;
+}
+
+QColor ColorCurve::getColorByX(float x)
+{
+ if (!_initValueRange)
+ {
+ QMessageBox::critical(nullptr, QObject::tr("critical"), QObject::tr("Color curve must be initilized its value range before being used!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ return QColor();
+ }
+
+ if (x < _controlPoints[0].x)
+ return _controlPoints[0].color;
+
+ if (x >= _controlPoints[_controlPoints.size() - 1].x)
+ return _controlPoints[_controlPoints.size() - 1].color;
+
+ if (_needSample)
+ _doSamplePoints();
+
+ size_t pntCount = _colorSamplePnts.size();
+
+ if(pntCount < 2)
+ {
+ return QColor();
+ }
+
+ for (size_t i = 0; i < pntCount - 1; i++)
+ {
+ if(_colorSamplePnts[i].x <= x && _colorSamplePnts[i + 1].x > x)
+ {
+ ColorPoint& colorPnt0 = _colorSamplePnts[i];
+ ColorPoint& colorPnt1 = _colorSamplePnts[i + 1];
+ float fRate = (x - colorPnt0.x) / (colorPnt1.x - colorPnt0.x);
+
+ float red = colorPnt0.color.red() + fRate * (colorPnt1.color.red() - colorPnt0.color.red());
+ rectifyColorValue(red);
+ float green = colorPnt0.color.green() + fRate * (colorPnt1.color.green() - colorPnt0.color.green());
+ rectifyColorValue(green);
+ float blue = colorPnt0.color.blue() + fRate * (colorPnt1.color.blue() - colorPnt0.color.blue());
+ rectifyColorValue(blue);
+ float alpha = colorPnt0.color.alpha() + fRate * (colorPnt1.color.alpha() - colorPnt0.color.alpha());
+ rectifyColorValue(alpha);
+
+ return QColor(red, green, blue, alpha);
+ }
+ }
+
+ return QColor();
+}
+
+ColorCurve& ColorCurve::operator = (const ColorCurve& right)
+{
+ if (this == &right)
+ return *this;
+
+ _needSample = right._needSample;
+ _initValueRange = right._initValueRange;
+ _minValue = right._minValue;
+ _maxValue = right._maxValue;
+ _segmentCount = right._segmentCount;
+ _colorSamplePnts = right._colorSamplePnts;
+ _controlPoints = right._controlPoints;
+
+ return *this;
+}
+
+BezierSpline _generateColorBezierSpline(ColorControlPoint& ctrlPntFront, ColorControlPoint& ctrlPntBehind, int component, int numSegments = 100)
+{
+ BezierSplinePoint bezierPnt0;
+ BezierSplinePoint bezierPnt1;
+
+ QColor colorFront = ctrlPntFront.color;
+ if (!ctrlPntFront.texturePath.empty())
+ colorFront = ctrlPntFront.textureAverageColor;
+ QColor colorBehind = ctrlPntBehind.color;
+ if (!ctrlPntBehind.texturePath.empty())
+ colorBehind = ctrlPntBehind.textureAverageColor;
+
+ float y0 = 0.0f, y1 = 0.0f;
+ switch (component) {
+ case 0:
+ y0 = colorFront.red();
+ y1 = colorBehind.red();
+ break;
+ case 1:
+ y0 = colorFront.green();
+ y1 = colorBehind.green();
+ break;
+ case 2:
+ y0 = colorFront.blue();
+ y1 = colorBehind.blue();
+ break;
+ case 3:
+ y0 = colorFront.alpha();
+ y1 = colorBehind.alpha();
+ break;
+ default:
+ break;
+ }
+
+ QPointF pntFront = QPointF(ctrlPntFront.x, y0);
+ QPointF pntBehind = QPointF(ctrlPntBehind.x, y1);
+ float xStride = ctrlPntBehind.x - ctrlPntFront.x;
+ bezierPnt0.ctrlPoint0 = pntFront;
+ bezierPnt0.valuePoint = pntFront;
+ float xDelta = ctrlPntFront.splineData.outLen * xStride;
+ bezierPnt0.ctrlPoint1 = pntFront + QPointF(xDelta, xDelta * ctrlPntFront.splineData.outTan);
+
+ if (eBezierSpline == ctrlPntBehind.mode)
+ {
+ xDelta = ctrlPntBehind.splineData.inLen * xStride;
+ bezierPnt1.ctrlPoint0 = pntBehind - QPointF(xDelta, xDelta * ctrlPntBehind.splineData.inTan);
+ bezierPnt1.valuePoint = pntBehind;
+ bezierPnt1.ctrlPoint1 = pntBehind;
+ }
+ else
+ {
+ bezierPnt1.ctrlPoint0 = pntBehind;
+ bezierPnt1.valuePoint = pntBehind;
+ bezierPnt1.ctrlPoint1 = pntBehind;
+ }
+
+ BezierSpline spline(numSegments);
+ spline.appendControlPoint(bezierPnt0);
+ spline.appendControlPoint(bezierPnt1);
+ return spline;
+}
+
+void _doBezierColorSample(ColorControlPoint& ctrlPntFront, ColorControlPoint& ctrlPntBehind, std::vector<ColorPoint>& colorSamplePnts, int numSegments = 100)
+{
+ BezierSpline redSpline = _generateColorBezierSpline(ctrlPntFront, ctrlPntBehind, 0, numSegments);
+ BezierSpline greenSpline = _generateColorBezierSpline(ctrlPntFront, ctrlPntBehind, 1, numSegments);
+ BezierSpline blueSpline = _generateColorBezierSpline(ctrlPntFront, ctrlPntBehind, 2, numSegments);
+ BezierSpline alphaSpline = _generateColorBezierSpline(ctrlPntFront, ctrlPntBehind, 3, numSegments);
+
+ std::vector<QPointF> redSamplePnts = redSpline.getSamplePoints();
+ std::vector<QPointF> greenSamplePnts = greenSpline.getSamplePoints();
+ std::vector<QPointF> blueSamplePnts = blueSpline.getSamplePoints();
+ std::vector<QPointF> alphaSamplePnts = alphaSpline.getSamplePoints();
+
+ size_t samplePntsCount = redSamplePnts.size();
+ for (size_t i = 0; i < samplePntsCount; ++i)
+ {
+ colorSamplePnts.push_back(ColorPoint(redSamplePnts[i].x() , QColor(redSamplePnts[i].y()
+ , greenSamplePnts[i].y()
+ , blueSamplePnts[i].y()
+ , alphaSamplePnts[i].y())));
+ }
+}
+
+float saturate( float v)
+{
+ if( v < 0.0 ) v = 0.0;
+ if( v > 1.0 ) v = 1.0;
+ return v;
+}
+
+float _GetRatio(float s, float weight, float fallOff)
+{
+ float ratio = s;
+
+ // add bias for first/second color variation
+ if (weight < 0.5f)
+ {
+ float slope = 2.0f * weight;
+ ratio = slope * ratio;
+ }
+ else
+ {
+ float slope = 2.0f * (1.0f - weight) ;
+ ratio = slope * (ratio - 1.0f) + 1.0f;
+ }
+
+ // modify ratio for falloff
+ float slope = 1.0f / (fallOff + 0.001f);
+ ratio = saturate(0.5f + slope * (ratio - 0.5f));
+
+ return ratio;
+}
+
+void ColorCurve::_doSamplePoints()
+{
+ _colorSamplePnts.clear();
+
+ for (long i = 1; i < _controlPoints.size(); ++i)
+ {
+ ColorControlPoint& ctrlPntFront = _controlPoints[i-1];
+ ColorControlPoint& ctrlPntBehind = _controlPoints[i];
+ QColor colorFront = ctrlPntFront.color;
+ if (!ctrlPntFront.texturePath.empty())
+ colorFront = ctrlPntFront.textureAverageColor;
+ QColor colorBehind = ctrlPntBehind.color;
+ if (!ctrlPntBehind.texturePath.empty())
+ colorBehind = ctrlPntBehind.textureAverageColor;
+
+ switch (ctrlPntFront.mode)
+ {
+ case eDiscret:
+ {
+ _colorSamplePnts.push_back(ColorPoint(ctrlPntFront.x, colorFront));
+ _colorSamplePnts.push_back(ColorPoint(ctrlPntBehind.x, colorFront));
+ break;
+ }
+ case eLinear:
+ {
+ for (long j = 0; j <= _segmentCount; ++j)
+ {
+ float s = (float)j / _segmentCount;
+ float ratio = s;
+ if (ctrlPntBehind.weight >= 0)
+ ratio = _GetRatio(s, ctrlPntFront.weight, ctrlPntFront.fallOff);
+
+ float xPos = ctrlPntFront.x + s * (ctrlPntBehind.x - ctrlPntFront.x);
+
+ int red = colorBehind.red() - colorFront.red();
+ int green = colorBehind.green() - colorFront.green();
+ int blue = colorBehind.blue() - colorFront.blue();
+ int alpha = colorBehind.alpha() - colorFront.alpha();
+
+ QColor color(colorFront.red() + ratio * red
+ , colorFront.green() + ratio * green
+ , colorFront.blue() + ratio * blue
+ , colorFront.alpha() + ratio * alpha);
+ _colorSamplePnts.push_back(ColorPoint(xPos, color));
+ }
+ break;
+ }
+ case eBezierSpline:
+ {
+ _doBezierColorSample(ctrlPntFront, ctrlPntBehind, _colorSamplePnts, _segmentCount);
+ break;
+ }
+ case eCatmullRomSpline:
+ {
+ CatmullRomSpline redSpline(_segmentCount);
+ CatmullRomSpline greenSpline(_segmentCount);
+ CatmullRomSpline blueSpline(_segmentCount);
+ CatmullRomSpline alphaSpline(_segmentCount);
+
+ for (i = i - 1; i < _controlPoints.size(); ++i)
+ {
+ QColor color = _controlPoints[i].color;
+ if (!_controlPoints[i].texturePath.empty())
+ color = _controlPoints[i].textureAverageColor;
+ redSpline.appendControlPoint(QPointF(_controlPoints[i].x, color.red()));
+ greenSpline.appendControlPoint(QPointF(_controlPoints[i].x, color.green()));
+ blueSpline.appendControlPoint(QPointF(_controlPoints[i].x, color.blue()));
+ alphaSpline.appendControlPoint(QPointF(_controlPoints[i].x, color.alpha()));
+ if (eCatmullRomSpline != _controlPoints[i].mode)
+ {
+ break;
+ }
+ }
+
+ std::vector<QPointF> redSamplePnts = redSpline.getSamplePoints();
+ std::vector<QPointF> greenSamplePnts = greenSpline.getSamplePoints();
+ std::vector<QPointF> blueSamplePnts = blueSpline.getSamplePoints();
+ std::vector<QPointF> alphaSamplePnts = alphaSpline.getSamplePoints();
+
+ size_t samplePntsCount = redSamplePnts.size();
+ for (size_t i = 0; i < samplePntsCount; ++i)
+ {
+ rectifyColorValue(redSamplePnts[i]);
+ rectifyColorValue(greenSamplePnts[i]);
+ rectifyColorValue(blueSamplePnts[i]);
+ rectifyColorValue(alphaSamplePnts[i]);
+ _colorSamplePnts.push_back(ColorPoint(redSamplePnts[i].x() , QColor(redSamplePnts[i].y()
+ , greenSamplePnts[i].y()
+ , blueSamplePnts[i].y()
+ , alphaSamplePnts[i].y())));
+ }
+
+ break;
+ }
+ }
+ }
+
+ _needSample = false;
+}
+
+void ColorCurve::_reOrderControlPoints(int& pickedPoint)
+{
+ for (size_t i = 0; i < _controlPoints.size() - 1; ++i)
+ {
+ if (_controlPoints[i].x > _controlPoints[i+1].x)
+ {
+ ColorControlPoint temp = _controlPoints[i];
+ _controlPoints[i] = _controlPoints[i + 1];
+ _controlPoints[i + 1] = temp;
+
+ if (pickedPoint == i)
+ pickedPoint = (int)(i + 1);
+ else if (pickedPoint == (i + 1) )
+ pickedPoint = (int)i;
+
+ break;
+ }
+ }
+}
+
+QColor ColorCurve::_calcTextureAverageColor(const char* texturePath)
+{
+ QImage img(texturePath);
+ double red = 0, green = 0, blue = 0, alpha = 0;
+
+ // Try stb_image for .TGA
+ int width = 0;
+ int height = 0;
+ int numComponents = 0;
+ unsigned char *pSTBIRes = stbi_load(texturePath, &width, &height, &numComponents, 4);
+
+ if (!pSTBIRes)
+ return QColor(0, 0, 0);
+
+ int colorCount = width * height;
+ unsigned int* pixels = (unsigned int*)pSTBIRes;
+
+ for (int i = 0; i < height; ++i)
+ {
+ for (int j = 0; j < width; ++j)
+ {
+ QRgb pixel = *pixels++;
+ QColor color(pixel);
+ red += color.redF();
+ green += color.greenF();
+ blue += color.blueF();
+ alpha += color.alphaF();
+ }
+ }
+
+ if (colorCount != 0)
+ {
+ red /= colorCount;
+ green /= colorCount;
+ blue /= colorCount;
+ alpha /= colorCount;
+ }
+
+ QColor color;
+ color.setRgbF(red, green, blue, alpha);
+ return color;
+}
+
+} // namespace CurveEditor
+} // namespace nvidia \ No newline at end of file
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Curve/Spline.cpp b/NvBlast/tools/CurveEditor/source/Internal/Curve/Spline.cpp
new file mode 100644
index 0000000..c40a4f9
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Curve/Spline.cpp
@@ -0,0 +1,151 @@
+#include "Spline.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+Spline::Spline(long segmentCount)
+ : _needSample(true)
+ , _samplePoints()
+ , _edgeLengths()
+ , _totolLength(0.0f)
+{
+ _segmentCount = segmentCount < 1 ? 1 : segmentCount;
+}
+
+Spline::~Spline(void)
+{
+}
+
+bool Spline::getPercentPoint(float percent, QPointF& point)
+{
+ long lPointCount = (long)_samplePoints.size();
+
+ if (lPointCount == 0)
+ {
+ return false;
+ }
+ else if (lPointCount == 1)
+ {
+ point = _samplePoints[0];
+ return true;
+ }
+
+ if (_needSample)
+ _sample();
+
+ if (percent > 1.0)
+ {
+ percent -= (int)percent;
+ }
+
+ if (percent < 0.0)
+ {
+ percent += (int)(-percent) + 1;
+ }
+
+ if (percent <= 0.0)
+ {
+ // return begin point
+ point = _samplePoints[0];
+ return true;
+ }
+ else if (percent >= 1.0)
+ {
+ // return end point
+ point = _samplePoints[_samplePoints.size() - 1];
+ return true;
+ }
+
+ float fCurPos = _totolLength * percent;
+ int index = 0;
+
+ {// get edge's index the point is on based on the percent value
+ long lEdgeCount = (long)_edgeLengths.size();
+ for ( ; index < lEdgeCount; index++)
+ {
+ if (fCurPos < _edgeLengths[index])
+ {
+ break;
+ }
+
+ fCurPos -= _edgeLengths[index];
+ }
+
+ if (index == lEdgeCount)
+ {
+ point = _samplePoints[_samplePoints.size() - 1];
+ return true;
+ }
+ }
+
+ QPointF v1 = _samplePoints[index];
+ QPointF v2 = _samplePoints[index + 1];
+
+ point = v1 + (v2 - v1) * (fCurPos / _edgeLengths[index]);
+
+ return true;
+}
+
+bool Spline::getPointByX(float x, QPointF& point)
+{
+ if (_needSample)
+ _sample();
+
+ long lPointCount = (long)_samplePoints.size();
+
+ if(lPointCount < 2)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < lPointCount - 1; i++)
+ {
+ if(_samplePoints[i].x() <= x && _samplePoints[i + 1].x() > x)
+ {
+ point.setX( x );
+ float fRate = (x - _samplePoints[i].x())/ (_samplePoints[i + 1].x() - _samplePoints[i].x());
+ point.setY(_samplePoints[i].y() + (_samplePoints[i+1].y() - _samplePoints[i].y()) * fRate);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Spline::setSegmentCount(long segmentCount)
+{
+ _segmentCount = segmentCount < 1 ? 1 : segmentCount;
+ _needSample = true;
+}
+
+std::vector<QPointF> Spline::getSamplePoints()
+{
+ if (_needSample)
+ _sample();
+ return _samplePoints;
+}
+
+void Spline::_sample()
+{
+ _samplePoints.clear();
+
+ _doSample();
+
+ // get all edges length and total length
+ _totolLength = 0;
+ _edgeLengths.clear();
+ float fEdgeLength;
+
+ long lPointCount = (long)_samplePoints.size();
+ for (int i = 1; i < lPointCount; i++)
+ {
+ QPointF dist = _samplePoints[i] - _samplePoints[i - 1];
+ fEdgeLength = (sqrt(dist.x()*dist.x() + dist.y() + dist.y()));
+ _edgeLengths.push_back(fEdgeLength);
+ _totolLength += fEdgeLength;
+ }
+
+ _needSample = false;
+}
+
+} // namespace CurveEditor
+} // namespace nvidia \ No newline at end of file
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Curve/Spline.h b/NvBlast/tools/CurveEditor/source/Internal/Curve/Spline.h
new file mode 100644
index 0000000..fc111a7
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Curve/Spline.h
@@ -0,0 +1,43 @@
+#ifndef Spline_h__
+#define Spline_h__
+#include <vector>
+#include <QtCore/QPointF>
+
+namespace nvidia {
+namespace CurveEditor {
+
+class Spline
+{
+public:
+ Spline(long segmentCount = 100);
+ virtual ~Spline(void) = 0;
+
+ // return the point which lies on the polyline after sample.
+ // percent: the length between the returned point and the begin point along the polyline after sample
+ // ������������������������������������������������������������������������������������������
+ // the length between the end point and the begin point along the polyline after sample
+ // [0.0, 1.0]
+ bool getPercentPoint(float percent, QPointF& point);
+
+ bool getPointByX(float x, QPointF& point);
+
+ void setSegmentCount(long segmentCount);
+
+ std::vector<QPointF> getSamplePoints();
+
+protected:
+ void _sample();
+ virtual void _doSample() = 0;
+
+protected:
+ bool _needSample;
+ long _segmentCount;
+ std::vector<QPointF> _samplePoints;
+ std::vector<float> _edgeLengths; // the number of edges + 1 == the number of sample points
+ float _totolLength;// the total length of all edges
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // Spline_h__
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Window/AlphaDialog.cpp b/NvBlast/tools/CurveEditor/source/Internal/Window/AlphaDialog.cpp
new file mode 100644
index 0000000..a51a802
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Window/AlphaDialog.cpp
@@ -0,0 +1,181 @@
+#include "AlphaDialog.h"
+#include "ui_AlphaDialog.h"
+#include <QtGui/QPaintEvent>
+#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
+
+namespace nvidia {
+namespace CurveEditor {
+
+const int MARGIN_X = 8;
+const int MARGIN_Y = 8;
+
+const int ALPHA_W = 255;
+const int ALPHA_H = 30;
+
+const int CURSOR_W = 12;
+const int CURSOR_H = 12;
+
+static QImage s_triangleUp;
+
+void InitTriangleResources(int w, int h)
+{
+ s_triangleUp = QImage(w, h, QImage::Format_ARGB32);
+ s_triangleUp.fill(QColor(0, 0, 0, 0));
+
+ // a painter cannot switch device?
+ QPainterPath path;
+ QPainter painter(&s_triangleUp);
+ painter.setRenderHint(QPainter::Antialiasing,true);
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w>>1, 0);
+ path.lineTo(0, h);
+ path.lineTo(w, h);
+ path.lineTo(w>>1, 0);
+ painter.setPen(Qt::NoPen);
+ painter.fillPath(path, QBrush(QColor(50, 50, 50)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool isClickedInCursor(const QPoint& cursorPos, const QPoint& p)
+{
+ QVector<QPoint> points;
+ points.push_back(cursorPos);
+ points.push_back(QPoint(cursorPos.x() - (CURSOR_W>>1), cursorPos.y() + CURSOR_H));
+ points.push_back(QPoint(cursorPos.x() + (CURSOR_W>>1), cursorPos.y() + CURSOR_H));
+ points.push_back(cursorPos);
+
+ QPolygon polygon(points);
+ return polygon.containsPoint(p, Qt::OddEvenFill);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+ int AlphaDialog::getAlpha(int alpha, QWidget *parent)
+ {
+ AlphaDialog dlg(parent, alpha);
+ dlg.exec();
+ return dlg._alpha;
+ }
+
+//////////////////////////////////////////////////////////////////////////////
+AlphaDialog::AlphaDialog(QWidget *parent, int alpha) :
+ QDialog(parent),
+ ui(new Ui::AlphaDialog),
+ _drag(false),
+ _alpha(alpha),
+ _xOffset(0)
+{
+ ui->setupUi(this);
+ setWindowFlags(windowFlags()&~Qt::WindowContextHelpButtonHint);
+ setFixedWidth(271);
+ setFixedHeight(120);
+
+ ui->spinBoxAlpha->setValue(_alpha);
+
+ InitTriangleResources(12, 12);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+AlphaDialog::~AlphaDialog()
+{
+ delete ui;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void AlphaDialog::paintEvent(QPaintEvent * e)
+{
+ QDialog::paintEvent(e);
+
+ QPainter painter;
+ painter.begin(this);
+ drawAlphaRectangle(painter);
+ drawCursor(painter, _alpha + MARGIN_X);
+ painter.end();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void AlphaDialog::mousePressEvent( QMouseEvent* e )
+{
+ if(e->button() & Qt::LeftButton)
+ {
+ QPoint mousePos = e->pos();
+
+ if (isClickedInCursor(QPoint(_alpha + MARGIN_X, MARGIN_Y + ALPHA_H), mousePos))
+ {
+ _xOffset = _alpha + MARGIN_X - mousePos.x();
+ _drag = true;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void AlphaDialog::mouseReleaseEvent( QMouseEvent* e )
+{
+ _drag = false;
+ _xOffset = -1;
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void AlphaDialog::mouseMoveEvent( QMouseEvent* e )
+{
+ Qt::MouseButtons buttons = e->buttons();
+
+ if(buttons & Qt::LeftButton)
+ {
+ if (_drag)
+ {
+ QPoint mousePos = e->pos();
+
+ _alpha = mousePos.x() + _xOffset - MARGIN_X;
+ if (_alpha < 0)
+ {
+ _alpha = 0;
+ }
+ else if(_alpha > ALPHA_W)
+ {
+ _alpha = ALPHA_W;
+ }
+ ui->spinBoxAlpha->setValue(_alpha);
+ update();
+ }
+ }
+}
+
+void AlphaDialog::drawAlphaRectangle(QPainter& painter)
+{
+ QPointF topLeftPnt(MARGIN_X, MARGIN_Y);
+ QPointF topRightPnt(MARGIN_X + ALPHA_W, MARGIN_Y);
+ QPointF bottomRightPnt(MARGIN_X + ALPHA_W, MARGIN_Y + ALPHA_H);
+ QPointF bottomLeftPnt(MARGIN_X, MARGIN_Y + ALPHA_H);
+ QPainterPath path;
+ path.moveTo(topLeftPnt);
+ path.lineTo(topRightPnt);
+ path.lineTo(bottomRightPnt);
+ path.lineTo(bottomLeftPnt);
+
+ QColor colorLeft(0, 0, 0, 255);
+ QColor colorRight(255, 255, 255, 255);
+ colorLeft.setAlpha(255);
+ colorRight.setAlpha(255);
+ QLinearGradient indicatorGradient(topLeftPnt,topRightPnt);
+ indicatorGradient.setColorAt(0.0, colorLeft);
+ indicatorGradient.setColorAt(1.0, colorRight);
+
+ painter.fillPath(path, indicatorGradient);
+}
+
+void AlphaDialog::drawCursor(QPainter& painter, int xPos)
+{
+ QRect rect(xPos - (CURSOR_W>>1), MARGIN_Y + ALPHA_H, CURSOR_W, CURSOR_H);
+ painter.drawImage(rect, s_triangleUp);
+
+}
+
+void AlphaDialog::on_spinBoxAlpha_valueChanged(int arg1)
+{
+ _alpha = arg1;
+}
+
+} // namespace CurveEditor
+} // namespace nvidia \ No newline at end of file
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Window/AlphaDialog.h b/NvBlast/tools/CurveEditor/source/Internal/Window/AlphaDialog.h
new file mode 100644
index 0000000..985d0b4
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Window/AlphaDialog.h
@@ -0,0 +1,47 @@
+#ifndef ALPHADIALOG_H
+#define ALPHADIALOG_H
+
+#include <QtWidgets/QDialog>
+
+namespace Ui {
+ class AlphaDialog;
+}
+
+namespace nvidia {
+namespace CurveEditor {
+
+class AlphaDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ static int getAlpha(int alpha = 255, QWidget *parent = 0);
+
+ explicit AlphaDialog(QWidget *parent = 0, int alpha = 255);
+ ~AlphaDialog();
+
+protected:
+ // QWidget events
+ virtual void paintEvent(QPaintEvent * e);
+
+ virtual void mousePressEvent(QMouseEvent* e);
+ virtual void mouseReleaseEvent(QMouseEvent* e);
+ virtual void mouseMoveEvent(QMouseEvent* e);
+private slots:
+ void on_spinBoxAlpha_valueChanged(int arg1);
+
+private:
+ void drawAlphaRectangle(QPainter& painter);
+ void drawCursor(QPainter& painter, int xPos);
+
+private:
+ Ui::AlphaDialog *ui;
+ bool _drag;
+ int _alpha;
+ int _xOffset;
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // ALPHADIALOG_H
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Window/ColorWidget.cpp b/NvBlast/tools/CurveEditor/source/Internal/Window/ColorWidget.cpp
new file mode 100644
index 0000000..a84ee70
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Window/ColorWidget.cpp
@@ -0,0 +1,1724 @@
+#include "ColorWidget.h"
+#include <QtGui/QPaintEvent>
+#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
+#include <QtGui/QImage>
+#include <assert.h>
+#include <QtCore/QDebug>
+#include <QtCore/QTime>
+#include <QtWidgets/QToolTip>
+#include "CurveEditorMainWindow.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+const int MARGIN_X = 8;
+const int MARGIN_Y = 4;
+const int CONTROL_POINT_CURSOR_W = 12;
+const int CONTROL_POINT_CURSOR_H = 12;
+const int WEIGHT_CURSOR_W = 6;
+const int WEIGHT_CURSOR_H = 6;
+const int SPACING_V = 0;
+
+static QImage S_CtrlPntWithTexCursorNormalImg;
+static QImage S_CtrlPntWithTexCursorPickedImg;
+static QImage S_WeightCursorNormalImg;
+static QImage S_WeightCursorPickedImg;
+
+#define ROUND(v) (int(v + 0.5))
+
+class TimeConsumeTracker
+{
+public:
+ TimeConsumeTracker(QString text)
+ : _text(text)
+ {
+ _time.start();
+ }
+
+ ~TimeConsumeTracker()
+ {
+ qDebug()<<_text<<" consume: "<<_time.elapsed();
+ }
+
+ QTime _time;
+ QString _text;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+void InitCursorResources()
+{
+ int w = CONTROL_POINT_CURSOR_W;
+ int h = CONTROL_POINT_CURSOR_H;
+ S_CtrlPntWithTexCursorNormalImg = QImage(w, h, QImage::Format_ARGB32);
+ S_CtrlPntWithTexCursorPickedImg = QImage(w, h, QImage::Format_ARGB32);
+ S_CtrlPntWithTexCursorNormalImg.fill(QColor(0, 0, 0, 0));
+ S_CtrlPntWithTexCursorPickedImg.fill(QColor(0, 0, 0, 0));
+
+ ///////////////////////////////////////////////////////////////////////////
+ QPainter painter(&S_CtrlPntWithTexCursorNormalImg);
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ QPainterPath path; // trick to clear up a path
+ path.moveTo(w >> 1, 0);
+ path.lineTo(w >> 2, h >> 2);
+ path.lineTo(w >> 1, h >> 1);
+ path.lineTo((w >> 1) + (w >> 2), h >> 2);
+ path.lineTo(w >> 1, 0);
+ painter.setPen(Qt::NoPen);
+ painter.fillPath(path, QBrush(QColor(255, 255, 255)));
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w >> 2, h >> 2);
+ path.lineTo(0, h >> 1);
+ path.lineTo(w >> 2, (h >> 1) + (h >> 2));
+ path.lineTo(w >> 1, h >> 1);
+ path.lineTo(w >> 2, h >> 2);
+ painter.setPen(Qt::NoPen);
+ painter.fillPath(path, (QColor(0, 0, 0)));
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w >> 1, h >> 1);
+ path.lineTo(w >> 2, (h >> 1) + (h >> 2));
+ path.lineTo(w >> 1, h);
+ path.lineTo((w >> 1) + (w >> 2), (h >> 1) + (h >> 2));
+ path.lineTo(w >> 1, h >> 1);
+ painter.setPen(Qt::NoPen);
+ painter.fillPath(path, QBrush(QColor(255, 255, 255)));
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo((w >> 1) + (w >> 2), h >> 2);
+ path.lineTo(w >> 1, h >> 1);
+ path.lineTo((w >> 1) + (w >> 2), (h >> 1) + (h >> 2));
+ path.lineTo(w, h >> 1);
+ path.lineTo((w >> 1) + (w >> 2), h >> 2);
+ painter.setPen(Qt::NoPen);
+ painter.fillPath(path, (QColor(0, 0, 0)));
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w >> 1, 0);
+ path.lineTo(0, h >> 1);
+ path.lineTo(w >> 1, h);
+ path.lineTo(w, h >> 1);
+ path.lineTo(w >> 1, 0);
+ painter.setPen(QPen(Qt::white, 1, Qt::SolidLine));
+ painter.drawPath(path);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // a painter cannot switch device?
+ QPainter painter2(&S_CtrlPntWithTexCursorPickedImg);
+ painter2.setRenderHint(QPainter::Antialiasing,true);
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w>>1, 0);
+ path.lineTo(w>>2, h>>2);
+ path.lineTo(w>>1, h>>1);
+ path.lineTo((w>>1)+(w>>2), h>>2);
+ path.lineTo(w>>1, 0);
+ painter2.setPen(Qt::NoPen);
+ painter2.fillPath(path, QBrush(QColor(255, 255, 255)));
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w>>2, h>>2);
+ path.lineTo(0, h>>1);
+ path.lineTo(w>>2, (h>>1)+(h>>2));
+ path.lineTo(w>>1, h>>1);
+ path.lineTo(w>>2, h>>2);
+ painter2.setPen(Qt::NoPen);
+ painter2.fillPath(path, (QColor(0, 0, 0)));
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w>>1, h>>1);
+ path.lineTo(w>>2, (h>>1)+(h>>2));
+ path.lineTo(w>>1, h);
+ path.lineTo((w>>1)+(w>>2), (h>>1)+(h>>2));
+ path.lineTo(w>>1, h>>1);
+ painter2.setPen(Qt::NoPen);
+ painter2.fillPath(path, QBrush(QColor(255, 255, 255)));
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo((w>>1)+(w>>2), h>>2);
+ path.lineTo(w>>1, h>>1);
+ path.lineTo((w>>1)+(w>>2), (h>>1)+(h>>2));
+ path.lineTo(w, h>>1);
+ path.lineTo((w>>1)+(w>>2), h>>2);
+ painter2.setPen(Qt::NoPen);
+ painter2.fillPath(path, (QColor(0, 0, 0)));
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w>>1, 0);
+ path.lineTo(0, h>>1);
+ path.lineTo(w>>1, h);
+ path.lineTo(w, h>>1);
+ path.lineTo(w>>1, 0);
+ painter2.setPen(QPen(Qt::green,1, Qt::SolidLine));
+ painter2.drawPath(path);
+
+ ///////////////////////////////////////////////////////////////////////////
+ w = WEIGHT_CURSOR_W;
+ h = WEIGHT_CURSOR_H;
+ S_WeightCursorNormalImg = QImage(w, h, QImage::Format_ARGB32);
+ S_WeightCursorPickedImg = QImage(w, h, QImage::Format_ARGB32);
+ S_WeightCursorNormalImg.fill(QColor(0, 0, 0, 0));
+ S_WeightCursorPickedImg.fill(QColor(0, 0, 0, 0));
+ ///////////////////////////////////////////////////////////////////////////
+ QPainter painter3(&S_WeightCursorNormalImg);
+ painter3.setRenderHints(QPainter::Antialiasing,true);
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w>>1, 0);
+ path.lineTo(0, h>>1);
+ path.lineTo(w>>1, h);
+ path.lineTo(w, h>>1);
+ path.lineTo(w>>1, 0);
+ painter3.setPen(QPen(Qt::black, 1, Qt::SolidLine));
+ painter3.drawPath(path);
+ painter3.fillPath(path, QBrush(QColor(255, 255, 255)));
+
+ ///////////////////////////////////////////////////////////////////////////
+ QPainter painter4(&S_WeightCursorPickedImg);
+ painter4.setRenderHints(QPainter::Antialiasing,true);
+
+ path = QPainterPath(); // trick to clear up a path
+ path.moveTo(w>>1, 0);
+ path.lineTo(0, h>>1);
+ path.lineTo(w>>1, h);
+ path.lineTo(w, h>>1);
+ path.lineTo(w>>1, 0);
+ painter4.setPen(QPen(Qt::black, 1, Qt::SolidLine));
+ painter4.drawPath(path);
+ painter4.fillPath(path, QBrush(QColor(0, 0, 0)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+float NDCToScreenCoord(QWidget* pWidget, float xValueOfUnitInterval)
+{
+ int w = pWidget->width();
+ return MARGIN_X + (w - MARGIN_X * 2.0) * xValueOfUnitInterval;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+float _screenToNDC(QWidget* pWidget, int xPos)
+{
+ int w = pWidget->width();
+ return ((float)(xPos - MARGIN_X)) / (w - MARGIN_X * 2.0f);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool isClickedInCtrlPntCursor(const QPointF& cursorPos, const QPointF& p)
+{
+ QVector<QPointF> points;
+ points.push_back(cursorPos);
+ points.push_back(QPointF(cursorPos.x() - CONTROL_POINT_CURSOR_W/2, cursorPos.y() + CONTROL_POINT_CURSOR_H/2));
+ points.push_back(QPointF(cursorPos.x(), cursorPos.y() + CONTROL_POINT_CURSOR_H));
+ points.push_back(QPointF(cursorPos.x() + CONTROL_POINT_CURSOR_W/2, cursorPos.y() + CONTROL_POINT_CURSOR_H/2));
+ points.push_back(cursorPos);
+ QPolygonF polygon(points);
+ return polygon.containsPoint(p, Qt::OddEvenFill);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool isClickedInWeightCursor(const QPointF& cursorPos, const QPointF& p)
+{
+ QVector<QPointF> points;
+ points.push_back(cursorPos);
+ points.push_back(QPointF(cursorPos.x() - WEIGHT_CURSOR_W/2, cursorPos.y() + WEIGHT_CURSOR_H/2));
+ points.push_back(QPointF(cursorPos.x(), cursorPos.y() + WEIGHT_CURSOR_H));
+ points.push_back(QPointF(cursorPos.x() + WEIGHT_CURSOR_W/2, cursorPos.y() + WEIGHT_CURSOR_H/2));
+ points.push_back(cursorPos);
+ QPolygonF polygon(points);
+ return polygon.containsPoint(p, Qt::OddEvenFill);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QImage genControlPointCursorImg(const QColor& color, bool picked = false)
+{
+ int w = CONTROL_POINT_CURSOR_W;
+ int h = CONTROL_POINT_CURSOR_H;
+ QImage image = QImage(w, h, QImage::Format_ARGB32);
+ image.fill(QColor(0, 0, 0, 0));
+
+ QPainter painter(&image);
+ painter.setRenderHints(QPainter::Antialiasing,true);
+
+ QPainterPath path;
+ path.moveTo(w>>1, 0);
+ path.lineTo(0, h>>1);
+ path.lineTo(w>>1, h);
+ path.lineTo(w, h>>1);
+ path.lineTo(w>>1, 0);
+ if (picked)
+ {
+ painter.setPen(QPen(Qt::green, 1, Qt::SolidLine));
+ painter.drawPath(path);
+ }
+
+ painter.fillPath(path, QBrush(color));
+
+ return image;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+ColorWidget::ColorWidget(QWidget *parent) :
+ QFrame(parent),
+ _isLink(false),
+ _colorAttribute(nullptr),
+ _colorCurve(nullptr),
+ _alphaCurve(nullptr),
+ _canAddRemoveControlPoint(false),
+ _canAddCtrlPntByClick(false),
+ _canRemoveCtrlPntByClick(false),
+ _curveFitWindowScale(1),
+ _curveFitWindowOffset(0),
+ _pickedColorCtrlPnt(-1),
+ _pickedAlphaCtrlPnt(-1),
+ _pickedColorWeight(-1),
+ _pickedAlphaWeight(-1),
+ _dragColorCtrlPnt(false),
+ _dragAlphaCtrlPnt(false),
+ _dragColorWeight(false),
+ _dragAlphaWeight(false),
+ _colorCtrlPntToRemove(-1),
+ _alphaCtrlPntToRemove(-1),
+ _contextMenu(nullptr),
+ _removeCtrlPntAction(nullptr)
+{
+ setFocusPolicy(Qt::ClickFocus );
+
+ InitCursorResources();
+
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onShowContextMenu(const QPoint&)));
+
+ _contextMenu = new QMenu(this);;
+ _removeCtrlPntAction = new QAction(this);
+ _removeCtrlPntAction->setText(tr("Remove Control Point"));
+ _contextMenu->addAction(_removeCtrlPntAction);
+
+ connect(_removeCtrlPntAction, SIGNAL(triggered()), this, SLOT(onRemoveControlPoint()) );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QColor ColorWidget::getColor()
+{
+ QColor color;
+ if (_pickedColorCtrlPnt != -1)
+ {
+ color = _colorCurve->getControlPoint(_pickedColorCtrlPnt).color;
+ }
+ return color;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+int ColorWidget::getAlpha()
+{
+ if (_pickedAlphaCtrlPnt != -1)
+ {
+ if (_isLink)
+ {
+ return _colorCurve->getControlPoint(_pickedAlphaCtrlPnt).color.alpha();
+ }
+ else
+ {
+ return _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt).color.alpha();
+ }
+ }
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setColor(const QColor& color)
+{
+ if (_pickedColorCtrlPnt != -1)
+ {
+ ColorControlPoint pickedColorPnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+
+ pickedColorPnt.color.setRed(color.red());
+ pickedColorPnt.color.setGreen(color.green());
+ pickedColorPnt.color.setBlue(color.blue());
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pickedColorPnt);
+
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setAlpha(int alpha)
+{
+ if (_pickedColorCtrlPnt != -1)
+ {
+ ColorControlPoint pickedColorPnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pickedColorPnt.color.setAlpha(alpha);
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pickedColorPnt);
+
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+float ColorWidget::getColorFallOff()
+{
+ if (_colorCurve && -1 != _pickedColorCtrlPnt)
+ {
+ const ColorControlPoint& pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ return pnt.fallOff;
+ }
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setColorFallOff(float fallOff)
+{
+ if (_colorCurve && -1 != _pickedColorCtrlPnt)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.fallOff = fallOff;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+float ColorWidget::getAlphaFallOff()
+{
+ if (_isLink)
+ {
+ if (_colorCurve && -1 != _pickedColorCtrlPnt)
+ {
+ const ColorControlPoint& pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ return pnt.fallOff;
+ }
+ }
+ else
+ {
+ if (_alphaCurve && -1 != _pickedAlphaCtrlPnt)
+ {
+ const ColorControlPoint& pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+ return pnt.fallOff;
+ }
+ }
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setAlphaFallOff(float fallOff)
+{
+ if (_isLink)
+ {
+ if (_colorCurve && -1 != _pickedColorCtrlPnt)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.fallOff = fallOff;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+ }
+ else
+ {
+ if (_alphaCurve && -1 != _pickedAlphaCtrlPnt)
+ {
+ ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+ pnt.fallOff = fallOff;
+ _alphaCurve->setControlPoint(_pickedAlphaCtrlPnt, pnt);
+
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setColorAttribute(ColorAttribute* colorAttribute)
+{
+ _colorAttribute = colorAttribute;
+ if (colorAttribute != nullptr)
+ {
+ _colorCurve = &(colorAttribute->colorCurve);
+ _alphaCurve = &(colorAttribute->alphaCurve);
+ }
+ else
+ {
+ _colorCurve = nullptr;
+ _alphaCurve = nullptr;
+ }
+
+ if (_alphaCurve !=nullptr && _alphaCurve->getControlPointCount() < 2)
+ {
+ _isLink = true;
+ }
+ else
+ {
+ _isLink = false;
+ }
+
+ _pickedColorCtrlPnt = -1;
+ _pickedAlphaCtrlPnt = -1;
+ _pickedColorWeight = -1;
+ _pickedAlphaWeight = -1;
+ _dragColorCtrlPnt = false;
+ _dragAlphaCtrlPnt = false;
+ _dragColorWeight = false;
+ _dragAlphaWeight = false;
+
+ _updateCurveFitWindowPara();
+ if (_colorCurve)
+ _colorCurve->_needSample = true;
+ if (_alphaCurve)
+ _alphaCurve->_needSample = true;
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::reset()
+{
+ if (_colorAttribute)
+ {
+ _colorAttribute->colorCurve.reset();
+ _colorAttribute->alphaCurve.reset();
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::addControlPointsBeforeSelected()
+{
+ if (-1 != _pickedColorCtrlPnt)
+ {
+ if (_pickedColorCtrlPnt == 0)
+ return;
+
+ _colorCurve->insertControlPointAt(_pickedColorCtrlPnt);
+ ++_pickedColorCtrlPnt;
+ }
+ else if (-1 != _pickedAlphaCtrlPnt)
+ {
+ if (_pickedAlphaCtrlPnt == 0)
+ return;
+
+ _alphaCurve->insertControlPointAt(_pickedAlphaCtrlPnt);
+ ++_pickedAlphaCtrlPnt;
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::addControlPointsAfterSelected()
+{
+ if (-1 != _pickedColorCtrlPnt )
+ {
+ _colorCurve->insertControlPointAt(_pickedColorCtrlPnt + 1);
+ }
+ else if (-1 != _pickedAlphaCtrlPnt)
+ {
+ _alphaCurve->insertControlPointAt(_pickedAlphaCtrlPnt + 1);
+ }
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::removeSelectedControlPoint()
+{
+ if (-1 != _pickedColorCtrlPnt)
+ {
+ _colorCurve->removeControlPoint(_pickedColorCtrlPnt);
+ _pickedColorCtrlPnt = -1;
+ }
+ else if (-1 != _pickedAlphaCtrlPnt)
+ {
+ _alphaCurve->removeControlPoint(_pickedAlphaCtrlPnt);
+ _pickedAlphaCtrlPnt = -1;
+ }
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setTangentType(InterpolateMode mode)
+{
+ if (-1 != _pickedColorCtrlPnt)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.mode = mode;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+ else if (-1 != _pickedAlphaCtrlPnt)
+ {
+ ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.mode = mode;
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setSmoothTangent()
+{
+ if (-1 != _pickedColorCtrlPnt && _pickedColorCtrlPnt < (_colorCurve->getControlPointCount() - 1) )
+ {
+ ColorControlPoint ctrlctrlPntFront = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 1.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront);
+
+ ColorControlPoint ctrlPntBehiand = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 1.0;
+ ctrlPntBehiand.splineData.inTan = 0.0;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand);
+
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+ else if (-1 != _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (_alphaCurve->getControlPointCount() - 1) )
+ {
+ ColorControlPoint ctrlctrlPntFront = _alphaCurve->getControlPoint(_pickedColorCtrlPnt);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 1.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront);
+
+ ColorControlPoint ctrlPntBehiand = _alphaCurve->getControlPoint(_pickedColorCtrlPnt + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 1.0;
+ ctrlPntBehiand.splineData.inTan = 0.0;
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setEaseInTangent()
+{
+ if (-1 != _pickedColorCtrlPnt && _pickedColorCtrlPnt < (_colorCurve->getControlPointCount() - 1) )
+ {
+ ColorControlPoint ctrlctrlPntFront = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 0.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront);
+
+ ColorControlPoint ctrlPntBehiand = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 1.0;
+ ctrlPntBehiand.splineData.inTan = 0;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand);
+
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+ else if (-1 != _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (_alphaCurve->getControlPointCount() - 1) )
+ {
+ ColorControlPoint ctrlctrlPntFront = _alphaCurve->getControlPoint(_pickedColorCtrlPnt);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 0.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront);
+
+ ColorControlPoint ctrlPntBehiand = _alphaCurve->getControlPoint(_pickedColorCtrlPnt + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 1.0;
+ ctrlPntBehiand.splineData.inTan = 0;
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setEaseOutTangent()
+{
+ if (-1 != _pickedColorCtrlPnt && _pickedColorCtrlPnt < (_colorCurve->getControlPointCount() - 1) )
+ {
+ ColorControlPoint ctrlctrlPntFront = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 1.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront);
+
+ ColorControlPoint ctrlPntBehiand = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 0.0;
+ ctrlPntBehiand.splineData.inTan = 0;
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand);
+
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+ else if (-1 != _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (_alphaCurve->getControlPointCount() - 1) )
+ {
+ ColorControlPoint ctrlctrlPntFront = _alphaCurve->getControlPoint(_pickedColorCtrlPnt);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 1.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront);
+
+ ColorControlPoint ctrlPntBehiand = _alphaCurve->getControlPoint(_pickedColorCtrlPnt + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 0.0;
+ ctrlPntBehiand.splineData.inTan = 0;
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString ColorWidget::getColorTex()
+{
+ if (-1 != _pickedColorCtrlPnt)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ return pnt.texturePath.c_str();
+ }
+ return "";
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setColorTex(const QString& strPath)
+{
+ if (-1 != _pickedColorCtrlPnt)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.texturePath = strPath.toStdString();
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::reloadColorTex()
+{
+ if (-1 != _pickedColorCtrlPnt)
+ {
+ emit ReloadColorAttributeTexture(_colorAttribute, true, _pickedColorCtrlPnt);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::clearColorTex()
+{
+ if (-1 != _pickedColorCtrlPnt)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.texturePath = "";
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString ColorWidget::getAlphaTex()
+{
+ if (-1 != _pickedColorCtrlPnt && _isLink)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ return pnt.texturePath.c_str();
+ }
+ else if (-1 != _pickedAlphaCtrlPnt)
+ {
+ ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+ return pnt.texturePath.c_str();
+ }
+
+ return "";
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setAlphaTex(const QString& strPath)
+{
+ if (-1 != _pickedColorCtrlPnt && _isLink)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.texturePath = strPath.toStdString();
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+ else if (-1 != _pickedAlphaCtrlPnt)
+ {
+ ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+ pnt.texturePath = strPath.toStdString();
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::reloadAlphaTex()
+{
+ if (-1 != _pickedColorCtrlPnt && _isLink)
+ {
+ emit ReloadColorAttributeTexture(_colorAttribute, false, _pickedColorCtrlPnt);
+ }
+ else if (-1 != _pickedAlphaCtrlPnt)
+ {
+ emit ReloadColorAttributeTexture(_colorAttribute, false, _pickedAlphaCtrlPnt);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::clearAlphaTex()
+{
+ if (-1 != _pickedColorCtrlPnt && _isLink)
+ {
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.texturePath = "";
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+ else if (-1 != _pickedAlphaCtrlPnt)
+ {
+ ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+ pnt.texturePath = "";
+ _alphaCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::setUseAlphaFromColor(bool val)
+{
+ if (_colorAttribute && _colorAttribute->useAlphaFromColor != val)
+ {
+ _colorAttribute->useAlphaFromColor = val;
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::onShowContextMenu(const QPoint& pos)
+{
+ _colorCtrlPntToRemove = _checkColorCtrlPntCursorSelected(pos);
+ _alphaCtrlPntToRemove = _checkAlphaCtrlPntCursorSelected(pos);
+
+ if ( !_canAddRemoveControlPoint
+ || (-1 == _colorCtrlPntToRemove && -1 == _alphaCtrlPntToRemove)
+ || 2 == _colorCurve->_controlPoints.size() && -1 != _colorCtrlPntToRemove
+ || 2 == _alphaCurve->_controlPoints.size() && -1 != _alphaCtrlPntToRemove)
+ {
+ _removeCtrlPntAction->setEnabled(false);
+ }
+ else
+ {
+ _removeCtrlPntAction->setEnabled(true);
+ }
+ _contextMenu->exec(QCursor::pos());
+}
+
+void ColorWidget::onRemoveControlPoint()
+{
+ if (-1 != _colorCtrlPntToRemove)
+ {
+ _colorCurve->removeControlPoint(_colorCtrlPntToRemove);
+
+ if (_colorCtrlPntToRemove == _pickedColorCtrlPnt)
+ {
+ if (_isLink)
+ {
+ _colorCtrlPntToRemove = -1;
+ _pickedColorCtrlPnt = -1;
+ _pickedAlphaCtrlPnt = -1;
+ }
+ else
+ {
+ _colorCtrlPntToRemove = -1;
+ _pickedColorCtrlPnt = -1;
+ }
+ }
+
+ _colorCurve->_needSample = true;
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+ else if (-1 != _alphaCtrlPntToRemove && _isLink)
+ {
+ _colorCurve->removeControlPoint(_alphaCtrlPntToRemove);
+
+ if (_alphaCtrlPntToRemove == _pickedAlphaCtrlPnt)
+ {
+ _alphaCtrlPntToRemove = -1;
+ _pickedColorCtrlPnt = -1;
+ _pickedAlphaCtrlPnt = -1;
+ }
+
+ _colorCurve->_needSample = true;
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+ else if (-1 != _alphaCtrlPntToRemove && !_isLink)
+ {
+ _alphaCurve->removeControlPoint(_alphaCtrlPntToRemove);
+
+ if (_alphaCtrlPntToRemove == _pickedAlphaCtrlPnt)
+ {
+ _colorCtrlPntToRemove = -1;
+ _pickedColorCtrlPnt = -1;
+ }
+
+ _alphaCurve->_needSample = true;
+ emit ColorAttributeChanged(_colorAttribute);
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool ColorWidget::event(QEvent *event)
+{
+ if (event->type() == QEvent::ToolTip) {
+ QHelpEvent* helpEvent = static_cast<QHelpEvent*>(event);
+ QPoint mousePos = helpEvent->pos();
+
+ QPointF mousePosF(mousePos.x(), mousePos.y());
+ int pickedColorCtrlPnt = _checkColorCtrlPntCursorSelected(mousePosF);
+ int pickedAlphaCtrlPnt = _checkAlphaCtrlPntCursorSelected(mousePosF);
+
+ if (-1 != pickedColorCtrlPnt)
+ {
+ const std::string& tex = _colorCurve->getControlPoint(pickedColorCtrlPnt).texturePath;
+ if (!tex.empty())
+ QToolTip::showText(helpEvent->globalPos(), tex.c_str());
+
+ }
+ else if (-1 != pickedAlphaCtrlPnt)
+ {
+ if (_isLink)
+ {
+ const std::string& tex = _colorCurve->getControlPoint(pickedAlphaCtrlPnt).texturePath;
+ if (!tex.empty())
+ QToolTip::showText(helpEvent->globalPos(), tex.c_str());
+ }
+ else
+ {
+ const std::string& tex = _alphaCurve->getControlPoint(pickedAlphaCtrlPnt).texturePath;
+ if (!tex.empty())
+ QToolTip::showText(helpEvent->globalPos(), tex.c_str());
+ }
+ }
+ else
+ {
+ QToolTip::hideText();
+ event->ignore();
+ }
+
+ return true;
+ }
+ return QWidget::event(event);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::paintEvent(QPaintEvent * e)
+{
+ //TimeConsumeTracker t("update");
+ QFrame::paintEvent(e);
+
+ QPainter painter;
+ painter.begin(this);
+ painter.setRenderHints(QPainter::Antialiasing, true);
+
+ if (_colorCurve)
+ {
+ _drawRampArea(painter);
+ _drawCtrlPntCursors(painter);
+ _drawWeightCursors(painter);
+ }
+ painter.end();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::resizeEvent(QResizeEvent* e)
+{
+ if (_colorCurve)
+ _updateCurveFitWindowPara();
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::mousePressEvent( QMouseEvent* e )
+{
+ if(_colorCurve && e->button() & Qt::LeftButton)
+ {
+ QPoint mousePos = e->pos();
+ QPointF mousePosF(mousePos.x(), mousePos.y());
+ int pickedColorCtrlPnt = _checkColorCtrlPntCursorSelected(mousePosF);
+ int pickedAlphaCtrlPnt = _checkAlphaCtrlPntCursorSelected(mousePosF);
+
+ if (-1 != pickedColorCtrlPnt || -1 != pickedAlphaCtrlPnt)
+ {
+ if (_canAddRemoveControlPoint && _canRemoveCtrlPntByClick)
+ {
+ if (-1 != pickedColorCtrlPnt)
+ {
+ _colorCurve->removeControlPoint(pickedColorCtrlPnt);
+ _pickedColorCtrlPnt = -1;
+ }
+
+ if (-1 != pickedAlphaCtrlPnt)
+ {
+ if (_isLink)
+ {
+ _colorCurve->removeControlPoint(pickedAlphaCtrlPnt);
+ _pickedColorCtrlPnt = -1;
+ pickedAlphaCtrlPnt = -1;
+ }
+ else
+ {
+ _alphaCurve->removeControlPoint(pickedAlphaCtrlPnt);
+ pickedAlphaCtrlPnt = -1;
+ }
+ }
+ return;
+ }
+
+ _pickedColorCtrlPnt = pickedColorCtrlPnt;
+ _pickedAlphaCtrlPnt = pickedAlphaCtrlPnt;
+
+ if (-1 < _pickedColorCtrlPnt)
+ _dragColorCtrlPnt = true;
+
+ if (-1 < _pickedAlphaCtrlPnt)
+ _dragAlphaCtrlPnt = true;
+
+ if (_isLink)
+ {
+ if (-1 != pickedColorCtrlPnt)
+ {
+ _pickedAlphaCtrlPnt = _pickedColorCtrlPnt;
+ _dragAlphaCtrlPnt = _dragColorCtrlPnt;
+ }
+
+ if (-1 != pickedAlphaCtrlPnt)
+ {
+ _pickedColorCtrlPnt = _pickedAlphaCtrlPnt;
+ _dragColorCtrlPnt = _dragAlphaCtrlPnt;
+ }
+ PickedControlPointChanged(true);
+ }
+ else
+ {
+ if (-1 != pickedColorCtrlPnt)
+ {
+ PickedControlPointChanged(true);
+ }
+
+ if (-1 != pickedAlphaCtrlPnt)
+ {
+ PickedControlPointChanged(false);
+ }
+ }
+
+
+ }
+ else
+ {
+ int pickedColorWeight = _checkColorWeightCursorSelected(mousePosF);
+ int pickedAlphaWeight = _checkAlphaWeightCursorSelected(mousePosF);
+
+ if (-1 != pickedColorWeight || -1 != pickedAlphaWeight)
+ {
+ _pickedColorWeight = pickedColorWeight;
+ _pickedAlphaWeight = pickedAlphaWeight;
+
+ if (-1 < _pickedColorWeight)
+ _dragColorWeight = true;
+
+ if (-1 < _pickedAlphaCtrlPnt)
+ _dragAlphaWeight = true;
+
+ if (_isLink)
+ {
+ if (-1 != _pickedColorWeight)
+ {
+ _pickedAlphaWeight = _pickedColorWeight;
+ _dragAlphaWeight = _dragColorWeight;
+ }
+
+ if (-1 != _pickedAlphaWeight)
+ {
+ _pickedColorWeight = _pickedAlphaWeight;
+ _dragColorWeight = _dragAlphaWeight;
+ }
+ }
+ }
+ else
+ {
+ if (_canAddRemoveControlPoint && _canAddCtrlPntByClick)
+ {
+ int yMiddle = height() / 2;
+ if (mousePos.y() <= yMiddle)
+ {
+ _addColorControlPoint(mousePos.x());
+ PickedControlPointChanged(true);
+ }
+ else if (mousePos.y() > yMiddle)
+ {
+ if (_isLink)
+ {
+ _addColorControlPoint(mousePos.x());
+ PickedControlPointChanged(true);
+ }
+ else
+ {
+ _addAlphaControlPoint(mousePos.x());
+ PickedControlPointChanged(false);
+ }
+ }
+ }
+ }
+ }
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::mouseReleaseEvent( QMouseEvent* /*e*/ )
+{
+ _dragColorCtrlPnt = false;
+ _dragAlphaCtrlPnt = false;
+ _dragColorWeight = false;
+ _dragAlphaWeight = false;
+ _pickedColorWeight = -1;
+ _pickedAlphaWeight = -1;
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::mouseMoveEvent( QMouseEvent* e )
+{
+ Qt::MouseButtons buttons = e->buttons();
+
+ if(_colorCurve && buttons & Qt::LeftButton)
+ {
+ if (_dragColorCtrlPnt)
+ {
+ if (!_colorAttribute->canMoveControlPointHorizontally())
+ return;
+
+ QPoint mousePos = e->pos();
+ ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ pnt.x = _screenToValue(mousePos.x());
+
+ //make control point move in value range
+ if (pnt.x < _colorCurve->getMinValue())
+ pnt.x = _colorCurve->getMinValue();
+ else if (pnt.x > _colorCurve->getMaxValue())
+ pnt.x = _colorCurve->getMaxValue();
+
+ _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt);
+ _colorCurve->_reOrderControlPoints(_pickedColorCtrlPnt);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ if (_dragColorWeight)
+ {
+ QPoint mousePos = e->pos();
+ ColorControlPoint pnt0 = _colorCurve->getControlPoint(_pickedColorWeight);
+ ColorControlPoint pnt1 = _colorCurve->getControlPoint(_pickedColorWeight + 1);
+ int xPnt0Screen = _valueToScreen(pnt0.x);
+ int xPnt1Screen = _valueToScreen(pnt1.x);
+ if (mousePos.x() < (xPnt0Screen + WEIGHT_CURSOR_W))
+ mousePos.setX(xPnt0Screen + WEIGHT_CURSOR_W);
+ if (mousePos.x() > (xPnt1Screen - WEIGHT_CURSOR_W))
+ mousePos.setX(xPnt1Screen - WEIGHT_CURSOR_W);
+ pnt0.weight = ((float)(mousePos.x() - xPnt0Screen))/(xPnt1Screen - xPnt0Screen);
+ _colorCurve->setControlPoint(_pickedColorWeight, pnt0);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ if (!_isLink)
+ {
+ if (_dragAlphaCtrlPnt)
+ {
+ if (!_colorAttribute->canMoveControlPointHorizontally())
+ return;
+
+ QPoint mousePos = e->pos();
+ ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+ pnt.x = _screenToValue(mousePos.x());
+
+ //make control point move in value range
+ if (pnt.x < _alphaCurve->getMinValue())
+ pnt.x = _alphaCurve->getMinValue();
+ else if (pnt.x > _alphaCurve->getMaxValue())
+ pnt.x = _alphaCurve->getMaxValue();
+
+ _alphaCurve->setControlPoint(_pickedAlphaCtrlPnt, pnt);
+ _alphaCurve->_reOrderControlPoints(_pickedAlphaCtrlPnt);
+ _alphaCurve->_needSample = true;
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+
+ if (_dragAlphaWeight)
+ {
+ QPoint mousePos = e->pos();
+ ColorControlPoint pnt0 = _alphaCurve->getControlPoint(_pickedAlphaWeight);
+ ColorControlPoint pnt1 = _alphaCurve->getControlPoint(_pickedAlphaWeight + 1);
+ int xPnt0Screen = _valueToScreen(pnt0.x);
+ int xPnt1Screen = _valueToScreen(pnt1.x);
+ if (mousePos.x() < (xPnt0Screen + WEIGHT_CURSOR_W))
+ mousePos.setX(xPnt0Screen + WEIGHT_CURSOR_W);
+ if (mousePos.x() > (xPnt1Screen - WEIGHT_CURSOR_W))
+ mousePos.setX(xPnt1Screen - WEIGHT_CURSOR_W);
+ pnt0.weight = ((float)(mousePos.x() - xPnt0Screen))/(xPnt1Screen - xPnt0Screen);
+ _alphaCurve->setControlPoint(_pickedAlphaWeight, pnt0);
+ emit ColorAttributeChanged(_colorAttribute);
+ }
+ }
+
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::_updateCurveFitWindowPara()
+{
+ int widgetWidth = width();
+
+ if (_colorCurve && _colorCurve->getControlPointCount() > 1)
+ {
+ float minX = _colorCurve->getMinValue();
+ float maxX = _colorCurve->getMaxValue();
+
+ if (!_isLink)
+ {
+ if (minX < _alphaCurve->getMinValue())
+ minX = _alphaCurve->getMinValue();
+
+ if (maxX < _alphaCurve->getMaxValue())
+ maxX = _alphaCurve->getMaxValue();
+ }
+
+ float curveWidth = maxX - minX;
+
+ if (0 == curveWidth)
+ {
+ curveWidth = 1.0;
+ }
+
+ _curveFitWindowScale = (widgetWidth - MARGIN_X * 2) / curveWidth;
+ _curveFitWindowOffset = MARGIN_X - minX * _curveFitWindowScale;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+float ColorWidget::_valueToScreen(float x)
+{
+ return ROUND(_curveFitWindowScale * x + _curveFitWindowOffset);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+float ColorWidget::_screenToValue(float x)
+{
+ return (x - _curveFitWindowOffset) / _curveFitWindowScale;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void ColorWidget::_fillRampImage(QImage& colorImg, QImage& alphaImg)
+{
+ assert(colorImg.width() == alphaImg.width());
+ assert(colorImg.height() == alphaImg.height());
+
+ int width = colorImg.width();
+ int height = colorImg.height();
+
+ QRgb *colorPixels = nullptr;
+ QRgb *alphaPixels = nullptr;
+ {
+ colorPixels = new QRgb[width];
+ //TimeConsumeTracker t("calcuate one line colorPixels");
+ for (int i = 0; i < width; ++i)
+ {
+ colorPixels[i] = _colorCurve->getColorByX(_screenToValue(i + MARGIN_X)).rgba();
+ }
+
+ if (!_isLink)
+ {
+ alphaPixels = new QRgb[width];
+ //TimeConsumeTracker t("calcuate one line alphaPixels");
+ for (int i = 0; i < width; ++i)
+ {
+ alphaPixels[i] = _alphaCurve->getColorByX(_screenToValue(i + MARGIN_X)).rgba();
+ }
+ }
+ }
+
+ {
+ //TimeConsumeTracker tt("fill images' pixel");
+ for (int m = 0; m < height; ++m)
+ {
+ void* bytesPerLine = const_cast<uchar*>(colorImg.scanLine(m));
+ memcpy(bytesPerLine, colorPixels, sizeof(QRgb) * width);
+
+ bytesPerLine = const_cast<uchar*>(alphaImg.scanLine(m));
+ if (nullptr == alphaPixels)
+ memcpy(bytesPerLine, colorPixels, sizeof(QRgb) * width);
+ else
+ memcpy(bytesPerLine, alphaPixels, sizeof(QRgb) * width);
+ }
+ }
+
+ delete[] colorPixels;
+}
+
+void ColorWidget::_drawRampArea(QPainter& painter)
+{
+ QImage colorImg(width() - MARGIN_X * 2, (height() - SPACING_V - CONTROL_POINT_CURSOR_H * 2 - MARGIN_Y * 2) / 2, QImage::Format_RGB32);
+ QImage alphaImg(width() - MARGIN_X * 2, (height() - SPACING_V - CONTROL_POINT_CURSOR_H * 2 - MARGIN_Y * 2) / 2, QImage::Format_RGB32);
+ _fillRampImage(colorImg, alphaImg);
+ painter.drawImage(MARGIN_X, MARGIN_Y + CONTROL_POINT_CURSOR_H, colorImg);
+ painter.drawImage(MARGIN_X, MARGIN_Y + CONTROL_POINT_CURSOR_H + (height() - SPACING_V - CONTROL_POINT_CURSOR_H * 2 - MARGIN_Y * 2) / 2, alphaImg);
+}
+
+void ColorWidget::_drawCtrlPntCursors(QPainter& painter)
+{
+ int colorCtrlPntCount = _colorCurve->getControlPointCount();
+
+ for (int i = 0; i < colorCtrlPntCount; ++i)
+ {
+ const ColorControlPoint& pnt = _colorCurve->getControlPoint(i);
+
+ float xPosCtrlPnt = ROUND(_valueToScreen(pnt.x));
+ float yColorCtrlPnt = MARGIN_Y;
+ float yAlphaCtrlPnt = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y;
+
+ QRect rcColorCtrnPntCursor(xPosCtrlPnt - CONTROL_POINT_CURSOR_W / 2, yColorCtrlPnt, CONTROL_POINT_CURSOR_W, CONTROL_POINT_CURSOR_H);
+ QRect rcAlphaCtrnPntCursor(xPosCtrlPnt - CONTROL_POINT_CURSOR_W / 2, yAlphaCtrlPnt, CONTROL_POINT_CURSOR_W, CONTROL_POINT_CURSOR_H);
+ if (i == _pickedColorCtrlPnt)
+ {
+ if (pnt.texturePath.empty())
+ painter.drawImage(rcColorCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.red(), pnt.color.green(), pnt.color.blue(), 255), true));
+ else
+ painter.drawImage(rcColorCtrnPntCursor, S_CtrlPntWithTexCursorPickedImg);
+
+ if (_isLink)
+ {
+ if (pnt.texturePath.empty())
+ painter.drawImage(rcAlphaCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.alpha(), pnt.color.alpha(), pnt.color.alpha()), true));
+ else
+ painter.drawImage(rcAlphaCtrnPntCursor, S_CtrlPntWithTexCursorPickedImg);
+ }
+ }
+ else
+ {
+ if (pnt.texturePath.empty())
+ painter.drawImage(rcColorCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.red(), pnt.color.green(), pnt.color.blue(), 255)));
+ else
+ painter.drawImage(rcColorCtrnPntCursor, S_CtrlPntWithTexCursorNormalImg);
+
+ if (_isLink)
+ {
+ if (pnt.texturePath.empty())
+ painter.drawImage(rcAlphaCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.alpha(), pnt.color.alpha(), pnt.color.alpha())));
+ else
+ painter.drawImage(rcAlphaCtrnPntCursor, S_CtrlPntWithTexCursorNormalImg);
+ }
+
+ }
+ }
+
+ if (!_isLink)
+ {
+ int alphaCtrlPntCount = _alphaCurve->getControlPointCount();
+
+ for (int i = 0; i < alphaCtrlPntCount; ++i)
+ {
+ const ColorControlPoint& pnt = _alphaCurve->getControlPoint(i);
+
+ float xPosCtrlPnt = ROUND(_valueToScreen(pnt.x));
+ float yAlphaCtrlPnt = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y;
+
+ QRect rcAlphaCtrnPntCursor(xPosCtrlPnt - CONTROL_POINT_CURSOR_W / 2, yAlphaCtrlPnt, CONTROL_POINT_CURSOR_W, CONTROL_POINT_CURSOR_H);
+
+ if (i == _pickedAlphaCtrlPnt)
+ {
+ if (pnt.texturePath.empty())
+ painter.drawImage(rcAlphaCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.alpha(), pnt.color.alpha(), pnt.color.alpha()), true));
+ else
+ painter.drawImage(rcAlphaCtrnPntCursor, S_CtrlPntWithTexCursorPickedImg);
+ }
+ else
+ {
+ if (pnt.texturePath.empty())
+ painter.drawImage(rcAlphaCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.alpha(), pnt.color.alpha(), pnt.color.alpha()) ));
+ else
+ painter.drawImage(rcAlphaCtrnPntCursor, S_CtrlPntWithTexCursorNormalImg);
+ }
+ }
+ }
+}
+
+void ColorWidget::_drawWeightCursors(QPainter& painter)
+{
+ float yColorWeight = MARGIN_Y + CONTROL_POINT_CURSOR_H - WEIGHT_CURSOR_H;
+
+ int colorCtrlPntCount = _colorCurve->getControlPointCount();
+ if (0 == _pickedColorCtrlPnt)
+ {
+ const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1);
+
+ _drawColorWeightCursor(painter, pnt0, pnt1, _pickedColorCtrlPnt == _pickedColorWeight);
+ }
+ else if ((colorCtrlPntCount - 1) == _pickedColorCtrlPnt)
+ {
+ const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(_pickedColorCtrlPnt - 1);
+ const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+
+ _drawColorWeightCursor(painter, pnt0, pnt1, (_pickedColorCtrlPnt - 1) == _pickedColorWeight);
+ }
+ else if (0 < _pickedColorCtrlPnt && _pickedColorCtrlPnt < (colorCtrlPntCount - 1))
+ {
+ const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(_pickedColorCtrlPnt - 1);
+ const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(_pickedColorCtrlPnt);
+ const ColorControlPoint& pnt2 = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1);
+
+ _drawColorWeightCursor(painter, pnt0, pnt1, (_pickedColorCtrlPnt - 1) == _pickedColorWeight);
+ _drawColorWeightCursor(painter, pnt1, pnt2, _pickedColorCtrlPnt == _pickedColorWeight);
+ }
+
+ if (!_isLink)
+ {
+ float yAlphaWeight = height() - SPACING_V - WEIGHT_CURSOR_H - MARGIN_Y;
+ int alphaCtrlPntCount = _alphaCurve->getControlPointCount();
+ if (0 == _pickedAlphaCtrlPnt)
+ {
+ const ColorControlPoint& pnt0 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+ const ColorControlPoint& pnt1 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt + 1);
+
+ _drawAlphaWeightCursor(painter, pnt0, pnt1, _pickedAlphaCtrlPnt == _pickedAlphaWeight);
+ }
+ else if ((alphaCtrlPntCount - 1) == _pickedAlphaCtrlPnt)
+ {
+ const ColorControlPoint& pnt0 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt - 1);
+ const ColorControlPoint& pnt1 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+
+ _drawAlphaWeightCursor(painter, pnt0, pnt1, (_pickedAlphaCtrlPnt - 1) == _pickedAlphaWeight);
+ }
+ else if (0 < _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (alphaCtrlPntCount - 1))
+ {
+ const ColorControlPoint& pnt0 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt - 1);
+ const ColorControlPoint& pnt1 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt);
+ const ColorControlPoint& pnt2 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt + 1);
+
+ _drawAlphaWeightCursor(painter, pnt0, pnt1, (_pickedAlphaCtrlPnt - 1) == _pickedAlphaWeight);
+ _drawAlphaWeightCursor(painter, pnt1, pnt2, _pickedAlphaCtrlPnt == _pickedAlphaWeight);
+ }
+ }
+}
+
+void ColorWidget::_drawColorWeightCursor(QPainter& painter, const ColorControlPoint& pnt0, const ColorControlPoint& pnt1, bool picked)
+{
+ if (pnt0.mode != eLinear)
+ return ;
+
+ float yColorWeight = MARGIN_Y + CONTROL_POINT_CURSOR_H - WEIGHT_CURSOR_H;
+ float yAlphaWeight = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y;
+
+ float xPosWeightCursor = ROUND(_valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x)));
+ QRect rcColorWeightCursor(xPosWeightCursor - WEIGHT_CURSOR_W / 2, yColorWeight, WEIGHT_CURSOR_W, WEIGHT_CURSOR_H);
+ QRect rcAlphaWeightCursor(xPosWeightCursor - WEIGHT_CURSOR_W / 2, yAlphaWeight, WEIGHT_CURSOR_W, WEIGHT_CURSOR_H);
+
+ painter.drawImage(rcColorWeightCursor, picked?S_WeightCursorPickedImg:S_WeightCursorNormalImg);
+
+ if (_isLink)
+ painter.drawImage(rcAlphaWeightCursor, picked?S_WeightCursorPickedImg:S_WeightCursorNormalImg);
+}
+
+void ColorWidget::_drawAlphaWeightCursor(QPainter& painter, const ColorControlPoint& pnt0, const ColorControlPoint& pnt1, bool picked)
+{
+ if (pnt0.mode != eLinear)
+ return ;
+
+ float yColorWeight = MARGIN_Y + CONTROL_POINT_CURSOR_H - WEIGHT_CURSOR_H;
+ float yAlphaWeight = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y;
+
+ float xPosWeightCursor = ROUND(_valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x)));
+ QRect rcColorWeightCursor(xPosWeightCursor - WEIGHT_CURSOR_W / 2, yColorWeight, WEIGHT_CURSOR_W, WEIGHT_CURSOR_H);
+ QRect rcAlphaWeightCursor(xPosWeightCursor - WEIGHT_CURSOR_W / 2, yAlphaWeight, WEIGHT_CURSOR_W, WEIGHT_CURSOR_H);
+
+ painter.drawImage(rcAlphaWeightCursor, picked?S_WeightCursorPickedImg:S_WeightCursorNormalImg);
+
+ if (_isLink)
+ painter.drawImage(rcColorWeightCursor, picked?S_WeightCursorPickedImg:S_WeightCursorNormalImg);
+}
+
+int ColorWidget::_checkColorCtrlPntCursorSelected(const QPointF& pickPos)
+{
+ if (nullptr == _colorCurve)
+ return -1;
+ int colorCtrlPntCount = _colorCurve->getControlPointCount();
+ for (int i = 0; i < colorCtrlPntCount; ++i)
+ {
+ const ColorControlPoint& pnt = _colorCurve->getControlPoint(i);
+
+ float xPos = _valueToScreen(pnt.x);
+ float yPos = MARGIN_Y;
+ bool picked = isClickedInCtrlPntCursor(QPointF(xPos, yPos), pickPos);
+ if (picked)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int ColorWidget::_checkAlphaCtrlPntCursorSelected(const QPointF& pickPos)
+{
+ if (_isLink)
+ {
+ if (nullptr == _colorCurve)
+ return -1;
+ int colorCtrlPntCount = _colorCurve->getControlPointCount();
+ for (int i = 0; i < colorCtrlPntCount; ++i)
+ {
+ const ColorControlPoint& pnt = _colorCurve->getControlPoint(i);
+
+ float xPos = _valueToScreen(pnt.x);
+ float yPos = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y;
+ bool picked = isClickedInCtrlPntCursor(QPointF(xPos, yPos), pickPos);
+ if (picked)
+ {
+ return i;
+ }
+ }
+ }
+ else
+ {
+ if (nullptr == _alphaCurve)
+ return -1;
+ int colorCtrlPntCount = _alphaCurve->getControlPointCount();
+ for (int i = 0; i < colorCtrlPntCount; ++i)
+ {
+ const ColorControlPoint& pnt = _alphaCurve->getControlPoint(i);
+
+ float xPos = _valueToScreen(pnt.x);
+ float yPos = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y;
+ bool picked = isClickedInCtrlPntCursor(QPointF(xPos, yPos), pickPos);
+ if (picked)
+ {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int ColorWidget::_checkColorWeightCursorSelected(const QPointF& pickPos)
+{
+ int colorCtrlPntCount = _colorCurve->getControlPointCount();
+ if (-1 != _pickedColorCtrlPnt)
+ {
+ if (0 == _pickedColorCtrlPnt)
+ {
+ return _checkColorWeightCursorSelected(0, pickPos);
+ }
+ else if ((colorCtrlPntCount - 1) == _pickedColorCtrlPnt)
+ {
+ return _checkColorWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos);
+ }
+ else if (0 < _pickedColorCtrlPnt && _pickedColorCtrlPnt < (colorCtrlPntCount - 1))
+ {
+ int pickedWeightCursor = _checkColorWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos);
+ if (-1 != pickedWeightCursor)
+ return pickedWeightCursor;
+ else
+ return _checkColorWeightCursorSelected(_pickedColorCtrlPnt, pickPos);
+ }
+ }
+
+ return -1;
+}
+
+int ColorWidget::_checkColorWeightCursorSelected(int pickedCtrlPnt, const QPointF& pickPos)
+{
+ const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(pickedCtrlPnt);
+ const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(pickedCtrlPnt + 1);
+
+ if (pnt0.weight >= 0)
+ {
+ float xPos = _valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x));
+ float yPos = MARGIN_Y + CONTROL_POINT_CURSOR_H - WEIGHT_CURSOR_H;
+ bool picked = isClickedInWeightCursor(QPointF(xPos, yPos), pickPos);
+ if (picked)
+ {
+ return pickedCtrlPnt;
+ }
+ }
+
+ return - 1;
+}
+
+int ColorWidget::_checkAlphaWeightCursorSelected(const QPointF& pickPos)
+{
+ if (_isLink)
+ {
+ int count = _colorCurve->getControlPointCount();
+ if (-1 != _pickedAlphaCtrlPnt)
+ {
+ if (0 == _pickedAlphaCtrlPnt)
+ {
+ return _checkAlphaWeightCursorSelected(0, pickPos);
+ }
+ else if ((count - 1) == _pickedAlphaCtrlPnt)
+ {
+ return _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos);
+ }
+ else if (0 < _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (count - 1))
+ {
+ int pickedWeightCursor = _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos);
+ if (-1 != pickedWeightCursor)
+ return pickedWeightCursor;
+ else
+ return _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt, pickPos);
+ }
+ }
+ }
+ else
+ {
+ int count = _alphaCurve->getControlPointCount();
+ if (-1 != _pickedAlphaCtrlPnt)
+ {
+ if (0 == _pickedAlphaCtrlPnt)
+ {
+ return _checkAlphaWeightCursorSelected(0, pickPos);
+ }
+ else if ((count - 1) == _pickedAlphaCtrlPnt)
+ {
+ return _checkAlphaWeightCursorSelected(count - 1, pickPos);
+ }
+ else if (0 < _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (count - 1))
+ {
+ int pickedWeightCursor = _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos);
+ if (-1 != pickedWeightCursor)
+ return pickedWeightCursor;
+ else
+ return _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt, pickPos);
+ }
+ }
+ }
+
+ return -1;
+}
+
+int ColorWidget::_checkAlphaWeightCursorSelected(int pickedCtrlPnt, const QPointF& pickPos)
+{
+ if (_isLink)
+ {
+ const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(pickedCtrlPnt);
+ const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(pickedCtrlPnt + 1);
+
+ if (pnt0.weight >= 0)
+ {
+ float xPos = _valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x));
+ float yPos = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y;
+ bool picked = isClickedInWeightCursor(QPointF(xPos, yPos), pickPos);
+ if (picked)
+ {
+ return pickedCtrlPnt;
+ }
+ }
+ }
+ else
+ {
+ int colorCtrlPntCount = _alphaCurve->getControlPointCount();
+ for (int i = 0; i < colorCtrlPntCount - 1; ++i)
+ {
+ const ColorControlPoint& pnt0 = _alphaCurve->getControlPoint(i);
+ const ColorControlPoint& pnt1 = _alphaCurve->getControlPoint(i + 1);
+
+ if (pnt0.weight >= 0)
+ {
+ float xPos = _valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x));
+ float yPos = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y;
+ bool picked = isClickedInCtrlPntCursor(QPointF(xPos, yPos), pickPos);
+ if (picked)
+ {
+ return i;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+ return -1;
+}
+
+void ColorWidget::_addColorControlPoint(int xPos)
+{
+ float x = _screenToValue(xPos);
+
+ int ctrlPntCount = _colorCurve->getControlPointCount();
+ for (int i = 0; i < ctrlPntCount - 1; ++i)
+ {
+ const ColorControlPoint& pntLeft = _colorCurve->getControlPoint(i);
+ const ColorControlPoint& pntRight = _colorCurve->getControlPoint(i + 1);
+
+ if (pntLeft.x < x && x < pntRight.x)
+ {
+ QColor color = _colorCurve->getColorByX(x);
+ ColorControlPoint newCtrlPnt(x, color, pntLeft.mode);
+
+ std::vector<ColorControlPoint>::iterator itr = _colorCurve->_controlPoints.begin();
+ std::advance(itr, i + 1);
+ _colorCurve->_controlPoints.insert(itr, newCtrlPnt);
+
+ _pickedColorCtrlPnt = i + 1;
+ if (_isLink)
+ _pickedAlphaCtrlPnt = _pickedColorCtrlPnt;
+
+ break;
+ }
+ }
+}
+
+void ColorWidget::_addAlphaControlPoint(int xPos)
+{
+ float x = _screenToValue(xPos);
+
+ int ctrlPntCount = _alphaCurve->getControlPointCount();
+ for (int i = 0; i < ctrlPntCount - 1; ++i)
+ {
+ const ColorControlPoint& pntLeft = _alphaCurve->getControlPoint(i);
+ const ColorControlPoint& pntRight = _alphaCurve->getControlPoint(i + 1);
+
+ if (pntLeft.x < x && x < pntRight.x)
+ {
+ QColor color = _alphaCurve->getColorByX(x);
+ ColorControlPoint newCtrlPnt(x, color, pntLeft.mode);
+
+ std::vector<ColorControlPoint>::iterator itr = _alphaCurve->_controlPoints.begin();
+ std::advance(itr, i + 1);
+ _alphaCurve->_controlPoints.insert(itr, newCtrlPnt);
+
+ _pickedAlphaCtrlPnt = i + 1;
+ if (_isLink)
+ _pickedColorCtrlPnt = _pickedAlphaCtrlPnt;
+
+ break;
+ }
+ }
+}
+
+} // namespace CurveEditor
+} // namespace nvidia \ No newline at end of file
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Window/ColorWidget.h b/NvBlast/tools/CurveEditor/source/Internal/Window/ColorWidget.h
new file mode 100644
index 0000000..d910789
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Window/ColorWidget.h
@@ -0,0 +1,126 @@
+#ifndef COLORWIDGET_H
+#define COLORWIDGET_H
+
+#include <QtWidgets/QFrame>
+#include <QtWidgets/QMenu>
+#include <QtWidgets/QAction>
+#include "Attribute.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+class ColorWidget : public QFrame
+{
+ Q_OBJECT
+public:
+ explicit ColorWidget(QWidget *parent = 0);
+
+ inline bool isLink() { return _isLink; }
+ QColor getColor();
+ int getAlpha();
+ void setColor(const QColor& color);
+ void setAlpha(int alpha);
+ float getColorFallOff();
+ void setColorFallOff(float fallOff);
+ float getAlphaFallOff();
+ void setAlphaFallOff(float fallOff);
+
+ // if alphaCurve of colorAttribute is with less than 2 control points,
+ // it treats that rgb color curve and alpha curve share same control points
+ // else, it uses rgb components of colorCurve of ColorAttribute, and it uses alpha component of alphaCurve of ColorAttribute
+ void setColorAttribute(ColorAttribute* colorAttribute);
+ void reset();
+ inline void setCanAddRemoveControlPoint(bool val) { _canAddRemoveControlPoint = val; }
+
+ void addControlPointsBeforeSelected();
+ void addControlPointsAfterSelected();
+ void removeSelectedControlPoint();
+
+ void setTangentType(InterpolateMode mode);
+ void setSmoothTangent();
+ void setEaseInTangent();
+ void setEaseOutTangent();
+
+ QString getColorTex();
+ void setColorTex(const QString& strPath);
+ void reloadColorTex();
+ void clearColorTex();
+ QString getAlphaTex();
+ void setAlphaTex(const QString& strPath);
+ void reloadAlphaTex();
+ void clearAlphaTex();
+
+ void setAddCtrlPntByClick(bool value) { _canAddCtrlPntByClick = value; }
+ void setRemoveCtrlPntByClick(bool value) { _canRemoveCtrlPntByClick = value; }
+
+ void setUseAlphaFromColor(bool val);
+
+signals:
+ void PickedControlPointChanged(bool isColorCtrlPnt);
+ void ColorAttributeChanged(nvidia::CurveEditor::ColorAttribute* attribute);
+ void ReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute* attribute, bool reloadColorTex, int selectedCtrlPntIndex);
+
+private slots:
+ void onShowContextMenu(const QPoint& pos);
+ void onRemoveControlPoint();
+
+protected:
+ // QWidget events
+ virtual bool event(QEvent *event);
+ virtual void paintEvent(QPaintEvent * e);
+ virtual void resizeEvent(QResizeEvent* e);
+ virtual void mousePressEvent(QMouseEvent* e);
+ virtual void mouseReleaseEvent(QMouseEvent* e);
+ virtual void mouseMoveEvent(QMouseEvent* e);
+
+private:
+ void _updateCurveFitWindowPara();
+ inline float _valueToScreen(float x);
+ inline float _screenToValue(float x);
+
+ void _fillRampImage(QImage& colorImg, QImage& alphaImg);
+ void _drawRampArea(QPainter& painter);
+ void _drawCtrlPntCursors(QPainter& painter);
+ void _drawWeightCursors(QPainter& painter);
+ void _drawColorWeightCursor(QPainter& painter, const ColorControlPoint& pnt0, const ColorControlPoint& pnt1, bool picked = false);
+ void _drawAlphaWeightCursor(QPainter& painter, const ColorControlPoint& pnt0, const ColorControlPoint& pnt1, bool picked = false);
+ int _checkColorCtrlPntCursorSelected(const QPointF& pickPos);
+ int _checkAlphaCtrlPntCursorSelected(const QPointF& pickPos);
+ int _checkColorWeightCursorSelected(const QPointF& pickPos);
+ int _checkColorWeightCursorSelected(int pickedCtrlPnt, const QPointF& pickPos);
+ int _checkAlphaWeightCursorSelected(const QPointF& pickPos);
+ int _checkAlphaWeightCursorSelected(int pickedCtrlPnt, const QPointF& pickPos);
+ void _addColorControlPoint(int xPos);
+ void _addAlphaControlPoint(int xPos);
+
+private:
+ bool _isLink; // if it's true, rgb color and alpha share the same control points
+ ColorAttribute* _colorAttribute;
+ ColorCurve* _colorCurve;
+ ColorCurve* _alphaCurve;
+ bool _canAddRemoveControlPoint;
+ bool _canAddCtrlPntByClick;
+ bool _canRemoveCtrlPntByClick;
+
+ float _curveFitWindowScale;
+ float _curveFitWindowOffset;
+
+ int _pickedColorCtrlPnt;
+ int _pickedAlphaCtrlPnt;
+ int _pickedColorWeight;
+ int _pickedAlphaWeight;
+ bool _dragColorCtrlPnt;
+ bool _dragAlphaCtrlPnt;
+ bool _dragColorWeight;
+ bool _dragAlphaWeight;
+
+ int _colorCtrlPntToRemove;
+ int _alphaCtrlPntToRemove;
+ QMenu* _contextMenu;
+ QAction* _removeCtrlPntAction;
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // COLORWIDGET_H
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Window/CurveEditorMainWindow.cpp b/NvBlast/tools/CurveEditor/source/Internal/Window/CurveEditorMainWindow.cpp
new file mode 100644
index 0000000..b11c4cf
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Window/CurveEditorMainWindow.cpp
@@ -0,0 +1,1530 @@
+#include "CurveEditorMainWindow.h"
+#include "ui_CurveEditorMainWindow.h"
+#include <QtWidgets/QSplitter>
+#include <QtWidgets/QColorDialog>
+#include "CurveWidget.h"
+#include "ColorWidget.h"
+#include "AlphaDialog.h"
+#include <QtCore/QDebug>
+#include <QtWidgets/QFileDialog>
+#include <QtWidgets/QMessageBox>
+#include <float.h>
+
+namespace nvidia {
+namespace CurveEditor {
+
+// each value is associated with the tab index of tab control of attributes
+enum AttributesTabIndex
+{
+ eCurveTab = 0,
+ eColorTab = 1,
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+QString InterpolateModeToString(InterpolateMode mode)
+{
+ switch(mode)
+ {
+ case eDiscret:
+ return "Discret";
+ case eLinear:
+ return "Linear";
+ case eBezierSpline:
+ return "BezierSpline";
+ case eCatmullRomSpline:
+ return "CatmullRomSpline";
+ default:
+ return "Discret";
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+InterpolateMode StringToInterpolateMode(const QString& mode)
+{
+ if (mode == "Discret")
+ {
+ return eDiscret;
+ }
+ else if (mode == "Linear")
+ {
+ return eLinear;
+ }
+ else if (mode == "BezierSpline")
+ {
+ return eBezierSpline;
+ }
+ else if (mode == "CatmullRomSpline")
+ {
+ return eCatmullRomSpline;
+ }
+ else
+ {
+ return eDiscret;
+ }
+}
+
+QString OpenTextureFile( QString lastDir, QString title = "")
+{
+ QString titleStr = "Open Texture File";
+ if(!title.isEmpty())
+ titleStr = title;
+
+ QString fileName = QFileDialog::getOpenFileName(nullptr, titleStr, lastDir, "Images (*.dds *.png *.bmp *.jpg *.tga)");
+
+ return fileName;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+void setTextureButtons(QPushButton *pTex, QPushButton *pReload, QPushButton *pClear)
+{
+ pTex->setIcon(QIcon(":/AppMainWindow/Icon/TextureEnabled_icon.png"));
+ pReload->setIcon(QIcon(":/AppMainWindow/Icon/Refresh_icon.png"));
+ pClear->setIcon(QIcon(":/AppMainWindow/Icon/Remove_icon.png"));
+
+ pTex->setIconSize(QSize(12,12));
+ pReload->setIconSize(QSize(12,12));
+ pClear->setIconSize(QSize(12,12));
+}
+
+//////////////////////////////////////////////////////////
+QString addStar(QString text, bool add)
+{
+ QByteArray ba = text.toUtf8();
+
+ const char* in = ba.data();
+ char out[1024];
+
+ int i = 0;
+ for (i = 0; i < strlen(in); i++)
+ {
+ if (in[i] == '*')
+ break;
+ out[i] = in[i];
+ }
+ out[i] = 0;
+
+ QString newtext;
+ if (add)
+ newtext = QString((const char*)out) + QString("*");
+ else
+ newtext = QString((const char*)out) ;
+ return newtext;
+}
+
+//////////////////////////////////////////////////////////
+void setFocusColor(QWidget* qWidget, bool sameForAllAttributes)
+{
+ if (!qWidget)
+ return;
+
+ QString sameStyle = QString("font: ; color: rgb(150,150,150);") ;
+ QString differentStyle = QString("font: bold; color: rgb(255,55,55);");
+ QString style = (sameForAllAttributes) ? sameStyle : differentStyle;
+
+ qWidget->setStyleSheet(style);
+
+ QLabel* label = dynamic_cast<QLabel*>(qWidget);
+ if (label)
+ {
+ QString newtext = addStar(label->text(), !sameForAllAttributes);
+
+ label->setFrameStyle(0);
+ label->setText(newtext);
+ }
+}
+
+//////////////////////////////////////////////////////////
+void pickColor(QColor& color, QWidget* parent)
+{
+ QColor newColor = QColorDialog::getColor(color, parent);
+ if(newColor.isValid())
+ {
+ color = newColor;
+ }
+}
+
+//////////////////////////////////////////////////////////
+void pickAlpha(int& alpha, QWidget* parent)
+{
+ alpha = AlphaDialog::getAlpha(alpha, parent);
+}
+
+//////////////////////////////////////////////////////////
+void setButtonColor(QPushButton *button, const QColor& color)
+{
+ QString specBtnStyle = QString("background-color: rgb(%1,%2,%3);")
+ .arg(color.red())
+ .arg(color.green())
+ .arg(color.blue());
+
+ button->setStyleSheet(specBtnStyle);
+}
+
+//////////////////////////////////////////////////////////
+void setButtonTex(QPushButton *button, bool used)
+{
+ if (used)
+ button->setIcon(QIcon(":/AppMainWindow/Icon/TextureIsUsed_icon.png"));
+ else
+ button->setIcon(QIcon(":/AppMainWindow/Icon/TextureEnabled_icon.png"));
+}
+
+CurveEditorMainWindow::CurveEditorMainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::CurveEditorMainWindow)
+ , _curveWidget(nullptr)
+ , _colorWidget(nullptr)
+ , _curveAttributeCache(nullptr)
+ , _colorAttributeCache(nullptr)
+ , _updateUIFromData(false)
+ , _canMoveCurveControlPointHorizontally(true)
+ , _canAddRemoveCurveControlPoint(true)
+ , _canChangeCurveTangentType(true)
+{
+ Q_INIT_RESOURCE(CurveEditor);
+
+ ui->setupUi(this);
+
+ setTextureButtons(ui->btnColorTex, ui->btnColorReload, ui->btnColorClear);
+ setTextureButtons(ui->btnAlphaTex, ui->btnAlphaReload, ui->btnAlphaClear);
+
+ ui->centralWidget->setStretchFactor(0, 30);
+ ui->centralWidget->setStretchFactor(1, 70);
+
+ {
+ QActionGroup* groupSnap = new QActionGroup(this);
+ groupSnap->addAction(ui->actionSnap_All);
+ groupSnap->addAction(ui->actionSnap_Horizontal);
+ groupSnap->addAction(ui->actionSnap_Vertical);
+ }
+
+ {
+ QActionGroup* groupAddRemoveCtrlPnt = new QActionGroup(this);
+ groupAddRemoveCtrlPnt->addAction(ui->actionAdd_Control_Point_By_Click);
+ groupAddRemoveCtrlPnt->addAction(ui->actionRemove_Control_Point_By_Click);
+ }
+
+ _fillCurveAttributesTree();
+
+ _fillColorAttributesTree();
+
+ {
+ _curveWidget = new CurveWidget(ui->frameCurveEditorArea);
+ ui->layoutCurveEditorArea->addWidget(_curveWidget);
+ connect(_curveWidget, SIGNAL(PickedControlPointChanged(const std::vector<CurveEntity*>)), this, SLOT(onCurvePickedControlPointChanged(const std::vector<CurveEntity*>)));
+ connect(_curveWidget, SIGNAL(PickedControlPointValueChanged(QPointF&)), this, SLOT(onCurvePickedControlPointValueChanged(QPointF&)));
+ }
+
+ {
+ _colorWidget = new ColorWidget(ui->frameColorAlphaRamp);
+ ui->layoutColorEditorArea->addWidget(_colorWidget);
+ connect(_colorWidget, SIGNAL(PickedControlPointChanged(bool)), this, SLOT(onColorPickedControlPointChanged(bool)));
+
+ QColor color = _colorWidget->getColor();
+ setButtonColor(ui->btnColor, color);
+ setButtonColor(ui->btnAlpha, QColor(color.alpha(), color.alpha(), color.alpha()));
+ }
+
+ connect(_curveWidget, SIGNAL(CurveAttributeChanged(nvidia::CurveEditor::CurveAttribute*)), this, SIGNAL(CurveAttributeChanged(nvidia::CurveEditor::CurveAttribute*)));
+ connect(_colorWidget, SIGNAL(ColorAttributeChanged(nvidia::CurveEditor::ColorAttribute*)), this, SIGNAL(ColorAttributeChanged(nvidia::CurveEditor::ColorAttribute*)));
+ connect(_colorWidget, SIGNAL(ReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute*, bool, int)), this, SIGNAL(ReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute*, bool, int)));
+
+ QString defFilePath;
+
+ QString appDir = qApp->applicationDirPath();
+ QDir dir(appDir);
+ if (dir.cd("../../media"))
+ defFilePath = dir.absolutePath();
+
+ _lastFilePath = defFilePath;
+ _presetPath = _lastFilePath + "/Presets/";
+}
+
+CurveEditorMainWindow::~CurveEditorMainWindow()
+{
+ delete ui;
+ ui = nullptr;
+}
+
+void CurveEditorMainWindow::setCurveAttributes(const std::vector<CurveAttributeBase*>& attributes)
+{
+ _curveWidget->setCurveAttributes(std::vector<CurveAttributeBase*>());
+
+ _curveAttributes = attributes;
+ _fillCurveAttributesTree();
+
+ _canMoveCurveControlPointHorizontally = false;
+ _canAddRemoveCurveControlPoint = false;
+ _canChangeCurveTangentType = false;
+ size_t countAttributes = _curveAttributes.size();
+ for (size_t i = 0; i < countAttributes; ++i)
+ {
+ CurveAttributeBase* attribute = _curveAttributes[i];
+
+ if (attribute->getType() == eGroupAttr)
+ {
+ CurveAttributeGroup* attributeGroup = static_cast<CurveAttributeGroup*>(attribute);
+ size_t countAttributesInGroup = attributeGroup->attributes.size();
+ for (size_t j = 0; j < countAttributesInGroup; ++j)
+ {
+ CurveAttribute* attributeInGroup = static_cast<CurveAttribute*>(attributeGroup->attributes[j]);
+ if (attributeInGroup->canMoveControlPointHorizontally())
+ _canMoveCurveControlPointHorizontally = true;
+ if (attributeInGroup->canAddRemoveControlPoint())
+ _canAddRemoveCurveControlPoint = true;
+ if (attributeInGroup->canChangeTangentType())
+ _canChangeCurveTangentType = true;
+ }
+ }
+ else
+ {
+ CurveAttribute* attributeSecific = static_cast<CurveAttribute*>(attribute);
+ if (attributeSecific->canMoveControlPointHorizontally())
+ _canMoveCurveControlPointHorizontally = true;
+ if (attributeSecific->canAddRemoveControlPoint())
+ _canAddRemoveCurveControlPoint = true;
+ if (attributeSecific->canChangeTangentType())
+ _canChangeCurveTangentType = true;
+ }
+ }
+
+ ui->spinBoxLocation->setEnabled(_canMoveCurveControlPointHorizontally);
+ _syncUIStatusWithSelectedAttribute(_canAddRemoveCurveControlPoint, _canChangeCurveTangentType);
+}
+
+void CurveEditorMainWindow::setColorCurveAttributes(const std::vector<ColorAttribute*>& attributes)
+{
+ _colorWidget->setColorAttribute(nullptr);
+
+ _colorAttributes = attributes;
+ _fillColorAttributesTree();
+}
+
+void CurveEditorMainWindow::setSelectedCurveAttributes(const std::vector<CurveAttributeBase*>& attributes)
+{
+ ui->tabWidgetAttributes->setCurrentIndex(eCurveTab);
+
+ for (size_t i = 0; i < attributes.size(); ++i)
+ {
+ CurveAttributeBase* attribute = attributes[i];
+ QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->findItems(attribute->getName().c_str(), Qt::MatchExactly);
+ if (items.size() > 0)
+ items[0]->setSelected(true);
+ }
+}
+
+void CurveEditorMainWindow::setSelectedColorAttribute(const ColorAttribute* attribute)
+{
+ ui->tabWidgetAttributes->setCurrentIndex(eColorTab);
+
+ if (attribute)
+ {
+ QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->findItems(attribute->getName().c_str(), Qt::MatchExactly);
+ if (items.size() > 0)
+ items[0]->setSelected(true);
+ }
+}
+
+void CurveEditorMainWindow::setResampleEnabled(bool enable)
+{
+ ui->checkBoxResamplePoints->setVisible(enable);
+ ui->spinBoxResamplePoints->setVisible(enable);
+ ui->checkBoxResamplePoints->setEnabled(enable);
+ ui->spinBoxResamplePoints->setEnabled(enable);
+}
+
+void CurveEditorMainWindow::on_actionCopy_triggered()
+{
+ if (eCurveTab == ui->tabWidgetAttributes->currentIndex())
+ {
+ QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems();
+ if (1 == items.count())
+ {
+ CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(0));
+
+ if (eSingleAttr == item->_attribute->getType())
+ {
+ if (_curveAttributeCache == nullptr)
+ _curveAttributeCache = new CurveAttribute("curveAttributeCache");
+
+ CurveAttribute* selectedAttribute = static_cast<CurveAttribute*>(item->_attribute);
+ _curveAttributeCache->curve = selectedAttribute->curve;
+ return ;
+ }
+ }
+
+ QMessageBox::warning(this, tr("Warning"), tr("You should select only one attribute to copy attribute data."));
+ }
+ else if (eColorTab == ui->tabWidgetAttributes->currentIndex())
+ {
+ QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems();
+ if (1 == items.count())
+ {
+ ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0));
+
+ if (eColorAttr == item->_attribute->getType())
+ {
+ if (_colorAttributeCache == nullptr)
+ _colorAttributeCache = new ColorAttribute("colorAttributeCache");
+
+ ColorAttribute* selectedAttribute = static_cast<ColorAttribute*>(item->_attribute);
+ _colorAttributeCache->colorCurve = selectedAttribute->colorCurve;
+ _colorAttributeCache->alphaCurve = selectedAttribute->alphaCurve;
+ return ;
+ }
+ }
+ }
+}
+
+void CurveEditorMainWindow::on_actionPaste_triggered()
+{
+ if (eCurveTab == ui->tabWidgetAttributes->currentIndex())
+ {
+ if (nullptr == _curveAttributeCache)
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("You should copy or load an curve attribute's data first."));
+ return ;
+ }
+
+ QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems();
+ if (1 == items.count())
+ {
+ CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(0));
+
+ if (eSingleAttr == item->_attribute->getType())
+ {
+ CurveAttribute* selectedAttribute = static_cast<CurveAttribute*>(item->_attribute);
+ bool compatible = true;
+ if (compatible)
+ {
+ selectedAttribute->curve = _curveAttributeCache->curve;
+ on_treeWidgetCurveAttributes_itemSelectionChanged();
+ CurveAttributeChanged(selectedAttribute);
+ }
+ else
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("The data types between the curve attribute copyed from and the curve attribute copy to are incompatible ."));
+ }
+ return ;
+ }
+ }
+
+ QMessageBox::warning(this, tr("Warning"), tr("You should select only one curve attribute to paste curve attribute data."));
+ }
+ else if (eColorTab == ui->tabWidgetAttributes->currentIndex())
+ {
+ if (nullptr == _colorAttributeCache)
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("You should copy or load an color attribute's data first."));
+ return ;
+ }
+
+ QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems();
+ if (1 == items.count())
+ {
+ ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0));
+
+ if (eColorAttr == item->_attribute->getType())
+ {
+ ColorAttribute* selectedAttribute = static_cast<ColorAttribute*>(item->_attribute);
+ bool compatible = true;
+ if (compatible)
+ {
+ selectedAttribute->colorCurve = _colorAttributeCache->colorCurve;
+ selectedAttribute->alphaCurve = _colorAttributeCache->alphaCurve;
+ on_treeWidgetColorAttributes_itemSelectionChanged();
+ ColorAttributeChanged(selectedAttribute);
+ }
+ else
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("The data types between copy from attribute and copy to attribute are incompatible ."));
+ }
+ return ;
+ }
+ }
+
+ QMessageBox::warning(this, tr("Warning"), tr("You should select only one attribute to paste attribute data."));
+ }
+}
+
+void CurveEditorMainWindow::on_actionSave_Selected_as_Preset_triggered()
+{
+ QDir dir(_presetPath);
+ if (!dir.exists())
+ dir.mkdir(_presetPath);
+
+ CurveAttribute* curveAttribute = nullptr;
+ ColorAttribute* colorAttribute = nullptr;
+ QString presetFile = _presetPath;
+
+ if (eCurveTab == ui->tabWidgetAttributes->currentIndex())
+ {
+ QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems();
+ if (1 != items.count())
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("You should select one attribute only to save preset."));
+ return ;
+ }
+
+ CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(0));
+
+ if (eSingleAttr != item->_attribute->getType())
+ {
+ return;
+ }
+
+ curveAttribute = static_cast<CurveAttribute*>(item->_attribute);
+ presetFile += curveAttribute->getName().c_str();
+ presetFile += ".cps";
+ }
+ else if (eColorTab == ui->tabWidgetAttributes->currentIndex())
+ {
+ QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems();
+ if (1 != items.count())
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("You should select one attribute only to save preset."));
+ return ;
+ }
+
+ ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0));
+
+ if (eColorAttr != item->_attribute->getType())
+ {
+ return;
+ }
+
+ colorAttribute = item->_attribute;
+ presetFile += colorAttribute->getName().c_str();
+ presetFile += ".cps";
+ }
+
+ QString filePath = QFileDialog::getSaveFileName(this, tr("Save Curve PreSet"), presetFile, tr("Curve PreSet(*.cps)"));
+ if (filePath.length() == 0)
+ {
+ QMessageBox::warning(this, tr("Path"), tr("You didn't select any files."));
+ return ;
+ }
+
+ QFileInfo fileInfo(filePath);
+ _presetPath = fileInfo.absoluteDir().absolutePath();
+ if (!_presetPath.endsWith("/"))
+ _presetPath += "/";
+
+ QFile file(filePath);
+ if (!file.open(QIODevice::WriteOnly|QIODevice::Truncate))
+ {
+ return;
+ }
+ QTextStream out(&file);
+
+ QDomDocument xmlDoc;
+ QDomElement rootElm = xmlDoc.createElement(tr("CurvePreSet"));
+ xmlDoc.appendChild(rootElm);
+
+ if (curveAttribute != nullptr)
+ {
+ _saveAttribute(rootElm, curveAttribute);
+ }
+ else if (colorAttribute != nullptr)
+ {
+ _saveAttribute(rootElm, colorAttribute);
+ }
+ // 4 is count of indent
+ xmlDoc.save(out, 4);
+}
+
+void CurveEditorMainWindow::on_actionLoad_Preset_to_Copy_Buffer_triggered()
+{
+ QString filePath = QFileDialog::getOpenFileName(this, tr("Open Curve PreSet"), _presetPath, tr("Curve PreSet(*.cps)"));
+ if (filePath.length() == 0)
+ {
+ QMessageBox::warning(this, tr("Path"), tr("You didn't select any files."));
+ return;
+ }
+
+ QFileInfo fileInfo(filePath);
+ _presetPath = fileInfo.absoluteDir().absolutePath();
+ if (!_presetPath.endsWith("/"))
+ _presetPath += "/";
+
+ QFile file(filePath);
+
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ return;
+ }
+
+ QDomDocument xmlDoc;
+ if (!xmlDoc.setContent(&file))
+ {
+ file.close();
+ return;
+ }
+ file.close();
+
+ if (xmlDoc.isNull() || xmlDoc.documentElement().tagName() != tr("CurvePreSet"))
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("The file you selected is empty or not a cps file."));
+ return;
+ }
+
+ QDomElement elm = xmlDoc.documentElement().firstChildElement();
+ CurveAttributeBase* presetAttribute = _loadAttribute(elm);
+ if (nullptr == presetAttribute)
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("Faid to load the cps file!"));
+ return;
+ }
+
+ if (eSingleAttr == presetAttribute->_type)
+ {
+ if (_curveAttributeCache == nullptr)
+ _curveAttributeCache = new CurveAttribute("curveAttributeCache");
+
+ CurveAttribute* presetCurveAttribute = static_cast<CurveAttribute*>(presetAttribute);
+ _curveAttributeCache->curve = presetCurveAttribute->curve;
+ }
+ else if (eColorAttr == presetAttribute->_type)
+ {
+ if (_colorAttributeCache == nullptr)
+ _colorAttributeCache = new ColorAttribute("colorAttributeCache");
+
+ ColorAttribute* presetColorAttribute = static_cast<ColorAttribute*>(presetAttribute);
+ _colorAttributeCache->colorCurve = presetColorAttribute->colorCurve;
+ _colorAttributeCache->alphaCurve = presetColorAttribute->alphaCurve;
+ }
+}
+
+void CurveEditorMainWindow::on_actionImport_Preset_onto_Selected_triggered()
+{
+ CurveAttribute* curveAttribute = nullptr;
+ ColorAttribute* colorAttribute = nullptr;
+ if (eCurveTab == ui->tabWidgetAttributes->currentIndex())
+ {
+ QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems();
+ if (1 != items.count())
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("You should select only one attribute to import preset."));
+ return;
+ }
+
+ CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(0));
+
+ if (eSingleAttr != item->_attribute->getType())
+ {
+ return;
+ }
+
+ curveAttribute = static_cast<CurveAttribute*>(item->_attribute);
+ }
+ else if (eColorTab == ui->tabWidgetAttributes->currentIndex())
+ {
+ QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems();
+ if (1 != items.count())
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("You should select only one attribute to import preset."));
+ return;
+ }
+
+ ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0));
+
+ if (eColorAttr != item->_attribute->getType())
+ {
+ return;
+ }
+
+ colorAttribute = item->_attribute;
+ }
+
+ QString filePath = QFileDialog::getOpenFileName(this, tr("Open Curve PreSet"), _presetPath, tr("Curve PreSet(*.cps)"));
+ if (filePath.length() == 0)
+ {
+ QMessageBox::warning(this, tr("Path"), tr("You didn't select any files."));
+ return;
+ }
+
+ QFileInfo fileInfo(filePath);
+ _presetPath = fileInfo.absoluteDir().absolutePath();
+ if (!_presetPath.endsWith("/"))
+ _presetPath += "/";
+
+ QFile file(filePath);
+
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ return;
+ }
+
+ QDomDocument xmlDoc;
+ if (!xmlDoc.setContent(&file))
+ {
+ file.close();
+ return;
+ }
+ file.close();
+
+ if (xmlDoc.isNull() || xmlDoc.documentElement().tagName() != tr("CurvePreSet"))
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("The file you selected is empty or not a cps file."));
+ return;
+ }
+
+ QDomElement elm = xmlDoc.documentElement().firstChildElement();
+ CurveAttributeBase* presetAttribute = _loadAttribute(elm);
+ if (nullptr == presetAttribute)
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("Faid to load the cps file!"));
+ return;
+ }
+
+ if (eSingleAttr == presetAttribute->_type)
+ {
+ CurveAttribute* presetCurveAttribute = static_cast<CurveAttribute*>(presetAttribute);
+
+ bool compatible = (curveAttribute != nullptr) ? true:false;
+ if (compatible)
+ {
+ curveAttribute->curve = presetCurveAttribute->curve;
+ on_treeWidgetCurveAttributes_itemSelectionChanged();
+ CurveAttributeChanged(curveAttribute);
+ }
+ else
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("The selected attribute is incompatible with preset attribute."));
+ }
+ }
+ else if (eColorAttr == presetAttribute->_type)
+ {
+ ColorAttribute* presetColorAttribute = static_cast<ColorAttribute*>(presetAttribute);
+
+ bool compatible = (colorAttribute != nullptr) ? true:false;;
+ if (compatible)
+ {
+ colorAttribute->colorCurve = presetColorAttribute->colorCurve;
+ colorAttribute->alphaCurve = presetColorAttribute->alphaCurve;
+ on_treeWidgetColorAttributes_itemSelectionChanged();
+ ColorAttributeChanged(colorAttribute);
+ }
+ else
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("The selected attribute is incompatible with preset attribute."));
+ }
+ }
+}
+
+void CurveEditorMainWindow::on_actionReset_Curve_triggered()
+{
+ if (ui->tabWidgetAttributes->currentIndex() == eCurveTab)
+ {
+ _curveWidget->reset();
+ }
+ else if (ui->tabWidgetAttributes->currentIndex() == eColorTab)
+ {
+ _colorWidget->reset();
+ }
+
+}
+
+void CurveEditorMainWindow::on_actionAdd_Before_Selected_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->addControlPointsBeforeSelected();
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->addControlPointsBeforeSelected();
+}
+
+void CurveEditorMainWindow::on_actionAdd_After_Selected_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->addControlPointsAfterSelected();
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->addControlPointsAfterSelected();
+}
+
+void CurveEditorMainWindow::on_actionRemove_Selected_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->removeSelectedControlPoints();
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->removeSelectedControlPoint();
+}
+
+void CurveEditorMainWindow::on_actionTangent_Stepped_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->setTangentType(eDiscret);
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->setTangentType(eDiscret);
+}
+
+void CurveEditorMainWindow::on_actionTangent_Linear_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->setTangentType(eLinear);
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->setTangentType(eLinear);
+}
+
+void CurveEditorMainWindow::on_actionTangent_Smooth_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->setSmoothTangent();
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->setSmoothTangent();
+}
+
+void CurveEditorMainWindow::on_actionTangent_Ease_Out_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->setEaseOutTangent();
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->setEaseOutTangent();
+}
+
+void CurveEditorMainWindow::on_actionTangent_Ease_In_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->setEaseInTangent();
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->setEaseInTangent();
+}
+
+void CurveEditorMainWindow::on_actionTangent_Spline_triggered()
+{
+ if (_curveWidget->hasFocus())
+ _curveWidget->setTangentType(eCatmullRomSpline);
+
+ if (_colorWidget->hasFocus())
+ _colorWidget->setTangentType(eCatmullRomSpline);
+}
+
+void CurveEditorMainWindow::on_actionSnap_All_triggered()
+{
+ _curveWidget->setSnapAll();
+}
+
+void CurveEditorMainWindow::on_actionSnap_Horizontal_triggered()
+{
+ _curveWidget->setSnapHorizontal();
+}
+
+void CurveEditorMainWindow::on_actionSnap_Vertical_triggered()
+{
+ _curveWidget->setSnapVertical();
+}
+
+void CurveEditorMainWindow::on_actionContract_Horizontally_triggered()
+{
+ _curveWidget->decreaseCurveScaleHorizontally();
+}
+
+void CurveEditorMainWindow::on_actionExpand_Horizontally_triggered()
+{
+ _curveWidget->increaseCurveScaleHorizontally();
+}
+
+void CurveEditorMainWindow::on_actionContract_Vertically_triggered()
+{
+ _curveWidget->decreaseCurveScaleVertically();
+}
+
+void CurveEditorMainWindow::on_actionExpand_Vertically_triggered()
+{
+ _curveWidget->increaseCurveScaleVertically();
+}
+
+void CurveEditorMainWindow::on_actionFrame_Horizontally_triggered()
+{
+ _curveWidget->frameCurveScaleHorizontally();
+}
+
+void CurveEditorMainWindow::on_actionFrame_Vertically_triggered()
+{
+ _curveWidget->frameCurveScaleVertically();
+}
+
+void CurveEditorMainWindow::on_actionFrame_All_triggered()
+{
+ _curveWidget->frameCurveScale();
+}
+
+void CurveEditorMainWindow::on_spinBoxLocation_valueChanged(double value)
+{
+ if (!_updateUIFromData)
+ _curveWidget->setLocation(value);
+}
+
+void CurveEditorMainWindow::on_spinBoxValue_valueChanged(double value)
+{
+ if (!_updateUIFromData)
+ _curveWidget->setValue(value);
+}
+
+void CurveEditorMainWindow::on_btnColor_clicked()
+{
+ QColor color = _colorWidget->getColor();
+ pickColor(color, nullptr);
+ _colorWidget->setColor(color);
+ setButtonColor(ui->btnColor, color);
+}
+
+void CurveEditorMainWindow::on_btnColorTex_clicked()
+{
+ QString filePath = OpenTextureFile(_colorWidget->getColorTex().isEmpty() ? _lastFilePath : _colorWidget->getColorTex());
+ _colorWidget->setColorTex(filePath);
+ setButtonTex(ui->btnColorTex, !filePath.isEmpty());
+
+ if (!filePath.isEmpty())
+ {
+ QFileInfo fileInfo(filePath);
+ _lastFilePath = fileInfo.absoluteDir().absolutePath();
+ }
+}
+
+void CurveEditorMainWindow::on_btnColorReload_clicked()
+{
+ QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems();
+ if (0 ==items.count())
+ return;
+
+ _colorWidget->reloadColorTex();
+}
+
+void CurveEditorMainWindow::on_btnColorClear_clicked()
+{
+ _colorWidget->clearColorTex();
+ setButtonTex(ui->btnColorTex, false);
+}
+
+void CurveEditorMainWindow::on_btnAlpha_clicked()
+{
+ int alpha = _colorWidget->getAlpha();
+ pickAlpha(alpha, nullptr);
+ _colorWidget->setAlpha(alpha);
+ setButtonColor(ui->btnAlpha, QColor(alpha, alpha, alpha));
+}
+
+void CurveEditorMainWindow::on_btnAlphaTex_clicked()
+{
+ QString filePath = OpenTextureFile(_colorWidget->getAlphaTex().isEmpty() ? _lastFilePath : _colorWidget->getAlphaTex());
+ _colorWidget->setAlphaTex(filePath);
+ setButtonTex(ui->btnAlphaTex, !filePath.isEmpty());
+
+ if (!filePath.isEmpty())
+ {
+ QFileInfo fileInfo(filePath);
+ _lastFilePath = fileInfo.absoluteDir().absolutePath();
+ }
+}
+
+void CurveEditorMainWindow::on_btnAlphaReload_clicked()
+{
+ QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems();
+ if (0 ==items.count())
+ return;
+
+ _colorWidget->reloadAlphaTex();
+}
+
+void CurveEditorMainWindow::on_btnAlphaClear_clicked()
+{
+ _colorWidget->clearAlphaTex();
+ setButtonTex(ui->btnAlphaTex, false);
+}
+
+void CurveEditorMainWindow::on_checkBoxUseAlphaChannellFromColor_stateChanged(int val)
+{
+ _colorWidget->setUseAlphaFromColor(0 != val);
+}
+
+void CurveEditorMainWindow::on_treeWidgetCurveAttributes_itemSelectionChanged()
+{
+ std::vector<CurveAttributeBase*> attributes;
+
+ QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems();
+ int count = items.count();
+ for (int i = 0; i < items.count(); ++i)
+ {
+ CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(i));
+
+ attributes.push_back(item->_attribute);
+
+ qDebug()<< item->_attribute->getName().c_str();
+ }
+
+ _curveWidget->setCurveAttributes(attributes);
+
+ bool canMoveControlPointHorizontally = _canMoveCurveControlPointHorizontally;
+ bool canAddRemoveControlPoint = _canAddRemoveCurveControlPoint;
+ bool canChangeTangentType = _canChangeCurveTangentType;
+ for (size_t i = 0; i < attributes.size(); ++i)
+ {
+ CurveAttributeBase* attribute = attributes[i];
+ if (eGroupAttr == attribute->getType())
+ {
+ CurveAttributeGroup* attributeGroup = static_cast<CurveAttributeGroup*>(attribute);
+ for (size_t j = 0; j < attributeGroup->attributes.size(); ++j)
+ {
+ CurveAttributeBase* attributeInGroup = attributeGroup->attributes[j];
+
+ if (attributeInGroup->canMoveControlPointHorizontally())
+ canMoveControlPointHorizontally = true;
+
+ if (attributeInGroup->canAddRemoveControlPoint())
+ canAddRemoveControlPoint = true;
+
+ if (attributeInGroup->canChangeTangentType())
+ canChangeTangentType = true;
+ }
+ }
+ else
+ {
+ if (attribute->canMoveControlPointHorizontally())
+ canMoveControlPointHorizontally = true;
+
+ if (attribute->canAddRemoveControlPoint())
+ canAddRemoveControlPoint = attribute->canAddRemoveControlPoint();
+
+ if (attribute->canChangeTangentType())
+ canChangeTangentType = true;
+ }
+ }
+
+ ui->spinBoxLocation->setEnabled(canMoveControlPointHorizontally);
+ _syncUIStatusWithSelectedAttribute(canAddRemoveControlPoint, canChangeTangentType);
+}
+
+void CurveEditorMainWindow::on_treeWidgetColorAttributes_itemSelectionChanged()
+{
+ QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems();
+ if (0 == items.count())
+ return;
+
+ ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0));
+ _colorWidget->setColorAttribute(item->_attribute);
+ _colorWidget->setCanAddRemoveControlPoint(item->_attribute->canAddRemoveControlPoint());
+
+ _syncUIStatusWithSelectedAttribute(item->_attribute->canAddRemoveControlPoint(), item->_attribute->canChangeTangentType());
+}
+
+void CurveEditorMainWindow::on_tabWidgetAttributes_currentChanged(int index)
+{
+ //if (eCurveTab == index)
+ //{
+ // _setCurveExclusiveUIEnable(true);
+ //}
+ //else if (eColorTab == index)
+ //{
+ // _setCurveExclusiveUIEnable(false);
+ //}
+}
+
+void CurveEditorMainWindow::on_sliderColorFallOff_sliderMoved(int value)
+{
+ if (!_updateUIFromData)
+ {
+ _colorWidget->setColorFallOff((float)value/100);
+
+ if (_colorWidget->isLink())
+ {
+ _updateUIFromData = true;
+ ui->sliderAlphaFallOff->setValue(value);
+ _updateUIFromData = false;
+ }
+ }
+}
+
+void CurveEditorMainWindow::on_sliderAlphaFallOff_sliderMoved(int value)
+{
+ if (!_updateUIFromData)
+ {
+ _colorWidget->setAlphaFallOff((float)value/100);
+
+ if (_colorWidget->isLink())
+ {
+ _updateUIFromData = true;
+ ui->sliderAlphaFallOff->setValue(value);
+ _updateUIFromData = false;
+ }
+ }
+}
+
+void CurveEditorMainWindow::on_actionAdd_Control_Point_By_Click_triggered(bool val)
+{
+ _curveWidget->setAddCtrlPntByClick(val);
+ _curveWidget->setRemoveCtrlPntByClick(false);
+
+ _colorWidget->setAddCtrlPntByClick(val);
+ _colorWidget->setRemoveCtrlPntByClick(false);
+}
+
+void CurveEditorMainWindow::on_actionRemove_Control_Point_By_Click_triggered(bool val)
+{
+ _curveWidget->setAddCtrlPntByClick(false);
+ _curveWidget->setRemoveCtrlPntByClick(val);
+
+ _colorWidget->setAddCtrlPntByClick(false);
+ _colorWidget->setRemoveCtrlPntByClick(val);
+}
+
+void CurveEditorMainWindow::onCurvePickedControlPointChanged(const std::vector<CurveEntity*>& pickedCurves)
+{
+ bool enableChangeTangentType = true;
+ bool enableAddRemoveCtrlPnts = true;
+ bool enableLoactionEditor = true;
+ bool locationSameForAllAttributes = true;
+ bool valueSameForAllAttributes = true;
+ float location = FLT_MIN, value = FLT_MIN;
+ _updateUIFromData = true;
+ ui->spinBoxLocation->setValue(location);
+ ui->spinBoxValue->setValue(value);
+ _updateUIFromData = false;
+ for(size_t i = 0; i < pickedCurves.size(); ++i)
+ {
+ CurveEntity* curveEntity = pickedCurves[i];
+ std::vector<int>& pickedControlPoints = pickedCurves[i]->getPickedControlPointIndexes();
+ const ControlPoint& ctrlPnt = pickedCurves[i]->_curve->getControlPoint(pickedControlPoints[0]);
+
+ if (!curveEntity->_attribute->canMoveControlPointHorizontally())
+ enableLoactionEditor = false;
+
+ if (pickedControlPoints.size() > 1)
+ enableLoactionEditor = false;
+
+ if (location == FLT_MIN)
+ {
+ location = ctrlPnt.value.x();
+ _updateUIFromData = true;
+ ui->spinBoxLocation->setValue(location);
+ _updateUIFromData = false;
+ }
+ else if (location != ctrlPnt.value.x())
+ locationSameForAllAttributes = false;
+
+ if (value == FLT_MIN)
+ {
+ value = ctrlPnt.value.y();
+ _updateUIFromData = true;
+ ui->spinBoxValue->setValue(value);
+ _updateUIFromData = false;
+ }
+ else if (value != ctrlPnt.value.y())
+ valueSameForAllAttributes = false;
+
+ if (!curveEntity->_attribute->canChangeTangentType() && pickedControlPoints.size() != 0)
+ enableChangeTangentType = false;
+
+ if (!curveEntity->_attribute->canAddRemoveControlPoint() && pickedControlPoints.size() != 0)
+ enableAddRemoveCtrlPnts = false;
+
+ }
+
+ if (pickedCurves.size() > 0)
+ {
+ ui->spinBoxLocation->setEnabled(enableLoactionEditor);
+
+ setFocusColor(ui->labelLoacation, locationSameForAllAttributes);
+ setFocusColor(ui->labelValue, valueSameForAllAttributes);
+
+ _setTangentTypeUIStatus(enableChangeTangentType);
+ _setAddRemoveCtrlPntUIStatus(enableAddRemoveCtrlPnts);
+ }
+ else
+ {
+ on_treeWidgetCurveAttributes_itemSelectionChanged();
+ }
+
+}
+
+void CurveEditorMainWindow::onCurvePickedControlPointValueChanged(QPointF& value)
+{
+ _updateUIFromData = true;
+ ui->spinBoxLocation->setValue(value.x());
+ ui->spinBoxValue->setValue(value.y());
+ _updateUIFromData = false;
+
+ QList<QTreeWidgetItem*> selectedAttributes = ui->treeWidgetCurveAttributes->selectedItems();
+ if (selectedAttributes.count() > 0)
+ {
+
+ }
+}
+
+void CurveEditorMainWindow::_fillCurveAttributesTree()
+{
+ ui->treeWidgetCurveAttributes->clear();
+
+ size_t countAttributes = _curveAttributes.size();
+ for (size_t i = 0; i < countAttributes; ++i)
+ {
+ CurveAttributeBase* attribute = _curveAttributes[i];
+ CurveAttributeTreeItem* itemFirstLevel = new CurveAttributeTreeItem(ui->treeWidgetCurveAttributes, attribute);
+ itemFirstLevel->setText(0, attribute->getName().c_str());
+
+ if (attribute->getType() == eGroupAttr)
+ {
+ CurveAttributeGroup* attributeGroup = static_cast<CurveAttributeGroup*>(attribute);
+ size_t countAttributesInGroup = attributeGroup->attributes.size();
+ for (size_t j = 0; j < countAttributesInGroup; ++j)
+ {
+ CurveAttribute* attributeInGroup = static_cast<CurveAttribute*>(attributeGroup->attributes[j]);
+ CurveAttributeTreeItem* itemSecondLevel = new CurveAttributeTreeItem(itemFirstLevel, attributeInGroup);
+ itemSecondLevel->setText(0, attributeInGroup->getName().c_str());
+ itemSecondLevel->setForeground(0, QBrush(attributeInGroup->color));
+ }
+ }
+ else
+ {
+ CurveAttribute* attributeSecific = static_cast<CurveAttribute*>(attribute);
+ itemFirstLevel->setForeground(0, QBrush(attributeSecific->color));
+ }
+ }
+}
+
+void CurveEditorMainWindow::_fillColorAttributesTree()
+{
+ ui->treeWidgetColorAttributes->clear();
+
+ size_t countAttributes = _colorAttributes.size();
+ for (size_t i = 0; i < countAttributes; ++i)
+ {
+ ColorAttribute* attribute = _colorAttributes[i];
+ ColorAttributeTreeItem* itemFirstLevel = new ColorAttributeTreeItem(ui->treeWidgetColorAttributes, attribute);
+ itemFirstLevel->setText(0, attribute->getName().c_str());
+ }
+}
+
+void CurveEditorMainWindow::_syncUIStatusWithSelectedAttribute(bool canAddRemoveControlPoint, bool canChangeTangentType)
+{
+ _setAddRemoveCtrlPntUIStatus(canAddRemoveControlPoint);
+ _setTangentTypeUIStatus(canChangeTangentType);
+}
+
+void CurveEditorMainWindow::_setCurveExclusiveUIEnable(bool enable)
+{
+ ui->actionSnap_All->setEnabled(enable);
+ ui->actionSnap_Horizontal->setEnabled(enable);
+ ui->actionSnap_Vertical->setEnabled(enable);
+ ui->actionExpand_Horizontally->setEnabled(enable);
+ ui->actionExpand_Vertically->setEnabled(enable);
+ ui->actionFrame_Horizontally->setEnabled(enable);
+ ui->actionFrame_Vertically->setEnabled(enable);
+ ui->actionFrame_All->setEnabled(enable);
+ ui->actionContract_Horizontally->setEnabled(enable);
+ ui->actionContract_Vertically->setEnabled(enable);
+}
+
+void CurveEditorMainWindow::_setColorUIEnable(bool enable)
+{
+ ui->btnColor->setEnabled(enable);
+ ui->btnColorTex->setEnabled(enable);
+ ui->btnColorReload->setEnabled(enable);
+ ui->btnColorClear->setEnabled(enable);
+ ui->sliderColorFallOff->setEnabled(enable);
+}
+
+void CurveEditorMainWindow::_setAlphaUIEnable(bool enable)
+{
+ if (_colorWidget->isLink())
+ ui->btnAlpha->setEnabled(true);
+ else
+ ui->btnAlpha->setEnabled(enable);
+ ui->btnAlphaTex->setEnabled(enable);
+ ui->btnAlphaReload->setEnabled(enable);
+ ui->btnAlphaClear->setEnabled(enable);
+ ui->sliderAlphaFallOff->setEnabled(enable);
+}
+
+void CurveEditorMainWindow::onColorPickedControlPointChanged(bool isColorCtrlPnt)
+{
+ QColor color = _colorWidget->getColor();
+ setButtonColor(ui->btnColor, color);
+ int alpha = _colorWidget->getAlpha();
+ setButtonColor(ui->btnAlpha, QColor(alpha, alpha, alpha));
+
+ QString colorTex = _colorWidget->getColorTex();
+ setButtonTex(ui->btnColorTex, !colorTex.isEmpty());
+ QString alphaTex = _colorWidget->getAlphaTex();
+ setButtonTex(ui->btnAlphaTex, !alphaTex.isEmpty());
+
+ _updateUIFromData = true;
+ ui->sliderColorFallOff->setValue(_colorWidget->getColorFallOff() * 100);
+ ui->sliderAlphaFallOff->setValue(_colorWidget->getAlphaFallOff() * 100);
+ _setColorUIEnable(isColorCtrlPnt);
+ _setAlphaUIEnable(!isColorCtrlPnt);
+ _updateUIFromData = false;
+}
+
+void CurveEditorMainWindow::_saveAttribute(QDomElement& parentElm, CurveAttribute* attribute)
+{
+ QDomElement newElm = parentElm.ownerDocument().createElement(tr("Attribute"));
+ parentElm.appendChild(newElm);
+ newElm.setAttribute(tr("Name"), attribute->getName().c_str());
+ newElm.setAttribute(tr("Color"), QString().setNum(attribute->color.rgba(), 16));
+ if (!ui->checkBoxResamplePoints->isChecked())
+ {
+ _saveCurve(newElm, attribute->curve);
+ }
+ else
+ {
+ _saveCurve(newElm, attribute->curve.resampleCurve(ui->spinBoxResamplePoints->value()));
+ }
+}
+
+void CurveEditorMainWindow::_saveAttribute(QDomElement& parentElm, ColorAttribute* attribute)
+{
+ QDomElement newElm = parentElm.ownerDocument().createElement(tr("Attribute"));
+ parentElm.appendChild(newElm);
+ newElm.setAttribute(tr("Name"), attribute->getName().c_str());
+
+ _saveCurve(newElm, attribute->colorCurve, tr("ColorCurve"));
+ if (attribute->alphaCurve.getControlPointCount() > 0)
+ _saveCurve(newElm, attribute->alphaCurve, tr("AlphaCurve"));
+}
+
+void CurveEditorMainWindow::_saveCurve(QDomElement& parentElm, Curve& curve)
+{
+ QDomDocument domDoc = parentElm.ownerDocument();
+ QDomElement curveElm = domDoc.createElement(tr("Curve"));
+ parentElm.appendChild(curveElm);
+ curveElm.setAttribute(tr("MinValueX"), curve.getMinValue().x());
+ curveElm.setAttribute(tr("MinValueY"), curve.getMinValue().y());
+ curveElm.setAttribute(tr("MaxValueX"), curve.getMaxValue().x());
+ curveElm.setAttribute(tr("MaxValueY"), curve.getMaxValue().y());
+
+ int ctrlPntCount = curve.getControlPointCount();
+ for (int i = 0; i < ctrlPntCount; ++i)
+ {
+ const ControlPoint& ctrlPnt = curve.getControlPoint(i);
+ _saveCtrlPnt(curveElm, ctrlPnt);
+ }
+}
+
+void CurveEditorMainWindow::_saveCurve(QDomElement& parentElm, ColorCurve& curve, const QString& curveName)
+{
+ QDomDocument domDoc = parentElm.ownerDocument();
+ QDomElement curveElm = domDoc.createElement(curveName);
+ parentElm.appendChild(curveElm);
+ curveElm.setAttribute(tr("MinValue"), curve.getMinValue());
+ curveElm.setAttribute(tr("MaxValue"), curve.getMaxValue());
+
+ int ctrlPntCount = curve.getControlPointCount();
+ for (int i = 0; i < ctrlPntCount; ++i)
+ {
+ const ColorControlPoint& ctrlPnt = curve.getControlPoint(i);
+ _saveCtrlPnt(curveElm, ctrlPnt);
+ }
+}
+
+void CurveEditorMainWindow::_saveCtrlPnt(QDomElement& parentElm, const ControlPoint& ctrlPnt)
+{
+ QDomDocument domDoc = parentElm.ownerDocument();
+ QDomElement ctrlPntElm = domDoc.createElement(tr("ControlPoint"));
+ parentElm.appendChild(ctrlPntElm);
+
+ QDomElement valueElm = domDoc.createElement(tr("Value"));
+ ctrlPntElm.appendChild(valueElm);
+ valueElm.setAttribute(tr("X"), ctrlPnt.value.x());
+ valueElm.setAttribute(tr("Y"), ctrlPnt.value.y());
+
+ QDomElement modeElm = domDoc.createElement(tr("InterpolateMode"));
+ ctrlPntElm.appendChild(modeElm);
+ QDomNode txt = domDoc.createTextNode(InterpolateModeToString(ctrlPnt.mode));
+ modeElm.appendChild(txt);
+
+ if (eBezierSpline == ctrlPnt.mode)
+ {
+ QDomElement bezierSplineDataElm = domDoc.createElement(tr("BezierSplineData"));
+ ctrlPntElm.appendChild(bezierSplineDataElm);
+
+ bezierSplineDataElm.setAttribute(tr("InTan"), QString("%0").arg(ctrlPnt.splineData.inTan));
+ bezierSplineDataElm.setAttribute(tr("InLen"), QString("%0").arg(ctrlPnt.splineData.inLen));
+ bezierSplineDataElm.setAttribute(tr("OutTan"), QString("%0").arg(ctrlPnt.splineData.outTan));
+ bezierSplineDataElm.setAttribute(tr("OutLen"), QString("%0").arg(ctrlPnt.splineData.outLen));
+ }
+}
+
+void CurveEditorMainWindow::_saveCtrlPnt(QDomElement& parentElm, const ColorControlPoint& ctrlPnt)
+{
+ QDomDocument domDoc = parentElm.ownerDocument();
+ QDomElement ctrlPntElm = domDoc.createElement(tr("ColorControlPoint"));
+ parentElm.appendChild(ctrlPntElm);
+
+ QDomElement valueElm = domDoc.createElement(tr("Value"));
+ ctrlPntElm.appendChild(valueElm);
+ valueElm.setAttribute(tr("X"), ctrlPnt.x);
+ valueElm.setAttribute(tr("Color"), QString().setNum(ctrlPnt.color.rgba(), 16));
+ valueElm.setAttribute(tr("Weight"), ctrlPnt.weight);
+ valueElm.setAttribute(tr("FallOff"), ctrlPnt.fallOff);
+ valueElm.setAttribute(tr("TexturePath"), ctrlPnt.texturePath.c_str());
+
+ QDomElement modeElm = domDoc.createElement(tr("InterpolateMode"));
+ ctrlPntElm.appendChild(modeElm);
+ QDomNode txt = domDoc.createTextNode(InterpolateModeToString(ctrlPnt.mode));
+ modeElm.appendChild(txt);
+
+ if (eBezierSpline == ctrlPnt.mode)
+ {
+ QDomElement bezierSplineDataElm = domDoc.createElement(tr("BezierSplineData"));
+ ctrlPntElm.appendChild(bezierSplineDataElm);
+
+ bezierSplineDataElm.setAttribute(tr("InTan"), QString("%0").arg(ctrlPnt.splineData.inTan));
+ bezierSplineDataElm.setAttribute(tr("InLen"), QString("%0").arg(ctrlPnt.splineData.inLen));
+ bezierSplineDataElm.setAttribute(tr("OutTan"), QString("%0").arg(ctrlPnt.splineData.outTan));
+ bezierSplineDataElm.setAttribute(tr("OutLen"), QString("%0").arg(ctrlPnt.splineData.outLen));
+ }
+}
+
+CurveAttributeBase* CurveEditorMainWindow::_loadAttribute(QDomElement& elm)
+{
+ QString name = elm.attribute(tr("Name"));
+
+ QDomElement curveElm = elm.firstChildElement(tr("Curve"));
+ if (!curveElm.isNull())
+ {
+ CurveAttribute* attribute = new CurveAttribute("");
+ attribute->_name = name.toStdString();
+ //qDebug()<<"attribute Name"<<name<<" Color:"<<elm.attribute(tr("Color"));
+ attribute->color.setRgba(elm.attribute(tr("Color")).toUInt(0, 16));
+ //qDebug()<<"color:::"<<QString().setNum(attrData->color.rgba(), 16);
+ float minValueX = curveElm.attribute(tr("MinValueX")).toFloat();
+ float minValueY = curveElm.attribute(tr("MinValueY")).toFloat();
+ float maxValueX = curveElm.attribute(tr("MaxValueX")).toFloat();
+ float maxValueY = curveElm.attribute(tr("MaxValueY")).toFloat();
+ attribute->curve.initValueRange(QPointF(minValueX, minValueY), QPointF(maxValueX, maxValueY));
+ _loadCurve(curveElm, attribute->curve);
+
+ return attribute;
+ }
+ else
+ {
+ curveElm = elm.firstChildElement(tr("ColorCurve"));
+
+ if (!curveElm.isNull())
+ {
+ ColorAttribute* attribute = new ColorAttribute("");
+ attribute->_name = name.toStdString();
+ float minValue = curveElm.attribute(tr("MinValue")).toFloat();
+ float maxValue = curveElm.attribute(tr("MaxValue")).toFloat();
+ attribute->colorCurve.initValueRange(minValue, maxValue);
+ _loadCurve(curveElm, attribute->colorCurve);
+
+ curveElm = elm.firstChildElement(tr("AlphaCurve"));
+ minValue = curveElm.attribute(tr("MinValue")).toFloat();
+ maxValue = curveElm.attribute(tr("MaxValue")).toFloat();
+ attribute->alphaCurve.initValueRange(minValue, maxValue);
+ _loadCurve(curveElm, attribute->alphaCurve);
+ return attribute;
+ }
+ }
+
+ return nullptr;
+}
+
+void CurveEditorMainWindow::_loadCurve(QDomElement& elm, Curve& curve)
+{
+ QDomNodeList nodeList = elm.elementsByTagName(tr("ControlPoint"));
+ for (int i = 0; i < nodeList.count(); ++i)
+ {
+ QDomElement ctrlElm = nodeList.at(i).toElement();
+
+ ControlPoint ctrlPnt;
+ if (!ctrlElm.isNull())
+ {
+ _loadCtrlPnt(ctrlElm, ctrlPnt);
+ curve.appendControlPoint(ctrlPnt, false);
+ }
+ }
+}
+
+void CurveEditorMainWindow::_loadCurve(QDomElement& elm, ColorCurve& curve)
+{
+ QDomNodeList nodeList = elm.elementsByTagName(tr("ColorControlPoint"));
+ for (int i = 0; i < nodeList.count(); ++i)
+ {
+ QDomElement ctrlElm = nodeList.at(i).toElement();
+
+ ColorControlPoint ctrlPnt;
+ if (!ctrlElm.isNull())
+ {
+ _loadCtrlPnt(ctrlElm, ctrlPnt);
+ curve.appendControlPoint(ctrlPnt, false);
+ }
+ }
+}
+
+void CurveEditorMainWindow::_loadCtrlPnt(QDomElement& elm, ControlPoint& ctrlPnt)
+{
+ QDomElement valueElm = elm.firstChildElement(tr("Value"));
+ ctrlPnt.value.setX(valueElm.attribute(tr("X")).toFloat());
+ ctrlPnt.value.setY(valueElm.attribute(tr("Y")).toFloat());
+
+ QDomElement modeElm = elm.firstChildElement(tr("InterpolateMode"));
+
+ ctrlPnt.mode = StringToInterpolateMode(modeElm.text());
+
+ if (eBezierSpline == ctrlPnt.mode)
+ {
+ QDomElement bezierElm = elm.firstChildElement(tr("BezierSplineData"));
+
+ ctrlPnt.splineData.inTan = bezierElm.attribute(tr("InTan")).toFloat();
+ ctrlPnt.splineData.inLen = bezierElm.attribute(tr("InLen")).toFloat();
+ ctrlPnt.splineData.outTan = bezierElm.attribute(tr("OutTan")).toFloat();
+ ctrlPnt.splineData.outLen = bezierElm.attribute(tr("OutLen")).toFloat();
+ }
+}
+
+void CurveEditorMainWindow::_loadCtrlPnt(QDomElement& elm, ColorControlPoint& ctrlPnt)
+{
+ QDomElement valueElm = elm.firstChildElement(tr("Value"));
+ ctrlPnt.x = valueElm.attribute(tr("X")).toFloat();
+ ctrlPnt.color.setRgba(valueElm.attribute(tr("Color")).toUInt(0, 16));
+ ctrlPnt.weight = valueElm.attribute(tr("Weight")).toFloat();
+ ctrlPnt.fallOff = valueElm.attribute(tr("FallOff")).toFloat();
+ ctrlPnt.weight = valueElm.attribute(tr("Weight")).toFloat();
+ ctrlPnt.texturePath = valueElm.attribute(tr("TexturePath")).toStdString();
+
+ QDomElement modeElm = elm.firstChildElement(tr("InterpolateMode"));
+
+ ctrlPnt.mode = StringToInterpolateMode(modeElm.text());
+
+ if (eBezierSpline == ctrlPnt.mode)
+ {
+ QDomElement bezierElm = elm.firstChildElement(tr("BezierSplineData"));
+
+ ctrlPnt.splineData.inTan = bezierElm.attribute(tr("InTan")).toFloat();
+ ctrlPnt.splineData.inLen = bezierElm.attribute(tr("InLen")).toFloat();
+ ctrlPnt.splineData.outTan = bezierElm.attribute(tr("OutTan")).toFloat();
+ ctrlPnt.splineData.outLen = bezierElm.attribute(tr("OutLen")).toFloat();
+ }
+}
+
+void CurveEditorMainWindow::_setTangentTypeUIStatus(bool enable)
+{
+ ui->actionTangent_Stepped->setEnabled(enable);
+ ui->actionTangent_Linear->setEnabled(enable);
+ ui->actionTangent_Smooth->setEnabled(enable);
+ ui->actionTangent_Ease_Out->setEnabled(enable);
+ ui->actionTangent_Ease_In->setEnabled(enable);
+ ui->actionTangent_Spline->setEnabled(enable);
+}
+
+void CurveEditorMainWindow::_setAddRemoveCtrlPntUIStatus(bool enable)
+{
+ ui->actionAdd_Before_Selected->setEnabled(enable);
+ ui->actionAdd_After_Selected->setEnabled(enable);
+ ui->actionRemove_Selected->setEnabled(enable);
+ ui->actionAdd_Control_Point_By_Click->setEnabled(enable);
+ ui->actionRemove_Control_Point_By_Click->setEnabled(enable);
+}
+
+} // namespace CurveEditor
+} // namespace nvidia \ No newline at end of file
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Window/CurveWidget.cpp b/NvBlast/tools/CurveEditor/source/Internal/Window/CurveWidget.cpp
new file mode 100644
index 0000000..fc778e5
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Window/CurveWidget.cpp
@@ -0,0 +1,1229 @@
+#include "CurveWidget.h"
+
+#include <QtWidgets/QLabel>
+#include <QtGui/QImage>
+#include <QtWidgets/QVBoxLayout>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QPaintEvent>
+#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
+#include <QtCore/QDebug>
+#include "CurveEditorMainWindow.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+const int MARGIN_X = 2;
+const int MARGIN_Y = 2;
+const int SNAP_DISTANCE = 5;
+const float CROSS_THRESHOLD = 5.0f;
+const int GRID_INTIAL_SEGMENT_COUNT = 4;
+const int CTRL_PNT_ICON_SIZE = 6;
+const int CLICK_ON_CURVE_THRESHOLD = 4;
+const int CURVE_WIDTH = 2;
+const QColor GRID_COLOR = QColor(32, 32, 32, 64);
+
+//////////////////////////////////////////////////////////////////////////////
+QPointF NDCToScreenCoord(QWidget* pWidget, QPointF p)
+{
+ int w = pWidget->width();
+ int h = pWidget->height();
+
+ float x = MARGIN_X + p.x() * (w - MARGIN_X * 2.0f);
+ float y = h - MARGIN_Y * 2.0 + p.y() * (MARGIN_Y * 3.0f - h);
+
+ return QPointF(x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QPointF ScreenToNDC(QWidget* pWidget, QPointF p)
+{
+ int w = pWidget->width();
+ int h = pWidget->height();
+
+ float sizey = 1.0f - 2.0f * MARGIN_Y;
+
+ float x = (p.x() - MARGIN_X) / (2 - MARGIN_X * 2.0f);
+ float y = (MARGIN_Y * 2.0f + p.y() - h) / (MARGIN_Y * 3.0f - h);
+
+ return QPointF(x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool IsInSelectedCtrlPnts(const std::vector<int>& pickedPoints, int pointIndex)
+{
+ for (std::vector<int>::const_iterator itr = pickedPoints.begin(); itr != pickedPoints.end(); ++itr)
+ {
+ if (*itr == pointIndex)
+ return true;
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool IsSamePoint(const QPointF& pntA, const QPointF& pntB, int threshold)
+{
+ float dx = pntB.x() - pntA.x();
+ float dy = pntB.y() - pntA.y();
+
+ float r = sqrt(dx * dx + dy * dy);
+ if (r <= threshold)
+ return true;
+ else
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+int FindSelectedCtrlPnt(const std::vector<QPointF>& points, const QPointF& pickPos)
+{
+ for (size_t i = 0; i < points.size(); i++)
+ {
+ if (IsSamePoint(points[i], pickPos, CTRL_PNT_ICON_SIZE/2))
+ return (int)i;
+ }
+ return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+CurveEntity::CurveEntity(CurveWidget* holder, CurveAttribute* attribute, const QColor& color)
+ : _holder(holder)
+ , _attribute(attribute)
+ , _curve(&(attribute->curve))
+ , _color(color)
+ , _pickedPoint(-1)
+ , _pickedPoints()
+ , _lastMousePosScreen()
+ , _ctrlPntToRemove(-1)
+{
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::setLocation(float location)
+{
+ if (_pickedPoints.size() != 1)
+ return ;
+
+ ControlPoint pnt = _curve->getControlPoint(_pickedPoints[0]);
+ pnt.value.setX(location);
+ _curve->setControlPoint(_pickedPoints[0], pnt);
+ emit _holder->CurveAttributeChanged(_attribute);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::setValue(float value)
+{
+ if (_pickedPoints.size() != 1)
+ return ;
+
+ ControlPoint pnt = _curve->getControlPoint(_pickedPoints[0]);
+ pnt.value.setY(value);
+ _curve->setControlPoint(_pickedPoints[0], pnt);
+ emit _holder->CurveAttributeChanged(_attribute);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::addControlPointsBeforeSelected()
+{
+ bool update = false;
+ for (std::vector<int>::iterator itr = _pickedPoints.begin(); itr != _pickedPoints.end(); ++itr)
+ {
+ if (*itr == 0)
+ continue;
+
+ _curve->insertControlPointAt(*itr);
+ ++(*itr);
+ update = true;
+
+ if (*itr <= _pickedPoint)
+ {
+ ++_pickedPoint;
+ }
+
+ for (std::vector<int>::iterator itrRight = itr + 1; itrRight != _pickedPoints.end(); ++itrRight)
+ {
+ ++(*itrRight);
+ }
+ }
+
+ if (update)
+ {
+ _curve->_needSample = true;
+ emit _holder->CurveAttributeChanged(_attribute);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::addControlPointsAfterSelected()
+{
+ bool update = false;
+ for (std::vector<int>::iterator itr = _pickedPoints.begin(); itr != _pickedPoints.end(); ++itr)
+ {
+ _curve->insertControlPointAt(*itr + 1);
+ update = true;
+
+ if ((*itr + 1) < _pickedPoint)
+ {
+ ++_pickedPoint;
+ }
+
+ for (std::vector<int>::iterator itrRight = itr + 1; itrRight != _pickedPoints.end(); ++itrRight)
+ {
+ ++(*itrRight);
+ }
+ }
+
+ if (update)
+ {
+ _curve->_needSample = true;
+ emit _holder->CurveAttributeChanged(_attribute);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::removeSelectedControlPoints()
+{
+ if (_pickedPoints.size() > 0)
+ {
+ _curve->removeControlPoints(_pickedPoints);
+ _pickedPoints.clear();
+ _pickedPoint = -1;
+ _curve->_needSample = true;
+ emit _holder->CurveAttributeChanged(_attribute);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::setTangentType(InterpolateMode mode)
+{
+ size_t pointsCount = _curve->getControlPointCount();
+ for (int i = 0; i < pointsCount; i++)
+ {
+ if (IsInSelectedCtrlPnts(_pickedPoints, i))
+ {
+ ControlPoint ctrlPnt = _curve->getControlPoint(i);
+ ctrlPnt.mode = mode;
+ _curve->setControlPoint(i, ctrlPnt);
+ emit _holder->CurveAttributeChanged(_attribute);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::setSmoothTangent()
+{
+ size_t pointsCount = _curve->getControlPointCount();
+ for (int i = 0; i < pointsCount; i++)
+ {
+ if (IsInSelectedCtrlPnts(_pickedPoints, i) && i != pointsCount - 1)
+ {
+ ControlPoint ctrlctrlPntFront = _curve->getControlPoint(i);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 1.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _curve->setControlPoint(i, ctrlctrlPntFront);
+
+ ControlPoint ctrlPntBehiand = _curve->getControlPoint(i + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 1.0;
+ ctrlPntBehiand.splineData.inTan = 0.0;
+ _curve->setControlPoint(i + 1, ctrlPntBehiand);
+
+ emit _holder->CurveAttributeChanged(_attribute);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::setEaseInTangent()
+{
+ size_t pointsCount = _curve->getControlPointCount();
+ for (int i = 0; i < pointsCount; i++)
+ {
+ if (IsInSelectedCtrlPnts(_pickedPoints, i) && i != pointsCount - 1)
+ {
+ ControlPoint ctrlctrlPntFront = _curve->getControlPoint(i);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 0.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _curve->setControlPoint(i, ctrlctrlPntFront);
+
+ ControlPoint ctrlPntBehiand = _curve->getControlPoint(i + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 1.0;
+ ctrlPntBehiand.splineData.inTan = 0;
+ _curve->setControlPoint(i + 1, ctrlPntBehiand);
+
+ emit _holder->CurveAttributeChanged(_attribute);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::setEaseOutTangent()
+{
+ size_t pointsCount = _curve->getControlPointCount();
+ for (int i = 0; i < pointsCount; i++)
+ {
+ if (IsInSelectedCtrlPnts(_pickedPoints, i) && i != pointsCount - 1)
+ {
+ ControlPoint ctrlctrlPntFront = _curve->getControlPoint(i);
+ ctrlctrlPntFront.mode = eBezierSpline;
+ ctrlctrlPntFront.splineData.outLen = 1.0;
+ ctrlctrlPntFront.splineData.outTan = 0;
+ _curve->setControlPoint(i, ctrlctrlPntFront);
+
+ ControlPoint ctrlPntBehiand = _curve->getControlPoint(i + 1);
+ ctrlPntBehiand.mode = eBezierSpline;
+ ctrlPntBehiand.splineData.inLen = 0.0;
+ ctrlPntBehiand.splineData.inTan = 0;
+ _curve->setControlPoint(i + 1, ctrlPntBehiand);
+
+ emit _holder->CurveAttributeChanged(_attribute);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+int CurveEntity::getControlPointCount()
+{
+ return _curve->getControlPointCount();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QRectF CurveEntity::getBoundingBox()
+{
+ return QRectF(_curve->getMinValue(), _curve->getMaxValue());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::mousePressEvent( QMouseEvent* e, bool& pickedPoint)
+{
+ if (!(e->modifiers() & Qt::ControlModifier))
+ {
+ _pickedPoints.clear();
+ }
+
+ std::vector<QPointF> points;
+ _makePoints(points);
+ QPoint mousePos = e->pos();
+ _lastMousePosScreen = mousePos;
+
+ _pickedPoint = FindSelectedCtrlPnt(points, mousePos);
+ if (-1 != _pickedPoint)
+ {
+ if (_holder->_canRemoveCtrlPntByClick && _attribute->canAddRemoveControlPoint())
+ {
+ _curve->removeControlPoint(_pickedPoint);
+ _pickedPoint = -1;
+ return;
+ }
+ pickedPoint = true;
+ }
+ else
+ {
+ if (_holder->_canAddCtrlPntByClick)
+ {
+ _addCtrlPntByClick(mousePos);
+ }
+ return ;
+ }
+
+ std::vector<int>::iterator itr = _pickedPoints.begin();
+ for (; itr != _pickedPoints.end(); ++itr)
+ {
+ if (*itr == _pickedPoint)
+ break;
+ else if (*itr > _pickedPoint)
+ {
+ itr = _pickedPoints.insert(itr, _pickedPoint);
+ break;
+ }
+ }
+
+ if (itr == _pickedPoints.end())
+ {
+ _pickedPoints.insert(itr, _pickedPoint);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::mouseReleaseEvent( QMouseEvent* e )
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::mouseMoveEvent( QMouseEvent* e )
+{
+ Qt::MouseButton buttons = e->button();
+
+ {
+ //if (_pickedPoint >= 0)
+ QPointF mousePosScreen = e->pos();
+ QPointF deltaPosScreen = mousePosScreen - _lastMousePosScreen;
+ QPointF destinationPosScreen = mousePosScreen;
+ _lastMousePosScreen = mousePosScreen;
+ std::vector<int>::iterator itr = _pickedPoints.begin();
+ for (; itr != _pickedPoints.end(); ++itr)
+ {
+ int pickedPoint = *itr;
+ ControlPoint pickedCtrlPnt = _curve->getControlPoint(pickedPoint);
+ QPointF ctrlPntLastScreenPos = _holder->_valueToScreen(pickedCtrlPnt.value);
+
+ destinationPosScreen = ctrlPntLastScreenPos + deltaPosScreen;
+ destinationPosScreen = _holder->_getSnapSreenPos(destinationPosScreen);
+
+ if (!_attribute->canMoveControlPointHorizontally())
+ destinationPosScreen.setX(ctrlPntLastScreenPos.x());
+ else
+ {
+ // make sure this picked control point not move accross other control point
+ if (pickedPoint == 0)
+ {
+ QPointF nextCtrlPntScreenPos = _holder->_valueToScreen(_curve->getControlPoint(pickedPoint + 1).value);
+ if (destinationPosScreen.x() > (nextCtrlPntScreenPos.x() - CROSS_THRESHOLD))
+ destinationPosScreen.setX(nextCtrlPntScreenPos.x() - CROSS_THRESHOLD);
+ }
+ else if (pickedPoint == (_curve->getControlPointCount() - 1) )
+ {
+ QPointF fomerCtrlPntScreenPos = _holder->_valueToScreen(_curve->getControlPoint(pickedPoint - 1).value);
+ if (destinationPosScreen.x() < (fomerCtrlPntScreenPos.x() + CROSS_THRESHOLD))
+ destinationPosScreen.setX(fomerCtrlPntScreenPos.x() + CROSS_THRESHOLD);
+ }
+ else
+ {
+ QPointF fomerCtrlPntScreenPos = _holder->_valueToScreen(_curve->getControlPoint(pickedPoint - 1).value);
+ QPointF nextCtrlPntScreenPos = _holder->_valueToScreen(_curve->getControlPoint(pickedPoint + 1).value);
+ if (destinationPosScreen.x() < (fomerCtrlPntScreenPos.x() + CROSS_THRESHOLD))
+ destinationPosScreen.setX(fomerCtrlPntScreenPos.x() + CROSS_THRESHOLD);
+ if (destinationPosScreen.x() > (nextCtrlPntScreenPos.x() - CROSS_THRESHOLD))
+ destinationPosScreen.setX(nextCtrlPntScreenPos.x() - CROSS_THRESHOLD);
+ }
+ }
+
+ QPointF p = _holder->_screenToValue(destinationPosScreen);
+
+ QPointF min = _curve->getMinValue();
+ QPointF max = _curve->getMaxValue();
+
+ //make control point move in value range
+ {
+ if (p.x() < min.x())
+ p.setX(min.x());
+ else if (p.x() > max.x())
+ p.setX(max.x());
+
+ if (p.y() < min.y())
+ p.setY(min.y());
+ else if (p.y() > max.y())
+ p.setY(max.y());
+ }
+
+ pickedCtrlPnt.value = p;
+ _curve->setControlPoint(pickedPoint, pickedCtrlPnt);
+ emit _holder->PickedControlPointValueChanged(p);
+
+ emit _holder->CurveAttributeChanged(_attribute);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::draw(QPainter &painter)
+{
+ std::vector<QPointF> points;
+ _makePoints(points);
+
+ _drawCurve(painter);
+
+ _drawPoints(points, painter, _pickedPoints);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::_drawCurve(QPainter &painter)
+{
+ painter.save();
+
+ {
+ QPen pen( Qt::black );
+ pen.setColor(_color);
+ pen.setWidth(CURVE_WIDTH);
+ pen.setStyle(Qt::SolidLine);
+
+ painter.setPen(pen);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ }
+
+ QPainterPath path;
+
+ std::vector<QPointF> samplePoints = _curve->getSamplePoints();
+ path.moveTo(_holder->_valueToScreen(samplePoints[0]));
+
+ for (size_t i = 0; i < samplePoints.size(); ++i)
+ {
+ path.lineTo(_holder->_valueToScreen(samplePoints[i]));
+ }
+ painter.drawPath(path);
+
+ painter.restore();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::_makePoints(std::vector<QPointF>& points)
+{
+ size_t ctrlPntsCount = _curve->getControlPointCount();
+ for (int i = 0; i < ctrlPntsCount; i++)
+ points.push_back( _holder->_valueToScreen(_curve->getControlPoint(i).value) );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::_drawPoints(const std::vector<QPointF>& points, QPainter &painter, const std::vector<int>& pickedPoints)
+{
+ {
+ QPen pen( Qt::black );
+ pen.setColor(QColor(255,255,255));
+ pen.setWidth(6);
+ pen.setStyle(Qt::SolidLine);
+
+ painter.setPen(pen);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ }
+
+ for (int i = 0; i < points.size(); i++)
+ {
+ QPen pen( Qt::black );
+ pen.setWidth(CTRL_PNT_ICON_SIZE);
+ pen.setStyle(Qt::SolidLine);
+
+ if (IsInSelectedCtrlPnts(pickedPoints,i))
+ pen.setColor(QColor(255,0,0));
+ else
+ pen.setColor(QColor(255,255,255));
+
+ painter.setPen(pen);
+ painter.drawPoint( points[i] );
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveEntity::_addCtrlPntByClick(const QPointF& mouseScreenPos)
+{
+ if (!_attribute->canAddRemoveControlPoint())
+ return ;
+
+ QPointF pos= _holder->_screenToValue(mouseScreenPos);
+
+ QPointF pntOnCurve = _curve->getPointByX(pos.x());
+ QPointF pntOnCurveScreen = _holder->_valueToScreen(pntOnCurve);
+
+ if ( IsSamePoint(mouseScreenPos, pntOnCurveScreen, CLICK_ON_CURVE_THRESHOLD) )
+ {
+ _pickedPoint = _curve->appendControlPoint(pntOnCurve.x());
+ _holder->update();
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool CurveEntity::_canRemoveCtrlPntByRightClick(const QPointF& mouseScreenPos)
+{
+ std::vector<QPointF> points;
+ _makePoints(points);
+
+ _ctrlPntToRemove = FindSelectedCtrlPnt(points, mouseScreenPos);
+
+ if ( !_attribute->canAddRemoveControlPoint()
+ || (-1 == _ctrlPntToRemove)
+ || 2 == _curve->_controlPoints.size() && -1 != _ctrlPntToRemove)
+ {
+ return false;
+ }
+ else
+ return true;
+}
+
+void CurveEntity::_removeCtrlPntByRightClick()
+{
+ if (-1 != _ctrlPntToRemove && _attribute->canAddRemoveControlPoint())
+ {
+ _curve->removeControlPoint(_ctrlPntToRemove);
+ }
+ _ctrlPntToRemove = -1;
+ _pickedPoint = -1;
+ _pickedPoints.clear();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+CurveWidget::CurveWidget(QWidget* parent)
+ : QFrame(parent)
+ , _parent(parent)
+ , _moveCrossOtherCtrlPnt(false)
+ , _moveCtrlPnt(false)
+ , _pan(false)
+ , _snapHorizontal(false)
+ , _snapVertical(false)
+ , _canAddCtrlPntByClick(false)
+ , _canRemoveCtrlPntByClick(false)
+ , _curveFitWindowScale(1.0, 1.0)
+ , _curveFitWindowOffset(0.0, 0.0)
+ , _curveScaleLevel(1.0, 1.0)
+ , _contextMenu(nullptr)
+ , _removeCtrlPntAction(nullptr)
+{
+ setFocusPolicy(Qt::ClickFocus );
+ //QString focusStyle = QString("QFrame:focus { border:1px solid #FF0000; }");
+ //setStyleSheet(focusStyle);
+
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onShowContextMenu(const QPoint&)));
+
+ _contextMenu = new QMenu(this);;
+ _removeCtrlPntAction = new QAction(this);
+ _removeCtrlPntAction->setText(tr("Remove Control Point"));
+ _contextMenu->addAction(_removeCtrlPntAction);
+
+ connect(_removeCtrlPntAction, SIGNAL(triggered()), this, SLOT(onRemoveControlPoint()) );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::onShowContextMenu(const QPoint& pos)
+{
+ bool enableRemoveCtrlPntAction = false;
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ if (curveEntity._canRemoveCtrlPntByRightClick(pos))
+ enableRemoveCtrlPntAction = true;
+ }
+
+ _removeCtrlPntAction->setEnabled(enableRemoveCtrlPntAction);
+ _contextMenu->exec(QCursor::pos());
+}
+
+void CurveWidget::onRemoveControlPoint()
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity._removeCtrlPntByRightClick();
+ }
+
+ std::vector<CurveEntity*> pickedCurves;
+ emit PickedControlPointChanged(pickedCurves);
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::paintEvent(QPaintEvent * e)
+{
+ QFrame::paintEvent(e);
+
+ QPainter painter(this);
+ painter.setRenderHints(QPainter::Antialiasing, true);
+
+ _drawGrid(painter);
+
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.draw(painter);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::resizeEvent(QResizeEvent* e)
+{
+ _updateCurveFitWindowPara();
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::mousePressEvent( QMouseEvent* e )
+{
+ if (e->buttons() == Qt::MiddleButton)
+ {
+ setCursor(Qt::OpenHandCursor);
+ _mousePressScreenPos = QPointF(e->pos().x(), e->pos().y());
+ _pan = true;
+ }
+ else
+ {
+ std::vector<CurveEntity*> pickedCurves;
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.mousePressEvent(e, _moveCtrlPnt);
+ if (curveEntity.getPickedControlPointIndexes().size() > 0)
+ pickedCurves.push_back(&curveEntity);
+ }
+
+ emit PickedControlPointChanged(pickedCurves);
+
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::mouseReleaseEvent( QMouseEvent* e )
+{
+ if (_moveCtrlPnt)
+ {
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.mouseReleaseEvent(e);
+ }
+ }
+ else if (_pan)
+ {
+ setCursor(Qt::ArrowCursor);
+ _curOrinScreenPos = _lastOrinScreenPos + (QPointF(e->pos().x() - _mousePressScreenPos.x(), _mousePressScreenPos.y() - e->pos().y()));
+ _lastOrinScreenPos = _curOrinScreenPos;
+ _updateCurveFitWindowPara();
+
+ }
+
+ _moveCtrlPnt = false;
+ _pan = false;
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::mouseMoveEvent( QMouseEvent* e )
+{
+ if (_moveCtrlPnt)
+ {
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.mouseMoveEvent(e);
+ }
+ }
+ else if (e->buttons() & Qt::MiddleButton)
+ {
+ _curOrinScreenPos = _lastOrinScreenPos + (QPointF(e->pos().x() - _mousePressScreenPos.x(), _mousePressScreenPos.y() - e->pos().y()));
+ _updateCurveFitWindowPara();
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::wheelEvent(QWheelEvent *e)
+{
+ int numDegrees = e->delta() / 8;
+
+ float zoom = 1.0 + numDegrees / 360.0f;
+ _curveScaleLevel.setX(_curveScaleLevel.x() * zoom);
+ _curveScaleLevel.setY(_curveScaleLevel.y() * zoom);
+
+ _updateCurveFitWindowPara();
+ update();
+ e->accept();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::keyPressEvent(QKeyEvent *e)
+{
+ bool move = false;
+ switch(e->key())
+ {
+ case Qt::Key_Left:
+ _curOrinScreenPos = _lastOrinScreenPos + QPointF(-1.0f, 0.0f);
+ _lastOrinScreenPos = _curOrinScreenPos;
+ move = true;
+ break;
+ case Qt::Key_Up:
+ _curOrinScreenPos = _lastOrinScreenPos + QPointF(0.0f, 1.0f);
+ _lastOrinScreenPos = _curOrinScreenPos;
+ move = true;
+ break;
+ case Qt::Key_Right:
+ _curOrinScreenPos = _lastOrinScreenPos + QPointF(1.0f, 0.0f);
+ _lastOrinScreenPos = _curOrinScreenPos;
+ move = true;
+ break;
+ case Qt::Key_Down:
+ _curOrinScreenPos = _lastOrinScreenPos + QPointF(0.0f, -1.0f);
+ _lastOrinScreenPos = _curOrinScreenPos;
+ move = true;
+ break;
+ }
+
+ if (move)
+ {
+ _updateCurveFitWindowPara();
+ update();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::setLocation(float location)
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.setLocation(location);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::setValue(float value)
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.setValue(value);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::setCurveAttributes(std::vector<CurveAttributeBase*> attributes)
+{
+ _curves.clear();
+
+ for (std::vector<CurveAttributeBase*>::iterator itr = attributes.begin(); itr != attributes.end(); ++itr)
+ {
+ CurveAttributeBase* attribute = *itr;
+ if (attribute->getType() == eSingleAttr)
+ {
+ CurveAttribute* attributeSpecific = static_cast<CurveAttribute*>(attribute);
+
+ CurveEntity curveEntity(this, attributeSpecific, attributeSpecific->color);
+ _curves.push_back(curveEntity);
+ }
+ else if (attribute->getType() == eGroupAttr)
+ {
+ CurveAttributeGroup* attributeGroup = static_cast<CurveAttributeGroup*>(attribute);
+ size_t countAttributesInGroup = attributeGroup->attributes.size();
+ for (size_t i = 0; i < countAttributesInGroup; ++i)
+ {
+ CurveAttribute* attributeInGroup = attributeGroup->attributes[i];
+
+ CurveEntity curveEntity(this, attributeInGroup, attributeInGroup->color);
+ _curves.push_back(curveEntity);
+ }
+ }
+ }
+
+ _updateCurveFitWindowPara();
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::reset()
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity._attribute->curve.reset();
+ emit CurveAttributeChanged(curveEntity._attribute);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::addControlPointsBeforeSelected()
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.addControlPointsBeforeSelected();
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::addControlPointsAfterSelected()
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.addControlPointsAfterSelected();
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::removeSelectedControlPoints()
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.removeSelectedControlPoints();
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::setTangentType(InterpolateMode mode)
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.setTangentType(mode);
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::setSmoothTangent()
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.setSmoothTangent();
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::setEaseInTangent()
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.setEaseInTangent();
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::setEaseOutTangent()
+{
+ size_t curveCount = _curves.size();
+ for (size_t i = 0; i < curveCount; ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+ curveEntity.setEaseOutTangent();
+ }
+
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::increaseCurveScaleHorizontally()
+{
+ _curveScaleLevel.setX(_curveScaleLevel.x() * 2);
+ _updateCurveFitWindowPara();
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::decreaseCurveScaleHorizontally()
+{
+ _curveScaleLevel.setX(_curveScaleLevel.x() / 2);
+ _updateCurveFitWindowPara();
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::increaseCurveScaleVertically()
+{
+ _curveScaleLevel.setY(_curveScaleLevel.y() * 2);
+ _updateCurveFitWindowPara();
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::decreaseCurveScaleVertically()
+{
+ _curveScaleLevel.setY(_curveScaleLevel.y() / 2);
+ _updateCurveFitWindowPara();
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::frameCurveScaleHorizontally()
+{
+ _curveScaleLevel.setX(1.0f);
+ _curOrinScreenPos.setX(0);
+ _lastOrinScreenPos.setX(0);
+ _updateCurveFitWindowPara();
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::frameCurveScaleVertically()
+{
+ _curveScaleLevel.setY(1.0f);
+ _curOrinScreenPos.setY(0);
+ _lastOrinScreenPos.setY(0);
+ _updateCurveFitWindowPara();
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::frameCurveScale()
+{
+ _curveScaleLevel.setX(1.0f);
+ _curveScaleLevel.setY(1.0f);
+ _curOrinScreenPos = QPointF(0,0);
+ _lastOrinScreenPos = QPointF(0,0);
+ _updateCurveFitWindowPara();
+ update();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::_updateCurveFitWindowPara()
+{
+ QRect winSize = rect();
+
+ float minX = 0;
+ float minY = 0;
+ float maxX = 0;
+ float maxY = 0;
+
+ for (size_t i = 0; i < _curves.size(); ++i)
+ {
+ CurveEntity& curveEntity = _curves[i];
+
+ QRectF boundingBox = curveEntity.getBoundingBox();
+
+ if (minX > boundingBox.x())
+ minX = boundingBox.x();
+
+ if (minY > boundingBox.y())
+ minY = boundingBox.y();
+
+ if (maxX < boundingBox.right())
+ maxX = boundingBox.right();
+
+ if (maxY < boundingBox.bottom())
+ maxY = boundingBox.bottom();
+ }
+
+ float curveWidth = maxX - minX;
+ float curveHeight = maxY - minY;
+
+ if (0 == curveWidth && 0 == curveHeight)
+ {
+ curveWidth = 1.0;
+ curveHeight = 1.0;
+ }
+ else if (0 == curveWidth)
+ {
+ curveWidth = curveHeight;
+ }
+ else if (0 == curveHeight)
+ {
+ curveHeight = curveWidth;
+ }
+
+ float widthScale = (winSize.width() - MARGIN_X * 2.0f) / curveWidth;
+ float heightScale = (MARGIN_Y * 2.0f - winSize.height()) / curveHeight;
+ _curveFitWindowScale = QPointF(widthScale, heightScale);
+
+ float widthOffset = MARGIN_X + _curOrinScreenPos.x() - minX * widthScale * _curveScaleLevel.x();
+ float heightOffset = (winSize.height() - MARGIN_Y - _curOrinScreenPos.y())- minY * heightScale * _curveScaleLevel.y();
+ _curveFitWindowOffset = QPointF(widthOffset, heightOffset);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QPointF CurveWidget::_valueToScreen(const QPointF& pnt)
+{
+ QPointF curveScale = QPointF(_curveFitWindowScale.x() * _curveScaleLevel.x(), _curveFitWindowScale.y() * _curveScaleLevel.y());
+
+ float x = pnt.x() * curveScale.x() + _curveFitWindowOffset.x();
+ float y = pnt.y() * curveScale.y() + _curveFitWindowOffset.y();
+ return QPointF(x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QPointF CurveWidget::_screenToValue(const QPointF& pnt)
+{
+ QPointF curveScale = QPointF(_curveFitWindowScale.x() * _curveScaleLevel.x(), _curveFitWindowScale.y() * _curveScaleLevel.y());
+
+ float x = (pnt.x() - _curveFitWindowOffset.x()) / curveScale.x();
+ float y = (pnt.y() - _curveFitWindowOffset.y()) / curveScale.y();
+
+ return QPointF(x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::_drawAxis(QPainter &painter)
+{
+ painter.save();
+ {
+ QPen pen( Qt::black );
+ pen.setColor(GRID_COLOR);
+ pen.setWidth(2);
+ pen.setStyle(Qt::SolidLine);
+
+ painter.setPen(pen);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ }
+
+ {
+ int w = width() - MARGIN_X * 2;
+ int h = height() - MARGIN_Y * 2;
+
+ QPainterPath path;
+
+ QPointF x = _dragedCoordinateToScreen(QPointF(w, 0));
+ QPointF y = _dragedCoordinateToScreen(QPointF(0, h));
+
+ path.moveTo(_dragedCoordinateToScreen(QPointF(0, 0)));
+ path.lineTo(x);
+ path.moveTo(_dragedCoordinateToScreen(QPointF(0, 0)));
+ path.lineTo(y);
+
+ painter.drawPath(path);
+ }
+
+ painter.restore();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void CurveWidget::_drawGrid(QPainter &painter)
+{
+ painter.save();
+ {
+ QPen pen( Qt::black );
+ pen.setColor(GRID_COLOR);
+ pen.setWidth(1);
+ pen.setStyle(Qt::SolidLine);
+
+ painter.setPen(pen);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ }
+
+ {
+ QPainterPath path;
+
+ int w = width() - MARGIN_X * 2;
+ int h = height() - MARGIN_Y * 2;
+
+ QPointF newOri = _dragedCoordinateToScreen(_curOrinScreenPos);
+
+ float width = w;
+ float height = h;
+ int gridXSegmentCount = GRID_INTIAL_SEGMENT_COUNT / _curveScaleLevel.x();
+ int gridYSegmentCount = GRID_INTIAL_SEGMENT_COUNT / _curveScaleLevel.y();
+
+ if (_curveScaleLevel.x() > 1)
+ {
+ width = w * _curveScaleLevel.x();
+ gridXSegmentCount *= _curveScaleLevel.x();
+ }
+
+ if (_curveScaleLevel.y() > 1)
+ {
+ height = h * _curveScaleLevel.y();
+ gridYSegmentCount *= _curveScaleLevel.y();
+ }
+
+ // draw horizontal lines
+ for (int i = 0 - gridXSegmentCount; i <= gridXSegmentCount * 2; ++i)
+ {
+ QPointF bottom = _dragedCoordinateToScreen(QPointF(width * i / (float)gridXSegmentCount, -height));
+ QPointF up = _dragedCoordinateToScreen(QPointF(width * i / (float)gridXSegmentCount, height * 2));
+ path.moveTo(bottom);
+ path.lineTo(up);
+
+ painter.drawPath(path);
+ }
+
+ // draw vertical lines
+ for (int i = 0 - gridYSegmentCount; i <= gridYSegmentCount * 2; ++i)
+ {
+ QPointF left = _dragedCoordinateToScreen(QPointF(-width, i * height / (float)gridYSegmentCount));
+ QPointF right = _dragedCoordinateToScreen(QPointF(2 * width, i * height / (float)gridYSegmentCount));
+ path.moveTo(left);
+ path.lineTo(right);
+
+ painter.drawPath(path);
+ }
+
+ }
+ painter.restore();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QPointF CurveWidget::_getSnapSreenPos(const QPointF& mouseScreenPos)
+{
+ int w = width() - MARGIN_X * 2;
+ int h = height() - MARGIN_Y * 2;
+
+ QPointF pos = _screenToDragedCoordinate(mouseScreenPos);
+
+ // snap horizontally
+ if (_snapHorizontal)
+ {
+ int gridXSegmentCount = GRID_INTIAL_SEGMENT_COUNT / _curveScaleLevel.x();
+ if (gridXSegmentCount < 2)
+ gridXSegmentCount = 2;
+ for (int i = 0; i <= gridXSegmentCount; ++i)
+ {
+ if (abs(i * w / gridXSegmentCount - pos.x()) <= SNAP_DISTANCE )
+ {
+ pos.setX(i * w / gridXSegmentCount);
+ break;
+ }
+ }
+ }
+
+ // snap vertically
+ if (_snapVertical)
+ {
+ int gridYSegmentCount = GRID_INTIAL_SEGMENT_COUNT / _curveScaleLevel.y();
+ if (gridYSegmentCount < 2)
+ gridYSegmentCount = 2;
+ for (int i = 0; i <= gridYSegmentCount; ++i)
+ {
+ if (abs(i * h / gridYSegmentCount - pos.y()) <= SNAP_DISTANCE)
+ {
+ pos.setY(i * h / gridYSegmentCount);
+ }
+ }
+ }
+
+ return _dragedCoordinateToScreen(pos);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QPointF CurveWidget::_dragedCoordinateToScreen(const QPointF& pnt)
+{
+ float x = pnt.x() + MARGIN_X + _curOrinScreenPos.x();
+ float y = height() - MARGIN_Y - pnt.y() - _curOrinScreenPos.y();
+ return QPointF(x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QPointF CurveWidget::_screenToDragedCoordinate(const QPointF& pnt)
+{
+ float x = pnt.x() - MARGIN_X - _curOrinScreenPos.x();
+ float y = height() - MARGIN_Y - pnt.y() - _curOrinScreenPos.y();
+ return QPointF(x, y);
+}
+
+} // namespace CurveEditor
+} // namespace nvidia \ No newline at end of file
diff --git a/NvBlast/tools/CurveEditor/source/Internal/Window/CurveWidget.h b/NvBlast/tools/CurveEditor/source/Internal/Window/CurveWidget.h
new file mode 100644
index 0000000..04c38d0
--- /dev/null
+++ b/NvBlast/tools/CurveEditor/source/Internal/Window/CurveWidget.h
@@ -0,0 +1,158 @@
+#ifndef CurveWidget_h__
+#define CurveWidget_h__
+
+#include <QtWidgets/QWidget>
+#include <QtWidgets/QFrame>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QMenu>
+#include <QtWidgets/QAction>
+#include <vector>
+#include "Curve.h"
+
+namespace nvidia {
+namespace CurveEditor {
+
+class CurveAttributeBase;
+class CurveAttribute;
+class CurveWidget;
+
+class CurveEntity
+{
+ friend class CurveWidget;
+ friend class CurveEditorMainWindow;
+public:
+ CurveEntity(CurveWidget* holder, CurveAttribute* attribute, const QColor& color);
+
+ void setLocation(float location);
+ void setValue(float value);
+
+ void addControlPointsBeforeSelected();
+ void addControlPointsAfterSelected();
+ void removeSelectedControlPoints();
+ void setTangentType(InterpolateMode mode);
+ void setSmoothTangent();
+ void setEaseInTangent();
+ void setEaseOutTangent();
+
+ int getControlPointCount();
+ int getPickedControlPointIndex() { return _pickedPoint; }
+ std::vector<int>& getPickedControlPointIndexes() { return _pickedPoints; }
+
+ QRectF getBoundingBox();
+
+ void mousePressEvent(QMouseEvent* e, bool& pickedPoint);
+ void mouseReleaseEvent(QMouseEvent* e);
+ void mouseMoveEvent(QMouseEvent* e);
+
+ void draw(QPainter &painter);
+
+private:
+ void _drawCurve(QPainter &painter);
+ void _makePoints(std::vector<QPointF>& points);
+ void _drawPoints(const std::vector<QPointF>& points, QPainter &painter, const std::vector<int>& pickedPoints);
+ void _addCtrlPntByClick(const QPointF& mouseScreenPos);
+ bool _canRemoveCtrlPntByRightClick(const QPointF& mouseScreenPos);
+ void _removeCtrlPntByRightClick();
+
+ CurveWidget* _holder;
+ CurveAttribute* _attribute;
+ Curve* _curve;
+ QColor _color;
+ int _pickedPoint;
+ std::vector<int> _pickedPoints;
+ QPointF _lastMousePosScreen;
+ int _ctrlPntToRemove;
+};
+
+class CurveWidget : public QFrame
+{
+ Q_OBJECT
+
+ friend class CurveEntity;
+
+public:
+ explicit CurveWidget(QWidget* parent);
+
+ void setLocation(float location);
+ void setValue(float value);
+
+ void setCurveAttributes(std::vector<CurveAttributeBase*> attributes);
+ void reset();
+
+ void addControlPointsBeforeSelected();
+ void addControlPointsAfterSelected();
+ void removeSelectedControlPoints();
+ void setTangentType(InterpolateMode mode);
+ void setSmoothTangent();
+ void setEaseInTangent();
+ void setEaseOutTangent();
+
+ void setSnapAll() { _snapHorizontal = true; _snapVertical = true; }
+ void setSnapHorizontal() { _snapHorizontal = true; _snapVertical = false; }
+ void setSnapVertical() { _snapHorizontal = false; _snapVertical = true; }
+
+ void increaseCurveScaleHorizontally();
+ void decreaseCurveScaleHorizontally();
+ void increaseCurveScaleVertically();
+ void decreaseCurveScaleVertically();
+ void frameCurveScaleHorizontally();
+ void frameCurveScaleVertically();
+ void frameCurveScale();
+
+ void setAddCtrlPntByClick(bool value) { _canAddCtrlPntByClick = value; }
+ void setRemoveCtrlPntByClick(bool value) { _canRemoveCtrlPntByClick = value; }
+
+signals:
+ void PickedControlPointValueChanged(QPointF& value);
+ void PickedControlPointChanged(const std::vector<CurveEntity*> pickedCurves);
+ void CurveAttributeChanged(nvidia::CurveEditor::CurveAttribute* attribute);
+
+private slots:
+ void onShowContextMenu(const QPoint& pos);
+ void onRemoveControlPoint();
+
+private:
+ // QWidget events
+ virtual void paintEvent(QPaintEvent * e);
+ virtual void resizeEvent(QResizeEvent* e);
+
+ virtual void mousePressEvent(QMouseEvent* e);
+ virtual void mouseReleaseEvent(QMouseEvent* e);
+ virtual void mouseMoveEvent(QMouseEvent* e);
+ virtual void wheelEvent(QWheelEvent *e);
+ virtual void keyPressEvent(QKeyEvent *e);
+
+ void _updateCurveFitWindowPara();
+ QPointF _valueToScreen(const QPointF& pnt);
+ QPointF _screenToValue(const QPointF& pnt);
+ void _drawAxis(QPainter &painter);
+ void _drawGrid(QPainter &painter);
+ QPointF _getSnapSreenPos(const QPointF& mouseScreenPos);
+ QPointF _dragedCoordinateToScreen(const QPointF& pnt);
+ QPointF _screenToDragedCoordinate(const QPointF& pnt);
+
+private:
+ QWidget* _parent;
+ bool _moveCrossOtherCtrlPnt;// whether can move control point across other control points
+ bool _moveCtrlPnt;
+ bool _pan;
+ bool _snapHorizontal;
+ bool _snapVertical;
+ bool _canAddCtrlPntByClick;
+ bool _canRemoveCtrlPntByClick;
+ std::vector<CurveEntity> _curves;
+ QPointF _curveFitWindowScale;
+ QPointF _curveFitWindowOffset;
+ QPointF _curveScaleLevel;
+ QPointF _mousePressScreenPos;
+ QPointF _lastOrinScreenPos;
+ QPointF _curOrinScreenPos;
+
+ QMenu* _contextMenu;
+ QAction* _removeCtrlPntAction;
+};
+
+} // namespace CurveEditor
+} // namespace nvidia
+
+#endif // CurveWidget_h__