diff options
| author | Bryan Galdrikian <[email protected]> | 2017-02-21 12:07:59 -0800 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2017-02-21 12:07:59 -0800 |
| commit | 446ce137c6823ba9eff273bdafdaf266287c7c98 (patch) | |
| tree | d20aab3e2ed08d7b3ca71c2f40db6a93ea00c459 /NvBlast/tools/CurveEditor/source | |
| download | blast-1.0.0-beta.tar.xz blast-1.0.0-beta.zip | |
first commitv1.0.0-beta
Diffstat (limited to 'NvBlast/tools/CurveEditor/source')
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__ |