diff --git a/CMakeLists.txt b/CMakeLists.txt index c9aa5e4..f57aab6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,10 +23,7 @@ endif() set(PROJECT_SOURCES src/main.cpp src/editor/mainWindow.cpp - src/editor/emitterSetWidget.cpp - src/editor/fluctuationEditorWidget.cpp src/editor/ptclListWidget.cpp - src/editor/stripeEditorWidget.cpp src/editor/textureListWidget.cpp src/editor/textureImportDialog.cpp src/editor/textureSelectDialog.cpp @@ -40,45 +37,46 @@ set(PROJECT_SOURCES src/editor/components/loadingSpinner.cpp src/editor/components/rgbaColorWidget.cpp src/editor/components/thumbnailWidget.cpp - src/editor/childEditor/alphaPropertiesWidget.cpp - src/editor/childEditor/basicPropertiesWidget.cpp - src/editor/childEditor/childEditorWidget.cpp - src/editor/childEditor/colorPropertiesWidget.cpp - src/editor/childEditor/combinerPropertiesWidget.cpp - src/editor/childEditor/emissionPropertiesWidget.cpp - src/editor/childEditor/rotationPropertiesWidget.cpp - src/editor/childEditor/scalePropertiesWidget.cpp - src/editor/childEditor/texturePropertiesWidget.cpp - src/editor/childEditor/velocityPropertiesWidget.cpp - src/editor/emitterWidget/alphaPropertiesWidget.cpp - src/editor/emitterWidget/basicPropertiesWidget.cpp - src/editor/emitterWidget/colorPropertiesWidget.cpp - src/editor/emitterWidget/combinerPropertiesWidget.cpp - src/editor/emitterWidget/emissionPropertiesWidget.cpp - src/editor/emitterWidget/emitterWidget.cpp - src/editor/emitterWidget/gravityPropertiesWidget.cpp - src/editor/emitterWidget/lifespanPropertiesWidget.cpp - src/editor/emitterWidget/rotationPropertiesWidget.cpp - src/editor/emitterWidget/scalePropertiesWidget.cpp - src/editor/emitterWidget/terminationPropertiesWidget.cpp - src/editor/emitterWidget/texturePropertiesWidget.cpp - src/editor/emitterWidget/transformPropertiesWidget.cpp - src/editor/emitterWidget/velocityPropertiesWidget.cpp - src/editor/emitterWidget/volumePropertiesWidget.cpp - src/editor/fieldEditor/collisionDataWidget.cpp - src/editor/fieldEditor/convergenceDataWidget.cpp - src/editor/fieldEditor/fieldEditorWidget.cpp - src/editor/fieldEditor/magnetDataWidget.cpp - src/editor/fieldEditor/posAddDataWidget.cpp - src/editor/fieldEditor/randomDataWidget.cpp - src/editor/fieldEditor/spinDataWidget.cpp + src/editor/inspector/alphaAnimInspector.cpp + src/editor/inspector/colorInspector.cpp + src/editor/inspector/combinerInspector.cpp + src/editor/inspector/emissionInspector.cpp + src/editor/inspector/emitterSetInspector.cpp + src/editor/inspector/generalEmitterInspector.cpp + src/editor/inspector/inspectorPanel.cpp + src/editor/inspector/inspectorWidgetBase.cpp + src/editor/inspector/fluctuationInspector.cpp + src/editor/inspector/gravityInspector.cpp + src/editor/inspector/lifespanInspector.cpp + src/editor/inspector/rotationInspector.cpp + src/editor/inspector/scaleAnimInspector.cpp + src/editor/inspector/stripeInspector.cpp + src/editor/inspector/terminationInspector.cpp + src/editor/inspector/textureInspector.cpp + src/editor/inspector/transformInspector.cpp + src/editor/inspector/velocityInspector.cpp + src/editor/inspector/volumeInspector.cpp + src/editor/inspector/child/childAlphaInspector.cpp + src/editor/inspector/child/childColorInspector.cpp + src/editor/inspector/child/childCombinerInspector.cpp + src/editor/inspector/child/childEmissionInspector.cpp + src/editor/inspector/child/childGeneralInspector.cpp + src/editor/inspector/child/childRotationInspector.cpp + src/editor/inspector/child/childScaleInspector.cpp + src/editor/inspector/child/childTextureInspector.cpp + src/editor/inspector/child/childVelocityInspector.cpp + src/editor/inspector/field/fieldCollisionInspector.cpp + src/editor/inspector/field/fieldConvergenceInspector.cpp + src/editor/inspector/field/fieldMagnetInspector.cpp + src/editor/inspector/field/fieldPosAddInspector.cpp + src/editor/inspector/field/fieldRandomInspector.cpp + src/editor/inspector/field/fieldSpinInspector.cpp src/etc1/rg_etc1.cpp src/ptcl/ptcl.cpp src/ptcl/ptclBinary.cpp - src/ptcl/ptclChildData.cpp + src/ptcl/ptclDocument.cpp src/ptcl/ptclEmitter.cpp src/ptcl/ptclEmitterSet.cpp - src/ptcl/ptclFieldData.cpp src/ptcl/ptclSeed.cpp src/ptcl/ptclTexture.cpp src/util/imageUtil.cpp @@ -90,10 +88,7 @@ set(PROJECT_SOURCES set(PROJECT_HEADERS include/typedefs.h include/editor/mainWindow.h - include/editor/emitterSetWidget.h - include/editor/fluctuationEditorWidget.h include/editor/ptclListWidget.h - include/editor/stripeEditorWidget.h include/editor/textureImportDialog.h include/editor/textureListWidget.h include/editor/textureSelectDialog.h @@ -110,52 +105,52 @@ set(PROJECT_HEADERS include/editor/components/sizedSpinBox.h include/editor/components/thumbnailWidget.h include/editor/components/vectorSpinBox.h - include/editor/childEditor/alphaPropertiesWidget.h - include/editor/childEditor/basicPropertiesWidget.h - include/editor/childEditor/childEditorWidget.h - include/editor/childEditor/colorPropertiesWidget.h - include/editor/childEditor/combinerPropertiesWidget.h - include/editor/childEditor/emissionPropertiesWidget.h - include/editor/childEditor/rotationPropertiesWidget.h - include/editor/childEditor/scalePropertiesWidget.h - include/editor/childEditor/texturePropertiesWidget.h - include/editor/childEditor/velocityPropertiesWidget.h - include/editor/emitterWidget/alphaPropertiesWidget.h - include/editor/emitterWidget/basicPropertiesWidget.h - include/editor/emitterWidget/colorPropertiesWidget.h - include/editor/emitterWidget/combinerPropertiesWidget.h - include/editor/emitterWidget/emissionPropertiesWidget.h - include/editor/emitterWidget/emitterWidget.h - include/editor/emitterWidget/gravityPropertiesWidget.h - include/editor/emitterWidget/lifespanPropertiesWidget.h - include/editor/emitterWidget/rotationPropertiesWidget.h - include/editor/emitterWidget/scalePropertiesWidget.h - include/editor/emitterWidget/terminationPropertiesWidget.h - include/editor/emitterWidget/texturePropertiesWidget.h - include/editor/emitterWidget/transformPropertiesWidget.h - include/editor/emitterWidget/velocityPropertiesWidget.h - include/editor/emitterWidget/volumePropertiesWidget.h - include/editor/fieldEditor/collisionDataWidget.h - include/editor/fieldEditor/convergenceDataWidget.h - include/editor/fieldEditor/fieldEditorWidget.h - include/editor/fieldEditor/magnetDataWidget.h - include/editor/fieldEditor/posAddDataWidget.h - include/editor/fieldEditor/randomDataWidget.h - include/editor/fieldEditor/spinDataWidget.h + include/editor/inspector/alphaAnimInspector.h + include/editor/inspector/colorInspector.h + include/editor/inspector/combinerInspector.h + include/editor/inspector/emitterSetInspector.h + include/editor/inspector/emissionInspector.h + include/editor/inspector/generalEmitterInspector.h + include/editor/inspector/inspectorPanel.h + include/editor/inspector/inspectorWidgetBase.h + include/editor/inspector/fluctuationInspector.h + include/editor/inspector/gravityInspector.h + include/editor/inspector/lifespanInspector.h + include/editor/inspector/rotationInspector.h + include/editor/inspector/scaleAnimInspector.h + include/editor/inspector/stripeInspector.h + include/editor/inspector/terminationInspector.h + include/editor/inspector/textureInspector.h + include/editor/inspector/transformInspector.h + include/editor/inspector/velocityInspector.h + include/editor/inspector/volumeInspector.h + include/editor/inspector/child/childAlphaInspector.h + include/editor/inspector/child/childColorInspector.h + include/editor/inspector/child/childEmissionInspector.h + include/editor/inspector/child/childGeneralInspector.h + include/editor/inspector/child/childCombinerInspector.h + include/editor/inspector/child/childRotationInspector.h + include/editor/inspector/child/childScaleInspector.h + include/editor/inspector/child/childTextureInspector.h + include/editor/inspector/child/childVelocityInspector.h + include/editor/inspector/field/fieldCollisionInspector.h + include/editor/inspector/field/fieldConvergenceInspector.h + include/editor/inspector/field/fieldMagnetInspector.h + include/editor/inspector/field/fieldPosAddInspector.h + include/editor/inspector/field/fieldRandomInspector.h + include/editor/inspector/field/fieldSpinInspector.h include/etc1/rg_etc1.h include/math/matrix.h include/math/util.h include/math/vector.h include/ptcl/ptcl.h include/ptcl/ptclBinary.h - include/ptcl/ptclChildData.h + include/ptcl/ptclCommand.h + include/ptcl/ptclDocument.h include/ptcl/ptclEmitter.h include/ptcl/ptclEmitterSet.h include/ptcl/ptclEnum.h - include/ptcl/ptclFieldData.h - include/ptcl/ptclFluctuationData.h include/ptcl/ptclSeed.h - include/ptcl/ptclStripeData.h include/ptcl/ptclTexture.h include/util/bitflagUtil.h include/util/imageUtil.h diff --git a/include/editor/childEditor/childEditorWidget.h b/include/editor/childEditor/childEditorWidget.h deleted file mode 100644 index 945a7e0..0000000 --- a/include/editor/childEditor/childEditorWidget.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "ptcl/ptcl.h" -#include "ptcl/ptclChildData.h" - -#include -#include -#include -#include -#include - -namespace PtclEditor { - - -// ========================================================================== // - - -class ChildEditorWidget final : public QWidget { - Q_OBJECT -public: - explicit ChildEditorWidget(QWidget* parent = nullptr); - - void setChildData(Ptcl::ChildData* childData, const BitFlag& childFlag); - void setTextureList(const Ptcl::TextureList* textureList); - void setParentColor0(const Ptcl::binColor4f& parentColor0); - - void clear(); - -signals: - void flagsUpdated(const BitFlag& childFlag); - -private: - void setupLayout(QVBoxLayout* mainLayout); - void setupConnections(); - void setCombinerPropertiesSrc(); - -private: - class BasicPropertiesWidget; - class EmissionPropertiesWidget; - class VelocityPropertiesWidget; - class RotationPropertiesWidget; - class ScalePropertiesWidget; - class TexturePropertiesWidget; - class ColorPropertiesWidget; - class AlphaPropertiesWidget; - class CombinerPropertiesWidget; - -private: - Ptcl::ChildData* mDataPtr{nullptr}; - BitFlag mChildFlag{}; - - const Ptcl::TextureList* mTextureList{nullptr}; - Ptcl::binColor4f mParentColor0{}; - - QCheckBox mEnabledCheckbox{}; - QWidget* mSectionsContainer{}; - BasicPropertiesWidget* mBasicProperties{nullptr}; - EmissionPropertiesWidget* mEmissionProperties{nullptr}; - VelocityPropertiesWidget* mVelocityProperties{nullptr}; - RotationPropertiesWidget* mRotationProperties{nullptr}; - ScalePropertiesWidget* mScaleProperties{nullptr}; - TexturePropertiesWidget* mTextureProperties{nullptr}; - ColorPropertiesWidget* mColorProperties{nullptr}; - AlphaPropertiesWidget* mAlphaProperties{nullptr}; - CombinerPropertiesWidget* mCombinerProperties{nullptr}; -}; - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/include/editor/emitterWidget/alphaPropertiesWidget.h b/include/editor/emitterWidget/alphaPropertiesWidget.h deleted file mode 100644 index 33c3092..0000000 --- a/include/editor/emitterWidget/alphaPropertiesWidget.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "editor/components/animGraph.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -class EmitterWidget::AlphaPropertiesWidget final : public QWidget { - Q_OBJECT -public: - explicit AlphaPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::AlphaProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::AlphaProperties& properties); - -private: - Ptcl::Emitter::AlphaProperties mProps{}; - - AnimGraph mGraphA{}; -}; - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/include/editor/emitterWidget/emissionPropertiesWidget.h b/include/editor/emitterWidget/emissionPropertiesWidget.h deleted file mode 100644 index 9e48865..0000000 --- a/include/editor/emitterWidget/emissionPropertiesWidget.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" - -#include -#include -#include -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -class EmitterWidget::EmissionPropertiesWidget final : public QWidget { - Q_OBJECT -public: - explicit EmissionPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::EmissionProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::EmissionProperties& properties); - -private: - Ptcl::Emitter::EmissionProperties mProps{}; - - QSpinBox mStartFrameSpinBox; - QSpinBox mEndFrameSpinBox; - QCheckBox mInfiniteEmitCheckBox; - QSpinBox mLifeStepSpinBox; - QSpinBox mLifeStepRndSpinBox; - QSpinBox mEmitRateSpinBox; - - static constexpr s32 sEmitInfinite = std::numeric_limits::max(); -}; - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/include/editor/emitterWidget/emitterWidget.h b/include/editor/emitterWidget/emitterWidget.h deleted file mode 100644 index 28b4c0c..0000000 --- a/include/editor/emitterWidget/emitterWidget.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -#include "editor/childEditor/childEditorWidget.h" -#include "editor/components/collapsibleWidget.h" -#include "editor/fluctuationEditorWidget.h" -#include "editor/fieldEditor/fieldEditorWidget.h" -#include "editor/stripeEditorWidget.h" - -#include "ptcl/ptclEmitter.h" -#include "ptcl/ptcl.h" - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -class EmitterWidget final : public QWidget { - Q_OBJECT -public: - explicit EmitterWidget(QWidget* parent = nullptr); - - void setEmitter(Ptcl::Emitter* emitter); - void setTextureList(const Ptcl::TextureList* textureList); - void showStandardEditor(); - void showChildEditor(); - void showFluctuationEditor(); - void showFieldEditor(); - - void clear(); - -signals: - void nameUpdated(const QString& name); - void emitterTypeChanged(); - void emitterNameChanged(); - void complexFlagsChanged(); - void propertiesChanged(); - -private: - void setupStandardLayout(QVBoxLayout* mainLayout); - void setupConnections(); - void updateStripeVisibility(); - -private: - class BasicPropertiesWidget; - class GravityPropertiesWidget; - class TransformPropertiesWidget; - class LifespanPropertiesWidget; - class TerminationPropertiesWidget; - class EmissionPropertiesWidget; - class VelocityPropertiesWidget; - class VolumePropertiesWidget; - class ColorPropertiesWidget; - class AlphaPropertiesWidget; - class RotationPropertiesWidget; - class ScalePropertiesWidget; - class TexturePropertiesWidget; - class CombinerPropertiesWidget; - -private: - Ptcl::Emitter* mEmitterPtr{nullptr}; - const Ptcl::TextureList* mTextureList{nullptr}; - - BasicPropertiesWidget* mBasicProperties{nullptr}; - GravityPropertiesWidget* mGravityProperties{nullptr}; - TransformPropertiesWidget* mTransformProperties{nullptr}; - LifespanPropertiesWidget* mLifespanProperties{nullptr}; - TerminationPropertiesWidget* mTerminationProperties{nullptr}; - EmissionPropertiesWidget* mEmissionProperties{nullptr}; - VelocityPropertiesWidget* mVelocityProperties{nullptr}; - VolumePropertiesWidget* mVolumeProperties{nullptr}; - ColorPropertiesWidget* mColorProperties{nullptr}; - AlphaPropertiesWidget* mAlphaProperties{nullptr}; - RotationPropertiesWidget* mRotationProperties{nullptr}; - ScalePropertiesWidget* mScaleProperties{nullptr}; - TexturePropertiesWidget* mTextureProperties{nullptr}; - CombinerPropertiesWidget* mCombinerProperties{nullptr}; - - QStackedWidget* mStackedWidget{nullptr}; - ChildEditorWidget* mChildEditorWidget{nullptr}; - FluctuationEditorWidget* mFluctuationEditorWidget{nullptr}; - FieldEditorWidget* mFieldEditorWidget{nullptr}; - StripeEditorWidget* mStripeEditorWidget{nullptr}; - - CollapsibleWidget* mStripeSection{nullptr}; -}; - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/include/editor/emitterWidget/terminationPropertiesWidget.h b/include/editor/emitterWidget/terminationPropertiesWidget.h deleted file mode 100644 index 1e3561a..0000000 --- a/include/editor/emitterWidget/terminationPropertiesWidget.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" - -#include -#include -#include -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -class EmitterWidget::TerminationPropertiesWidget final : public QWidget { - Q_OBJECT -public: - explicit TerminationPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::TerminationProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::TerminationProperties& properties); - -private: - Ptcl::Emitter::TerminationProperties mProps{}; - - QCheckBox mIsStopEmitCheckBox; - QDoubleSpinBox mAlphaAddInSpinBox; -}; - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/include/editor/emitterWidget/transformPropertiesWidget.h b/include/editor/emitterWidget/transformPropertiesWidget.h deleted file mode 100644 index eb0a1ef..0000000 --- a/include/editor/emitterWidget/transformPropertiesWidget.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "editor/components/vectorSpinBox.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" - - -namespace PtclEditor { - - -// ========================================================================== // - - -class EmitterWidget::TransformPropertiesWidget final : public QWidget { - Q_OBJECT -public: - explicit TransformPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::TransformProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::TransformProperties& properties); - -private: - void rebuildMatrices(); - -private: - Ptcl::Emitter::TransformProperties mProps{}; - - VectorSpinBox mScaleSpinBox; - VectorSpinBox mRotationSpinBox; - VectorSpinBox mTranslationSpinBox; -}; - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/include/editor/emitterWidget/volumePropertiesWidget.h b/include/editor/emitterWidget/volumePropertiesWidget.h deleted file mode 100644 index c459602..0000000 --- a/include/editor/emitterWidget/volumePropertiesWidget.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "editor/components/enumComboBox.h" -#include "editor/components/vectorSpinBox.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" - -#include -#include -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -class EmitterWidget::VolumePropertiesWidget : public QWidget { - Q_OBJECT -public: - explicit VolumePropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::VolumeProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::VolumeProperties& properties); - -private: - void setupUi(); - void setupSignals(); - void populateWidgets(); - void updateFieldVisibility(Ptcl::VolumeType volumeType); - -private: - struct VolumeField { - QWidget* widget; - std::function label; - std::function isVisible; - }; - -private: - Ptcl::Emitter::VolumeProperties mProps{}; - - std::vector mFields; - std::unordered_map mFieldLabels; - - QComboBox mVolumeTblIndexComboBox; - EnumComboBox mTypeComboBox; - VectorSpinBox mRadiusSpinBox; - QDoubleSpinBox mSweepStartSpinBox; - QDoubleSpinBox mSweepParamSpinBox; - QDoubleSpinBox mLengthSpinBox; -}; - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/include/editor/fieldEditor/fieldEditorWidget.h b/include/editor/fieldEditor/fieldEditorWidget.h deleted file mode 100644 index 91f4a8e..0000000 --- a/include/editor/fieldEditor/fieldEditorWidget.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "ptcl/ptclFieldData.h" -#include "util/bitflagUtil.h" - -#include -#include - -namespace PtclEditor { - - -// ========================================================================== // - - -class FieldEditorWidget final : public QWidget { - Q_OBJECT -public: - explicit FieldEditorWidget(QWidget* parent = nullptr); - - void setData(Ptcl::FieldData* fieldData, const BitFlag& fieldFlag); - -signals: - void flagsUpdated(const BitFlag& fieldFlag); - -private: - void setupLayout(QVBoxLayout* mainLayout); - void setupConnections(); - void setCombinerPropertiesSrc(); - -private: - class RandomDataWidget; - class MagnetDataWidget; - class SpinDataWidget; - class CollisionDataWidget; - class ConvergenceDataWidget; - class PosAddDataWidget; - -private: - Ptcl::FieldData* mDataPtr{nullptr}; - BitFlag mFieldFlag{}; - - QWidget* mSectionsContainer{}; - RandomDataWidget* mRandomDataWidget{nullptr}; - MagnetDataWidget* mMagnetDataWidget{nullptr}; - SpinDataWidget* mSpinDataWidget{nullptr}; - CollisionDataWidget* mCollisionDataWidget{nullptr}; - ConvergenceDataWidget* mConvergenceDataWidget{nullptr}; - PosAddDataWidget* mPosAddDataWidget{nullptr}; -}; - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/include/editor/inspector/alphaAnimInspector.h b/include/editor/inspector/alphaAnimInspector.h new file mode 100644 index 0000000..0d8bac1 --- /dev/null +++ b/include/editor/inspector/alphaAnimInspector.h @@ -0,0 +1,32 @@ +#pragma once + +#include "editor/components/animGraph.h" +#include "editor/inspector/inspectorWidgetBase.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +class AlphaAnimInspector final : public InspectorWidgetBase { + Q_OBJECT +public: + explicit AlphaAnimInspector(QWidget* parent = nullptr); + +private: + void populateProperties() final; + void updateAnimPoint(s32 pointIndex, const AnimGraph::GraphPoint& point); + +private: + AnimGraph mGraphA{}; +}; + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/include/editor/childEditor/alphaPropertiesWidget.h b/include/editor/inspector/child/childAlphaInspector.h similarity index 57% rename from include/editor/childEditor/alphaPropertiesWidget.h rename to include/editor/inspector/child/childAlphaInspector.h index 484f21a..ee31afc 100644 --- a/include/editor/childEditor/alphaPropertiesWidget.h +++ b/include/editor/inspector/child/childAlphaInspector.h @@ -1,6 +1,6 @@ #pragma once -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -14,23 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::AlphaPropertiesWidget final : public QWidget { +class ChildAlphaInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit AlphaPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::AlphaProperties& properties, bool inheritAlpha); - -signals: - void propertiesUpdated(const Ptcl::ChildData::AlphaProperties& properties); - void inheritAlphaUpdated(bool inherit); + explicit ChildAlphaInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::ChildData::AlphaProperties mProps{}; - QDoubleSpinBox mAlphaSpinBox{}; QDoubleSpinBox mAlphaTargetSpinBox{}; QDoubleSpinBox mAlphaInitSpinBox{}; diff --git a/include/editor/childEditor/colorPropertiesWidget.h b/include/editor/inspector/child/childColorInspector.h similarity index 52% rename from include/editor/childEditor/colorPropertiesWidget.h rename to include/editor/inspector/child/childColorInspector.h index 231d2a2..d6db69a 100644 --- a/include/editor/childEditor/colorPropertiesWidget.h +++ b/include/editor/inspector/child/childColorInspector.h @@ -1,7 +1,7 @@ #pragma once #include "editor/components/rgbaColorWidget.h" -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -13,23 +13,16 @@ namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::ColorPropertiesWidget final : public QWidget { +class ChildColorInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit ColorPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::ColorProperties& properties, bool inheritColor); - -signals: - void propertiesUpdated(const Ptcl::ChildData::ColorProperties& properties); - void inheritColorUpdated(bool inherit); + explicit ChildColorInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::ChildData::ColorProperties mProps{}; - RGBAColorWidget mColor0Widget{}; RGBAColorWidget mColor1Widget{}; QCheckBox mInheritColorCheckBox{}; diff --git a/include/editor/childEditor/combinerPropertiesWidget.h b/include/editor/inspector/child/childCombinerInspector.h similarity index 52% rename from include/editor/childEditor/combinerPropertiesWidget.h rename to include/editor/inspector/child/childCombinerInspector.h index 8377a13..607fa2e 100644 --- a/include/editor/childEditor/combinerPropertiesWidget.h +++ b/include/editor/inspector/child/childCombinerInspector.h @@ -2,32 +2,27 @@ #include "editor/components/combinerPreviewWidget.h" #include "editor/components/enumComboBox.h" -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include + namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::CombinerPropertiesWidget final : public QWidget { +class ChildCombinerInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit CombinerPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::CombinerProperties& properties); - void setCombinerSrc(const Ptcl::TextureHandle* texture, const Ptcl::binColor3f* constant, const Ptcl::binColor4f* primary); - - void updateCombinerPreview(); - -signals: - void propertiesUpdated(const Ptcl::ChildData::CombinerProperties& properties); + explicit ChildCombinerInspector(QWidget* parent = nullptr); private: - Ptcl::ChildData::CombinerProperties mProps{}; + void populateProperties() final; + void setupConnections(); +private: EnumComboBox mBlendFuncComboBox{}; EnumComboBox mDepthFuncComboBox{}; EnumComboBox mCombinerFuncComboBox{}; diff --git a/include/editor/childEditor/emissionPropertiesWidget.h b/include/editor/inspector/child/childEmissionInspector.h similarity index 57% rename from include/editor/childEditor/emissionPropertiesWidget.h rename to include/editor/inspector/child/childEmissionInspector.h index 5eaf39e..b5f17b0 100644 --- a/include/editor/childEditor/emissionPropertiesWidget.h +++ b/include/editor/inspector/child/childEmissionInspector.h @@ -1,9 +1,9 @@ #pragma once -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include -#include +#include #include @@ -13,22 +13,16 @@ namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::EmissionPropertiesWidget final : public QWidget { +class ChildEmissionInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit EmissionPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::EmissionProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::ChildData::EmissionProperties& properties); + explicit ChildEmissionInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::ChildData::EmissionProperties mProps{}; - QSpinBox mEmitRateSpinBox{}; QSpinBox mEmitTimingSpinBox{}; QSpinBox mLifeSpinBox{}; diff --git a/include/editor/childEditor/basicPropertiesWidget.h b/include/editor/inspector/child/childGeneralInspector.h similarity index 58% rename from include/editor/childEditor/basicPropertiesWidget.h rename to include/editor/inspector/child/childGeneralInspector.h index e910c8c..8744cbd 100644 --- a/include/editor/childEditor/basicPropertiesWidget.h +++ b/include/editor/inspector/child/childGeneralInspector.h @@ -1,6 +1,6 @@ #pragma once -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -13,23 +13,14 @@ namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::BasicPropertiesWidget final : public QWidget { +class ChildGeneralInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit BasicPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::BasicProperties& properties, bool isFollow, bool isParentField, bool isPreDraw); - -signals: - void propertiesUpdated(const Ptcl::ChildData::BasicProperties& properties); - void isFollowUpdated(bool isFollow); - void isParentFieldUpdated(bool isField); - void isPolygonUpdated(bool isPolygon); - void isPreDrawUpdated(bool isPreDraw); + explicit ChildGeneralInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); - void populateBillboardType(); private: static constexpr std::array sChildBillboardTypes{ @@ -47,10 +38,9 @@ class ChildEditorWidget::BasicPropertiesWidget final : public QWidget { }; private: - Ptcl::ChildData::BasicProperties mProps{}; - QComboBox mBillboardComboBox{}; QComboBox mDrawOrderComboBox{}; + QCheckBox mEnabledCheckBox{}; QCheckBox mFollowCheckBox{}; QCheckBox mParentFieldCheckBox{}; }; diff --git a/include/editor/childEditor/rotationPropertiesWidget.h b/include/editor/inspector/child/childRotationInspector.h similarity index 63% rename from include/editor/childEditor/rotationPropertiesWidget.h rename to include/editor/inspector/child/childRotationInspector.h index 38a1be7..3b25a73 100644 --- a/include/editor/childEditor/rotationPropertiesWidget.h +++ b/include/editor/inspector/child/childRotationInspector.h @@ -2,7 +2,7 @@ #include "editor/components/enumComboBox.h" #include "editor/components/vectorSpinBox.h" -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -15,24 +15,17 @@ namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::RotationPropertiesWidget final : public QWidget { +class ChildRotationInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit RotationPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::RotationProperties& properties, bool inheritRotation); - -signals: - void propertiesUpdated(const Ptcl::ChildData::RotationProperties& properties); - void inheritRotationUpdated(bool inherit); + explicit ChildRotationInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); void updateAxis(); private: - Ptcl::ChildData::RotationProperties mProps{}; - EnumComboBox mRotTypeSpinBox{}; VectorSpinBox mInitRotSpinBox{}; VectorSpinBox mInitRotRandSpinBox{}; diff --git a/include/editor/childEditor/scalePropertiesWidget.h b/include/editor/inspector/child/childScaleInspector.h similarity index 58% rename from include/editor/childEditor/scalePropertiesWidget.h rename to include/editor/inspector/child/childScaleInspector.h index 7cb83f9..9e61e74 100644 --- a/include/editor/childEditor/scalePropertiesWidget.h +++ b/include/editor/inspector/child/childScaleInspector.h @@ -1,7 +1,7 @@ #pragma once #include "editor/components/vectorSpinBox.h" -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -15,23 +15,16 @@ namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::ScalePropertiesWidget final : public QWidget { +class ChildScaleInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit ScalePropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::ScaleProperties& properties, bool inheritScale); - -signals: - void propertiesUpdated(const Ptcl::ChildData::ScaleProperties& properties); - void inheritScaleUpdated(bool inherit); + explicit ChildScaleInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::ChildData::ScaleProperties mProps{}; - VectorSpinBox mScaleSpinBox{}; VectorSpinBox mScaleTargetSpinBox{}; QDoubleSpinBox mInheritRateSpinBox{}; diff --git a/include/editor/childEditor/texturePropertiesWidget.h b/include/editor/inspector/child/childTextureInspector.h similarity index 54% rename from include/editor/childEditor/texturePropertiesWidget.h rename to include/editor/inspector/child/childTextureInspector.h index b84ba85..7390993 100644 --- a/include/editor/childEditor/texturePropertiesWidget.h +++ b/include/editor/inspector/child/childTextureInspector.h @@ -3,7 +3,7 @@ #include "editor/components/enumComboBox.h" #include "editor/components/thumbnailWidget.h" #include "editor/components/vectorSpinBox.h" -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include @@ -14,30 +14,19 @@ namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::TexturePropertiesWidget final : public QWidget { +class ChildTextureInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit TexturePropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::TextureProperties& properties, const std::shared_ptr& texture); - void setTextureList(const Ptcl::TextureList* textureList); - -signals: - void propertiesUpdated(const Ptcl::ChildData::TextureProperties& properties); - void textureUpdated(const std::shared_ptr& oldTexture, const std::shared_ptr& newTexture); + explicit ChildTextureInspector(QWidget* parent = nullptr); private slots: void changeTexture(); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::ChildData::TextureProperties mProps{}; - std::shared_ptr mTexture{}; - - const Ptcl::TextureList* mTextureList{nullptr}; - ThumbnailWidget mTexturePreview{}; EnumComboBox mWrapTComboBox{}; diff --git a/include/editor/childEditor/velocityPropertiesWidget.h b/include/editor/inspector/child/childVelocityInspector.h similarity index 60% rename from include/editor/childEditor/velocityPropertiesWidget.h rename to include/editor/inspector/child/childVelocityInspector.h index b10c1f1..3c593dc 100644 --- a/include/editor/childEditor/velocityPropertiesWidget.h +++ b/include/editor/inspector/child/childVelocityInspector.h @@ -1,7 +1,7 @@ #pragma once #include "editor/components/vectorSpinBox.h" -#include "editor/childEditor/childEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -14,23 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class ChildEditorWidget::VelocityPropertiesWidget final : public QWidget { +class ChildVelocityInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit VelocityPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::ChildData::VelocityProperties& properties, bool inheritVelocity); - -signals: - void propertiesUpdated(const Ptcl::ChildData::VelocityProperties& properties); - void inheritVelUpdated(bool inherit); + explicit ChildVelocityInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::ChildData::VelocityProperties mProps{}; - VectorSpinBox mRandVelSpinBox{}; VectorSpinBox mGravitySpinBox{}; QDoubleSpinBox mVelInheritSpinBox{}; diff --git a/include/editor/emitterWidget/colorPropertiesWidget.h b/include/editor/inspector/colorInspector.h similarity index 53% rename from include/editor/emitterWidget/colorPropertiesWidget.h rename to include/editor/inspector/colorInspector.h index ab7932f..75b0e62 100644 --- a/include/editor/emitterWidget/colorPropertiesWidget.h +++ b/include/editor/inspector/colorInspector.h @@ -4,9 +4,7 @@ #include "editor/components/enumComboBox.h" #include "editor/components/rgbaColorWidget.h" #include "editor/components/sizedSpinBox.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -20,7 +18,7 @@ namespace PtclEditor { enum class Behavior { Constant = 0, Random = 1, Animation = 2 }; -static Behavior behaviorFromIndex(int index) { +static Behavior behaviorFromIndex(s32 index) { switch (index) { case 1: return Behavior::Random; case 2: return Behavior::Animation; @@ -28,48 +26,49 @@ static Behavior behaviorFromIndex(int index) { } } -static int behaviorToIndex(Behavior behavior) { - return static_cast(behavior); +static s32 behaviorToIndex(Behavior behavior) { + return static_cast(behavior); } // ========================================================================== // -class EmitterWidget::ColorPropertiesWidget final : public QWidget { +class ColorInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit ColorPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::ColorProperties& properties); - void populateWidgets(); - -signals: - void propertiesUpdated(const Ptcl::Emitter::ColorProperties& properties); + explicit ColorInspector(QWidget* parent = nullptr); private slots: - void handleColorChanged(); void updateColorSection(ColorGradientEditor::HandleType handleType); - void handleBehaviorChanged(int index); + void handleBehaviorChanged(s32 index); private: - void updateUiFromFlags(); - void applyBehaviorToUI(Behavior behavior); - void showColorWidgets(std::array visibility); - void setColorLabels(const std::array& labels); + void populateProperties() final; + void setupConnections(); private: - Ptcl::Emitter::ColorProperties mProps{}; - QComboBox mColorBehavior{}; - std::array mColorLabels; - std::array mColor0Widgets; + + RGBAColorWidget mPrimaryColorWidget{}; + QWidget* mPrimaryColorUi{nullptr}; + + RGBAColorWidget mRandomColorAWidget{}; + RGBAColorWidget mRandomColorBWidget{}; + RGBAColorWidget mRandomColorCWidget{}; + QWidget* mRandomColorUi{nullptr}; + + RGBAColorWidget mStartColorWidget{}; + RGBAColorWidget mMidColorWidget{}; + RGBAColorWidget mEndColorWidget{}; + QWidget* mAnimColorUi{nullptr}; + + RGBAColorWidget mSecondaryColorWidget{}; + ColorGradientEditor mColorSections{}; SizedSpinBox mColorNumRepeatSpinBox{}; QLabel mRepetitionCountLabel{}; EnumComboBox mColorCalcTypeSpinBox{}; - - RGBAColorWidget mColor1Widget{}; }; diff --git a/include/editor/emitterWidget/combinerPropertiesWidget.h b/include/editor/inspector/combinerInspector.h similarity index 53% rename from include/editor/emitterWidget/combinerPropertiesWidget.h rename to include/editor/inspector/combinerInspector.h index 9c7192b..b614720 100644 --- a/include/editor/emitterWidget/combinerPropertiesWidget.h +++ b/include/editor/inspector/combinerInspector.h @@ -2,9 +2,7 @@ #include "editor/components/combinerPreviewWidget.h" #include "editor/components/enumComboBox.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -16,22 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class EmitterWidget::CombinerPropertiesWidget final : public QWidget { +class CombinerInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit CombinerPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::CombinerProperties& properties); - void setCombinerSrc(const Ptcl::TextureHandle* texture, const Ptcl::binColor3f* constant, const Ptcl::binColor4f* primary); - - void updateCombinerPreview(); - -signals: - void propertiesUpdated(const Ptcl::Emitter::CombinerProperties& properties); + explicit CombinerInspector(QWidget* parent = nullptr); private: - Ptcl::Emitter::CombinerProperties mProps{}; + void populateProperties() final; + void setupConnections(); +private: QCheckBox mFogCheckBox{}; EnumComboBox mBlendFuncComboBox{}; EnumComboBox mDepthFuncComboBox{}; diff --git a/include/editor/inspector/emissionInspector.h b/include/editor/inspector/emissionInspector.h new file mode 100644 index 0000000..337d8a2 --- /dev/null +++ b/include/editor/inspector/emissionInspector.h @@ -0,0 +1,41 @@ +#pragma once + +#include "editor/inspector/inspectorWidgetBase.h" + +#include +#include +#include +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +class EmissionInspector final : public InspectorWidgetBase { + Q_OBJECT +public: + explicit EmissionInspector(QWidget* parent = nullptr); + +private: + void populateProperties() final; + void setupConnections(); + +private: + QSpinBox mStartFrameSpinBox{}; + QSpinBox mEndFrameSpinBox{}; + QCheckBox mInfiniteEmitCheckBox{}; + QSpinBox mLifeStepSpinBox{}; + QSpinBox mLifeStepRndSpinBox{}; + QSpinBox mEmitRateSpinBox{}; + + static constexpr s32 sEmitInfinite = std::numeric_limits::max(); +}; + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/include/editor/emitterSetWidget.h b/include/editor/inspector/emitterSetInspector.h similarity index 56% rename from include/editor/emitterSetWidget.h rename to include/editor/inspector/emitterSetInspector.h index a2dfeb0..b33535b 100644 --- a/include/editor/emitterSetWidget.h +++ b/include/editor/inspector/emitterSetInspector.h @@ -1,6 +1,7 @@ #pragma once -#include "components/sizedSpinBox.h" +#include "editor/components/sizedSpinBox.h" +#include "ptcl/ptclDocument.h" #include "ptcl/ptclEmitterSet.h" #include @@ -14,25 +15,22 @@ namespace PtclEditor { // ========================================================================== // -class EmitterSetWidget final : public QWidget { +class EmitterSetInspector final : public QWidget { Q_OBJECT public: - explicit EmitterSetWidget(QWidget* parent = nullptr); + explicit EmitterSetInspector(QWidget* parent = nullptr); - void setEmitterSet(Ptcl::EmitterSet* emitterSet); - void clear(); - -signals: - void emitterSetNamedChanged(); - void propertiesChanged(); + void setDocument(Ptcl::Document* document); + void setSelection(Ptcl::Selection* selection); private: void populateProperties(); void setupConnections(); private: - Ptcl::EmitterSet* mEmitterSetPtr{nullptr}; - s32 mCurEmitterIdx{}; + Ptcl::Document* mDocument{nullptr}; + const Ptcl::Selection* mSelection{nullptr}; + const Ptcl::EmitterSet* mEmitterSet{nullptr}; QLineEdit mNameLineEdit{}; SizedSpinBox mUserDataSpinBox{}; diff --git a/include/editor/fieldEditor/collisionDataWidget.h b/include/editor/inspector/field/fieldCollisionInspector.h similarity index 60% rename from include/editor/fieldEditor/collisionDataWidget.h rename to include/editor/inspector/field/fieldCollisionInspector.h index 0cb60be..3467e8f 100644 --- a/include/editor/fieldEditor/collisionDataWidget.h +++ b/include/editor/inspector/field/fieldCollisionInspector.h @@ -1,7 +1,7 @@ #pragma once #include "editor/components/enumComboBox.h" -#include "editor/fieldEditor/fieldEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -14,23 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class FieldEditorWidget::CollisionDataWidget final : public QWidget { +class FieldCollisionInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit CollisionDataWidget(QWidget* parent = nullptr); - - void setData(const Ptcl::FieldData::FieldCollisionData& data, bool isEnabled); - -signals: - void dataUpdated(const Ptcl::FieldData::FieldCollisionData& data); - void isEnabledUpdated(bool isEnabled); + explicit FieldCollisionInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::FieldData::FieldCollisionData mData{}; - QWidget* mControlsWidget{nullptr}; EnumComboBox mCollisionTypeSpinBox{}; QCheckBox mIsWorldCheckBox{}; diff --git a/include/editor/fieldEditor/convergenceDataWidget.h b/include/editor/inspector/field/fieldConvergenceInspector.h similarity index 58% rename from include/editor/fieldEditor/convergenceDataWidget.h rename to include/editor/inspector/field/fieldConvergenceInspector.h index 099db12..c1e9228 100644 --- a/include/editor/fieldEditor/convergenceDataWidget.h +++ b/include/editor/inspector/field/fieldConvergenceInspector.h @@ -2,7 +2,7 @@ #include "editor/components/enumComboBox.h" #include "editor/components/vectorSpinBox.h" -#include "editor/fieldEditor/fieldEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -15,23 +15,16 @@ namespace PtclEditor { // ========================================================================== // -class FieldEditorWidget::ConvergenceDataWidget final : public QWidget { +class FieldConvergenceInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit ConvergenceDataWidget(QWidget* parent = nullptr); - - void setData(const Ptcl::FieldData::FieldConvergenceData& data, bool isEnabled); - -signals: - void dataUpdated(const Ptcl::FieldData::FieldConvergenceData& data); - void isEnabledUpdated(bool isEnabled); + explicit FieldConvergenceInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::FieldData::FieldConvergenceData mData{}; - QWidget* mControlsWidget{nullptr}; EnumComboBox mTypeSpinBox{}; VectorSpinBox mPosSpinBox{}; diff --git a/include/editor/fieldEditor/magnetDataWidget.h b/include/editor/inspector/field/fieldMagnetInspector.h similarity index 61% rename from include/editor/fieldEditor/magnetDataWidget.h rename to include/editor/inspector/field/fieldMagnetInspector.h index 070f323..21b2fdc 100644 --- a/include/editor/fieldEditor/magnetDataWidget.h +++ b/include/editor/inspector/field/fieldMagnetInspector.h @@ -1,7 +1,7 @@ #pragma once #include "editor/components/vectorSpinBox.h" -#include "editor/fieldEditor/fieldEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -14,23 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class FieldEditorWidget::MagnetDataWidget final : public QWidget { +class FieldMagnetInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit MagnetDataWidget(QWidget* parent = nullptr); - - void setData(const Ptcl::FieldData::FieldMagnetData& data, bool isEnabled); - -signals: - void dataUpdated(const Ptcl::FieldData::FieldMagnetData& data); - void isEnabledUpdated(bool isEnabled); + explicit FieldMagnetInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::FieldData::FieldMagnetData mData{}; - QWidget* mControlsWidget{nullptr}; QDoubleSpinBox mMagnetPowerSpinBox{}; VectorSpinBox mMagnetPosSpinBox{}; diff --git a/include/editor/fieldEditor/posAddDataWidget.h b/include/editor/inspector/field/fieldPosAddInspector.h similarity index 56% rename from include/editor/fieldEditor/posAddDataWidget.h rename to include/editor/inspector/field/fieldPosAddInspector.h index a69fa25..7d27ce6 100644 --- a/include/editor/fieldEditor/posAddDataWidget.h +++ b/include/editor/inspector/field/fieldPosAddInspector.h @@ -1,7 +1,7 @@ #pragma once #include "editor/components/vectorSpinBox.h" -#include "editor/fieldEditor/fieldEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -14,23 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class FieldEditorWidget::PosAddDataWidget final : public QWidget { +class FieldPosAddInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit PosAddDataWidget(QWidget* parent = nullptr); - - void setData(const Ptcl::FieldData::FieldPosAddData& data, bool isEnabled); - -signals: - void dataUpdated(const Ptcl::FieldData::FieldPosAddData& data); - void isEnabledUpdated(bool isEnabled); + explicit FieldPosAddInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::FieldData::FieldPosAddData mData{}; - QWidget* mControlsWidget{nullptr}; VectorSpinBox mPosSpinBox{}; QCheckBox mEnabledCheckBox{}; diff --git a/include/editor/fieldEditor/randomDataWidget.h b/include/editor/inspector/field/fieldRandomInspector.h similarity index 57% rename from include/editor/fieldEditor/randomDataWidget.h rename to include/editor/inspector/field/fieldRandomInspector.h index a047a0a..bc58486 100644 --- a/include/editor/fieldEditor/randomDataWidget.h +++ b/include/editor/inspector/field/fieldRandomInspector.h @@ -1,7 +1,7 @@ #pragma once #include "editor/components/vectorSpinBox.h" -#include "editor/fieldEditor/fieldEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -14,23 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class FieldEditorWidget::RandomDataWidget final : public QWidget { +class FieldRandomInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit RandomDataWidget(QWidget* parent = nullptr); - - void setData(const Ptcl::FieldData::FieldRandomData& data, bool isEnabled); - -signals: - void dataUpdated(const Ptcl::FieldData::FieldRandomData& data); - void isEnabledUpdated(bool isEnabled); + explicit FieldRandomInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::FieldData::FieldRandomData mData{}; - QWidget* mControlsWidget{nullptr}; QSpinBox mRandomBlankSpinBox{}; VectorSpinBox mRandomVelAddSpinBox{}; diff --git a/include/editor/fieldEditor/spinDataWidget.h b/include/editor/inspector/field/fieldSpinInspector.h similarity index 58% rename from include/editor/fieldEditor/spinDataWidget.h rename to include/editor/inspector/field/fieldSpinInspector.h index a09a0e0..f1580b0 100644 --- a/include/editor/fieldEditor/spinDataWidget.h +++ b/include/editor/inspector/field/fieldSpinInspector.h @@ -1,7 +1,7 @@ #pragma once #include "editor/components/enumComboBox.h" -#include "editor/fieldEditor/fieldEditorWidget.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -14,23 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class FieldEditorWidget::SpinDataWidget final : public QWidget { +class FieldSpinInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit SpinDataWidget(QWidget* parent = nullptr); - - void setData(const Ptcl::FieldData::FieldSpinData& data, bool isEnabled); - -signals: - void dataUpdated(const Ptcl::FieldData::FieldSpinData& data); - void isEnabledUpdated(bool isEnabled); + explicit FieldSpinInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::FieldData::FieldSpinData mData{}; - QWidget* mControlsWidget{nullptr}; QDoubleSpinBox mSpinRotateSpinBox{}; EnumComboBox mSpinAxisSpinBox{}; diff --git a/include/editor/fluctuationEditorWidget.h b/include/editor/inspector/fluctuationInspector.h similarity index 54% rename from include/editor/fluctuationEditorWidget.h rename to include/editor/inspector/fluctuationInspector.h index 5ea3ec0..e5af2bf 100644 --- a/include/editor/fluctuationEditorWidget.h +++ b/include/editor/inspector/fluctuationInspector.h @@ -1,8 +1,6 @@ #pragma once -#include "ptcl/ptclEnum.h" -#include "ptcl/ptclFluctuationData.h" -#include "util/bitflagUtil.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -16,24 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class FluctuationEditorWidget final : public QWidget { +class FluctuationInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit FluctuationEditorWidget(QWidget* parent = nullptr); - - void setData(const Ptcl::FluctuationData& data, const BitFlag& fluxFlag); - -signals: - void dataUpdated(const Ptcl::FluctuationData& data); - void flagsUpdated(const BitFlag& fluxFlags); + explicit FluctuationInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::FluctuationData mData{}; - BitFlag mFluxFlag{}; - QWidget* mControlsContainer{nullptr}; QDoubleSpinBox mScaleSpinBox{}; QDoubleSpinBox mFreqSpinBox{}; diff --git a/include/editor/emitterWidget/basicPropertiesWidget.h b/include/editor/inspector/generalEmitterInspector.h similarity index 76% rename from include/editor/emitterWidget/basicPropertiesWidget.h rename to include/editor/inspector/generalEmitterInspector.h index 21ae272..f253539 100644 --- a/include/editor/emitterWidget/basicPropertiesWidget.h +++ b/include/editor/inspector/generalEmitterInspector.h @@ -2,9 +2,7 @@ #include "editor/components/enumComboBox.h" #include "editor/components/sizedSpinBox.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -18,7 +16,7 @@ namespace PtclEditor { // ========================================================================== // -class EmitterWidget::BasicPropertiesWidget final : public QWidget { +class GeneralEmitterInspector final : public InspectorWidgetBase { Q_OBJECT private: static constexpr std::array sBillboardTypes{ @@ -42,29 +40,22 @@ class EmitterWidget::BasicPropertiesWidget final : public QWidget { }; public: - explicit BasicPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::BasicProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::BasicProperties& properties); - void emitterTypeChanged(); - void emitterNameChanged(); + explicit GeneralEmitterInspector(QWidget* parent = nullptr); private: + void populateProperties() final; + void setupConnections(); void updateShapeRowVisibility(); void updateBillboardRowVisibility(); void syncBillboardSelection(); - void applyBillboardType(Ptcl::BillboardType type); + void setBillboardType(Ptcl::BillboardType type, const QString& label, const QString& key); static bool isBillboardAllowedForShape(Ptcl::BillboardType billboard, ShapeType shape); static ShapeType shapeFromBillboard(Ptcl::BillboardType type); private: - Ptcl::Emitter::BasicProperties mProps{}; - QFormLayout* mMainLayout{nullptr}; QLineEdit mNameLineEdit{}; diff --git a/include/editor/emitterWidget/gravityPropertiesWidget.h b/include/editor/inspector/gravityInspector.h similarity index 51% rename from include/editor/emitterWidget/gravityPropertiesWidget.h rename to include/editor/inspector/gravityInspector.h index b32eb1d..38753f8 100644 --- a/include/editor/emitterWidget/gravityPropertiesWidget.h +++ b/include/editor/inspector/gravityInspector.h @@ -1,9 +1,7 @@ #pragma once #include "editor/components/vectorSpinBox.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -15,22 +13,18 @@ namespace PtclEditor { // ========================================================================== // -class EmitterWidget::GravityPropertiesWidget final : public QWidget { +class GravityInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit GravityPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::GravityProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::GravityProperties& properties); + explicit GravityInspector(QWidget* parent = nullptr); private: - Ptcl::Emitter::GravityProperties mProps{}; + void populateProperties() final; + void setupConnections(); +private: QCheckBox mIsDirectionalCheckBox{}; VectorSpinBox mGravitySpinBox{}; - }; diff --git a/include/editor/inspector/inspectorPanel.h b/include/editor/inspector/inspectorPanel.h new file mode 100644 index 0000000..2fe70e3 --- /dev/null +++ b/include/editor/inspector/inspectorPanel.h @@ -0,0 +1,128 @@ +#pragma once + +#include "ptcl/ptclDocument.h" +#include "ptcl/ptclEmitter.h" + +#include +#include +#include +#include + + +namespace PtclEditor { + +class EmitterSetInspector; + +class GeneralEmitterInspector; +class GravityInspector; +class TransformInspector; +class LifespanInspector; +class ScaleAnimInspector; +class TerminationInspector; +class EmissionInspector; +class VelocityInspector; +class VolumeInspector; +class RotationInspector; +class AlphaAnimInspector; +class CombinerInspector; +class ColorInspector; +class TextureInspector; +class StripeInspector; + +class FluctuationInspector; + +class FieldCollisionInspector; +class FieldConvergenceInspector; +class FieldMagnetInspector; +class FieldPosAddInspector; +class FieldRandomInspector; +class FieldSpinInspector; + +class ChildAlphaInspector; +class ChildColorInspector; +class ChildCombinerInspector; +class ChildEmissionInspector; +class ChildGeneralInspector; +class ChildRotationInspector; +class ChildScaleInspector; +class ChildTextureInspector; +class ChildVelocityInspector; + + +// ========================================================================== // + + +class InspectorPanel final : public QWidget { + Q_OBJECT +public: + explicit InspectorPanel(QWidget* parent = nullptr); + + void setDocument(Ptcl::Document* document); + void setSelection(Ptcl::Selection* selection); + +private: + void setupConnections(); + void populateProperties(); + + void buildTabs(); + void updateTabVisibility(); + +private: + Ptcl::Document* mDocument{nullptr}; + const Ptcl::Selection* mSelection{nullptr}; + const Ptcl::Emitter* mEmitter{nullptr}; + + QLineEdit* mProjNameLineEdit{nullptr}; + + EmitterSetInspector* mEmitterSetInspector{nullptr}; + + GeneralEmitterInspector* mGeneralInspector{nullptr}; + GravityInspector* mGravityInspector{nullptr}; + TransformInspector* mTransformInspector{nullptr}; + LifespanInspector* mLifespanInspector{nullptr}; + TerminationInspector* mTerminationInspector{nullptr}; + EmissionInspector* mEmissionInspector{nullptr}; + VelocityInspector* mVelocityInspector{nullptr}; + VolumeInspector* mVolumeInspector{nullptr}; + ColorInspector* mColorInspector{nullptr}; + AlphaAnimInspector* mAlphaAnimInspector{nullptr}; + RotationInspector* mRotationInspector{nullptr}; + ScaleAnimInspector* mScaleAnimInspector{nullptr}; + TextureInspector* mTextureInspector{nullptr}; + CombinerInspector* mCombinerInspector{nullptr}; + StripeInspector* mStripeInspector{nullptr}; + + FluctuationInspector* mFluctuationInspector{nullptr}; + + FieldCollisionInspector* mFieldCollisionInspector{nullptr}; + FieldConvergenceInspector* mFieldConvergenceInspector{nullptr}; + FieldMagnetInspector* mFieldMagnetInspector{nullptr}; + FieldPosAddInspector* mFieldPosAddInspector{nullptr}; + FieldRandomInspector* mFieldRandomInspector{nullptr}; + FieldSpinInspector* mFieldSpinInspector{nullptr}; + + ChildAlphaInspector* mChildAlphaInspector{nullptr}; + ChildColorInspector* mChildColorInspector{nullptr}; + ChildCombinerInspector* mChildCombinerInspector{nullptr}; + ChildEmissionInspector* mChildEmissionInspector{nullptr}; + ChildGeneralInspector* mChildGeneralInspector{nullptr}; + ChildRotationInspector* mChildRotationInspector{nullptr}; + ChildScaleInspector* mChildScaleInspector{nullptr}; + ChildTextureInspector* mChildTextureInspector{nullptr}; + ChildVelocityInspector* mChildVelocityInspector{nullptr}; + + QStackedWidget* mTabStack{nullptr}; + QTabWidget* mEmitterSetTabs{nullptr}; + QTabWidget* mEmitterTabs{nullptr}; + QTabWidget* mChildTabs{nullptr}; + QTabWidget* mFieldTabs{nullptr}; + QTabWidget* mFluxTabs{nullptr}; + + Ptcl::Selection::Type mLastSelectionType{}; +}; + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/include/editor/inspector/inspectorWidgetBase.h b/include/editor/inspector/inspectorWidgetBase.h new file mode 100644 index 0000000..c9e8277 --- /dev/null +++ b/include/editor/inspector/inspectorWidgetBase.h @@ -0,0 +1,51 @@ +#pragma once + +#include "ptcl/ptclEmitter.h" +#include "ptcl/ptclDocument.h" + +#include +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +class InspectorWidgetBase : public QWidget { + Q_OBJECT +public: + explicit InspectorWidgetBase(QWidget* parent = nullptr); + + virtual void setDocument(Ptcl::Document* document); + virtual void setSelection(Ptcl::Selection* selection); + +protected: + virtual void populateProperties() = 0; + + QString formatHistoryLabel(const QString& label) const; + + template + void setEmitterProperty(const QString& label, QString key, Getter getter, Setter setter, const T& value) { + if (!mDocument || !mSelection) { + return; + } + + mDocument->setEmitterProperty(mSelection->emitterSetIndex(), mSelection->emitterIndex(), formatHistoryLabel(label), key, getter, setter, value); + } + +protected slots: + virtual void onEmitterChanged(s32 setIndex, s32 emitterIndex); + +protected: + Ptcl::Document* mDocument{nullptr}; + const Ptcl::Selection* mSelection{nullptr}; + const Ptcl::Emitter* mEmitter{nullptr}; +}; + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/include/editor/emitterWidget/lifespanPropertiesWidget.h b/include/editor/inspector/lifespanInspector.h similarity index 55% rename from include/editor/emitterWidget/lifespanPropertiesWidget.h rename to include/editor/inspector/lifespanInspector.h index 6ab5b77..33e81e4 100644 --- a/include/editor/emitterWidget/lifespanPropertiesWidget.h +++ b/include/editor/inspector/lifespanInspector.h @@ -1,8 +1,6 @@ #pragma once -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -16,19 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class EmitterWidget::LifespanPropertiesWidget final : public QWidget { +class LifespanInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit LifespanPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::LifespanProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::LifespanProperties& properties); + explicit LifespanInspector(QWidget* parent = nullptr); private: - Ptcl::Emitter::LifespanProperties mProps{}; + void populateProperties() final; + void setupConnections(); +private: QCheckBox mInfiniteLifeCheckBox; QSpinBox mLifeSpanSpinBox; QSpinBox mLifeSpanRndSpinBox; diff --git a/include/editor/emitterWidget/rotationPropertiesWidget.h b/include/editor/inspector/rotationInspector.h similarity index 62% rename from include/editor/emitterWidget/rotationPropertiesWidget.h rename to include/editor/inspector/rotationInspector.h index 637ea69..81e7eea 100644 --- a/include/editor/emitterWidget/rotationPropertiesWidget.h +++ b/include/editor/inspector/rotationInspector.h @@ -2,9 +2,7 @@ #include "editor/components/enumComboBox.h" #include "editor/components/vectorSpinBox.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -17,23 +15,17 @@ namespace PtclEditor { // ========================================================================== // -class EmitterWidget::RotationPropertiesWidget final : public QWidget { +class RotationInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit RotationPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::RotationProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::RotationProperties& properties); + explicit RotationInspector(QWidget* parent = nullptr); private: - void populateWidgets(); + void populateProperties() final; + void setupConnections(); void updateAxis(); private: - Ptcl::Emitter::RotationProperties mProps{}; - EnumComboBox mRotTypeSpinBox{}; VectorSpinBox mInitRotSpinBox{}; VectorSpinBox mInitRotRandSpinBox{}; diff --git a/include/editor/emitterWidget/scalePropertiesWidget.h b/include/editor/inspector/scaleAnimInspector.h similarity index 57% rename from include/editor/emitterWidget/scalePropertiesWidget.h rename to include/editor/inspector/scaleAnimInspector.h index 5eaedf2..fb003a4 100644 --- a/include/editor/emitterWidget/scalePropertiesWidget.h +++ b/include/editor/inspector/scaleAnimInspector.h @@ -1,9 +1,7 @@ #pragma once #include "editor/components/animGraph.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include @@ -14,28 +12,23 @@ namespace PtclEditor { // ========================================================================== // -class EmitterWidget::ScalePropertiesWidget final : public QWidget { +class ScaleAnimInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit ScalePropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::ScaleProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::ScaleProperties& properties); + explicit ScaleAnimInspector(QWidget* parent = nullptr); private: + void populateProperties() final; + void setupConnections(); + void updateAnimPoint(s32 pointIndex, const AnimGraph::GraphPoint& point, f32 (Math::Vector2f::*get)() const); void updateGraphs(); private: - Ptcl::Emitter::ScaleProperties mProps{}; - AnimGraph mGraphX{}; AnimGraph mGraphY{}; QDoubleSpinBox mRandSpinbox{}; - }; diff --git a/include/editor/stripeEditorWidget.h b/include/editor/inspector/stripeInspector.h similarity index 60% rename from include/editor/stripeEditorWidget.h rename to include/editor/inspector/stripeInspector.h index 2c6661a..0b498d1 100644 --- a/include/editor/stripeEditorWidget.h +++ b/include/editor/inspector/stripeInspector.h @@ -1,9 +1,7 @@ #pragma once #include "editor/components/vectorSpinBox.h" -#include "ptcl/ptclEnum.h" -#include "ptcl/ptclStripeData.h" -#include "util/bitflagUtil.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -18,24 +16,16 @@ namespace PtclEditor { // ========================================================================== // -class StripeEditorWidget final : public QWidget { +class StripeInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit StripeEditorWidget(QWidget* parent = nullptr); - - void setData(const Ptcl::StripeData& data, const BitFlag& stripeFlag); - -signals: - void dataUpdated(const Ptcl::StripeData& data); - void flagsUpdated(const BitFlag& stripeFlags); + explicit StripeInspector(QWidget* parent = nullptr); private: + void populateProperties() final; void setupConnections(); private: - Ptcl::StripeData mData{}; - BitFlag mStripeFlag{}; - QComboBox mTypeComboBox{}; QSpinBox mNumHistSpinBox{}; QDoubleSpinBox mStartAlphaSpinBox{}; @@ -46,6 +36,7 @@ class StripeEditorWidget final : public QWidget { QCheckBox mEmitterCoordCheckBox{}; }; + // ========================================================================== // diff --git a/include/editor/inspector/terminationInspector.h b/include/editor/inspector/terminationInspector.h new file mode 100644 index 0000000..84cebad --- /dev/null +++ b/include/editor/inspector/terminationInspector.h @@ -0,0 +1,35 @@ +#pragma once + +#include "editor/inspector/inspectorWidgetBase.h" + +#include +#include +#include +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +class TerminationInspector final : public InspectorWidgetBase { + Q_OBJECT +public: + explicit TerminationInspector(QWidget* parent = nullptr); + +private: + void populateProperties() final; + void setupConnections(); + +private: + QCheckBox mIsStopEmitCheckBox; + QDoubleSpinBox mAlphaAddInSpinBox; +}; + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/include/editor/emitterWidget/texturePropertiesWidget.h b/include/editor/inspector/textureInspector.h similarity index 68% rename from include/editor/emitterWidget/texturePropertiesWidget.h rename to include/editor/inspector/textureInspector.h index 9c22626..c657bf5 100644 --- a/include/editor/emitterWidget/texturePropertiesWidget.h +++ b/include/editor/inspector/textureInspector.h @@ -3,10 +3,7 @@ #include "editor/components/enumComboBox.h" #include "editor/components/sizedSpinBox.h" #include "editor/components/thumbnailWidget.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptcl.h" -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -20,7 +17,7 @@ namespace PtclEditor { // ========================================================================== // -class EmitterWidget::TexturePropertiesWidget final : public QWidget { +class TextureInspector final : public InspectorWidgetBase { Q_OBJECT public: enum class AnimMode { @@ -37,24 +34,16 @@ class EmitterWidget::TexturePropertiesWidget final : public QWidget { } public: - explicit TexturePropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::TextureProperties& properties, const std::shared_ptr& texture); - - void populateWidgets(); - void setTextureList(const Ptcl::TextureList* textureList); - -signals: - void propertiesUpdated(const Ptcl::Emitter::TextureProperties& properties); - void textureUpdated(const std::shared_ptr& oldTexture, const std::shared_ptr& newTexture); + explicit TextureInspector(QWidget* parent = nullptr); private slots: void changeTexture(); private: - void updateTextureDetails(); + void populateProperties() final; + void setupConnections(); + void updateTexPatTblColumns(); - void updateUVScale(); std::optional calcFrameUVOffset(s32 frame) const; QImage getFrameTexture(s32 frame) const; @@ -64,11 +53,6 @@ private slots: s32 maxFrameCount() const; private: - Ptcl::Emitter::TextureProperties mProps{}; - std::shared_ptr mTexture{}; - - const Ptcl::TextureList* mTextureList{nullptr}; - ThumbnailWidget mTexturePreview{}; EnumComboBox mWrapTComboBox{}; diff --git a/include/editor/inspector/transformInspector.h b/include/editor/inspector/transformInspector.h new file mode 100644 index 0000000..fba5492 --- /dev/null +++ b/include/editor/inspector/transformInspector.h @@ -0,0 +1,32 @@ +#pragma once + +#include "editor/components/vectorSpinBox.h" +#include "editor/inspector/inspectorWidgetBase.h" + + +namespace PtclEditor { + + +// ========================================================================== // + + +class TransformInspector final : public InspectorWidgetBase { + Q_OBJECT +public: + explicit TransformInspector(QWidget* parent = nullptr); + +private: + void populateProperties() final; + void setupConnections(); + +private: + VectorSpinBox mScaleSpinBox{}; + VectorSpinBox mRotationSpinBox{}; + VectorSpinBox mTranslationSpinBox{}; +}; + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/include/editor/emitterWidget/velocityPropertiesWidget.h b/include/editor/inspector/velocityInspector.h similarity index 60% rename from include/editor/emitterWidget/velocityPropertiesWidget.h rename to include/editor/inspector/velocityInspector.h index 8dbd46e..50ac40a 100644 --- a/include/editor/emitterWidget/velocityPropertiesWidget.h +++ b/include/editor/inspector/velocityInspector.h @@ -1,9 +1,7 @@ #pragma once #include "editor/components/vectorSpinBox.h" -#include "editor/emitterWidget/emitterWidget.h" - -#include "ptcl/ptclEmitter.h" +#include "editor/inspector/inspectorWidgetBase.h" #include #include @@ -16,19 +14,16 @@ namespace PtclEditor { // ========================================================================== // -class EmitterWidget::VelocityPropertiesWidget final : public QWidget { +class VelocityInspector final : public InspectorWidgetBase { Q_OBJECT public: - explicit VelocityPropertiesWidget(QWidget* parent = nullptr); - - void setProperties(const Ptcl::Emitter::VelocityProperties& properties); - -signals: - void propertiesUpdated(const Ptcl::Emitter::VelocityProperties& properties); + explicit VelocityInspector(QWidget* parent = nullptr); private: - Ptcl::Emitter::VelocityProperties mProps{}; + void populateProperties() final; + void setupConnections(); +private: QDoubleSpinBox mFigureVelSpinbox{}; VectorSpinBox mVelDirSpinbox{}; QDoubleSpinBox mInitVelSpinbox{}; diff --git a/include/editor/inspector/volumeInspector.h b/include/editor/inspector/volumeInspector.h new file mode 100644 index 0000000..a1698b5 --- /dev/null +++ b/include/editor/inspector/volumeInspector.h @@ -0,0 +1,52 @@ +#pragma once + +#include "editor/components/enumComboBox.h" +#include "editor/components/vectorSpinBox.h" +#include "editor/inspector/inspectorWidgetBase.h" + +#include +#include +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +class VolumeInspector final : public InspectorWidgetBase { + Q_OBJECT +public: + explicit VolumeInspector(QWidget* parent = nullptr); + +private: + void populateProperties() final; + void setupConnections(); + void setupUi(); + void updateFieldVisibility(Ptcl::VolumeType volumeType); + +private: + struct VolumeField { + QWidget* widget{}; + std::function label{}; + std::function isVisible{}; + }; + +private: + std::vector mFields{}; + std::unordered_map mFieldLabels{}; + + QComboBox mVolumeTblIndexComboBox{}; + EnumComboBox mTypeComboBox{}; + VectorSpinBox mRadiusSpinBox{}; + QDoubleSpinBox mSweepStartSpinBox{}; + QDoubleSpinBox mSweepParamSpinBox{}; + QDoubleSpinBox mLengthSpinBox{}; +}; + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/include/editor/mainWindow.h b/include/editor/mainWindow.h index c707b84..9050532 100644 --- a/include/editor/mainWindow.h +++ b/include/editor/mainWindow.h @@ -1,9 +1,7 @@ #pragma once -#include "typedefs.h" -#include "ptcl/ptcl.h" -#include "editor/emitterSetWidget.h" -#include "editor/emitterWidget/emitterWidget.h" +#include "ptcl/ptclDocument.h" +#include "editor/inspector/inspectorPanel.h" #include "editor/ptclListWidget.h" #include "editor/textureListWidget.h" @@ -15,6 +13,7 @@ #include #include #include +#include #include @@ -26,18 +25,9 @@ namespace PtclEditor { class MainWindow final : public QMainWindow { Q_OBJECT - -private: - enum class PropertiesView { - EmitterSet, - Emitter, - EmitterChild, - EmitterFlux, - EmitterField - }; - public: MainWindow(QWidget* parent = nullptr); + ~MainWindow() final; protected: void closeEvent(QCloseEvent* event) final; @@ -54,52 +44,41 @@ private slots: private: void updateRecentFileList(); void loadPtclRes(const QString& path); - void selectEmitterSet(s32 setIndex); - void selectEmitter(s32 setIndex, s32 emitterIndex); void setupUi(); - void setupConnections(); void setupMenus(); - void setPropertiesView(PropertiesView view); - void updatePropertiesStatus(); - void updateWindowTitle(); void updateStatusBar(); - void setDirty(bool dirty); -private: - std::unique_ptr mPtclRes{}; - QString mCurrentFilePath{}; + void bindUndoStack(); - s32 mCurEmitterSetIdx{}; - s32 mCurEmitterIdx{}; +private: + std::unique_ptr mDocument{}; + Ptcl::Selection mSelection{}; QAction mOpenAction{}; QAction mSaveAction{}; QAction mSaveAsAction{}; std::vector mRecentFileActions{}; + QAction* mUndoAction{nullptr}; + QAction* mRedoAction{nullptr}; + QMenu mFileMenu{}; QMenu mRecentFilesMenu{}; + QMenu mEditMenu{}; QSplitter* mTopSplitter{nullptr}; QSplitter* mBottomSplitter{nullptr}; - QLineEdit mProjNameLineEdit{}; - - QStackedWidget* mPropertiesStack{nullptr}; - QGroupBox mPropertiesGroup{}; + QUndoView mUndoView{}; PtclEditor::PtclList mPtclList{}; - PtclEditor::EmitterWidget mEmitterWidget{}; - PtclEditor::EmitterSetWidget mEmitterSetWidget{}; + PtclEditor::InspectorPanel mInspector{}; PtclEditor::TextureListWidget mTextureWidget{}; - PropertiesView mCurPropertiesView{PropertiesView::EmitterSet}; - QLabel* mStatusLabel{nullptr}; - bool mHasUnsavedChanges{false}; }; diff --git a/include/editor/ptclListWidget.h b/include/editor/ptclListWidget.h index 45e2a5f..13525da 100644 --- a/include/editor/ptclListWidget.h +++ b/include/editor/ptclListWidget.h @@ -1,7 +1,7 @@ #pragma once #include "util/bitflagUtil.h" -#include "ptcl/ptcl.h" +#include "ptcl/ptclDocument.h" #include #include @@ -70,28 +70,15 @@ class PtclList : public QWidget { public: explicit PtclList(QWidget* parent = nullptr); - void setPtclRes(Ptcl::PtclRes* ptclRes); - - void selectEmitter(s32 setIndex, s32 emitterIndex); - void selectEmitterSet(s32 setIndex); + void setDocument(Ptcl::Document* document); + void setSelection(Ptcl::Selection* selection); void updateEmitter(s32 setIndex, s32 emitterIndex); void updateEmitterName(s32 setIndex, s32 emitterIndex); void updateEmitterSetName(s32 setIndex); void refresh(); -signals: - void selectedEmitterSetChanged(u32 index); - void selectedEmitterChanged(u32 setIndex, u32 emitterIndex); - void selectedChildData(u32 setIndex, u32 emitterIndex); - void selectedFluctuation(u32 setIndex, u32 emitterIndex); - void selectedField(u32 setIndex, u32 emitterIndex); - - void itemAdded(); - void itemRemoved(); - private slots: - void selectionChanged(const QItemSelection& selection); void filterList(const QString& text); private: @@ -103,6 +90,7 @@ private slots: void updateToolbarForSelection(const QStandardItem* item); + QStandardItem* findItem(s32 setIndex, s32 emitterIndex, Ptcl::Selection::Type type) const; static QStandardItem* findChildByType(QStandardItem* parent, NodeType type); void insertEmitterNode(QStandardItem* setItem, s32 setIndex, s32 emitterIndex); @@ -118,13 +106,17 @@ private slots: void reindexEmitters(QStandardItem* setItem, s32 setIndex); void reindexEmitterSets(); + void selectNearestValidEmitter(s32 setIndex, s32 preferredEmitter); + void selectNearestValidEmitterSet(s32 preferredSet); + void expandSourceIndex(const QModelIndex& sourceIndex); void copyItem(); void pasteItem(); private: - Ptcl::PtclRes* mResPtr{nullptr}; + Ptcl::Document* mDocument{nullptr}; + Ptcl::Selection* mSelection{nullptr}; QStandardItemModel mListModel{}; QTreeView mTreeView{}; diff --git a/include/editor/textureListWidget.h b/include/editor/textureListWidget.h index 02e6fdb..0cf6235 100644 --- a/include/editor/textureListWidget.h +++ b/include/editor/textureListWidget.h @@ -2,6 +2,7 @@ #include "components/thumbnailWidget.h" #include "ptcl/ptcl.h" +#include "ptcl/ptclDocument.h" #include #include @@ -50,16 +51,19 @@ class TextureListModel final : public QAbstractListModel { public: explicit TextureListModel(QObject* parent = nullptr); - void setTextures(Ptcl::TextureList* textures); + void setTextures(const Ptcl::TextureList* textures); s32 rowCount(const QModelIndex& parent = {}) const final; QVariant data(const QModelIndex& index, s32 role) const final; + void onTextureAdded(s32 index); + void onTextureRemoved(s32 index); + private: void emitRowChangedFor(Ptcl::Texture* texture); private: - Ptcl::TextureList* mTextures{nullptr}; + const Ptcl::TextureList* mTextures{nullptr}; }; @@ -70,18 +74,21 @@ class TextureDetailsPanel final : public QWidget { public: explicit TextureDetailsPanel(QWidget* parent = nullptr); - void setTexture(Ptcl::Texture* texture); + void setTexture(const QModelIndex& index, Ptcl::Texture* texture); signals: void exportRequested(Ptcl::Texture* texture); - void replaceRequested(Ptcl::Texture* texture); + void replaceRequested(const QModelIndex& index); + void deleteRequested(const QModelIndex& index); private: Ptcl::Texture* mTexturePtr{nullptr}; + QModelIndex mIndex; ThumbnailWidget mThumbnailWidget{}; QPushButton mExportButton{}; QPushButton mReplaceButton{}; + QPushButton mDeleteButton{}; }; @@ -93,14 +100,14 @@ class TextureListWidget final : public QWidget { public: explicit TextureListWidget(QWidget* parent = nullptr); - void setTextures(Ptcl::TextureList* textures); - void clear(); + void setDocument(Ptcl::Document* document); private slots: void exportAll(); void importTexture(); void exportTexture(Ptcl::Texture* texture); - void replaceTexture(Ptcl::Texture* texture); + void replaceTexture(const QModelIndex& index); + void deleteTexture(const QModelIndex& index); private: void setupToolbar(); @@ -110,7 +117,7 @@ private slots: void setupSelectionHandling(); private: - Ptcl::TextureList* mTexturesPtr{nullptr}; + Ptcl::Document* mDocument{nullptr}; QToolBar mToolbar{}; QAction* mActionExportAll{nullptr}; diff --git a/include/math/vector.h b/include/math/vector.h index c829b55..b221a2f 100644 --- a/include/math/vector.h +++ b/include/math/vector.h @@ -24,9 +24,12 @@ class Vector2 { Vector2(const Vector2&) = default; Vector2(Vector2&&) = default; + Vector2& operator=(const Vector2&) = default; Vector2& operator=(Vector2&&) = default; + bool operator==(const Vector2&) const = default; + T& operator[](std::size_t i) { assert(i < sAxisCount); return (&mX)[i]; @@ -71,9 +74,12 @@ class Vector3 { Vector3(const Vector3&) = default; Vector3(Vector3&&) = default; + Vector3& operator=(const Vector3&) = default; Vector3& operator=(Vector3&&) = default; + bool operator==(const Vector3&) const = default; + T& operator[](std::size_t i) { assert(i < sAxisCount); return (&mX)[i]; @@ -121,9 +127,12 @@ class Vector4 { Vector4(const Vector4&) = default; Vector4(Vector4&&) = default; + Vector4& operator=(const Vector4&) = default; Vector4& operator=(Vector4&&) = default; + bool operator==(const Vector4&) const = default; + T& operator[](std::size_t i) { assert(i < sAxisCount); return (&mX)[i]; diff --git a/include/ptcl/ptcl.h b/include/ptcl/ptcl.h index 3b1214d..79f105c 100644 --- a/include/ptcl/ptcl.h +++ b/include/ptcl/ptcl.h @@ -14,7 +14,7 @@ namespace Ptcl { // ========================================================================== // -using TextureList = std::vector>; +using TextureList = std::vector>; using EmitterSetList = std::vector>; @@ -31,7 +31,7 @@ class PtclBinaryReader { TextureList takeTextures(); private: - std::shared_ptr loadTexture(u32 texturePos, u32 size, u32 width, u32 height, TextureFormat format); + Texture* loadTexture(u32 texturePos, u32 size, u32 width, u32 height, TextureFormat format); std::unique_ptr readEmitterSet(s32 index); void readComplexData(Emitter& emitter, const BinCommonEmitterData& common); @@ -119,6 +119,11 @@ class PtclRes { public: PtclRes() = default; + ~PtclRes() { + mEmitterSets.clear(); + mTextures.clear(); + } + PtclRes(const PtclRes&) = delete; PtclRes& operator=(const PtclRes&) = delete; @@ -128,19 +133,29 @@ class PtclRes { const QString& name() const; void setName(const QString& name); - const EmitterSetList& getEmitterSets() const; EmitterSetList& getEmitterSets(); + const EmitterSetList& getEmitterSets() const; + + EmitterSet* emitterSet(s32 index); + const EmitterSet* emitterSet(s32 index) const; + + Emitter* emitter(s32 setIndex, s32 emitterIndex); + const Emitter* emitter(s32 setIndex, s32 emitterIndex) const; - const TextureList& textures() const; TextureList& textures(); + const TextureList& textures() const; - void addNewEmitterSet(); - void removeEmitterSet(s32 setIndex); + void insertEmitterSet(s32 setIndex, std::unique_ptr emitterSet); + std::unique_ptr removeEmitterSet(s32 setIndex); - u32 emitterSetCount() const; - u32 emitterCount() const; + void insertTexture(s32 index, std::unique_ptr texture); + void swapTexture(s32 index, std::unique_ptr& texture); + std::unique_ptr removeTexture(s32 index); - const std::unique_ptr& appendEmitterSet(std::unique_ptr& newSet); + s32 emitterSetCount() const; + s32 emitterCount(s32 setIndex) const; + u32 totalEmitterCount() const; + s32 textureCount() const; private: QString mName; diff --git a/include/ptcl/ptclBinary.h b/include/ptcl/ptclBinary.h index 817ce33..c9b31de 100644 --- a/include/ptcl/ptclBinary.h +++ b/include/ptcl/ptclBinary.h @@ -1,7 +1,6 @@ #pragma once #include "ptcl/ptclEnum.h" -#include "ptcl/ptclFieldData.h" #include "typedefs.h" #include "util/bitflagUtil.h" #include "math/matrix.h" @@ -128,6 +127,8 @@ struct alignas(4) binColor4f { friend QDataStream& operator<<(QDataStream& out, const binColor4f& item); friend QDebug operator<<(QDebug dbg, const binColor4f& item); + + bool operator==(const binColor4f&) const = default; }; static_assert(sizeof(binColor4f) == 0x10, "binColor4f is incorrect size."); @@ -150,6 +151,8 @@ struct alignas(4) binColor3f { friend QDataStream& operator<<(QDataStream& out, const binColor3f& item); friend QDebug operator<<(QDebug dbg, const binColor3f& item); + + bool operator==(const binColor3f&) const = default; }; static_assert(sizeof(binColor3f) == 0x0C, "binColor3f is incorrect size."); @@ -384,7 +387,7 @@ struct alignas(4) BinChildData { f32 childAirResist; // 0xE8 BinChildData() = default; - BinChildData(const Ptcl::ChildData& childData); + BinChildData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinChildData& item); friend QDataStream& operator<<(QDataStream& out, const BinChildData& item); @@ -402,7 +405,7 @@ struct alignas(4) BinFieldRandomData { binVec3f fieldRandomVelAdd; // 0x04 BinFieldRandomData() = default; - BinFieldRandomData(const Ptcl::FieldData::FieldRandomData& fieldRandomData); + BinFieldRandomData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinFieldRandomData& item); friend QDataStream& operator<<(QDataStream& out, const BinFieldRandomData& item); @@ -420,7 +423,7 @@ struct alignas(4) BinFieldMagnetData { BitFlag fieldMagnetFlag; // 0x10 BinFieldMagnetData() = default; - BinFieldMagnetData(const Ptcl::FieldData::FieldMagnetData& fieldMagnetData); + BinFieldMagnetData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinFieldMagnetData& item); friend QDataStream& operator<<(QDataStream& out, const BinFieldMagnetData& item); @@ -437,7 +440,7 @@ struct alignas(4) BinFieldSpinData { FieldSpinAxis fieldSpinAxis; // 0x04 BinFieldSpinData() = default; - BinFieldSpinData(const Ptcl::FieldData::FieldSpinData& fieldSpinData); + BinFieldSpinData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinFieldSpinData& item); friend QDataStream& operator<<(QDataStream& out, const BinFieldSpinData& item); @@ -457,7 +460,7 @@ struct alignas(4) BinFieldCollisionData { f32 fieldCollisionCoef; // 0x08 BinFieldCollisionData() = default; - BinFieldCollisionData(const Ptcl::FieldData::FieldCollisionData& fieldCollisionData); + BinFieldCollisionData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinFieldCollisionData& item); friend QDataStream& operator<<(QDataStream& out, const BinFieldCollisionData& item); @@ -475,7 +478,7 @@ struct alignas(4) BinFieldConvergenceData { binVec3f fieldConvergencePos; // 0x04 BinFieldConvergenceData() = default; - BinFieldConvergenceData(const Ptcl::FieldData::FieldConvergenceData& fieldConvergenceData); + BinFieldConvergenceData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinFieldConvergenceData& item); friend QDataStream& operator<<(QDataStream& out, const BinFieldConvergenceData& item); @@ -492,7 +495,7 @@ struct alignas(4) BinFieldPosAddData { binVec3f fieldPosAdd; // 0x00 BinFieldPosAddData() = default; - BinFieldPosAddData(const Ptcl::FieldData::FieldPosAddData& fieldPosAddData); + BinFieldPosAddData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinFieldPosAddData& item); friend QDataStream& operator<<(QDataStream& out, const BinFieldPosAddData& item); @@ -511,7 +514,7 @@ struct alignas(4) BinFluctuationData { s32 fluctuationPhaseRnd; // 0x08 BinFluctuationData() = default; - BinFluctuationData(const Ptcl::FluctuationData& fluctuationData); + BinFluctuationData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinFluctuationData& item); friend QDataStream& operator<<(QDataStream& out, const BinFluctuationData& item); @@ -534,7 +537,7 @@ struct alignas(4) BinStripeData { f32 stripeDirInterpolate; // 0x1C BinStripeData() = default; - BinStripeData(const Ptcl::StripeData& stripeData); + BinStripeData(const Ptcl::Emitter& emitterData); friend QDataStream& operator>>(QDataStream& in, BinStripeData& item); friend QDataStream& operator<<(QDataStream& out, const BinStripeData& item); diff --git a/include/ptcl/ptclChildData.h b/include/ptcl/ptclChildData.h deleted file mode 100644 index 674396d..0000000 --- a/include/ptcl/ptclChildData.h +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once - -#include "math/vector.h" - -#include "ptcl/ptclBinary.h" -#include "ptcl/ptclEnum.h" -#include "ptcl/ptclTexture.h" - -#include "typedefs.h" - - -namespace Ptcl { - - -// ========================================================================== // - - -class ChildData { - -public: - struct BasicProperties { - BillboardType billboardType{BillboardType::Billboard}; - }; - - struct EmissionProperties { - s32 emitRate{1}; - s32 emitTiming{0}; - s32 life{10}; - s32 emitStep{1}; - }; - - struct VelocityProperties { - Math::Vector3f randVel{0.0f, 0.0f, 0.0f}; - Math::Vector3f gravity{0.0f, -1.0f, 0.0f}; - f32 velInheritRate{1.0f}; - f32 initPosRand{0.0f}; - f32 figurVel{0.1f}; - f32 airResist{1.0f}; - }; - - struct RotationProperties { - RotType rotType{RotType::None}; - Math::Vector3i initRot{0, 0, 0}; - Math::Vector3i initRotRand{0, 0, 0}; - Math::Vector3i rotVel{0, 0, 0}; - Math::Vector3i rotVelRand{0, 0, 0}; - Math::Vector2f rotBasis{0.0f, 0.0f}; - }; - - struct ScaleProperties { - Math::Vector2f scale{1.0f, 1.0f}; - Math::Vector2f scaleTarget{1.0f, 1.0f}; - f32 scaleInheritRate{1.0f}; - s32 scaleStartFrame{0}; - }; - - struct TextureProperties { - TextureWrap textureWrapT{TextureWrap::ClampToEdge}; - TextureWrap textureWrapS{TextureWrap::ClampToEdge}; - TextureFilter textureMagFilter{TextureFilter::Nearest}; - TextureFilter textureMinFilter{TextureFilter::Nearest}; - TextureMipFilter textureMipFilter{TextureMipFilter::None}; - Math::Vector2f texUVScale{1.0f, 1.0f}; - }; - - struct ColorProperties { - binColor4f color0{1.0f, 1.0f, 1.0f, 1.0f}; - binColor3f color1{255.0f, 255.0f, 255.0f}; - }; - - struct AlphaProperties { - f32 alpha{1.0f}; - f32 alphaTarget{1.0f}; - f32 alphaInit{1.0f}; - s32 alphaStartFrame{1}; - s32 alphaBaseFrame{1}; - }; - - struct CombinerProperties { - BlendFuncType blendFunc{BlendFuncType::Translucent}; - DepthFuncType depthFunc{DepthFuncType::Unk0}; - ColorCombinerFuncType combinerFunc{ColorCombinerFuncType::CombinerConfig0}; - }; - -public: - ChildData() = default; - ChildData(const ChildData&) = delete; - - std::unique_ptr clone() const; - - TextureHandle& textureHandle(); - const TextureHandle& textureHandle() const; - void setTexture(const std::shared_ptr& texture); - - const BasicProperties &basicProperties() const; - void setBasicProperties(const BasicProperties &basicProperties); - - const EmissionProperties& emissionProperties() const; - void setEmissionProperties(const EmissionProperties& emissionProperties); - - const VelocityProperties& velocityProperties() const; - void setVelocityProperties(const VelocityProperties& velocityProperties); - - const TextureProperties& textureProperties() const; - void setTextureProperties(const TextureProperties& textureProperties); - - const ColorProperties& colorProperties() const; - void setColorProperties(const ColorProperties& colorProperties); - - const AlphaProperties& alphaProperties() const; - void setAlphaProperties(const AlphaProperties& alphaProperties); - - const CombinerProperties& combinerProperties() const; - void setCombinerProperties(const CombinerProperties& combinerProperties); - - const RotationProperties& rotationProperties() const; - void setRotationProperties(const RotationProperties& rotationProperties); - - const ScaleProperties& scaleProperties() const; - void setScaleProperties(const ScaleProperties& scaleProperties); - - void initFromBinary(const BinChildData& childData); - -private: - BasicProperties mBasicProperties{}; - EmissionProperties mEmissionProperties{}; - VelocityProperties mVelocityProperties{}; - TextureProperties mTextureProperties{}; - ColorProperties mColorProperties{}; - AlphaProperties mAlphaProperties{}; - CombinerProperties mCombinerProperties{}; - RotationProperties mRotationProperties{}; - ScaleProperties mScaleProperties{}; - - TextureHandle mTextureHandle{}; -}; - - -// ========================================================================== // - - -} // namespace Ptcl diff --git a/include/ptcl/ptclCommand.h b/include/ptcl/ptclCommand.h new file mode 100644 index 0000000..b2b7074 --- /dev/null +++ b/include/ptcl/ptclCommand.h @@ -0,0 +1,543 @@ +#pragma once + +#include "ptcl/ptclEmitter.h" +#include "ptcl/ptclDocument.h" + + +#include +#include + + +namespace Ptcl { + + +// ========================================================================== // + + +class DocumentCommandBase : public QUndoCommand { +public: + explicit DocumentCommandBase(Document* document, QString label, QUndoCommand* parent = nullptr) : + QUndoCommand{std::move(label), parent}, mDocument{document} {} + +protected: + Document* document() const { return mDocument; } + PtclRes& resource() { return mDocument->dataMutable(); } + + Emitter* emitter(s32 setIndex, s32 emitterIndex) { return mDocument->emitterMutable(setIndex, emitterIndex); } + EmitterSet* emitterSet(s32 setIndex) { return mDocument->emitterSetMutable(setIndex); } + + EmitterList& emitterList(s32 setIndex) { return mDocument->emitterSetMutable(setIndex)->emitters(); } + + void setProjectName(const QString& newName) { mDocument->dataMutable().setName(newName); } + + void notifyEmitterChanged(s32 setIndex, s32 emitterIndex) { mDocument->notifyEmitterChanged(setIndex, emitterIndex); } + void notifyEmitterSetChanged(s32 setIndex) { mDocument->notifyEmitterSetChanged(setIndex); } + void notifyTextureChanged(s32 index) { mDocument->notifyTextureChanged(index); } + void notifyProjectChanged() { mDocument->notifyProjectChanged(); } + + void notifyEmitterAdded(s32 setIndex, s32 emitterIndex) { mDocument->notifyEmitterAdded(setIndex, emitterIndex); } + void notifyEmitterRemoved(s32 setIndex, s32 emitterIndex) { mDocument->notifyEmitterRemoved(setIndex, emitterIndex); } + + void notifyEmitterSetAdded(s32 setIndex) { mDocument->notifyEmitterSetAdded(setIndex); } + void notifyEmitterSetRemoved(s32 setIndex) { mDocument->notifyEmitterSetRemoved(setIndex); } + + void notifyTextureAdded(s32 index) { mDocument->notifyTextureAdded(index); } + void notifyTextureRemoved(s32 index) { mDocument->notifyTextureRemoved(index); } + +private: + Document* mDocument; +}; + + +// ========================================================================== // + + +template +class SetEmitterPropertyCommand final : public DocumentCommandBase { +public: + using Getter = std::function; + using Setter = std::function; + + SetEmitterPropertyCommand(Document* document, s32 setIndex, s32 emitterIndex, QString label, + QString key, Getter getter, Setter setter, const T& newValue, QUndoCommand* parent = nullptr) : + DocumentCommandBase{document, std::move(label), parent}, + mSetIndex{setIndex}, + mEmitterIndex{emitterIndex}, + mPropertyKey{std::move(key)}, + mGetter{std::move(getter)}, + mSetter{std::move(setter)}, + mNewValue{newValue}, + mId{static_cast(qHash(mPropertyKey))} + { + auto& emitter = getEmitter(); + mOldValue = mGetter(emitter); + + if (mOldValue == mNewValue) { + setObsolete(true); + } + } + + s32 id() const override { + return mId; + } + + bool mergeWith(const QUndoCommand* other) override { + if (other->id() != id()) { + return false; + } + + auto otherCmd = static_cast(other); + + if (document() != otherCmd->document() || mSetIndex != otherCmd->mSetIndex || + mEmitterIndex != otherCmd->mEmitterIndex || mPropertyKey != otherCmd->mPropertyKey) { + return false; + } + + mNewValue = otherCmd->mNewValue; + return true; + } + + void undo() override { apply(mOldValue); } + void redo() override { apply(mNewValue); } + +private: + Emitter& getEmitter(); + void apply(const T& value); + +private: + s32 mSetIndex{}; + s32 mEmitterIndex{}; + + QString mPropertyKey{}; + + Getter mGetter{}; + Setter mSetter{}; + + T mOldValue{}; + T mNewValue{}; + + const s32 mId{}; +}; + +// ========================================================================== // + + +template +Emitter& SetEmitterPropertyCommand::getEmitter() { + return *emitter(mSetIndex, mEmitterIndex); +} + +template +void SetEmitterPropertyCommand::apply(const T& value) { + auto& emitterSet = getEmitter(); + mSetter(emitterSet, value); + notifyEmitterChanged(mSetIndex, mEmitterIndex); +} + + +// ========================================================================== // + + +template +class SetEmitterSetPropertyCommand final : public DocumentCommandBase { +public: + using Getter = std::function; + using Setter = std::function; + + SetEmitterSetPropertyCommand(Document* document, s32 setIndex, QString label, + QString key, Getter getter, Setter setter, const T& newValue, QUndoCommand* parent = nullptr) : + DocumentCommandBase{document, std::move(label), parent}, + mSetIndex{setIndex}, + mPropertyKey{std::move(key)}, + mGetter{std::move(getter)}, + mSetter{std::move(setter)}, + mNewValue{newValue}, + mId{static_cast(qHash(mPropertyKey))} + { + auto& emitterSet = getEmitterSet(); + mOldValue = mGetter(emitterSet); + + if (mOldValue == mNewValue) { + setObsolete(true); + } + } + + s32 id() const override { + return mId; + } + + bool mergeWith(const QUndoCommand* other) override { + if (other->id() != id()) { + return false; + } + + auto otherCmd = static_cast(other); + + if (document() != otherCmd->document() || mSetIndex != otherCmd->mSetIndex || + mPropertyKey != otherCmd->mPropertyKey) { + return false; + } + + mNewValue = otherCmd->mNewValue; + return true; + } + + void undo() override { apply(mOldValue); } + void redo() override { apply(mNewValue); } + +private: + EmitterSet& getEmitterSet(); + void apply(const T& value); + +private: + s32 mSetIndex{}; + + QString mPropertyKey{}; + + Getter mGetter{}; + Setter mSetter{}; + + T mOldValue{}; + T mNewValue{}; + + const s32 mId{}; +}; + + +// ========================================================================== // + + +template +EmitterSet& SetEmitterSetPropertyCommand::getEmitterSet() { + return *emitterSet(mSetIndex); +} + +template +void SetEmitterSetPropertyCommand::apply(const T& value) { + auto& emitterSet = getEmitterSet(); + mSetter(emitterSet, value); + notifyEmitterSetChanged(mSetIndex); +} + + +// ========================================================================== // + + +class RenameProjectNameCommand final : public DocumentCommandBase { +public: + RenameProjectNameCommand(Document* document, QString newName, QUndoCommand* parent = nullptr) : + DocumentCommandBase{document, std::move("Rename Project"), parent}, mNewName{std::move(newName)} { + mOldName = document->projectName(); + + if (mOldName == mNewName) { + setObsolete(true); + } + } + + s32 id() const override { + return mId; + } + + bool mergeWith(const QUndoCommand* other) override { + if (other->id() != id()) { + return false; + } + + auto otherCmd = static_cast(other); + + if (document() != otherCmd->document()) { + return false; + } + + mNewName = otherCmd->mNewName; + return true; + } + + void undo() override { apply(mOldName); } + void redo() override { apply(mNewName); } + +private: + void apply(const QString& value) { + setProjectName(value); + notifyProjectChanged(); + }; + +private: + QString mOldName{}; + QString mNewName{}; + + const s32 mId{static_cast(qHash("RenameProject"))}; +}; + + +// ========================================================================== // + + +class AddEmitterCommand final : public DocumentCommandBase { +public: + AddEmitterCommand(Document* doc, s32 setIndex, QString label, std::unique_ptr emitter = nullptr, QUndoCommand* parent = nullptr) : + DocumentCommandBase{doc, std::move(label), parent}, mSetIndex{setIndex} { + + if (emitter) { + mNewEmitter = std::move(emitter); + } else { + auto newEmitterPtr = std::make_unique("New_Emitter_" + QString::number(document()->emitterCount(mSetIndex))); + mNewEmitter = std::move(newEmitterPtr); + } + + } + + s32 id() const override { + return mId; + } + + void undo() override { + auto* set = emitterSet(mSetIndex); + mNewEmitter = set->removeEmitter(mEmitterIndex); + notifyEmitterRemoved(mSetIndex, mEmitterIndex); + } + + void redo() override { + auto* set = emitterSet(mSetIndex); + mEmitterIndex = set->emitterCount(); + set->insertEmitter(mEmitterIndex, std::move(mNewEmitter)); + notifyEmitterAdded(mSetIndex, mEmitterIndex); + } + +private: + s32 mSetIndex{}; + s32 mEmitterIndex{0}; + std::unique_ptr mNewEmitter{}; + + const s32 mId{static_cast(qHash("AddEmitter"))}; +}; + + +// ========================================================================== // + + +class RemoveEmitterCommand final : public DocumentCommandBase { +public: + RemoveEmitterCommand(Document* doc, s32 setIndex, s32 emitterIndex, QUndoCommand* parent = nullptr) : + DocumentCommandBase{doc, std::move("Remove Emitter"), parent}, mSetIndex{setIndex}, mEmitterIndex{emitterIndex} { + } + + s32 id() const override { + return mId; + } + + void undo() override { + auto* set = emitterSet(mSetIndex); + set->insertEmitter(mEmitterIndex, std::move(mRemovedEmitter)); + notifyEmitterAdded(mSetIndex, mEmitterIndex); + } + + void redo() override { + auto* set = emitterSet(mSetIndex); + mRemovedEmitter = set->removeEmitter(mEmitterIndex); + notifyEmitterRemoved(mSetIndex, mEmitterIndex); + } + +private: + s32 mSetIndex{}; + s32 mEmitterIndex{0}; + std::unique_ptr mRemovedEmitter{}; + + const s32 mId{static_cast(qHash("RemoveEmitter"))}; +}; + + +// ========================================================================== // + + +class AddEmitterSetCommand final : public DocumentCommandBase { +public: + AddEmitterSetCommand(Document* doc, QString label, std::unique_ptr emitterSet = nullptr, QUndoCommand* parent = nullptr) : + DocumentCommandBase{doc, std::move(label), parent} { + + if (emitterSet) { + mNewEmitterSet = std::move(emitterSet); + } else { + auto newEmitterSetPtr = std::make_unique("New_EmitterSet_" + QString::number(document()->emitterSetCount())); + mNewEmitterSet = std::move(newEmitterSetPtr); + } + } + + s32 id() const override { + return mId; + } + + void undo() override { + auto removed = resource().removeEmitterSet(mSetIndex); + if (!removed) { + Q_ASSERT(false && "removeEmitterSet returned null"); + return; + } + + mNewEmitterSet = std::move(removed); + notifyEmitterSetRemoved(mSetIndex); + + } + + void redo() override { + mSetIndex = resource().emitterSetCount(); + resource().insertEmitterSet(mSetIndex, std::move(mNewEmitterSet)); + notifyEmitterSetAdded(mSetIndex); + } + +private: + s32 mSetIndex{0}; + std::unique_ptr mNewEmitterSet{}; + + const s32 mId{static_cast(qHash("AddEmitterSet"))}; +}; + + +// ========================================================================== // + + +class RemoveEmitterSetCommand final : public DocumentCommandBase { +public: + RemoveEmitterSetCommand(Document* doc, s32 setIndex, QUndoCommand* parent = nullptr) : + DocumentCommandBase{doc, std::move("Remove EmitterSet"), parent}, mSetIndex{setIndex} { + } + + s32 id() const override { + return mId; + } + + void undo() override { + resource().insertEmitterSet(mSetIndex, std::move(mRemovedEmitterSet)); + notifyEmitterSetAdded(mSetIndex); + } + + void redo() override { + auto removed = resource().removeEmitterSet(mSetIndex); + if (!removed) { + Q_ASSERT(false && "removeEmitterSet returned null"); + return; + } + + mRemovedEmitterSet = std::move(removed); + notifyEmitterSetRemoved(mSetIndex); + } + +private: + s32 mSetIndex{0}; + std::unique_ptr mRemovedEmitterSet{}; + + const s32 mId{static_cast(qHash("RemoveEmitterSet"))}; +}; + + +// ========================================================================== // + + +class AddTextureCommand final : public DocumentCommandBase { +public: + AddTextureCommand(Document* doc, std::unique_ptr texture, QUndoCommand* parent = nullptr) : + DocumentCommandBase{doc, std::move("Add Texture"), parent}, mNewTexture{std::move(texture)} { + } + + s32 id() const override { + return mId; + } + + void undo() override { + auto removed = resource().removeTexture(mIndex); + if (!removed) { + Q_ASSERT(false && "removeTexture returned null"); + return; + } + + mNewTexture = std::move(removed); + notifyTextureRemoved(mIndex); + + } + + void redo() override { + mIndex = resource().textureCount(); + resource().insertTexture(mIndex, std::move(mNewTexture)); + notifyTextureAdded(mIndex); + } + +private: + s32 mIndex{0}; + std::unique_ptr mNewTexture{}; + + const s32 mId{static_cast(qHash("AddTexture"))}; +}; + + +// ========================================================================== // + + +class ReplaceTextureCommand final : public DocumentCommandBase { +public: + ReplaceTextureCommand(Document* doc, s32 index, std::unique_ptr texture, QUndoCommand* parent = nullptr) : + DocumentCommandBase{doc, std::move("Replace Texture"), parent}, mIndex{index}, mTexture{std::move(texture)} { + } + + s32 id() const override { + return mId; + } + + void undo() override { + resource().swapTexture(mIndex, mTexture); + notifyTextureChanged(mIndex); + + } + + void redo() override { + resource().swapTexture(mIndex, mTexture); + notifyTextureChanged(mIndex); + } + +private: + s32 mIndex{0}; + std::unique_ptr mTexture{}; + + const s32 mId{static_cast(qHash("ReplaceTexture"))}; +}; + + +// ========================================================================== // + + +class RemoveTextureCommand final : public DocumentCommandBase { +public: + RemoveTextureCommand(Document* doc, s32 index, QUndoCommand* parent = nullptr) : + DocumentCommandBase{doc, std::move("Remove Texture"), parent}, mIndex{index} { + } + + s32 id() const override { + return mId; + } + + void undo() override { + resource().insertTexture(mIndex, std::move(mRemovedTexture)); + notifyTextureAdded(mIndex); + } + + void redo() override { + auto removed = resource().removeTexture(mIndex); + if (!removed) { + Q_ASSERT(false && "removeTexture returned null"); + return; + } + + mRemovedTexture = std::move(removed); + notifyTextureRemoved(mIndex); + } + +private: + s32 mIndex{0}; + std::unique_ptr mRemovedTexture{}; + + const s32 mId{static_cast(qHash("RemoveTexture"))}; +}; + + +// ========================================================================== // + +} // namespace Ptcl diff --git a/include/ptcl/ptclDocument.h b/include/ptcl/ptclDocument.h new file mode 100644 index 0000000..8f5fd14 --- /dev/null +++ b/include/ptcl/ptclDocument.h @@ -0,0 +1,156 @@ +#pragma once + +#include "ptcl/ptcl.h" + +#include +#include + + +namespace Ptcl { + + +// ========================================================================== // + + +class Selection final : public QObject { + Q_OBJECT +public: + enum class Type { + None, + EmitterSet, + Emitter, + EmitterChild, + EmitterFlux, + EmitterField + }; + +public: + explicit Selection(QObject* parent = nullptr); + + void set(s32 setIndex, s32 emitterIndex, Type type); + + s32 emitterSetIndex() const { return mSetIndex; } + s32 emitterIndex() const { return mEmitterIndex; } + Type type() const { return mType; } + +signals: + void selectionChanged(s32 setIndex, s32 emitterIndex, Ptcl::Selection::Type type); + +private: + s32 mSetIndex{-1}; + s32 mEmitterIndex{-1}; + Type mType{Selection::Type::None}; +}; + + +// ========================================================================== // + + +class DocumentCommandBase; + +template +class SetEmitterPropertyCommand; + +template +class SetEmitterSetPropertyCommand; + +// ========================================================================== // + + +class Document final : public QObject { + Q_OBJECT +public: + explicit Document(QObject* parent = nullptr); + + bool load(const QString& filePath); + bool save(const QString& filePath); + + const Emitter* emitter(s32 setIndex, s32 emitterIndex) const { return mData.emitter(setIndex, emitterIndex); } + const EmitterSet* emitterSet(s32 index) const { return mData.emitterSet(index); } + + const EmitterSetList& emitterSets() const { return mData.getEmitterSets(); } + const TextureList& textures() const { return mData.textures(); } + + const QString& projectName() const { return mData.name(); } + void setProjectName(const QString& name); + + bool isDirty() const { return !mUndoStack.isClean(); } + QString filePath() const { return mFilePath; } + + QUndoStack* undoStack() { return &mUndoStack; } + + template + void setEmitterProperty(s32 setIndex, s32 emitterIndex, QString label, QString key, Getter getter, Setter setter, const T& value) { + mUndoStack.push(new SetEmitterPropertyCommand(this, setIndex, emitterIndex, label, key, getter, setter, value)); + } + + template + void setEmitterSetProperty(s32 setIndex, QString label, QString key, Getter getter, Setter setter, const T& value) { + mUndoStack.push(new SetEmitterSetPropertyCommand(this, setIndex, label, key, getter, setter, value)); + } + + s32 emitterCount(s32 setIndex) const { return mData.emitterCount(setIndex); } + s32 emitterSetCount() const { return mData.emitterSetCount(); } + + void addEmitter(QString label, s32 setIndex, std::unique_ptr emitter = nullptr); + void removeEmitter(s32 setIndex, s32 emitterIndex); + + void addEmitterSet(QString label, std::unique_ptr emitterSet = nullptr); + void removeEmitterSet(s32 setIndex); + + void addTexture(std::unique_ptr texture); + void removeTexture(s32 index); + void replaceTexture(s32 index, std::unique_ptr texture); + +private: + TextureList& texturesMutable() { return mData.textures(); } + Emitter* emitterMutable(s32 setIndex, s32 emitterIndex) { return mData.emitter(setIndex, emitterIndex); } + EmitterSet* emitterSetMutable(s32 index) { return mData.emitterSet(index); } + EmitterSetList& emitterSetsMutable() { return mData.getEmitterSets(); } + + PtclRes& dataMutable() { return mData; } + + void notifyEmitterChanged(s32 setIndex, s32 emitterIndex) { emit emitterChanged(setIndex, emitterIndex); } + void notifyEmitterSetChanged(s32 setIndex) { emit emitterSetChanged(setIndex); } + void notifyTextureChanged(s32 index) { emit textureChanged(index); } + void notifyProjectChanged() { emit projectChanged(); } + + void notifyEmitterAdded(s32 setIndex, s32 emitterIndex) { emit emitterAdded(setIndex, emitterIndex); } + void notifyEmitterRemoved(s32 setIndex, s32 emitterIndex) { emit emitterRemoved(setIndex, emitterIndex); } + + void notifyEmitterSetAdded(s32 setIndex) { emit emitterSetAdded(setIndex); } + void notifyEmitterSetRemoved(s32 setIndex) { emit emitterSetRemoved(setIndex); } + + void notifyTextureAdded(s32 index) { emit textureAdded(index); } + void notifyTextureRemoved(s32 index) { emit textureRemoved(index); } + + friend class DocumentCommandBase; + +signals: + void emitterChanged(s32 setIndex, s32 emitterIndex); + void emitterSetChanged(s32 setIndex); + void projectChanged(); + + void emitterAdded(s32 setIndex, s32 emitterIndex); + void emitterRemoved(s32 setIndex, s32 emitterIndex); + + void emitterSetAdded(s32 setIndex); + void emitterSetRemoved(s32 setIndex); + + void textureAdded(s32 index); + void textureRemoved(s32 index); + void textureChanged(s32 index); + +private: + PtclRes mData{}; + QString mFilePath{}; + QUndoStack mUndoStack{}; +}; + + +// ========================================================================== // + + +} // namespace Ptcl + +#include "ptcl/ptclCommand.h" diff --git a/include/ptcl/ptclEmitter.h b/include/ptcl/ptclEmitter.h index 5432a55..dbd2352 100644 --- a/include/ptcl/ptclEmitter.h +++ b/include/ptcl/ptclEmitter.h @@ -1,13 +1,10 @@ #pragma once #include "math/matrix.h" +#include "math/util.h" #include "ptcl/ptclBinary.h" -#include "ptcl/ptclChildData.h" #include "ptcl/ptclEnum.h" -#include "ptcl/ptclFieldData.h" -#include "ptclFluctuationData.h" -#include "ptcl/ptclStripeData.h" #include "ptcl/ptclSeed.h" #include "ptcl/ptclTexture.h" @@ -29,272 +26,916 @@ namespace Ptcl { class Emitter { public: - struct BasicProperties { - EmitterType type{EmitterType::Simple}; - FollowType followType{FollowType::All}; - QString name{"Emitter"}; - PtclSeed randomSeed{}; - BillboardType billboardType{BillboardType::Billboard}; - bool isPolygon{false}; - bool isVelLook{false}; - bool isEmitterBillboardMtx{false}; - bool isFollow{false}; - }; - - struct ScaleProperties { + struct ScaleAnim { Math::Vector2f initScale{1.0f, 1.0f}; Math::Vector2f diffScale21{0.0f, 0.0f}; Math::Vector2f diffScale32{0.0f, 0.0f}; s32 scaleSection1{0}; s32 scaleSection2{0}; - f32 scaleRand{0.0f}; - }; - - struct RotationProperties { - RotType rotType{RotType::None}; - Math::Vector3i initRot{0, 0, 0}; - Math::Vector3i initRotRand{0, 0, 0}; - Math::Vector3i rotVel{0, 0, 0}; - Math::Vector3i rotVelRand{0, 0, 0}; - Math::Vector2f rotBasis{0.0f, 0.0f}; - }; - - struct ColorProperties { - std::array color0{ - binColor4f{1.0f, 1.0f, 1.0f, 1.0f}, - binColor4f{1.0f, 1.0f, 1.0f, 1.0f}, - binColor4f{1.0f, 1.0f, 1.0f, 1.0f}, - }; - s32 colorSection1{20}; - s32 colorSection2{60}; - s32 colorSection3{80}; - s32 colorNumRepeat{1}; - bool colorRandom{false}; - bool colorAnimation{false}; - ColorCalcType colorCalcType{ColorCalcType::None}; - - binColor3f color1{255.0f, 255.0f, 255.0f}; + bool operator==(const ScaleAnim&) const = default; }; - struct AlphaProperties { + struct AlphaAnim { f32 initAlpha{1.0f}; f32 diffAlpha21{0.0f}; f32 diffAlpha32{0.0f}; s32 alphaSection1{0}; s32 alphaSection2{100}; - }; - struct VolumeProperties { - u8 volumeTblIndex{0}; - VolumeType volumeType{VolumeType::Point}; - Math::Vector3f volumeRadius{1.0f, 1.0f, 1.0f}; - s32 volumeSweepStart{0}; - s32 volumeSweepParam{0}; + bool operator==(const AlphaAnim&) const = default; }; - struct VelocityProperties { - f32 figureVel{0.1f}; - Math::Vector3f emitterVelDir{0.0f, 1.0f, 0.0f}; - f32 initVel{0.0f}; - f32 initVelRnd{0.0f}; - Math::Vector3f spreadVec{0.0f, 0.0f, 0.0f}; - f32 airResistance{1.0f}; - }; +public: + Emitter() = default; + Emitter(QString name); - struct EmissionProperties { - s32 startFrame{0}; - s32 endFrame{1}; - s32 lifeStep{10}; - s32 lifeStepRnd{1}; - s32 emitRate{1}; - }; + Emitter(const Emitter&) = delete; + Emitter& operator=(const Emitter&) = delete; - struct TerminationProperties { - bool isStopEmitInFade{true}; - f32 alphaAddInFade{0.0f}; - }; + std::unique_ptr clone() const; - struct LifespanProperties { - s32 ptclLife{100}; - s32 ptclLifeRnd{0}; - }; + BitFlag& flags(); + const BitFlag& flags() const; - struct TransformProperties { - Math::Matrix34f transformSRT{ - {1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - Math::Matrix34f transformRT{ - {1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - }; + void initFromBinary(const BinCommonEmitterData& emitterData); + void initComplexFromBinary(const BinComplexEmitterData& emitterData); - struct GravityProperties { - bool isDirectional{false}; - Math::Vector3f gravity{0.0f, -1.0f, 0.0f}; - }; + // ----- Basic Properties ----- \\ - struct TextureProperties { - TextureWrap textureWrapT{TextureWrap::ClampToEdge}; - TextureWrap textureWrapS{TextureWrap::ClampToEdge}; - TextureFilter textureMagFilter{TextureFilter::Nearest}; - TextureFilter textureMinFilter{TextureFilter::Nearest}; - TextureMipFilter textureMipFilter{TextureMipFilter::None}; + EmitterType type() const { return mType; } + void setType(EmitterType type) { mType = type; } - u16 numTexPat{1}; - u8 numTexDivX{1}; - u8 numTexDivY{1}; - Math::Vector2f texUVScale{1.0f, 1.0f}; - std::array texPatTbl{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - u16 texPatFreq{0}; - u16 texPatTblUse{2}; - bool isTexPatAnim{false}; - }; + FollowType followType() const { return mFollowType; } + void setFollowType(FollowType type) { + mFollowType = type; - struct CombinerProperties { - BlendFuncType blendFunc{BlendFuncType::Translucent}; - DepthFuncType depthFunc{DepthFuncType::Unk0}; - ColorCombinerFuncType combinerFunc{ColorCombinerFuncType::CombinerConfig0}; - bool isFogEnabled{false}; - }; + // TODO: Check if this should also be set for Ptcl::FollowType::PosOnly + mIsFollow = (type == Ptcl::FollowType::All); + } - struct ComplexProperties { - BitFlag childFlags{ - ChildFlag::AlphaInherit, - ChildFlag::ScaleInherit, - ChildFlag::RotateInherit, - ChildFlag::IsFollow, - ChildFlag::Unk80 - }; - BitFlag fieldFlags{}; - BitFlag fluctuationFlags{ - FluctuationFlag::ApplyAlpha, - FluctuationFlag::ApplyScale - }; - BitFlag stripeFlags{}; - }; + const QString& name() const { return mName; } + void setName(const QString& name) { mName = name; } -public: - Emitter() = default; + const PtclSeed& randomSeed() const { return mRandomSeed; } + void setRandomSeed(PtclSeed seed) { mRandomSeed = seed; } - Emitter(const Emitter&) = delete; - Emitter& operator=(const Emitter&) = delete; + BillboardType billboardType() const { return mBillboardType; } + void setBillboardType(BillboardType type) { + mBillboardType = type; + mIsPolygon = (type == Ptcl::BillboardType::PolygonXY || type == Ptcl::BillboardType::PolygonXZ); + mIsVelLook = (type == Ptcl::BillboardType::VelLook || type == Ptcl::BillboardType::VelLookPolygon); + } - std::unique_ptr clone() const; + bool isEmitterBillboardMtx() const { return mIsEmitterBillboardMtx; } + void setIsEmitterBillboardMtx(bool isEmitterBillboardMtx) { mIsEmitterBillboardMtx = isEmitterBillboardMtx; } - EmitterType type() const; + bool isPolygon() const { return mIsPolygon; } + bool isFollow() const { return mIsFollow; } + bool isVelLook() const { return mIsVelLook; } - BitFlag& flags(); - const BitFlag& flags() const; + // ----- Gravity Properties ----- \\ + + bool isDirectional() const { return mIsDirectional; } + void setDirectional(bool isDirectional) { mIsDirectional = isDirectional; } + + const Math::Vector3f& gravity() const { return mGravity; } + void setGravity(const Math::Vector3f& gravity) { mGravity = gravity; } + + // ----- Lifespan Properties ----- \\ + + s32 ptclLife() const { return mPtclLife; } + void setPtclLife(const s32 ptclLife) { mPtclLife = ptclLife; } + + s32 ptclLifeRandom() const { return mPtclLifeRnd; } + void setPtclLifeRandom(const s32 lifeRandom) { mPtclLifeRnd = lifeRandom; } + + // ----- Termination Properties ----- \\ + + bool isStopEmitInFade() const { return mIsStopEmitInFade; } + void setIsStopEmitInFade(bool isStop) { mIsStopEmitInFade = isStop; } + + f32 alphaAddInFade() const { return mAlphaAddInFade; } + void setAlphaAddInFade(f32 alpha) { mAlphaAddInFade = alpha; } + + // ----- Transform Properties ----- \\ + + const Math::Matrix34f& transformRT() const { return mTransformRT; } + const Math::Matrix34f& transformSRT() const { return mTransformSRT; } + + void setTransform(const Math::Vector3f& rotation, const Math::Vector3f& translation, const Math::Vector3f& scale) { + const auto mtxR = Math::Util::eulerToRotationMatrix(rotation); + + Math::Matrix34f mtxRT; + for (s32 r = 0; r < 3; ++r) { + for (s32 c = 0; c < 3; ++c) { + mtxRT(r, c) = mtxR(r, c); + } + mtxRT(r, 3) = translation[r]; + } + + mTransformRT = mtxRT; - const QString& name() const; - void setName(const QString &name); + Math::Matrix34f mtxSRT; + for (s32 r = 0; r < 3; ++r) { + mtxSRT(r, 0) = mtxRT(r, 0) * scale.getX(); + mtxSRT(r, 1) = mtxRT(r, 1) * scale.getY(); + mtxSRT(r, 2) = mtxRT(r, 2) * scale.getZ(); + mtxSRT(r, 3) = mtxRT(r, 3); + } - TextureHandle& textureHandle(); - const TextureHandle& textureHandle() const; - void setTexture(const std::shared_ptr& texture); + mTransformSRT = mtxSRT; + } - const BasicProperties &basicProperties() const; - void setBasicProperties(const BasicProperties &basicProperties); + Math::Vector3f translation() const { return Math::Util::getTranslation(mTransformRT); } + void setTranslation(const Math::Vector3f& translation) { setTransform(rotation(), translation, scale()); } - const GravityProperties& gravityProperties() const; - void setGravityProperties(const GravityProperties& gravityProperties); + Math::Vector3f rotation() const { + auto rot = Math::Util::getRotationEuler(mTransformRT); + rot.setX(Math::Util::to180(rot.getX())); + rot.setY(Math::Util::to180(rot.getY())); + rot.setZ(Math::Util::to180(rot.getZ())); + return rot; + } + void setRotation(const Math::Vector3f& rotation) { setTransform(rotation, translation(), scale()); } - const LifespanProperties& lifespanProperties() const; - void setLifespanProperties(const LifespanProperties& lifespanProperties); + Math::Vector3f scale() const { return Math::Util::getScale(mTransformSRT); } + void setScale(const Math::Vector3f& scale) { setTransform(rotation(), translation(), scale); } - const TerminationProperties& terminationProperties() const; - void setTerminationProperties(const TerminationProperties& terminationProperties); + // ----- Scale Properties ----- \\ - const EmissionProperties& emissionProperties() const; - void setEmissionProperties(const EmissionProperties& emissionProperties); + const ScaleAnim& scaleAnim() const { return mScaleAnim; } + void setScaleAnim(const ScaleAnim& scaleAnim) { mScaleAnim = scaleAnim; } - const VelocityProperties& velocityProperties() const; - void setVelocityProperties(const VelocityProperties& velocityProperties); + f32 scaleRand() const { return mScaleRand; } + void setScaleRand(f32 scaleRand) { mScaleRand = scaleRand; } - const VolumeProperties& volumeProperties() const; - void setVolumeProperties(const VolumeProperties& volumeProperties); + // ----- Emission Properties ----- \\ - const ColorProperties& colorProperties() const; - void setColorProperties(const ColorProperties& colorProperties); + s32 emitStartFrame() const { return mEmitStartFrame; } + void setEmitStartFrame(s32 startFrame) { mEmitStartFrame = startFrame; } - const AlphaProperties& alphaProperties() const; - void setAlphaProperties(const AlphaProperties& alphaProperties); + s32 emitEndFrame() const { return mEmitEndFrame; } + void setEmitEndFrame(s32 endFrame) { mEmitEndFrame = endFrame; } - const ScaleProperties& scaleProperties() const; - void setScaleProperties(const ScaleProperties& scaleProperties); + s32 lifeStep() const { return mLifeStep; } + void setLifeStep(s32 lifeStep) { mLifeStep = lifeStep; } - const TextureProperties& textureProperties() const; - void setTextureProperties(const TextureProperties& textureProperties); + s32 lifeStepRandom() const { return mLifeStepRnd; } + void setLifeStepRandom(s32 random) { mLifeStepRnd = random; } - const RotationProperties& rotationProperties() const; - void setRotationProperties(const RotationProperties& rotationProperties); + s32 emitRate() const { return mEmitRate; } + void setEmitRate(s32 emitRate) { mEmitRate = emitRate; } - const CombinerProperties& combinerProperties() const; - void setCombinerProperties(const CombinerProperties& combinerProperties); + // ----- Velocity Properties ----- \\ - const TransformProperties& transformProperties() const; - void setTransformProperties(const TransformProperties& transformProperties); + f32 figureVelocity() const { return mFigureVelocity; } + void setFigureVelocity(f32 velocity) { mFigureVelocity = velocity; } - const ComplexProperties& complexProperties() const; - void setComplexProperties(const ComplexProperties& complexProperties); + const Math::Vector3f& velocityDirection() const { return mVelocityDir; } + void setVelocityDirection(const Math::Vector3f& direction) { mVelocityDir = direction; } - void setChildFlags(const BitFlag& childFlags); - void setFluctuationFlags(const BitFlag& fluxFlags); - void setFieldFlags(const BitFlag& fieldFlags); - void setStripeFlags(const BitFlag& stripeFlags); + f32 initialVelocity() const { return mInitVelocity; } + void setInitialVelocity(f32 velocity) { mInitVelocity = velocity; } - const ChildData& childData() const; - ChildData& childData(); + f32 initialVelocityRandom() const { return mInitVelocityRnd; } + void setInitialVelocityRandom(f32 random) { mInitVelocityRnd = random; } + + const Math::Vector3f& spreadVector() const { return mSpreadVec; } + void setSpreadVector(const Math::Vector3f& vector) { mSpreadVec = vector; } + + f32 airResistance() const { return mAirResistance; } + void setAirResistance(f32 resistance) { mAirResistance = resistance; } + + // ----- Volume Properties ----- \\ + + u8 volumeTblIndex() const { return mVolumeTblIndex; } + void setVolumeTblIndex(u8 index) { mVolumeTblIndex = index; } + + VolumeType volumeType() const { return mVolumeType; } + void setVolumeType(VolumeType type) { mVolumeType = type; } + + const Math::Vector3f& volumeRadius() const { return mVolumeRadius; } + void setVolumeRadius(const Math::Vector3f& radius) { mVolumeRadius = radius; } + + s32 volumeSweepStart() const { return mVolumeSweepStart; } + void setVolumeSweepStart(s32 sweepStart) { mVolumeSweepStart = sweepStart; } + + s32 volumeSweepParam() const { return mVolumeSweepParam; } + void setVolumeSweepParam(s32 sweepParam) { mVolumeSweepParam = sweepParam; } + + // ----- Rotation Properties ----- \\ + + RotType rotationType() const { return mRotType; } + void setRotationType(RotType type) { mRotType = type; } + + const Math::Vector3i& initialRotation() const { return mInitRot; } + void setInitialRotation(const Math::Vector3i& rotation) { mInitRot = rotation; } + + const Math::Vector3i& initialRotationRandom() const { return mInitRotRand; } + void setInitialRotationRandom(const Math::Vector3i& rotation) { mInitRotRand = rotation; } + + const Math::Vector3i& rotationVelocity() const { return mRotVel; } + void setRotationVelocity(const Math::Vector3i& velocity) { mRotVel = velocity; } + + const Math::Vector3i& rotationVelocityRandom() const { return mRotVelRand; } + void setRotationVelocityRandom(const Math::Vector3i& random) { mRotVelRand = random; } + + const Math::Vector2f& rotationBasis() const { return mRotBasis; } + void setRotationBasis(const Math::Vector2f& basis) { mRotBasis = basis; } + + // ----- Alpha Properties ----- \\ + + const AlphaAnim& alphaAnim() const { return mAlphaAnim; } + void setAlphaAnim(const AlphaAnim& alphaAnim) { mAlphaAnim = alphaAnim; } + + // ----- Combiner Properties ----- \\ + + BlendFuncType blendFunction() const { return mBlendFunc; } + void setBlendFunction(BlendFuncType blendFunction) { mBlendFunc = blendFunction; } + + DepthFuncType depthFunction() const { return mDepthFunc; } + void setDepthFunction(DepthFuncType depthFunction) { mDepthFunc = depthFunction; } + + ColorCombinerFuncType combinerFunction() const { return mCombinerFunc; } + void setCombinerFunction(ColorCombinerFuncType combineFunc) { mCombinerFunc = combineFunc; } + + bool isFogEnabled() const { return mFlag.isSet(EmitterFlag::EnableFog); } + void setIsFogEnabled(bool enabled) { mFlag.set(EmitterFlag::EnableFog, enabled); } + + // ----- Color Properties ----- \\ + + const std::array& color0() const { return mColor0; } + + const binColor4f& primaryColor() const { return mColor0[0]; } + void setPrimaryColor(const binColor4f& color) { mColor0[0] = color; } + + const binColor4f& randomColorA() const { return mColor0[0]; } + void setRandomColorA(const binColor4f& color) { mColor0[0] = color; } + + const binColor4f& randomColorB() const { return mColor0[1]; } + void setRandomColorB(const binColor4f& color) { mColor0[1] = color; } + + const binColor4f& randomColorC() const { return mColor0[2]; } + void setRandomColorC(const binColor4f& color) { mColor0[2] = color; } + + const binColor4f& startColor() const { return mColor0[0]; } + void setStartColor(const binColor4f& color) { mColor0[0] = color; } + + const binColor4f& midColor() const { return mColor0[1]; } + void setMidColor(const binColor4f& color) { mColor0[1] = color; } + + const binColor4f& endColor() const { return mColor0[2]; } + void setEndColor(const binColor4f& color) { mColor0[2] = color; } + + s32 colorSection1() const { return mColorSection1; } + void setColorSection1(s32 section) { mColorSection1 = section; } + + s32 colorSection2() const { return mColorSection2; } + void setColorSection2(s32 section) { mColorSection2 = section; } + + s32 colorSection3() const { return mColorSection3; } + void setColorSection3(s32 section) { mColorSection3 = section; } + + s32 colorNumRepeat() const { return mColorNumRepeat; } + void setColorNumRepeat(s32 num) { mColorNumRepeat = num; } + + bool isColorRandom() const { return mFlag.isSet(EmitterFlag::ColorRandom); } + void setIsColorRandom(bool isRandom) { mFlag.set(EmitterFlag::ColorRandom, isRandom); } + + bool isColorAnimation() const { return mFlag.isSet(EmitterFlag::ColorAnimation); } + void setIsColorAnimation(bool isAnim) { mFlag.set(EmitterFlag::ColorAnimation, isAnim); } + + ColorCalcType colorCalcType() const { return mColorCalcType; } + void setColorCalcType(ColorCalcType type) { mColorCalcType = type; } + + const binColor3f& secondaryColor() const { return mColor1; } + void setSecondaryColor(const binColor3f& color) { mColor1 = color; } + + // ----- Texture Properties ----- \\ + + TextureWrap textureWrapT() const { return mTextureWrapT; } + void setTextureWrapT(TextureWrap wrap) { mTextureWrapT = wrap; } + + TextureWrap textureWrapS() const { return mTextureWrapS; } + void setTextureWrapS(TextureWrap wrap) { mTextureWrapS = wrap; } + + TextureFilter textureMagFilter() const { return mTextureMagFilter; } + void setTextureMagFilter(TextureFilter filter) { mTextureMagFilter = filter; } + + TextureFilter textureMinFilter() const { return mTextureMinFilter; } + void setTextureMinFilter(TextureFilter filter) { mTextureMinFilter = filter; } + + TextureMipFilter textureMipFilter() const { return mTextureMipFilter; } + void setTextureMipFilter(TextureMipFilter filter) { mTextureMipFilter = filter; } + + u16 numTexturePattern() const { return mNumTexturePattern; } + void setNumTexturePattern(u16 num) { mNumTexturePattern = num; } + + u8 numTextureDivisionX() const { return mNumTextureDivisionX; } + void setNumTextureDivisionX(u8 num) { + mTextureUVScale.setX(static_cast(numTextureRepetitionsX()) / static_cast(num)); + mNumTextureDivisionX = num; + } + + u8 numTextureDivisionY() const { return mNumTextureDivisionY; } + void setNumTextureDivisionY(u8 num) { + mTextureUVScale.setY(static_cast(numTextureRepetitionsY()) / static_cast(num)); + mNumTextureDivisionY = num; + } + + s32 numTextureRepetitionsX() const { return static_cast(std::round(mTextureUVScale.getX() * static_cast(mNumTextureDivisionX))); } + void setNumTextureRepetitionsX(s32 num) { mTextureUVScale.setX(static_cast(num) / static_cast(mNumTextureDivisionX)); } + + s32 numTextureRepetitionsY() const { return static_cast(std::round(mTextureUVScale.getY() * static_cast(mNumTextureDivisionY))); } + void setNumTextureRepetitionsY(s32 num) { mTextureUVScale.setY(static_cast(num) / static_cast(mNumTextureDivisionY)); } + + const Math::Vector2f& textureUVScale() const { return mTextureUVScale; } + void setTextureUVScale(const Math::Vector2f& scale) { mTextureUVScale = scale; } + + const std::array& texturePatternTable() const { return mTexturePatternTbl; } + void setTexturePatternTable(const std::array& table) { mTexturePatternTbl = table; } + + u16 texturePatternFrequency() const { return mTexturePatternFrequency; } + void setTexturePatternFrequency(u16 frequency) { mTexturePatternFrequency = frequency; } + + u16 texturePatternTableUse() const { return mTexturePatternTblUse; } + void setTexturePatternTableUse(u16 use) { mTexturePatternTblUse = use; } + + bool isTexturePatternAnim() const { return mIsTexturePatternAnim; } + void setIsTexturePatternAnim(bool isAnim) { mIsTexturePatternAnim = isAnim; } + + const TextureHandle& textureHandle() const { return mTextureHandle; } + + Texture* texture() const { return mTextureHandle.get(); } + void setTexture(Texture* texture) { mTextureHandle.set(texture); } + + // ----- Fluctuation Properties ----- \\ - const FluctuationData& fluctuationData() const; - void setFluctuationData(const FluctuationData& fluctuationData); void initFluctuationData(const BinFluctuationData& fluctuationData); - const FieldData& fieldData() const; - FieldData& fieldData(); - void setFieldData(const FieldData& fieldData); + const BitFlag& fluctuationFlags() const { return mFluctuationFlags; } + void setFluctuationFlags(const BitFlag& fluxFlags) { mFluctuationFlags = fluxFlags; } + + f32 fluctuationScale() const { return mFluctuationScale; } + void setFluctuationScale(f32 scale) { mFluctuationScale = scale; } + + f32 fluctuationFrequency() const { return mFluctuationFreq; } + void setFluctuationFrequency(f32 frequency) { mFluctuationFreq = frequency; } + + bool isFluctuationPhaseRandom() const { return mFluctuationPhaseRnd; } + void setFluctuationPhaseRandom(bool random) { mFluctuationPhaseRnd = random; } + + bool isFluctuationEnabled() const { return mFluctuationFlags.isSet(Ptcl::FluctuationFlag::Enabled); } + void setFluctuationEnabled(bool enabled) { mFluctuationFlags.set(Ptcl::FluctuationFlag::Enabled, enabled); } + + bool isFluctuationApplyAlpha() const { return mFluctuationFlags.isSet(Ptcl::FluctuationFlag::ApplyAlpha); } + void setFluctuationApplyAlpha(bool apply) { mFluctuationFlags.set(Ptcl::FluctuationFlag::ApplyAlpha, apply); } + + bool isFluctuationApplyScale() const { return mFluctuationFlags.isSet(Ptcl::FluctuationFlag::ApplyScale); } + void setFluctuationApplyScale(bool apply) { mFluctuationFlags.set(Ptcl::FluctuationFlag::ApplyScale, apply); } + + // ----- Stripe Properties ----- \\ - const StripeData& stripeData() const; - void setStripeData(const StripeData& stripeData); void initStripeData(const BinStripeData& stripeData); + const BitFlag& stripeFlags() const { return mStripeFlags; } + void setStripeFlags(const BitFlag& stripeFlags) { mStripeFlags = stripeFlags; } + bool hasStripeData() const; - void initFromBinary(const BinCommonEmitterData& emitterData); - void initComplexFromBinary(const BinComplexEmitterData& emitterData); + StripeType stripeType() const { return mStripeType; } + void setStripeType(StripeType type) { mStripeType = type; } + + s32 stripeNumHistory() const { return mStripeNumHistory; } + void setStripeNumHistory(s32 num) { mStripeNumHistory = num; } + + f32 stripeStartAlpha() const { return mStripeStartAlpha; } + void setStripeStartAlpha(f32 alpha) { mStripeStartAlpha = alpha; } + + f32 stripeEndAlpha() const { return mStripeEndAlpha; } + void setStripeEndAlpha(f32 alpha) { mStripeEndAlpha = alpha; } + + const Math::Vector2f& stripeUVScrollSpeed() const { return mStripeUVScrollSpeed; } + void setStripeUVScrollSpeed(const Math::Vector2f& speed) { mStripeUVScrollSpeed = speed; } + + s32 stripeHistoryStep() const { return mStripeHistoryStep; } + void setStripeHistoryStep(s32 step) { mStripeHistoryStep = step; } + + f32 stripeDirInterpolate() const { return mStripeDirInterpolate; } + void setStripeDirInterpolate(f32 interp) { mStripeDirInterpolate = interp; } + + bool isStripeEmitterCoord() const { return mStripeFlags.isSet(Ptcl::StripeFlag::EmitterCoord); } + void setStripeEmitterCoord(bool emitterCoord) { mStripeFlags.set(Ptcl::StripeFlag::EmitterCoord, emitterCoord); } + + // ----- Field Properties ----- \\ + + bool isFieldEnabled() const { return mFieldFlags.isSet(FieldFlag::Enabled); } + + const BitFlag& fieldFlags() const { return mFieldFlags; } + void setFieldFlags(const BitFlag& fieldFlags) { mFieldFlags = fieldFlags; } + + // Field Random + + void initFieldRandom(const BinFieldRandomData& randomData); + + bool isFieldRandomEnabled() const { return mFieldFlags.isSet(FieldFlag::Random); } + void setFieldRandomEnabled(bool enabled) { mFieldFlags.set(FieldFlag::Random, enabled); } + + s32 fieldRandomBlank() const { return mFieldRandom.randomBlank; } + void setFieldRandomBlank(s32 blank) { mFieldRandom.randomBlank = blank; } + + const Math::Vector3f& fieldRandomVelAdd() const { return mFieldRandom.randomVelAdd; } + void setFieldRandomVelAdd(const Math::Vector3f& velAdd) { mFieldRandom.randomVelAdd = velAdd; } + + // Field Magnet + + void initFieldMagnet(const BinFieldMagnetData& magnetData); + + bool isFieldMagnetEnabled() const { return mFieldFlags.isSet(FieldFlag::Magnet); } + void setFieldMagnetEnabled(bool enabled) { mFieldFlags.set(FieldFlag::Magnet, enabled); } + + f32 fieldMagnetPower() const { return mFieldMagnet.magnetPower; } + void setFieldMagnetPower(f32 power) { mFieldMagnet.magnetPower = power; } + + const Math::Vector3f& fieldMagnetPos() const { return mFieldMagnet.magnetPos; } + void setFieldMagnetPos(const Math::Vector3f& pos) { mFieldMagnet.magnetPos = pos; } + + const BitFlag& fieldMagnetFlag() const { return mFieldMagnet.magnetFlag; } + + bool isFieldMagnetAxisTargetX() const { return mFieldMagnet.magnetFlag.isSet(FieldMagnetFlag::AxisTargetX); } + void setFieldMagnetAxisTargetX(bool enabled) { mFieldMagnet.magnetFlag.set(FieldMagnetFlag::AxisTargetX, enabled); } + + bool isFieldMagnetAxisTargetY() const { return mFieldMagnet.magnetFlag.isSet(FieldMagnetFlag::AxisTargetY); } + void setFieldMagnetAxisTargetY(bool enabled) { mFieldMagnet.magnetFlag.set(FieldMagnetFlag::AxisTargetY, enabled); } + + bool isFieldMagnetAxisTargetZ() const { return mFieldMagnet.magnetFlag.isSet(FieldMagnetFlag::AxisTargetZ); } + void setFieldMagnetAxisTargetZ(bool enabled) { mFieldMagnet.magnetFlag.set(FieldMagnetFlag::AxisTargetZ, enabled); } + + // Field Spin + + void initFieldSpin(const BinFieldSpinData& spinData); + + bool isFieldSpinEnabled() const { return mFieldFlags.isSet(FieldFlag::Spin); } + void setFieldSpinEnabled(bool enabled) { mFieldFlags.set(FieldFlag::Spin, enabled); } + + s32 fieldSpinRotate() const { return mFieldSpin.spinRotate; } + void setFieldSpinRotate(s32 rotate) { mFieldSpin.spinRotate = rotate; } + + FieldSpinAxis fieldSpinAxis() const { return mFieldSpin.spinAxis; } + void setFieldSpinAxis(FieldSpinAxis axis) { mFieldSpin.spinAxis = axis; } + + // Field Collision + + void initFieldCollision(const BinFieldCollisionData& collisionData); + + bool isFieldCollisionEnabled() const { return mFieldFlags.isSet(FieldFlag::Collision); } + void setFieldCollisionEnabled(bool enabled) { mFieldFlags.set(FieldFlag::Collision, enabled); } + + FieldCollisionType fieldCollisionType() const { return mFieldCollision.collisionType; } + void setFieldCollisionType(FieldCollisionType type) { mFieldCollision.collisionType = type; } + + bool fieldCollisionIsWorld() const { return mFieldCollision.collisionIsWorld; } + void setFieldCollisionIsWorld(bool isWorld) { mFieldCollision.collisionIsWorld = isWorld; } + + f32 fieldCollisionCoord() const { return mFieldCollision.collisionCoord; } + void setFieldCollisionCoord(f32 coord) { mFieldCollision.collisionCoord = coord; } + + f32 fieldCollisionCoef() const { return mFieldCollision.collisionCoef; } + void setFieldCollisionCoef(f32 coef) { mFieldCollision.collisionCoef = coef; } + + // Field Convergence + + void initFieldConvergence(const BinFieldConvergenceData& convergenceData); + + bool isFieldConvergenceEnabled() const { return mFieldFlags.isSet(FieldFlag::Convergence); } + void setFieldConvergenceEnabled(bool enabled) { mFieldFlags.set(FieldFlag::Convergence, enabled); } + + FieldConvergenceType fieldConvergenceType() const { return mFieldConvergence.convergenceType; } + void setFieldConvergenceType(FieldConvergenceType type) { mFieldConvergence.convergenceType = type; } + + const Math::Vector3f& fieldConvergencePos() const { return mFieldConvergence.convergencePos; } + void setFieldConvergencePos(const Math::Vector3f& pos) { mFieldConvergence.convergencePos = pos; } + + // Field PosAdd + + void initFieldPosAdd(const BinFieldPosAddData& posAddData); + + bool isFieldPosAddEnabled() const { return mFieldFlags.isSet(FieldFlag::PosAdd); } + void setFieldPosAddEnabled(bool enabled) { mFieldFlags.set(FieldFlag::PosAdd, enabled); } + + const Math::Vector3f& fieldPosAddPosition() const { return mFieldPosAdd.posAdd; } + void setFieldPosAddPosition(const Math::Vector3f& pos) { mFieldPosAdd.posAdd = pos; } + + // ----- Child Properties ----- \\ + + void initChild(const BinChildData& childData); + + const BitFlag& childFlags() const { return mChildFlags; } + void setChildFlags(const BitFlag& childFlags) { mChildFlags = childFlags; } + + bool isChildEnabled() const { return mChildFlags.isSet(ChildFlag::Enabled); } + void setChildEnabled(bool inherit) { mChildFlags.set(ChildFlag::Enabled, inherit); } + + bool isChildInheritAlpha() const { return mChildFlags.isSet(ChildFlag::AlphaInherit); } + void setChildInheritAlpha(bool inherit) { mChildFlags.set(ChildFlag::AlphaInherit, inherit); } + + bool isChildFollow() const { return mChildFlags.isSet(ChildFlag::IsFollow); } + void setChildFollow(bool follow) { mChildFlags.set(ChildFlag::IsFollow, follow); } + + bool isChildParentField() const { return mChildFlags.isSet(ChildFlag::ParentField); } + void setChildParentField(bool isField) { mChildFlags.set(ChildFlag::ParentField, isField); } + + bool isChildPreDraw() const { return mChildFlags.isSet(ChildFlag::PreChildDraw); } + void setChildPreDraw(bool preDraw) { mChildFlags.set(ChildFlag::PreChildDraw, preDraw); } + + bool isChildInheritParentColor() const { return mChildFlags.isSet(ChildFlag::Color0Inherit); } + void setChildInheritParentColor(bool inherit) { mChildFlags.set(ChildFlag::Color0Inherit, inherit); } + + bool isChildInheritRotation() const { return mChildFlags.isSet(ChildFlag::RotateInherit); } + void setChildInheritRotation(bool inherit) { mChildFlags.set(ChildFlag::RotateInherit, inherit); } + + bool isChildInheritScale() const { return mChildFlags.isSet(ChildFlag::ScaleInherit); } + void setChildInheritScale(bool inherit) { mChildFlags.set(ChildFlag::ScaleInherit, inherit); } + + bool isChildInheritVelocity() const { return mChildFlags.isSet(ChildFlag::VelInherit); } + void setChildInheritVelocity(bool inherit) { mChildFlags.set(ChildFlag::VelInherit, inherit); } + + // Child Basic + + BillboardType childBillboardType() const { return mChild.billboardType; } + void setChildBillboardType(BillboardType type) { + mChild.billboardType = type; + + const bool isPolygon = (type == Ptcl::BillboardType::PolygonXY || type == Ptcl::BillboardType::PolygonXZ); + mChildFlags.set(ChildFlag::IsPolygon, isPolygon); + } + + // Child Emission + + s32 childEmitRate() const { return mChild.emitRate; } + void setChildEmitRate(s32 rate) { mChild.emitRate = rate; } + + s32 childEmitTiming() const { return mChild.emitTiming; } + void setChildEmitTiming(s32 timing) { mChild.emitTiming = timing; } + + s32 childLife() const { return mChild.life; } + void setChildLife(s32 life) { mChild.life = life; } + + s32 childEmitStep() const { return mChild.emitStep; } + void setChildEmitStep(s32 step) { mChild.emitStep = step; } + + // Child Velocity + + const Math::Vector3f& childRandVelocity() const { return mChild.randVel; } + void setChildRandVelocity(const Math::Vector3f& vel) { mChild.randVel = vel; } + + const Math::Vector3f& childGravity() const { return mChild.gravity; } + void setChildGravity(const Math::Vector3f& gravity) { mChild.gravity = gravity; } + + f32 childVelocityInheritRate() const { return mChild.velInheritRate; } + void setChildVelocityInheritRate(f32 rate) { mChild.velInheritRate = rate; } + + f32 childInitalPositionRand() const { return mChild.initPosRand; } + void setChildInitialPositionRand(f32 rand) { mChild.initPosRand = rand; } + + f32 childFigureVelocity() const { return mChild.figurVel; } + void setChildFigureVelocity(f32 vel) { mChild.figurVel = vel; } + + f32 childAirResistance() const { return mChild.airResist; } + void setChildAirResistance(f32 resist) { mChild.airResist = resist; } + + // Child Rotation + + RotType childRotationType() const { return mRotType; } + void setChildRotationType(RotType type) { mRotType = type; } + + const Math::Vector3i& childInitialRotation() const { return mChild.initRot; } + void setChildInitialRotation(const Math::Vector3i& rotation) { mChild.initRot = rotation; } + + const Math::Vector3i& childInitialRotationRandom() const { return mChild.initRotRand; } + void setChildInitialRotationRandom(const Math::Vector3i& rotation) { mChild.initRotRand = rotation; } + + const Math::Vector3i& childRotationVelocity() const { return mChild.rotVel; } + void setChildRotationVelocity(const Math::Vector3i& velocity) { mChild.rotVel = velocity; } + + const Math::Vector3i& childRotationVelocityRandom() const { return mChild.rotVelRand; } + void setChildRotationVelocityRandom(const Math::Vector3i& random) { mChild.rotVelRand = random; } + + const Math::Vector2f& childRotationBasis() const { return mChild.rotBasis; } + void setChildRotationBasis(const Math::Vector2f& basis) { mChild.rotBasis = basis; } + + // Child Scale + + const Math::Vector2f& childScale() const { return mChild.scale; } + void setChildScale(const Math::Vector2f& scale) { mChild.scale = scale; } + + const Math::Vector2f& childScaleTarget() const { return mChild.scaleTarget; } + void setChildScaleTarget(const Math::Vector2f& scale) { mChild.scaleTarget = scale; } + + f32 childScaleInheritRate() const { return mChild.scaleInheritRate; } + void setChildScaleInheritRate(f32 rate) { mChild.scaleInheritRate = rate; } + + s32 childScaleStartFrame() const { return mChild.scaleStartFrame; } + void setChildScaleStartFrame(s32 frame) { mChild.scaleStartFrame = frame; } + + // Child Texture + + TextureWrap childTextureWrapT() const { return mTextureWrapT; } + void setChildTextureWrapT(TextureWrap wrap) { mTextureWrapT = wrap; } + + TextureWrap childTextureWrapS() const { return mChild.textureWrapS; } + void setChildTextureWrapS(TextureWrap wrap) { mChild.textureWrapS = wrap; } + + TextureFilter childTextureMagFilter() const { return mChild.textureMagFilter; } + void setChildTextureMagFilter(TextureFilter filter) { mChild.textureMagFilter = filter; } + + TextureFilter childTextureMinFilter() const { return mChild.textureMinFilter; } + void setChildTextureMinFilter(TextureFilter filter) { mChild.textureMinFilter = filter; } + + TextureMipFilter childTextureMipFilter() const { return mChild.textureMipFilter; } + void setChildTextureMipFilter(TextureMipFilter filter) { mChild.textureMipFilter = filter; } + + const Math::Vector2f& childTextureUVScale() const { return mChild.texUVScale; } + void setChildTextureUVScale(const Math::Vector2f& scale) { mChild.texUVScale = scale; } + + const TextureHandle& childTextureHandle() const { return mChild.textureHandle; } + + Texture* childTexture() const { return mChild.textureHandle.get(); } + void setChildTexture(Texture* texture) { mChild.textureHandle.set(texture); } + + // Child Color + + const binColor4f& childPrimaryColor() const { return mChild.color0; } + void setChildPrimaryColor(const binColor4f& color) { mChild.color0 = color; } + + const binColor3f& childSecondaryColor() const { return mChild.color1; } + void setChildSecondaryColor(const binColor3f& color) { mChild.color1 = color; } + + // Child Alpha + + f32 childAlpha() const { return mChild.alpha; } + void setChildAlpha(f32 alpha) { mChild.alpha = alpha; } + + f32 childAlphaTarget() const { return mChild.alphaTarget; } + void setChildAlphaTarget(f32 alpha) { mChild.alphaTarget = alpha; } + + f32 childAlphaInit() const { return mChild.alphaInit; } + void setChildAlphaInit(f32 alpha) { mChild.alphaInit = alpha; } + + s32 childAlphaStartFrame() const { return mChild.alphaStartFrame; } + void setChildAlphaStartFrame(s32 frame) { mChild.alphaStartFrame = frame; } + + s32 childAlphaBaseFrame() const { return mChild.alphaBaseFrame; } + void setChildAlphaBaseFrame(s32 frame) { mChild.alphaBaseFrame = frame; } + + // Child Combiner + + BlendFuncType childBlendFunc() const { return mChild.blendFunc; } + void setChildBlendFunc(BlendFuncType type) { mChild.blendFunc = type; } + + DepthFuncType childDepthFunc() const { return mChild.depthFunc; } + void setChildDepthFunc(DepthFuncType type) { mChild.depthFunc = type; } + + ColorCombinerFuncType childCombinerFunc() const { return mChild.combinerFunc; } + void setChildCombinerFunc(ColorCombinerFuncType type) { mChild.combinerFunc = type; } private: BitFlag mFlag{}; - BasicProperties mBasicProperties{}; - GravityProperties mGravityProperties{}; - TransformProperties mTransformProperties{}; - LifespanProperties mLifespanProperties{}; - TerminationProperties mTerminationProperties{}; - EmissionProperties mEmissionProperties{}; - VelocityProperties mVelocityProperties{}; - VolumeProperties mVolumeProperties{}; - ColorProperties mColorProperties{}; - AlphaProperties mAlphaProperties{}; - ScaleProperties mScaleProperties{}; - RotationProperties mRotationProperties{}; - TextureProperties mTextureProperties{}; - CombinerProperties mCombinerProperties{}; + // Basic Properties + EmitterType mType{EmitterType::Simple}; + FollowType mFollowType{FollowType::All}; + QString mName{"Emitter"}; + PtclSeed mRandomSeed{}; + BillboardType mBillboardType{BillboardType::Billboard}; + bool mIsPolygon{false}; + bool mIsVelLook{false}; + bool mIsEmitterBillboardMtx{false}; + bool mIsFollow{false}; + + // Gravity Properties + bool mIsDirectional{false}; + Math::Vector3f mGravity{0.0f, -1.0f, 0.0f}; + + // Lifespan Properties + s32 mPtclLife{100}; + s32 mPtclLifeRnd{0}; + + // Termination Properties + bool mIsStopEmitInFade{true}; + f32 mAlphaAddInFade{0.0f}; + + // Transform Properties + Math::Matrix34f mTransformSRT{ + {1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + }; + Math::Matrix34f mTransformRT{ + {1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + }; + // Scale Properties + ScaleAnim mScaleAnim{}; + f32 mScaleRand{0.0f}; + + // Emission Properties + s32 mEmitStartFrame{0}; + s32 mEmitEndFrame{1}; + s32 mLifeStep{10}; + s32 mLifeStepRnd{1}; + s32 mEmitRate{1}; + + // Velocity Properties + f32 mFigureVelocity{0.1f}; + Math::Vector3f mVelocityDir{0.0f, 1.0f, 0.0f}; + f32 mInitVelocity{0.0f}; + f32 mInitVelocityRnd{0.0f}; + Math::Vector3f mSpreadVec{0.0f, 0.0f, 0.0f}; + f32 mAirResistance{1.0f}; + + // Volume Properties + u8 mVolumeTblIndex{0}; + VolumeType mVolumeType{VolumeType::Point}; + Math::Vector3f mVolumeRadius{1.0f, 1.0f, 1.0f}; + s32 mVolumeSweepStart{0}; + s32 mVolumeSweepParam{0}; + + // Rotation Properties + RotType mRotType{RotType::None}; + Math::Vector3i mInitRot{0, 0, 0}; + Math::Vector3i mInitRotRand{0, 0, 0}; + Math::Vector3i mRotVel{0, 0, 0}; + Math::Vector3i mRotVelRand{0, 0, 0}; + Math::Vector2f mRotBasis{0.0f, 0.0f}; + + // Alpha properties + AlphaAnim mAlphaAnim{}; + + // Combiner Properties + BlendFuncType mBlendFunc{BlendFuncType::Translucent}; + DepthFuncType mDepthFunc{DepthFuncType::Unk0}; + ColorCombinerFuncType mCombinerFunc{ColorCombinerFuncType::CombinerConfig0}; + + // Color Properties + std::array mColor0{ + binColor4f{1.0f, 1.0f, 1.0f, 1.0f}, + binColor4f{1.0f, 1.0f, 1.0f, 1.0f}, + binColor4f{1.0f, 1.0f, 1.0f, 1.0f}, + }; + s32 mColorSection1{20}; + s32 mColorSection2{60}; + s32 mColorSection3{80}; + s32 mColorNumRepeat{1}; + ColorCalcType mColorCalcType{ColorCalcType::None}; + + binColor3f mColor1{255.0f, 255.0f, 255.0f}; + + // Texture Properties + TextureWrap mTextureWrapT{TextureWrap::ClampToEdge}; + TextureWrap mTextureWrapS{TextureWrap::ClampToEdge}; + TextureFilter mTextureMagFilter{TextureFilter::Nearest}; + TextureFilter mTextureMinFilter{TextureFilter::Nearest}; + TextureMipFilter mTextureMipFilter{TextureMipFilter::None}; + u16 mNumTexturePattern{1}; + u8 mNumTextureDivisionX{1}; + u8 mNumTextureDivisionY{1}; + Math::Vector2f mTextureUVScale{1.0f, 1.0f}; + std::array mTexturePatternTbl{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + u16 mTexturePatternFrequency{0}; + u16 mTexturePatternTblUse{2}; + bool mIsTexturePatternAnim{false}; TextureHandle mTextureHandle{}; - ComplexProperties mComplexProperties{}; + // ----- Complex Properties ----- \\ + + // Fluctuation Properties + f32 mFluctuationScale{1.0f}; + f32 mFluctuationFreq{20.0f}; + bool mFluctuationPhaseRnd{false}; + BitFlag mFluctuationFlags{ + FluctuationFlag::ApplyAlpha, + FluctuationFlag::ApplyScale + }; + + // Stripe Properties + StripeType mStripeType{StripeType::Billboard}; + s32 mStripeNumHistory{60}; + f32 mStripeStartAlpha{1.0f}; + f32 mStripeEndAlpha{1.0f}; + Math::Vector2f mStripeUVScrollSpeed{0.0f, 0.0f}; + s32 mStripeHistoryStep{1}; + f32 mStripeDirInterpolate{1.0f}; + BitFlag mStripeFlags{}; + + // Field Properties + struct { + s32 randomBlank{1}; + Math::Vector3f randomVelAdd{0.0f, 0.0f, 0.0f}; + } mFieldRandom; + + struct { + f32 magnetPower{0.0f}; + Math::Vector3f magnetPos{0.0f, 0.0f, 0.0f}; + BitFlag magnetFlag{ + FieldMagnetFlag::AxisTargetX, + FieldMagnetFlag::AxisTargetY, + FieldMagnetFlag::AxisTargetZ + }; + } mFieldMagnet; + + struct { + s32 spinRotate{0}; + FieldSpinAxis spinAxis{FieldSpinAxis::AxisX}; + } mFieldSpin; + + struct { + FieldCollisionType collisionType{FieldCollisionType::Die}; + bool collisionIsWorld{false}; + f32 collisionCoord{0.0f}; + f32 collisionCoef{0.0f}; + } mFieldCollision; + + struct { + FieldConvergenceType convergenceType{FieldConvergenceType::AssignedPos}; + Math::Vector3f convergencePos{0.0f, 0.0f, 0.0f}; + } mFieldConvergence; + + struct { + Math::Vector3f posAdd{0.0f, 0.0f, 0.0f}; + } mFieldPosAdd; + + BitFlag mFieldFlags{}; + + // Child Propertiies + struct { + // Basic Properties + BillboardType billboardType{BillboardType::Billboard}; + + // Emission Properties + s32 emitRate{1}; + s32 emitTiming{0}; + s32 life{10}; + s32 emitStep{1}; + + // Velocity Properties + Math::Vector3f randVel{0.0f, 0.0f, 0.0f}; + Math::Vector3f gravity{0.0f, -1.0f, 0.0f}; + f32 velInheritRate{1.0f}; + f32 initPosRand{0.0f}; + f32 figurVel{0.1f}; + f32 airResist{1.0f}; + + // Rotation Properties + RotType rotType{RotType::None}; + Math::Vector3i initRot{0, 0, 0}; + Math::Vector3i initRotRand{0, 0, 0}; + Math::Vector3i rotVel{0, 0, 0}; + Math::Vector3i rotVelRand{0, 0, 0}; + Math::Vector2f rotBasis{0.0f, 0.0f}; + + // Scale properties + Math::Vector2f scale{1.0f, 1.0f}; + Math::Vector2f scaleTarget{1.0f, 1.0f}; + f32 scaleInheritRate{1.0f}; + s32 scaleStartFrame{0}; - ChildData mChildData{}; - FluctuationData mFluctuationData{}; - FieldData mFieldData{}; + // Texture Properties + TextureWrap textureWrapT{TextureWrap::ClampToEdge}; + TextureWrap textureWrapS{TextureWrap::ClampToEdge}; + TextureFilter textureMagFilter{TextureFilter::Nearest}; + TextureFilter textureMinFilter{TextureFilter::Nearest}; + TextureMipFilter textureMipFilter{TextureMipFilter::None}; + Math::Vector2f texUVScale{1.0f, 1.0f}; + TextureHandle textureHandle{}; + + // Color Properties + binColor4f color0{1.0f, 1.0f, 1.0f, 1.0f}; + binColor3f color1{255.0f, 255.0f, 255.0f}; + + // Alpha Properties + f32 alpha{1.0f}; + f32 alphaTarget{1.0f}; + f32 alphaInit{1.0f}; + s32 alphaStartFrame{1}; + s32 alphaBaseFrame{1}; - StripeData mStripeData{}; + // Combiner Properties + BlendFuncType blendFunc{BlendFuncType::Translucent}; + DepthFuncType depthFunc{DepthFuncType::Unk0}; + ColorCombinerFuncType combinerFunc{ColorCombinerFuncType::CombinerConfig0}; + } mChild; + + BitFlag mChildFlags{ + ChildFlag::AlphaInherit, + ChildFlag::ScaleInherit, + ChildFlag::RotateInherit, + ChildFlag::IsFollow, + ChildFlag::Unk80 + }; }; diff --git a/include/ptcl/ptclEmitterSet.h b/include/ptcl/ptclEmitterSet.h index aeb926f..45544e5 100644 --- a/include/ptcl/ptclEmitterSet.h +++ b/include/ptcl/ptclEmitterSet.h @@ -23,6 +23,7 @@ class EmitterSet { public: EmitterSet() = default; + EmitterSet(QString emitterName); EmitterSet(const BinEmitterSet& binEmitterSet); EmitterList& emitters(); @@ -38,19 +39,17 @@ class EmitterSet u32 userData() const; void setUserData(u32 data); - void addNewEmitter(); - void removeEmitter(s32 emitterIndex); + void insertEmitter(s32 emitterIndex, std::unique_ptr emitter); + std::unique_ptr removeEmitter(s32 emitterIndex); std::unique_ptr clone() const; - const std::unique_ptr& appendEmitter(std::unique_ptr& newEmitter); - private: - QString mName; - EmitterList mEmitters; + QString mName{}; + EmitterList mEmitters{}; - u32 mUserData; - u32 mLastUpdateDate; // TODO: check this + u32 mUserData{0}; + u32 mLastUpdateDate{0}; // TODO: check this }; diff --git a/include/ptcl/ptclFieldData.h b/include/ptcl/ptclFieldData.h deleted file mode 100644 index 893f4a6..0000000 --- a/include/ptcl/ptclFieldData.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include "typedefs.h" -#include "util/bitflagUtil.h" -#include "ptcl/ptclEnum.h" -#include "math/vector.h" - - -namespace Ptcl { - - -struct BinFieldRandomData; -struct BinFieldMagnetData; -struct BinFieldSpinData; -struct BinFieldCollisionData; -struct BinFieldConvergenceData; -struct BinFieldPosAddData; - - -// ========================================================================== // - - -class FieldData { -public: - struct FieldRandomData { - s32 randomBlank{1}; - Math::Vector3f randomVelAdd{0.0f, 0.0f, 0.0f}; - }; - - struct FieldMagnetData { - f32 magnetPower{0.0f}; - Math::Vector3f magnetPos{0.0f, 0.0f, 0.0f}; - BitFlag magnetFlag{ - FieldMagnetFlag::AxisTargetX, - FieldMagnetFlag::AxisTargetY, - FieldMagnetFlag::AxisTargetZ - }; - }; - - struct FieldSpinData { - s32 spinRotate{0}; - FieldSpinAxis spinAxis{FieldSpinAxis::AxisX}; - }; - - struct FieldCollisionData { - FieldCollisionType collisionType{FieldCollisionType::Die}; - bool collisionIsWorld{false}; - f32 collisionCoord{0.0f}; - f32 collisionCoef{0.0f}; - }; - - struct FieldConvergenceData { - FieldConvergenceType convergenceType{FieldConvergenceType::AssignedPos}; - Math::Vector3f convergencePos{0.0f, 0.0f, 0.0f}; - }; - - struct FieldPosAddData { - Math::Vector3f posAdd{0.0f, 0.0f, 0.0f}; - }; - -public: - FieldData() = default; - - const FieldRandomData& randomData() const; - void setRandomData(const FieldRandomData& randomData); - void initRandomData(const BinFieldRandomData& randomData); - - const FieldMagnetData& magnetData() const; - void setMagnetData(const FieldMagnetData& magnetData); - void initMagnetData(const BinFieldMagnetData& magnetData); - - const FieldSpinData& spinData() const; - void setSpinData(const FieldSpinData& spinData); - void initSpinData(const BinFieldSpinData& spinData); - - const FieldCollisionData& collisionData() const; - void setCollisionData(const FieldCollisionData& collisionData); - void initCollisionData(const BinFieldCollisionData& collisionData); - - const FieldConvergenceData& convergenceData() const; - void setConvergenceData(const FieldConvergenceData& convergenceData); - void initConvergenceData(const BinFieldConvergenceData& convergenceData); - - const FieldPosAddData& posAddData() const; - void setPosAddData(const FieldPosAddData& posAddData); - void initPosAddData(const BinFieldPosAddData& posAddData); - -private: - FieldRandomData mRandomData; - FieldMagnetData mMagnetData; - FieldSpinData mSpinData; - FieldCollisionData mCollisionData; - FieldConvergenceData mConvergenceData; - FieldPosAddData mPosAddData; -}; - - -// ========================================================================== // - - -} // namespace Ptcl diff --git a/include/ptcl/ptclFluctuationData.h b/include/ptcl/ptclFluctuationData.h deleted file mode 100644 index 876169f..0000000 --- a/include/ptcl/ptclFluctuationData.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "typedefs.h" - -namespace Ptcl { - - -// ========================================================================== // - - -struct FluctuationData { - f32 fluctuationScale{1.0f}; - f32 fluctuationFreq{20.0f}; - bool fluctuationPhaseRnd{false}; -}; - - -// ========================================================================== // - - -} // namespace Ptcl diff --git a/include/ptcl/ptclSeed.h b/include/ptcl/ptclSeed.h index 3a54f90..0044f6b 100644 --- a/include/ptcl/ptclSeed.h +++ b/include/ptcl/ptclSeed.h @@ -27,6 +27,8 @@ class PtclSeed { u32 raw() const; void setRaw(u32 raw); + bool operator==(const PtclSeed&) const = default; + private: u32 mValue = 1; }; diff --git a/include/ptcl/ptclStripeData.h b/include/ptcl/ptclStripeData.h deleted file mode 100644 index 80c9eae..0000000 --- a/include/ptcl/ptclStripeData.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "math/vector.h" -#include "ptcl/ptclEnum.h" -#include "typedefs.h" - - -namespace Ptcl { - - -// ========================================================================== // - - -struct StripeData -{ - StripeType type{StripeType::Billboard}; - s32 numHistory{60}; - f32 startAlpha{1.0f}; - f32 endAlpha{1.0f}; - Math::Vector2f uvScrollSpeed{0.0f, 0.0f}; - s32 historyStep{1}; - f32 dirInterpolate{1.0f}; -}; - - -// ========================================================================== // - - -} // namespace Ptcl diff --git a/include/ptcl/ptclTexture.h b/include/ptcl/ptclTexture.h index a03e4f2..bbc7489 100644 --- a/include/ptcl/ptclTexture.h +++ b/include/ptcl/ptclTexture.h @@ -31,10 +31,9 @@ class Texture { bool isPlaceholder() const; - void replaceTexture(std::vector* encodedData, s32 width, s32 height, TextureFormat format); - void replaceTexture(const Texture& other); + void swapTexture(Texture& other); - static const std::shared_ptr& placeholder(); + static Texture* placeholder(); void setUserCountCallback(UserCountCallback callback); @@ -68,7 +67,7 @@ class Texture { class TextureHandle { public: - TextureHandle(std::shared_ptr texture = nullptr); + TextureHandle(Texture* texture = nullptr); TextureHandle(const TextureHandle& other); TextureHandle(TextureHandle&& other) noexcept; @@ -82,18 +81,18 @@ class TextureHandle { void invalidate(); bool isValid() const; - std::shared_ptr get() const; - void set(const std::shared_ptr& texture); + Texture* get() const; + void set(Texture* texture); - TextureHandle& operator=(const std::shared_ptr& texture); - std::shared_ptr operator->() const; + TextureHandle& operator=(Texture* texture); + Texture* operator->() const; private: void incrementCount(); void decrementCount(); private: - std::shared_ptr mTexturePtr; + Texture* mTexturePtr; }; diff --git a/src/editor/childEditor/childEditorWidget.cpp b/src/editor/childEditor/childEditorWidget.cpp deleted file mode 100644 index 76621fe..0000000 --- a/src/editor/childEditor/childEditorWidget.cpp +++ /dev/null @@ -1,285 +0,0 @@ -#include "editor/components/collapsibleWidget.h" -#include "editor/childEditor/childEditorWidget.h" -#include "editor/childEditor/combinerPropertiesWidget.h" -#include "editor/childEditor/alphaPropertiesWidget.h" -#include "editor/childEditor/basicPropertiesWidget.h" -#include "editor/childEditor/colorPropertiesWidget.h" -#include "editor/childEditor/emissionPropertiesWidget.h" -#include "editor/childEditor/rotationPropertiesWidget.h" -#include "editor/childEditor/scalePropertiesWidget.h" -#include "editor/childEditor/texturePropertiesWidget.h" -#include "editor/childEditor/velocityPropertiesWidget.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -ChildEditorWidget::ChildEditorWidget(QWidget* parent) : - QWidget{parent} { - - mBasicProperties = new BasicPropertiesWidget(this); - mEmissionProperties = new EmissionPropertiesWidget(this); - mVelocityProperties = new VelocityPropertiesWidget(this); - mRotationProperties = new RotationPropertiesWidget(this); - mScaleProperties = new ScalePropertiesWidget(this); - mTextureProperties = new TexturePropertiesWidget(this); - mColorProperties = new ColorPropertiesWidget(this); - mAlphaProperties = new AlphaPropertiesWidget(this); - mCombinerProperties = new CombinerPropertiesWidget(this); - - // Standard Widget - auto* standardWidget = new QWidget(this); - auto* mainLayout = new QVBoxLayout(standardWidget); - standardWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); - standardWidget->setMinimumWidth(400); - - auto* scrollArea = new QScrollArea(this); - scrollArea->setWidget(standardWidget); - scrollArea->setWidgetResizable(true); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setFrameShape(QFrame::NoFrame); - - auto* outerLayout = new QVBoxLayout(this); - outerLayout->addWidget(scrollArea); - outerLayout->setContentsMargins(0, 0, 0, 0); - setLayout(outerLayout); - - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - - setupLayout(mainLayout); - setupConnections(); -} - -void ChildEditorWidget::setupLayout(QVBoxLayout* mainLayout) { - // ChildData row - auto* childDataRow = new QHBoxLayout(); - auto* childDataLabel = new QLabel("Child Emitter:"); - mEnabledCheckbox.setText("Enabled"); - - childDataRow->addWidget(childDataLabel); - childDataRow->addWidget(&mEnabledCheckbox); - childDataRow->addStretch(); - - mainLayout->addLayout(childDataRow); - - // Section Containers - mSectionsContainer = new QWidget(this); - auto* sectionsLayout = new QVBoxLayout(mSectionsContainer); - sectionsLayout->setContentsMargins(0, 0, 0, 0); - - auto addSection = [sectionsLayout](const QString& title, QWidget* widget) { - auto* section = new CollapsibleWidget(title); - section->setContent(widget); - sectionsLayout->addWidget(section); - }; - - addSection("Basic properties", mBasicProperties); - addSection("Emission properties", mEmissionProperties); - addSection("Velocity properties", mVelocityProperties); - addSection("Rotation properties", mRotationProperties); - addSection("Scale properties", mScaleProperties); - addSection("Texture Properties", mTextureProperties); - addSection("Color Properties", mColorProperties); - addSection("Alpha Properties", mAlphaProperties); - addSection("Combiner Properties", mCombinerProperties); - - sectionsLayout->addStretch(); - - mainLayout->addWidget(mSectionsContainer); - mainLayout->addStretch(); -} - -void ChildEditorWidget::setupConnections() { - // Enabled - connect(&mEnabledCheckbox, &QCheckBox::clicked, this, [this](bool checked) { - if (!mDataPtr) { return; } - - mSectionsContainer->setEnabled(checked); - mChildFlag.set(Ptcl::ChildFlag::Enabled, checked); - emit flagsUpdated(mChildFlag); - }); - - // Basic Properties - connect(mBasicProperties, &BasicPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::BasicProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setBasicProperties(properties); - }); - - connect(mBasicProperties, &BasicPropertiesWidget::isFollowUpdated, this, [this](bool follow) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::IsFollow, follow); - emit flagsUpdated(mChildFlag); - }); - - connect(mBasicProperties, &BasicPropertiesWidget::isParentFieldUpdated, this, [this](bool field) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::ParentField, field); - emit flagsUpdated(mChildFlag); - }); - - connect(mBasicProperties, &BasicPropertiesWidget::isPolygonUpdated, this, [this](bool polygon) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::IsPolygon, polygon); - emit flagsUpdated(mChildFlag); - }); - - connect(mBasicProperties, &BasicPropertiesWidget::isPreDrawUpdated, this, [this](bool preDraw) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::PreChildDraw, preDraw); - emit flagsUpdated(mChildFlag); - }); - - // Emission Properties - connect(mEmissionProperties, &EmissionPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::EmissionProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setEmissionProperties(properties); - }); - - // Velocity Properties - connect(mVelocityProperties, &VelocityPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::VelocityProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setVelocityProperties(properties); - }); - - connect(mVelocityProperties, &VelocityPropertiesWidget::inheritVelUpdated, this, [this](bool inherit) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::VelInherit, inherit); - emit flagsUpdated(mChildFlag); - }); - - // Rotation Properties - connect(mRotationProperties, &RotationPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::RotationProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setRotationProperties(properties); - }); - - connect(mRotationProperties, &RotationPropertiesWidget::inheritRotationUpdated, this, [this](bool inherit) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::RotateInherit, inherit); - emit flagsUpdated(mChildFlag); - }); - - // Scale Properties - connect(mScaleProperties, &ScalePropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::ScaleProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setScaleProperties(properties); - }); - - connect(mScaleProperties, &ScalePropertiesWidget::inheritScaleUpdated, this, [this](bool inherit) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::ScaleInherit, inherit); - emit flagsUpdated(mChildFlag); - }); - - // Texture Properties - connect(mTextureProperties, &TexturePropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::TextureProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setTextureProperties(properties); - }); - - connect(mTextureProperties, &TexturePropertiesWidget::textureUpdated, this, [this](const std::shared_ptr& oldTexture, const std::shared_ptr& newTexture) { - if (!mDataPtr) { return; } - mDataPtr->setTexture(newTexture); - mCombinerProperties->updateCombinerPreview(); - }); - - // Color Properties - connect(mColorProperties, &ColorPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::ColorProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setColorProperties(properties); - mCombinerProperties->updateCombinerPreview(); - }); - - connect(mColorProperties, &ColorPropertiesWidget::inheritColorUpdated, this, [this](bool inherit) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::Color0Inherit, inherit); - emit flagsUpdated(mChildFlag); - setCombinerPropertiesSrc(); - }); - - // Alpha Properties - connect(mAlphaProperties, &AlphaPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::AlphaProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setAlphaProperties(properties); - }); - - connect(mAlphaProperties, &AlphaPropertiesWidget::inheritAlphaUpdated, this, [this](bool inherit) { - if (!mDataPtr) { return; } - mChildFlag.set(Ptcl::ChildFlag::AlphaInherit, inherit); - emit flagsUpdated(mChildFlag); - }); - - // Combiner Properties - connect(mCombinerProperties, &CombinerPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::ChildData::CombinerProperties& properties) { - if (!mDataPtr) { return; } - mDataPtr->setCombinerProperties(properties); - }); -} - -void ChildEditorWidget::setChildData(Ptcl::ChildData* childData, const BitFlag& childFlag) { - QSignalBlocker b1(mBasicProperties); - QSignalBlocker b2(mEmissionProperties); - QSignalBlocker b3(mVelocityProperties); - QSignalBlocker b4(mRotationProperties); - QSignalBlocker b5(mScaleProperties); - QSignalBlocker b6(mTextureProperties); - QSignalBlocker b7(mColorProperties); - QSignalBlocker b8(mAlphaProperties); - QSignalBlocker b9(mCombinerProperties); - - mDataPtr = childData; - mChildFlag = childFlag; - - mBasicProperties->setProperties(mDataPtr->basicProperties(), mChildFlag.isSet(Ptcl::ChildFlag::IsFollow), mChildFlag.isSet(Ptcl::ChildFlag::ParentField), mChildFlag.isSet(Ptcl::ChildFlag::PreChildDraw)); - mEmissionProperties->setProperties(mDataPtr->emissionProperties()); - mVelocityProperties->setProperties(mDataPtr->velocityProperties(), mChildFlag.isSet(Ptcl::ChildFlag::VelInherit)); - mRotationProperties->setProperties(mDataPtr->rotationProperties(), mChildFlag.isSet(Ptcl::ChildFlag::RotateInherit)); - mScaleProperties->setProperties(mDataPtr->scaleProperties(), mChildFlag.isSet(Ptcl::ChildFlag::ScaleInherit)); - mTextureProperties->setProperties(mDataPtr->textureProperties(), mDataPtr->textureHandle().get()); - mColorProperties->setProperties(mDataPtr->colorProperties(), mChildFlag.isSet(Ptcl::ChildFlag::Color0Inherit)); - mAlphaProperties->setProperties(mDataPtr->alphaProperties(), mChildFlag.isSet(Ptcl::ChildFlag::AlphaInherit)); - mCombinerProperties->setProperties(mDataPtr->combinerProperties()); - setCombinerPropertiesSrc(); - - const bool isEnabled = mChildFlag.isSet(Ptcl::ChildFlag::Enabled); - mEnabledCheckbox.setChecked(isEnabled); - mSectionsContainer->setEnabled(isEnabled); - - setEnabled(true); -} - -void ChildEditorWidget::setTextureList(const Ptcl::TextureList* textureList) { - mTextureList = textureList; - mTextureProperties->setTextureList(textureList); -} - -void ChildEditorWidget::setParentColor0(const Ptcl::binColor4f& parentColor0) { - mParentColor0 = parentColor0; - mCombinerProperties->updateCombinerPreview(); -}; - -void ChildEditorWidget::setCombinerPropertiesSrc() { - if (mChildFlag.isSet(Ptcl::ChildFlag::Color0Inherit)) { - mCombinerProperties->setCombinerSrc(&mDataPtr->textureHandle(), &mDataPtr->colorProperties().color1, &mParentColor0); - } else { - mCombinerProperties->setCombinerSrc(&mDataPtr->textureHandle(), &mDataPtr->colorProperties().color1, &mDataPtr->colorProperties().color0); - } - mCombinerProperties->updateCombinerPreview(); -} - -void ChildEditorWidget::clear() { - setEnabled(false); - mDataPtr = nullptr; -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/childEditor/colorPropertiesWidget.cpp b/src/editor/childEditor/colorPropertiesWidget.cpp deleted file mode 100644 index 05ef0a5..0000000 --- a/src/editor/childEditor/colorPropertiesWidget.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "editor/childEditor/colorPropertiesWidget.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -ChildEditorWidget::ColorPropertiesWidget::ColorPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - auto* mainLayout = new QFormLayout(this); - - mInheritColorCheckBox.setText("Inherit Parent Color 0"); - mColor1Widget.enableAlpha(false); - - mainLayout->addRow("Color:", &mInheritColorCheckBox); - mainLayout->addRow("Color 0:", &mColor0Widget); - mainLayout->addRow("Color 1:", &mColor1Widget); - - setLayout(mainLayout); - setupConnections(); -} - -void ChildEditorWidget::ColorPropertiesWidget::setupConnections() { - // Inherit Color - connect(&mInheritColorCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - QSignalBlocker b1(mColor0Widget); - mColor0Widget.setDisabled(checked); - emit inheritColorUpdated(checked); - }); - - // Color 0 - connect(&mColor0Widget, &RGBAColorWidget::colorChanged, this, [this]() { - mProps.color0 = mColor0Widget.color(); - emit propertiesUpdated(mProps); - }); - - // Color 1 - connect(&mColor1Widget, &RGBAColorWidget::colorChanged, this, [this]() { - const auto& color = mColor1Widget.color(); - - Ptcl::binColor3f newColor{ - color.r * 255.0f, - color.g * 255.0f, - color.b * 255.0f - }; - - mProps.color1 = newColor; - emit propertiesUpdated(mProps); - }); -} - -void ChildEditorWidget::ColorPropertiesWidget::setProperties(const Ptcl::ChildData::ColorProperties& properties, bool inheritColor) { - QSignalBlocker b1(mColor0Widget); - QSignalBlocker b2(mColor1Widget); - QSignalBlocker b3(mInheritColorCheckBox); - - mProps = properties; - - mColor0Widget.setColor(mProps.color0); - mColor0Widget.setDisabled(inheritColor); - - Ptcl::binColor4f color1{ - std::clamp(mProps.color1.r / 255.0f, 0.0f, 1.0f), - std::clamp(mProps.color1.g / 255.0f, 0.0f, 1.0f), - std::clamp(mProps.color1.b / 255.0f, 0.0f, 1.0f), - 1.0f - }; - mColor1Widget.setColor(color1); - mInheritColorCheckBox.setChecked(inheritColor); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/childEditor/combinerPropertiesWidget.cpp b/src/editor/childEditor/combinerPropertiesWidget.cpp deleted file mode 100644 index d17acc5..0000000 --- a/src/editor/childEditor/combinerPropertiesWidget.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "editor/childEditor/combinerPropertiesWidget.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -ChildEditorWidget::CombinerPropertiesWidget::CombinerPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - auto* mainLayout = new QFormLayout(this); - - mainLayout->addRow("Blend Function:", &mBlendFuncComboBox); - mainLayout->addRow("Depth Function:", &mDepthFuncComboBox); - mainLayout->addRow("Combiner Function:", &mCombinerFuncComboBox); - mainLayout->addWidget(&mCombinerPreview); - - connect(&mBlendFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { - mProps.blendFunc = mBlendFuncComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - connect(&mDepthFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { - mProps.depthFunc = mDepthFuncComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - connect(&mCombinerFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { - auto value = mCombinerFuncComboBox.currentEnum(); - mProps.combinerFunc = value; - mCombinerPreview.setConfig(static_cast(value)); - emit propertiesUpdated(mProps); - }); -} - -void ChildEditorWidget::CombinerPropertiesWidget::setProperties(const Ptcl::ChildData::CombinerProperties& properties) { - QSignalBlocker b1(mBlendFuncComboBox); - QSignalBlocker b2(mDepthFuncComboBox); - QSignalBlocker b3(mCombinerFuncComboBox); - - mProps = properties; - - mBlendFuncComboBox.setCurrentEnum(mProps.blendFunc); - mDepthFuncComboBox.setCurrentEnum(mProps.depthFunc); - mCombinerFuncComboBox.setCurrentEnum(mProps.combinerFunc); - mCombinerPreview.setConfig(static_cast(mProps.combinerFunc)); -} - -void ChildEditorWidget::CombinerPropertiesWidget::setCombinerSrc(const Ptcl::TextureHandle* texture, const Ptcl::binColor3f* constant, const Ptcl::binColor4f* primary) { - mCombinerPreview.setCombinerSrc(texture, constant, primary); -} - -void ChildEditorWidget::CombinerPropertiesWidget::updateCombinerPreview() { - mCombinerPreview.updateStages(); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/childEditor/scalePropertiesWidget.cpp b/src/editor/childEditor/scalePropertiesWidget.cpp deleted file mode 100644 index f35aee5..0000000 --- a/src/editor/childEditor/scalePropertiesWidget.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "editor/childEditor/scalePropertiesWidget.h" - -#include - -namespace PtclEditor { - - -// ========================================================================== // - - -ChildEditorWidget::ScalePropertiesWidget::ScalePropertiesWidget(QWidget* parent) : - QWidget{parent} { - - auto* mainLayout = new QFormLayout(this); - - mInheritScaleCheckBox.setText("Inherit Parent Scale"); - mInheritRateSpinBox.setRange(0.0f, 1.0f); - mInheritRateSpinBox.setSingleStep(0.1f); - mScaleSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mScaleTargetSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mStartFrameSpinBox.setRange(0, std::numeric_limits::max()); - - mainLayout->addRow("Scale:", &mInheritScaleCheckBox); - mainLayout->addRow("Inherit Rate:", &mInheritRateSpinBox); - mainLayout->addRow("Initial Scale:", &mScaleSpinBox); - mainLayout->addRow("Target Scale:", &mScaleTargetSpinBox); - mainLayout->addRow("Start Frame:", &mStartFrameSpinBox); - - setupConnections(); -} - -void ChildEditorWidget::ScalePropertiesWidget::setupConnections() { - // Inherit Scale - connect(&mInheritScaleCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit inheritScaleUpdated(checked); - }); - - // Scale - connect(&mScaleSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.scale = mScaleSpinBox.getVector(); - emit propertiesUpdated(mProps); - }); - - // Scale Target - connect(&mScaleTargetSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.scaleTarget = mScaleTargetSpinBox.getVector(); - emit propertiesUpdated(mProps); - }); - - // Inherit Rate - connect(&mInheritRateSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.scaleInheritRate = static_cast(value); - emit propertiesUpdated(mProps); - }); - - // Inherit Rate - connect(&mStartFrameSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mProps.scaleStartFrame = value; - emit propertiesUpdated(mProps); - }); -} - -void ChildEditorWidget::ScalePropertiesWidget::setProperties(const Ptcl::ChildData::ScaleProperties& properties, bool inheritScale) { - QSignalBlocker b1(mScaleSpinBox); - QSignalBlocker b2(mScaleTargetSpinBox); - QSignalBlocker b3(mInheritRateSpinBox); - QSignalBlocker b4(mStartFrameSpinBox); - QSignalBlocker b5(mInheritScaleCheckBox); - - mProps = properties; - - mScaleSpinBox.setVector(mProps.scale); - mScaleTargetSpinBox.setVector(mProps.scaleTarget); - mInheritRateSpinBox.setValue(mProps.scaleInheritRate); - mStartFrameSpinBox.setValue(mProps.scaleStartFrame); - mInheritScaleCheckBox.setChecked(inheritScale); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/childEditor/velocityPropertiesWidget.cpp b/src/editor/childEditor/velocityPropertiesWidget.cpp deleted file mode 100644 index 7e2563b..0000000 --- a/src/editor/childEditor/velocityPropertiesWidget.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "editor/childEditor/velocityPropertiesWidget.h" - -#include - -namespace PtclEditor { - - -// ========================================================================== // - - -ChildEditorWidget::VelocityPropertiesWidget::VelocityPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - // TODO: Determine better ranges? - mRandVelSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mGravitySpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mVelInheritSpinBox.setRange(0.0f, 1.0f); - mInitPosRandSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mFigureVelSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mAirResistSpinBox.setRange(0.0f, 1.0f); - - auto* mainLayout = new QFormLayout(this); - - mainLayout->addRow("Random Velocity:", &mRandVelSpinBox); - mainLayout->addRow("Gravity:", &mGravitySpinBox); - mainLayout->addRow("Inherit Parent Velocity:", &mInheritVelCheckBox); - mainLayout->addRow("Velocity Inherit Rate:", &mVelInheritSpinBox); - mainLayout->addRow("Inital Position Random:", &mInitPosRandSpinBox); - mainLayout->addRow("Figure Velocity:", &mFigureVelSpinBox); - mainLayout->addRow("Air Resistance:", &mAirResistSpinBox); - - setupConnections(); -} - -void ChildEditorWidget::VelocityPropertiesWidget::setupConnections() { - // Rand Velocity - connect(&mRandVelSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.randVel = mRandVelSpinBox.getVector(); - emit propertiesUpdated(mProps); - }); - - // Gravity - connect(&mGravitySpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.gravity = mGravitySpinBox.getVector(); - emit propertiesUpdated(mProps); - }); - - // Inherit Velocity - connect(&mInheritVelCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - QSignalBlocker b1(mVelInheritSpinBox); - mVelInheritSpinBox.setEnabled(checked); - emit inheritVelUpdated(checked); - }); - - // Inherit Rate - connect(&mVelInheritSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.velInheritRate = static_cast(value); - emit propertiesUpdated(mProps); - }); - - // Init Pos Rand - connect(&mInitPosRandSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.initPosRand = static_cast(value); - emit propertiesUpdated(mProps); - }); - - // Figure Velocity - connect(&mFigureVelSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.figurVel = static_cast(value); - emit propertiesUpdated(mProps); - }); - - // Air Resistance - connect(&mAirResistSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.airResist = static_cast(value); - emit propertiesUpdated(mProps); - }); -} - -void ChildEditorWidget::VelocityPropertiesWidget::setProperties(const Ptcl::ChildData::VelocityProperties& properties, bool inheritVelocity) { - QSignalBlocker b1(mRandVelSpinBox); - QSignalBlocker b2(mGravitySpinBox); - QSignalBlocker b3(mVelInheritSpinBox); - QSignalBlocker b4(mInitPosRandSpinBox); - QSignalBlocker b5(mFigureVelSpinBox); - QSignalBlocker b6(mAirResistSpinBox); - QSignalBlocker b7(mInheritVelCheckBox); - - mProps = properties; - - mRandVelSpinBox.setVector(mProps.randVel); - mGravitySpinBox.setVector(mProps.gravity); - mVelInheritSpinBox.setValue(mProps.velInheritRate); - mVelInheritSpinBox.setEnabled(inheritVelocity); - mInitPosRandSpinBox.setValue(mProps.initPosRand); - mFigureVelSpinBox.setValue(mProps.figurVel); - mAirResistSpinBox.setValue(mProps.airResist); - mInheritVelCheckBox.setChecked(inheritVelocity); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterSetWidget.cpp b/src/editor/emitterSetWidget.cpp deleted file mode 100644 index 1a03b9a..0000000 --- a/src/editor/emitterSetWidget.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "editor/emitterSetWidget.h" -#include "util/nameValidator.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterSetWidget::EmitterSetWidget(QWidget* parent) : - QWidget{parent} { - mNameLineEdit.setPlaceholderText("EmitterSetName"); - mNameLineEdit.setValidator(new EmitterNameValidator(&mNameLineEdit)); - // TODO: Check these - mUserDataSpinBox.setRange(std::numeric_limits::min(), std::numeric_limits::max()); - mLastUpdateSpinBox.setRange(std::numeric_limits::min(), std::numeric_limits::max()); - - auto* mainLayout = new QFormLayout(this); - mainLayout->addRow("EmitterSet Name:", &mNameLineEdit); - mainLayout->addRow("UserData:", &mUserDataSpinBox); - mainLayout->addRow("LastUpdate:", &mLastUpdateSpinBox); - - setupConnections(); -} - -void EmitterSetWidget::setupConnections() { - // Name Edit - connect(&mNameLineEdit, &QLineEdit::textEdited, this, [this](const QString& text) { - if (!mEmitterSetPtr) { - return; - } - mEmitterSetPtr->setName(text); - emit emitterSetNamedChanged(); - emit propertiesChanged(); - }); - - // User Data - connect(&mUserDataSpinBox, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - mEmitterSetPtr->setUserData(static_cast(value)); - emit propertiesChanged(); - }); - - // Last Update - connect(&mLastUpdateSpinBox, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - mEmitterSetPtr->setLastUpdateDate(static_cast(value)); - emit propertiesChanged(); - }); -} - -void EmitterSetWidget::setEmitterSet(Ptcl::EmitterSet* emitterSet) { - setEnabled(true); - mEmitterSetPtr = emitterSet; - populateProperties(); -} - -void EmitterSetWidget::clear() { - setEnabled(false); - mEmitterSetPtr = nullptr; -} - -void EmitterSetWidget::populateProperties() { - blockSignals(true); - - mNameLineEdit.setText(mEmitterSetPtr->name()); - mUserDataSpinBox.setValue(mEmitterSetPtr->userData()); - mLastUpdateSpinBox.setValue(mEmitterSetPtr->lastUpdateDate()); - - blockSignals(false); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterWidget/alphaPropertiesWidget.cpp b/src/editor/emitterWidget/alphaPropertiesWidget.cpp deleted file mode 100644 index 56c9e20..0000000 --- a/src/editor/emitterWidget/alphaPropertiesWidget.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "editor/emitterWidget/alphaPropertiesWidget.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterWidget::AlphaPropertiesWidget::AlphaPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - mGraphA.setLineColor(QColor{20, 40, 60}); - mGraphA.setTickStepSize(0.1f); - mGraphA.setValueSnap(0.1f); - mGraphA.setValueRange(0.0f, 1.0f); - - auto* mainLayout = new QFormLayout(this); - mainLayout->addRow("Alpha Anim:", &mGraphA); - - connect(&mGraphA, &AnimGraph::pointEdited, this, [this](s32 pointIndex, const AnimGraph::GraphPoint& point) { - const f32 oldP0 = mProps.initAlpha; - const f32 oldP1 = oldP0 + mProps.diffAlpha21; - const f32 oldP2 = oldP1; - const f32 oldP3 = oldP2 + mProps.diffAlpha32; - - auto updateAlphaSection = [&](s32* section, bool isSection2 = false) { - mProps.diffAlpha21 = point.value - oldP0; - mProps.diffAlpha32 = oldP3 - point.value; - - const f32 sec1 = mGraphA.getPoints()[1].position; - const f32 sec2 = mGraphA.getPoints()[2].position; - - if (std::abs(sec1 - sec2) < std::numeric_limits::epsilon()) { - mProps.alphaSection1 = -127; // Disable section1 if handles overlap - if (isSection2) { *section = static_cast(point.position); } - } else { - *section = (std::abs(sec2 - 100.0f) < std::numeric_limits::epsilon()) ? 128 : static_cast(point.position); - } - }; - - switch (pointIndex) { - case 0: - mProps.initAlpha = point.value; - mProps.diffAlpha21 = oldP1 - point.value; - break; - case 1: - updateAlphaSection(&mProps.alphaSection1); - break; - case 2: - updateAlphaSection(&mProps.alphaSection2, true); - break; - case 3: - mProps.diffAlpha32 = point.value - oldP1; - break; - } - - emit propertiesUpdated(mProps); - }); -} - -void EmitterWidget::AlphaPropertiesWidget::setProperties(const Ptcl::Emitter::AlphaProperties& properties) { - mProps = properties; - - QSignalBlocker blocker(mGraphA); - - const f32 p0 = mProps.initAlpha; - const f32 p1 = p0 + mProps.diffAlpha21; - const f32 p2 = p1; - const f32 p3 = p2 + mProps.diffAlpha32; - - const bool disabled = mProps.alphaSection1 == -127; - const bool fullLife = mProps.alphaSection2 == 128; - - const f32 sec2 = fullLife ? 100.0f : static_cast(mProps.alphaSection2); - const f32 sec1 = disabled ? sec2 : static_cast(mProps.alphaSection1); - - AnimGraph::PointList points = { - { 0.0f, p0, AnimGraph::HandleType::Locked }, - { sec1, p1, AnimGraph::HandleType::HoldStart }, - { sec2, p2, AnimGraph::HandleType::HoldEnd }, - { 100.0f, p3, AnimGraph::HandleType::Locked } - }; - mGraphA.setControlPoints(points); - - update(); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterWidget/colorPropertiesWidget.cpp b/src/editor/emitterWidget/colorPropertiesWidget.cpp deleted file mode 100644 index 07ec4a7..0000000 --- a/src/editor/emitterWidget/colorPropertiesWidget.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "editor/emitterWidget/colorPropertiesWidget.h" - -#include -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterWidget::ColorPropertiesWidget::ColorPropertiesWidget(QWidget* parent) : - QWidget{parent} { - // Color Behavior Type - auto colorBehaviorLayout = new QHBoxLayout; - mColorBehavior.addItem("Constant", QVariant::fromValue(Behavior::Constant)); - mColorBehavior.addItem("Random", QVariant::fromValue(Behavior::Random)); - mColorBehavior.addItem("Animation", QVariant::fromValue(Behavior::Animation)); - colorBehaviorLayout->addWidget(new QLabel("Color Behavior")); - colorBehaviorLayout->addWidget(&mColorBehavior); - colorBehaviorLayout->addStretch(); - connect(&mColorBehavior, &QComboBox::currentIndexChanged, this, &ColorPropertiesWidget::handleBehaviorChanged); - - // Color Properties - auto colorLabelLayout = new QHBoxLayout; - auto colorsLayout = new QHBoxLayout; - for (s32 i = 0; i < mColor0Widgets.size(); ++i) { - colorsLayout->addWidget(&mColor0Widgets[i]); - mColor0Widgets[i].setProperty("colorIndex", i); - connect(&mColor0Widgets[i], &RGBAColorWidget::colorChanged, this, &ColorPropertiesWidget::handleColorChanged); - colorLabelLayout->addWidget(&mColorLabels[i]); - } - - // Color Sections - connect(&mColorSections, &ColorGradientEditor::handleMoved, this, &ColorPropertiesWidget::updateColorSection); - - // Color Repeat - auto colorRepeatLayout = new QHBoxLayout; - mRepetitionCountLabel.setText("Repetition Count"); - colorRepeatLayout->addWidget(&mRepetitionCountLabel); - colorRepeatLayout->addWidget(&mColorNumRepeatSpinBox); - colorRepeatLayout->addStretch(); - connect(&mColorNumRepeatSpinBox, &SizedSpinBoxBase::valueChanged, this, [this](s32 value) { - mColorSections.setRepetitionCount(value); - mProps.colorNumRepeat = value; - }); - - // Color Calc Type - connect(&mColorCalcTypeSpinBox, &QComboBox::currentIndexChanged, this, [this]() { - mProps.colorCalcType = mColorCalcTypeSpinBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - // Color1 - mColor1Widget.enableAlpha(false); - connect(&mColor1Widget, &RGBAColorWidget::colorChanged, this, [this]() { - const auto& color = mColor1Widget.color(); - - Ptcl::binColor3f newColor{ - color.r * 255.0f, - color.g * 255.0f, - color.b * 255.0f - }; - - mProps.color1 = newColor; - emit propertiesUpdated(mProps); - }); - - // Main Layout - auto mainLayout = new QVBoxLayout(this); - mainLayout->addLayout(colorBehaviorLayout); - mainLayout->addLayout(colorLabelLayout); - mainLayout->addLayout(colorsLayout); - mainLayout->addWidget(&mColorSections); - mainLayout->addLayout(colorRepeatLayout); - mainLayout->addWidget(new QLabel("Color1:")); - mainLayout->addWidget(&mColor1Widget); - mainLayout->addWidget(new QLabel("Calc Type:")); - mainLayout->addWidget(&mColorCalcTypeSpinBox); - - setLayout(mainLayout); -} - -void EmitterWidget::ColorPropertiesWidget::setProperties(const Ptcl::Emitter::ColorProperties& properties) { - mProps = properties; - populateWidgets(); -} - -void EmitterWidget::ColorPropertiesWidget::populateWidgets() { - QSignalBlocker b1(mColorSections); - QSignalBlocker b2(mColorNumRepeatSpinBox); - QSignalBlocker b3(mColorCalcTypeSpinBox); - QSignalBlocker b4(mColor1Widget); - - QSignalBlocker bColor0(mColor0Widgets[0]); - QSignalBlocker bColor1(mColor0Widgets[1]); - QSignalBlocker bColor2(mColor0Widgets[2]); - - for (s32 i = 0; i < mColor0Widgets.size(); ++i) { - mColor0Widgets[i].setColor(mProps.color0[i]); - } - - mColorSections.setTimings( - mProps.colorSection1, - mProps.colorSection2, - mProps.colorSection3 - ); - - const auto& colors = mProps.color0; - mColorSections.setInitialColor(QColor::fromRgbF(colors[0].r, colors[0].g, colors[0].b)); - mColorSections.setPeakColor(QColor::fromRgbF(colors[1].r, colors[1].g, colors[1].b)); - mColorSections.setEndColor(QColor::fromRgbF(colors[2].r, colors[2].g, colors[2].b)); - - mColorSections.setRepetitionCount(mProps.colorNumRepeat); - mColorNumRepeatSpinBox.setValue(mProps.colorNumRepeat); - mColorCalcTypeSpinBox.setCurrentEnum(mProps.colorCalcType); - - Ptcl::binColor4f color1{ - std::clamp(mProps.color1.r / 255.0f, 0.0f, 1.0f), - std::clamp(mProps.color1.g / 255.0f, 0.0f, 1.0f), - std::clamp(mProps.color1.b / 255.0f, 0.0f, 1.0f), - 1.0f - }; - mColor1Widget.setColor(color1); - - updateUiFromFlags(); -} - -void EmitterWidget::ColorPropertiesWidget::updateUiFromFlags() { - - Behavior behavior = Behavior::Constant; - if (mProps.colorRandom) { - behavior = Behavior::Random; - } else if (mProps.colorAnimation) { - behavior = Behavior::Animation; - } - - QSignalBlocker blocker(mColorBehavior); - mColorBehavior.setCurrentIndex(behaviorToIndex(behavior)); - applyBehaviorToUI(behavior); -} - -void EmitterWidget::ColorPropertiesWidget::applyBehaviorToUI(Behavior behavior) { - switch (behavior) { - case Behavior::Constant: - showColorWidgets({true, false, false}); - setColorLabels({"Constant Color", "", ""}); - mColorSections.setVisible(false); - break; - case Behavior::Random: - showColorWidgets({true, true, true}); - setColorLabels({"Random Color 1", "Random Color 2", "Random Color 3"}); - mColorSections.setVisible(false); - break; - case Behavior::Animation: - showColorWidgets({true, true, true}); - setColorLabels({"Initial Color", "Peak Color", "Out Color"}); - mColorSections.setVisible(true); - break; - } - - const bool showRepeat = (behavior == Behavior::Animation); - mColorNumRepeatSpinBox.setVisible(showRepeat); - mRepetitionCountLabel.setVisible(showRepeat); -} - -void EmitterWidget::ColorPropertiesWidget::showColorWidgets(std::array visibility) { - for (s32 i = 0; i < mColor0Widgets.size(); ++i) { - mColor0Widgets[i].setVisible(visibility[i]); - } -} - -void EmitterWidget::ColorPropertiesWidget::setColorLabels(const std::array& labels) { - for (s32 i = 0; i < mColorLabels.size(); ++i) { - mColorLabels[i].setText(labels[i]); - mColorLabels[i].setVisible(!labels[i].isEmpty()); - } -} - -void EmitterWidget::ColorPropertiesWidget::handleBehaviorChanged(s32 index) { - auto behavior = behaviorFromIndex(index); - - applyBehaviorToUI(behavior); - - switch (behavior) { - case Behavior::Constant: - mProps.colorRandom = false; - mProps.colorAnimation = false; - break; - case Behavior::Random: - mProps.colorRandom = true; - mProps.colorAnimation = false; - break; - case Behavior::Animation: - mProps.colorRandom = false; - mProps.colorAnimation = true; - break; - } - - emit propertiesUpdated(mProps); -} - -void EmitterWidget::ColorPropertiesWidget::handleColorChanged() { - auto* widget = qobject_cast(sender()); - if (!widget) { - return; - } - - s32 index = widget->property("colorIndex").toInt(); - if (index < 0 || index >= mColor0Widgets.size()) { - return; - } - - const auto& color = widget->color(); - mProps.color0[index] = color; - - QColor qcolor = QColor::fromRgbF(color.r, color.g, color.b); - if (index == 0) { - mColorSections.setInitialColor(qcolor); - } else if (index == 1) { - mColorSections.setPeakColor(qcolor); - } else if (index == 2) { - mColorSections.setEndColor(qcolor); - } - - emit propertiesUpdated(mProps); -} - -void EmitterWidget::ColorPropertiesWidget::updateColorSection(ColorGradientEditor::HandleType handleType) { - switch (handleType) { - case ColorGradientEditor::HandleType::InCompletedHandle: - mProps.colorSection1 = mColorSections.inCompletedTiming(); - break; - case ColorGradientEditor::HandleType::PeakHandle: - mProps.colorSection2 = mColorSections.peakTiming(); - break; - case ColorGradientEditor::HandleType::OutStartHandle: - mProps.colorSection3 = mColorSections.outStartTiming(); - break; - } - - emit propertiesUpdated(mProps); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterWidget/combinerPropertiesWidget.cpp b/src/editor/emitterWidget/combinerPropertiesWidget.cpp deleted file mode 100644 index 3eb8403..0000000 --- a/src/editor/emitterWidget/combinerPropertiesWidget.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "editor/emitterWidget/combinerPropertiesWidget.h" - -#include - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterWidget::CombinerPropertiesWidget::CombinerPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - auto* mainLayout = new QFormLayout(this); - - mFogCheckBox.setText("Enable Fog"); - - mainLayout->addRow("Fog:", &mFogCheckBox); - mainLayout->addRow("Blend Function:", &mBlendFuncComboBox); - mainLayout->addRow("Depth Function:", &mDepthFuncComboBox); - mainLayout->addRow("Combiner Function:", &mCombinerFuncComboBox); - mainLayout->addWidget(&mCombinerPreview); - - connect(&mFogCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mProps.isFogEnabled = checked; - emit propertiesUpdated(mProps); - }); - - connect(&mBlendFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { - mProps.blendFunc = mBlendFuncComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - connect(&mDepthFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { - mProps.depthFunc = mDepthFuncComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - connect(&mCombinerFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { - auto value = mCombinerFuncComboBox.currentEnum(); - mProps.combinerFunc = value; - mCombinerPreview.setConfig(static_cast(value)); - emit propertiesUpdated(mProps); - }); -} - -void EmitterWidget::CombinerPropertiesWidget::setProperties(const Ptcl::Emitter::CombinerProperties& properties) { - QSignalBlocker b1(mBlendFuncComboBox); - QSignalBlocker b2(mDepthFuncComboBox); - QSignalBlocker b3(mCombinerFuncComboBox); - QSignalBlocker b4(mFogCheckBox); - - mProps = properties; - - mFogCheckBox.setChecked(mProps.isFogEnabled); - mBlendFuncComboBox.setCurrentEnum(mProps.blendFunc); - mDepthFuncComboBox.setCurrentEnum(mProps.depthFunc); - mCombinerFuncComboBox.setCurrentEnum(mProps.combinerFunc); - mCombinerPreview.setConfig(static_cast(mProps.combinerFunc)); -} - -void EmitterWidget::CombinerPropertiesWidget::setCombinerSrc(const Ptcl::TextureHandle* texture, const Ptcl::binColor3f* constant, const Ptcl::binColor4f* primary) { - mCombinerPreview.setCombinerSrc(texture, constant, primary); -} - -void EmitterWidget::CombinerPropertiesWidget::updateCombinerPreview() { - mCombinerPreview.updateStages(); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterWidget/emitterWidget.cpp b/src/editor/emitterWidget/emitterWidget.cpp deleted file mode 100644 index 968795f..0000000 --- a/src/editor/emitterWidget/emitterWidget.cpp +++ /dev/null @@ -1,383 +0,0 @@ - -#include "editor/emitterWidget/emitterWidget.h" - -#include "editor/emitterWidget/alphaPropertiesWidget.h" -#include "editor/emitterWidget/basicPropertiesWidget.h" -#include "editor/emitterWidget/colorPropertiesWidget.h" -#include "editor/emitterWidget/combinerPropertiesWidget.h" -#include "editor/emitterWidget/emissionPropertiesWidget.h" -#include "editor/emitterWidget/gravityPropertiesWidget.h" -#include "editor/emitterWidget/lifespanPropertiesWidget.h" -#include "editor/emitterWidget/rotationPropertiesWidget.h" -#include "editor/emitterWidget/scalePropertiesWidget.h" -#include "editor/emitterWidget/terminationPropertiesWidget.h" -#include "editor/emitterWidget/texturePropertiesWidget.h" -#include "editor/emitterWidget/transformPropertiesWidget.h" -#include "editor/emitterWidget/velocityPropertiesWidget.h" -#include "editor/emitterWidget/volumePropertiesWidget.h" - -#include - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterWidget::EmitterWidget(QWidget* parent) : - QWidget{parent} { - - mBasicProperties = new BasicPropertiesWidget(this); - mGravityProperties = new GravityPropertiesWidget(this); - mTransformProperties = new TransformPropertiesWidget(this); - mLifespanProperties = new LifespanPropertiesWidget(this); - mTerminationProperties = new TerminationPropertiesWidget(this); - mEmissionProperties = new EmissionPropertiesWidget(this); - mVelocityProperties = new VelocityPropertiesWidget(this); - mVolumeProperties = new VolumePropertiesWidget(this); - mColorProperties = new ColorPropertiesWidget(this); - mAlphaProperties = new AlphaPropertiesWidget(this); - mRotationProperties = new RotationPropertiesWidget(this); - mScaleProperties = new ScalePropertiesWidget(this); - mTextureProperties = new TexturePropertiesWidget(this); - mCombinerProperties = new CombinerPropertiesWidget(this); - mStripeEditorWidget = new StripeEditorWidget(this); - - mStackedWidget = new QStackedWidget(this); - - // Standard Widget - auto* standardWidget = new QWidget(this); - auto* mainLayout = new QVBoxLayout(standardWidget); - standardWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); - standardWidget->setMinimumWidth(400); - - auto* scrollArea = new QScrollArea(this); - scrollArea->setWidget(standardWidget); - scrollArea->setWidgetResizable(true); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setFrameShape(QFrame::NoFrame); - - mStackedWidget->addWidget(scrollArea); - - // Child editor - mChildEditorWidget = new ChildEditorWidget(this); - mStackedWidget->addWidget(mChildEditorWidget); - - // Fluctuation editor - mFluctuationEditorWidget = new FluctuationEditorWidget(this); - mStackedWidget->addWidget(mFluctuationEditorWidget); - - // Field editor - mFieldEditorWidget = new FieldEditorWidget(this); - mStackedWidget->addWidget(mFieldEditorWidget); - - mStackedWidget->setCurrentIndex(0); - - auto* outerLayout = new QVBoxLayout(this); - outerLayout->addWidget(mStackedWidget); - outerLayout->setContentsMargins(0, 0, 0, 0); - setLayout(outerLayout); - - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - - setupStandardLayout(mainLayout); - setupConnections(); -} - -void EmitterWidget::setupStandardLayout(QVBoxLayout* mainLayout) { - auto addSection = [mainLayout](const QString& title, QWidget* widget) { - auto* section = new CollapsibleWidget(title); - section->setContent(widget); - mainLayout->addWidget(section); - return section; - }; - - addSection("Basic properties", mBasicProperties); - mStripeSection = addSection("Stripe properties", mStripeEditorWidget); - addSection("Lifespan properties", mLifespanProperties); - addSection("Termination properties", mTerminationProperties); - addSection("Gravity properties", mGravityProperties); - addSection("Emission properties", mEmissionProperties); - addSection("Volume properties", mVolumeProperties); - addSection("Velocity properties", mVelocityProperties); - addSection("Texture properties", mTextureProperties); - addSection("Color properties", mColorProperties); - addSection("Combiner properties", mCombinerProperties); - addSection("Alpha properties", mAlphaProperties); - addSection("Transform properties", mTransformProperties); - addSection("Rotation properties", mRotationProperties); - addSection("Scale properties", mScaleProperties); - - mainLayout->addStretch(); -} - -void EmitterWidget::setupConnections() { - // Basic Properties - connect(mBasicProperties, &BasicPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::BasicProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setBasicProperties(properties); - updateStripeVisibility(); - emit propertiesChanged(); - }); - - connect(mBasicProperties, &BasicPropertiesWidget::emitterTypeChanged, this, [this]() { - if (!mEmitterPtr) { return; } - updateStripeVisibility(); - emit emitterTypeChanged(); - emit propertiesChanged(); - }); - - connect(mBasicProperties, &BasicPropertiesWidget::emitterNameChanged, this, [this]() { - if (!mEmitterPtr) { return; } - emit emitterNameChanged(); - emit propertiesChanged(); - }); - - // Texture Properties - connect(mTextureProperties, &TexturePropertiesWidget::textureUpdated, this, [this](const std::shared_ptr& oldTexture, const std::shared_ptr& newTexture) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setTexture(newTexture); - mCombinerProperties->updateCombinerPreview(); - emit propertiesChanged(); - }); - - connect(mTextureProperties, &TexturePropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::TextureProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setTextureProperties(properties); - emit propertiesChanged(); - }); - - // Gravity Properties - connect(mGravityProperties, &GravityPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::GravityProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setGravityProperties(properties); - emit propertiesChanged(); - }); - - // Lifespan Properties - connect(mLifespanProperties, &LifespanPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::LifespanProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setLifespanProperties(properties); - emit propertiesChanged(); - }); - - // Termination Properties - connect(mTerminationProperties, &TerminationPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::TerminationProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setTerminationProperties(properties); - emit propertiesChanged(); - }); - - // Emission Properties - connect(mEmissionProperties, &EmissionPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::EmissionProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setEmissionProperties(properties); - emit propertiesChanged(); - }); - - // Volume Properties - connect(mVolumeProperties, &VolumePropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::VolumeProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setVolumeProperties(properties); - emit propertiesChanged(); - }); - - // Velocity Properties - connect(mVelocityProperties, &VelocityPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::VelocityProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setVelocityProperties(properties); - emit propertiesChanged(); - }); - - // Transform Properties - connect(mTransformProperties, &TransformPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::TransformProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setTransformProperties(properties); - emit propertiesChanged(); - }); - - // Color Properties - connect(mColorProperties, &ColorPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::ColorProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setColorProperties(properties); - mCombinerProperties->updateCombinerPreview(); - mChildEditorWidget->setParentColor0(mEmitterPtr->colorProperties().color0[0]); - emit propertiesChanged(); - }); - - // Combiner Properties - connect(mCombinerProperties, &CombinerPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::CombinerProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setCombinerProperties(properties); - emit propertiesChanged(); - }); - - // Alpha Properties - connect(mAlphaProperties, &AlphaPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::AlphaProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setAlphaProperties(properties); - emit propertiesChanged(); - }); - - // Rotation Properties - connect(mRotationProperties, &RotationPropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::RotationProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setRotationProperties(properties); - emit propertiesChanged(); - }); - - // Scale Properties - connect(mScaleProperties, &ScalePropertiesWidget::propertiesUpdated, this, [this](const Ptcl::Emitter::ScaleProperties& properties) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setScaleProperties(properties); - emit propertiesChanged(); - }); - - // Child Editor Widget - connect(mChildEditorWidget, &ChildEditorWidget::flagsUpdated, this, [this](const BitFlag& childFlags) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setChildFlags(childFlags); - emit complexFlagsChanged(); - emit propertiesChanged(); - }); - - // Fluctuation Editor Widget - connect(mFluctuationEditorWidget, &FluctuationEditorWidget::dataUpdated, this, [this](const Ptcl::FluctuationData& data) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setFluctuationData(data); - emit propertiesChanged(); - }); - - connect(mFluctuationEditorWidget, &FluctuationEditorWidget::flagsUpdated, this, [this](const BitFlag& fluxFlags) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setFluctuationFlags(fluxFlags); - complexFlagsChanged(); - emit propertiesChanged(); - }); - - // Field Editor Widget - connect(mFieldEditorWidget, &FieldEditorWidget::flagsUpdated, this, [this](const BitFlag& fieldFlags) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setFieldFlags(fieldFlags); - complexFlagsChanged(); - emit propertiesChanged(); - }); - - // Stripe Editor Widget - connect(mStripeEditorWidget, &StripeEditorWidget::dataUpdated, this, [this](const Ptcl::StripeData& data) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setStripeData(data); - emit propertiesChanged(); - }); - - connect(mStripeEditorWidget, &StripeEditorWidget::flagsUpdated, this, [this](const BitFlag& stripeFlags) { - if (!mEmitterPtr) { return; } - mEmitterPtr->setStripeFlags(stripeFlags); - complexFlagsChanged(); - emit propertiesChanged(); - }); - -} - -void EmitterWidget::setEmitter(Ptcl::Emitter* emitter) { - QSignalBlocker b1(mBasicProperties); - QSignalBlocker b2(mGravityProperties); - QSignalBlocker b3(mTransformProperties); - QSignalBlocker b4(mLifespanProperties); - QSignalBlocker b5(mTerminationProperties); - QSignalBlocker b6(mEmissionProperties); - QSignalBlocker b7(mVelocityProperties); - QSignalBlocker b8(mColorProperties); - QSignalBlocker b9(mAlphaProperties); - QSignalBlocker b10(mScaleProperties); - QSignalBlocker b11(mRotationProperties); - QSignalBlocker b12(mTextureProperties); - QSignalBlocker b13(mCombinerProperties); - QSignalBlocker b14(mBasicProperties); - QSignalBlocker b15(mChildEditorWidget); - QSignalBlocker b16(mFluctuationEditorWidget); - QSignalBlocker b17(mFieldEditorWidget); - QSignalBlocker b18(mStripeEditorWidget); - - mEmitterPtr = emitter; - - mBasicProperties->setProperties(mEmitterPtr->basicProperties()); - mGravityProperties->setProperties(mEmitterPtr->gravityProperties()); - mTransformProperties->setProperties(mEmitterPtr->transformProperties()); - mLifespanProperties->setProperties(mEmitterPtr->lifespanProperties()); - mTerminationProperties->setProperties(mEmitterPtr->terminationProperties()); - mEmissionProperties->setProperties(mEmitterPtr->emissionProperties()); - mVelocityProperties->setProperties(mEmitterPtr->velocityProperties()); - mVolumeProperties->setProperties(mEmitterPtr->volumeProperties()); - mColorProperties->setProperties(mEmitterPtr->colorProperties()); - mAlphaProperties->setProperties(mEmitterPtr->alphaProperties()); - mScaleProperties->setProperties(mEmitterPtr->scaleProperties()); - mRotationProperties->setProperties(mEmitterPtr->rotationProperties()); - mTextureProperties->setProperties(mEmitterPtr->textureProperties(), mEmitterPtr->textureHandle().get()); - mCombinerProperties->setProperties(mEmitterPtr->combinerProperties()); - mCombinerProperties->setCombinerSrc(&mEmitterPtr->textureHandle(), &mEmitterPtr->colorProperties().color1, &mEmitterPtr->colorProperties().color0[0]); - - mChildEditorWidget->setChildData(&mEmitterPtr->childData(), mEmitterPtr->complexProperties().childFlags); - mChildEditorWidget->setParentColor0(mEmitterPtr->colorProperties().color0[0]); - - mFluctuationEditorWidget->setData(mEmitterPtr->fluctuationData(), mEmitterPtr->complexProperties().fluctuationFlags); - mFieldEditorWidget->setData(&mEmitterPtr->fieldData(), mEmitterPtr->complexProperties().fieldFlags); - mStripeEditorWidget->setData(mEmitterPtr->stripeData(), mEmitterPtr->complexProperties().stripeFlags); - - updateStripeVisibility(); - - setEnabled(true); -} - -void EmitterWidget::setTextureList(const Ptcl::TextureList* textureList) { - mTextureList = textureList; - mTextureProperties->setTextureList(textureList); - mChildEditorWidget->setTextureList(textureList); -} - -void EmitterWidget::showStandardEditor() { - mStackedWidget->setCurrentIndex(0); -} - -void EmitterWidget::showChildEditor() { - if (mStackedWidget) { - mStackedWidget->setCurrentWidget(mChildEditorWidget); - } -} - -void EmitterWidget::showFluctuationEditor() { - if (mStackedWidget) { - mStackedWidget->setCurrentWidget(mFluctuationEditorWidget); - } -} - -void EmitterWidget::showFieldEditor() { - if (mStackedWidget) { - mStackedWidget->setCurrentWidget(mFieldEditorWidget); - } -} - -void EmitterWidget::clear() { - setEnabled(false); - mEmitterPtr = nullptr; -} - -void EmitterWidget::updateStripeVisibility() { - if (!mEmitterPtr || !mStripeSection) { - return; - } - - const auto eType = mEmitterPtr->type(); - const auto bbType = mEmitterPtr->basicProperties().billboardType; - - const bool show = (eType == Ptcl::EmitterType::Complex || eType == Ptcl::EmitterType::Compact) && - (bbType == Ptcl::BillboardType::Stripe || bbType == Ptcl::BillboardType::ComplexStripe); - - mStripeSection->setVisible(show); -} - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterWidget/gravityPropertiesWidget.cpp b/src/editor/emitterWidget/gravityPropertiesWidget.cpp deleted file mode 100644 index fea750c..0000000 --- a/src/editor/emitterWidget/gravityPropertiesWidget.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "editor/emitterWidget/gravityPropertiesWidget.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterWidget::GravityPropertiesWidget::GravityPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - auto* mainLayout = new QFormLayout(this); - - mIsDirectionalCheckBox.setText("Apply gravity in world coords"); - - mainLayout->addRow("Coordinates:", &mIsDirectionalCheckBox); - mainLayout->addRow("Gravity Direction:", &mGravitySpinBox); - - connect(&mIsDirectionalCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mProps.isDirectional = checked; - emit propertiesUpdated(mProps); - }); - - connect(&mGravitySpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.gravity = mGravitySpinBox.getVector(); - emit propertiesUpdated(mProps); - }); -} - -void EmitterWidget::GravityPropertiesWidget::setProperties(const Ptcl::Emitter::GravityProperties& properties) { - QSignalBlocker b1(mIsDirectionalCheckBox); - QSignalBlocker b2(mGravitySpinBox); - - mProps = properties; - - mIsDirectionalCheckBox.setChecked(mProps.isDirectional); - mGravitySpinBox.setVector(mProps.gravity); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterWidget/terminationPropertiesWidget.cpp b/src/editor/emitterWidget/terminationPropertiesWidget.cpp deleted file mode 100644 index eea48c8..0000000 --- a/src/editor/emitterWidget/terminationPropertiesWidget.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "editor/emitterWidget/terminationPropertiesWidget.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterWidget::TerminationPropertiesWidget::TerminationPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - auto* mainLayout = new QFormLayout(this); - - mAlphaAddInSpinBox.setRange(0.0f, 1.0f); - - mainLayout->addRow("Stop Emission During Fade:", &mIsStopEmitCheckBox); - mainLayout->addRow("Alpha Add During Fade:", &mAlphaAddInSpinBox); - - connect(&mIsStopEmitCheckBox, &QCheckBox::checkStateChanged, this, [this](Qt::CheckState state) { - mProps.isStopEmitInFade = (state == Qt::CheckState::Checked); - emit propertiesUpdated(mProps); - }); - - connect(&mAlphaAddInSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.alphaAddInFade = static_cast(value); - emit propertiesUpdated(mProps); - }); -} - -void EmitterWidget::TerminationPropertiesWidget::setProperties(const Ptcl::Emitter::TerminationProperties& properties) { - QSignalBlocker b1(mIsStopEmitCheckBox); - QSignalBlocker b2(mAlphaAddInSpinBox); - - mProps = properties; - - mIsStopEmitCheckBox.setChecked(mProps.isStopEmitInFade); - mAlphaAddInSpinBox.setValue(mProps.alphaAddInFade); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterWidget/transformPropertiesWidget.cpp b/src/editor/emitterWidget/transformPropertiesWidget.cpp deleted file mode 100644 index 33bf329..0000000 --- a/src/editor/emitterWidget/transformPropertiesWidget.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "editor/emitterWidget/transformPropertiesWidget.h" - -#include "math/util.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterWidget::TransformPropertiesWidget::TransformPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - auto* mainLayout = new QFormLayout(this); - - mainLayout->addRow("Translation", &mTranslationSpinBox); - mainLayout->addRow("Rotation", &mRotationSpinBox); - mainLayout->addRow("Scale", &mScaleSpinBox); - - connect(&mTranslationSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - rebuildMatrices(); - emit propertiesUpdated(mProps); - }); - - connect(&mRotationSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - rebuildMatrices(); - emit propertiesUpdated(mProps); - }); - - connect(&mScaleSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - rebuildMatrices(); - emit propertiesUpdated(mProps); - }); -} - -void EmitterWidget::TransformPropertiesWidget::setProperties(const Ptcl::Emitter::TransformProperties& properties) { - QSignalBlocker b1(mTranslationSpinBox); - QSignalBlocker b2(mRotationSpinBox); - QSignalBlocker b3(mScaleSpinBox); - - mProps = properties; - - auto translation = Math::Util::getTranslation(mProps.transformRT); - mTranslationSpinBox.setVector(translation); - - auto rotation = Math::Util::getRotationEuler(mProps.transformRT); - - rotation.setX(Math::Util::to180(rotation.getX())); - rotation.setY(Math::Util::to180(rotation.getY())); - rotation.setZ(Math::Util::to180(rotation.getZ())); - - mRotationSpinBox.setVector(rotation); - - auto scale = Math::Util::getScale(mProps.transformSRT); - mScaleSpinBox.setVector(scale); -} - -void EmitterWidget::TransformPropertiesWidget::rebuildMatrices() { - const auto rotation = mRotationSpinBox.getVector(); - const auto translation = mTranslationSpinBox.getVector(); - - const auto mtxR = Math::Util::eulerToRotationMatrix(rotation); - - Math::Matrix34f mtxRT; - for (s32 r = 0; r < 3; ++r) { - for (s32 c = 0; c < 3; ++c) { - mtxRT(r, c) = mtxR(r, c); - } - mtxRT(r, 3) = translation[r]; - } - - mProps.transformRT = mtxRT; - - const auto scale = mScaleSpinBox.getVector(); - - Math::Matrix34f mtxSRT; - for (s32 r = 0; r < 3; ++r) { - mtxSRT(r, 0) = mtxRT(r, 0) * scale.getX(); - mtxSRT(r, 1) = mtxRT(r, 1) * scale.getY(); - mtxSRT(r, 2) = mtxRT(r, 2) * scale.getZ(); - mtxSRT(r, 3) = mtxRT(r, 3); - } - - mProps.transformSRT = mtxSRT; -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/emitterWidget/velocityPropertiesWidget.cpp b/src/editor/emitterWidget/velocityPropertiesWidget.cpp deleted file mode 100644 index e6aca9e..0000000 --- a/src/editor/emitterWidget/velocityPropertiesWidget.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "editor/emitterWidget/velocityPropertiesWidget.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -EmitterWidget::VelocityPropertiesWidget::VelocityPropertiesWidget(QWidget* parent) : - QWidget{parent} { - - auto* mainLayout = new QFormLayout(this); - - mFigureVelSpinbox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mInitVelSpinbox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mVelRandomSpinbox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mAirResistanceSpinbox.setRange(0.0f, 1.0f); - - mainLayout->addRow("Figure Velocity:", &mFigureVelSpinbox); - mainLayout->addRow("Velocity Direction:", &mVelDirSpinbox); - mainLayout->addRow("Initial Velocity:", &mInitVelSpinbox); - mainLayout->addRow("Initial Velocity Random:", &mVelRandomSpinbox); - mainLayout->addRow("Spread Vector:", &mSpreadVecSpinbox); - mainLayout->addRow("Air Resistance:", &mAirResistanceSpinbox); - - connect(&mFigureVelSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.figureVel = static_cast(value); - emit propertiesUpdated(mProps); - }); - - connect(&mVelDirSpinbox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.emitterVelDir = mVelDirSpinbox.getVector(); - emit propertiesUpdated(mProps); - }); - - connect(&mInitVelSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.initVel = static_cast(value); - emit propertiesUpdated(mProps); - }); - - connect(&mVelRandomSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.initVelRnd = static_cast(value); - emit propertiesUpdated(mProps); - }); - - connect(&mSpreadVecSpinbox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.spreadVec = mSpreadVecSpinbox.getVector(); - emit propertiesUpdated(mProps); - }); - - connect(&mAirResistanceSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.airResistance = static_cast(value); - emit propertiesUpdated(mProps); - }); -} - -void EmitterWidget::VelocityPropertiesWidget::setProperties(const Ptcl::Emitter::VelocityProperties& properties) { - QSignalBlocker b1(mFigureVelSpinbox); - QSignalBlocker b2(mVelDirSpinbox); - QSignalBlocker b3(mInitVelSpinbox); - QSignalBlocker b4(mVelRandomSpinbox); - QSignalBlocker b5(mSpreadVecSpinbox); - QSignalBlocker b6(mAirResistanceSpinbox); - - mProps = properties; - - mFigureVelSpinbox.setValue(mProps.figureVel); - mVelDirSpinbox.setVector(mProps.emitterVelDir); - mInitVelSpinbox.setValue(mProps.initVel); - mVelRandomSpinbox.setValue(mProps.initVelRnd); - mSpreadVecSpinbox.setVector(mProps.spreadVec); - mAirResistanceSpinbox.setValue(mProps.airResistance); - - update(); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/fieldEditor/fieldEditorWidget.cpp b/src/editor/fieldEditor/fieldEditorWidget.cpp deleted file mode 100644 index 5e6d845..0000000 --- a/src/editor/fieldEditor/fieldEditorWidget.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "editor/components/collapsibleWidget.h" -#include "editor/fieldEditor/collisionDataWidget.h" -#include "editor/fieldEditor/convergenceDataWidget.h" -#include "editor/fieldEditor/fieldEditorWidget.h" -#include "editor/fieldEditor/magnetDataWidget.h" -#include "editor/fieldEditor/posAddDataWidget.h" -#include "editor/fieldEditor/randomDataWidget.h" -#include "editor/fieldEditor/spinDataWidget.h" - -#include - - -namespace PtclEditor { - - -// ========================================================================== // - - -FieldEditorWidget::FieldEditorWidget(QWidget* parent) : - QWidget{parent} { - - mRandomDataWidget = new RandomDataWidget(this); - mMagnetDataWidget = new MagnetDataWidget(this); - mSpinDataWidget = new SpinDataWidget(this); - mCollisionDataWidget = new CollisionDataWidget(this); - mConvergenceDataWidget = new ConvergenceDataWidget(this); - mPosAddDataWidget = new PosAddDataWidget(this); - - // Standard Widget - auto* standardWidget = new QWidget(this); - auto* mainLayout = new QVBoxLayout(standardWidget); - standardWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); - standardWidget->setMinimumWidth(400); - - auto* scrollArea = new QScrollArea(this); - scrollArea->setWidget(standardWidget); - scrollArea->setWidgetResizable(true); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setFrameShape(QFrame::NoFrame); - - auto* outerLayout = new QVBoxLayout(this); - outerLayout->addWidget(scrollArea); - outerLayout->setContentsMargins(0, 0, 0, 0); - setLayout(outerLayout); - - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - - setupLayout(mainLayout); - setupConnections(); -} - -void FieldEditorWidget::setupLayout(QVBoxLayout* mainLayout) { - // Section Containers - mSectionsContainer = new QWidget(this); - auto* sectionsLayout = new QVBoxLayout(mSectionsContainer); - sectionsLayout->setContentsMargins(0, 0, 0, 0); - - auto addSection = [sectionsLayout](const QString& title, QWidget* widget) { - auto* section = new CollapsibleWidget(title); - section->setContent(widget); - sectionsLayout->addWidget(section); - }; - - addSection("Randomness", mRandomDataWidget); - addSection("Magnetic Force", mMagnetDataWidget); - addSection("Spin Force", mSpinDataWidget); - addSection("Collision Plane", mCollisionDataWidget); - addSection("Convergence", mConvergenceDataWidget); - addSection("Add to Position", mPosAddDataWidget); - - sectionsLayout->addStretch(); - - mainLayout->addWidget(mSectionsContainer); - mainLayout->addStretch(); -} - -void FieldEditorWidget::setupConnections() { - // Randomness - connect(mRandomDataWidget, &RandomDataWidget::dataUpdated, this, [this](const Ptcl::FieldData::FieldRandomData& data) { - if (!mDataPtr) { return; } - mDataPtr->setRandomData(data); - }); - - connect(mRandomDataWidget, &RandomDataWidget::isEnabledUpdated, this, [this](bool isEnabled) { - if (!mDataPtr) { return; } - mFieldFlag.set(Ptcl::FieldFlag::Random, isEnabled); - emit flagsUpdated(mFieldFlag); - }); - - // Magnet - connect(mMagnetDataWidget, &MagnetDataWidget::dataUpdated, this, [this](const Ptcl::FieldData::FieldMagnetData& data) { - if (!mDataPtr) { return; } - mDataPtr->setMagnetData(data); - }); - - connect(mMagnetDataWidget, &MagnetDataWidget::isEnabledUpdated, this, [this](bool isEnabled) { - if (!mDataPtr) { return; } - mFieldFlag.set(Ptcl::FieldFlag::Magnet, isEnabled); - emit flagsUpdated(mFieldFlag); - }); - - // Spin - connect(mSpinDataWidget, &SpinDataWidget::dataUpdated, this, [this](const Ptcl::FieldData::FieldSpinData& data) { - if (!mDataPtr) { return; } - mDataPtr->setSpinData(data); - }); - - connect(mSpinDataWidget, &SpinDataWidget::isEnabledUpdated, this, [this](bool isEnabled) { - if (!mDataPtr) { return; } - mFieldFlag.set(Ptcl::FieldFlag::Spin, isEnabled); - emit flagsUpdated(mFieldFlag); - }); - - // Collision - connect(mCollisionDataWidget, &CollisionDataWidget::dataUpdated, this, [this](const Ptcl::FieldData::FieldCollisionData& data) { - if (!mDataPtr) { return; } - mDataPtr->setCollisionData(data); - }); - - connect(mCollisionDataWidget, &CollisionDataWidget::isEnabledUpdated, this, [this](bool isEnabled) { - if (!mDataPtr) { return; } - mFieldFlag.set(Ptcl::FieldFlag::Collision, isEnabled); - emit flagsUpdated(mFieldFlag); - }); - - // Convergence - connect(mConvergenceDataWidget, &ConvergenceDataWidget::dataUpdated, this, [this](const Ptcl::FieldData::FieldConvergenceData& data) { - if (!mDataPtr) { return; } - mDataPtr->setConvergenceData(data); - }); - - connect(mConvergenceDataWidget, &ConvergenceDataWidget::isEnabledUpdated, this, [this](bool isEnabled) { - if (!mDataPtr) { return; } - mFieldFlag.set(Ptcl::FieldFlag::Convergence, isEnabled); - emit flagsUpdated(mFieldFlag); - }); - - // PosAdd - connect(mPosAddDataWidget, &PosAddDataWidget::dataUpdated, this, [this](const Ptcl::FieldData::FieldPosAddData& data) { - if (!mDataPtr) { return; } - mDataPtr->setPosAddData(data); - }); - - connect(mPosAddDataWidget, &PosAddDataWidget::isEnabledUpdated, this, [this](bool isEnabled) { - if (!mDataPtr) { return; } - mFieldFlag.set(Ptcl::FieldFlag::PosAdd, isEnabled); - emit flagsUpdated(mFieldFlag); - }); -} - -void FieldEditorWidget::setData(Ptcl::FieldData* fieldData, const BitFlag& fieldFlag) { - QSignalBlocker b1(mRandomDataWidget); - QSignalBlocker b2(mMagnetDataWidget); - QSignalBlocker b3(mSpinDataWidget); - QSignalBlocker b4(mCollisionDataWidget); - QSignalBlocker b5(mConvergenceDataWidget); - QSignalBlocker b6(mPosAddDataWidget); - - mDataPtr = fieldData; - mFieldFlag = fieldFlag; - - mRandomDataWidget->setData(mDataPtr->randomData(), mFieldFlag.isSet(Ptcl::FieldFlag::Random)); - mMagnetDataWidget->setData(mDataPtr->magnetData(), mFieldFlag.isSet(Ptcl::FieldFlag::Magnet)); - mSpinDataWidget->setData(mDataPtr->spinData(), mFieldFlag.isSet(Ptcl::FieldFlag::Spin)); - mCollisionDataWidget->setData(mDataPtr->collisionData(), mFieldFlag.isSet(Ptcl::FieldFlag::Collision)); - mConvergenceDataWidget->setData(mDataPtr->convergenceData(), mFieldFlag.isSet(Ptcl::FieldFlag::Convergence)); - mPosAddDataWidget->setData(mDataPtr->posAddData(), mFieldFlag.isSet(Ptcl::FieldFlag::PosAdd)); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/fieldEditor/magnetDataWidget.cpp b/src/editor/fieldEditor/magnetDataWidget.cpp deleted file mode 100644 index 5980b20..0000000 --- a/src/editor/fieldEditor/magnetDataWidget.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "editor/fieldEditor/magnetDataWidget.h" - -#include - -namespace PtclEditor { - - -// ========================================================================== // - - -FieldEditorWidget::MagnetDataWidget::MagnetDataWidget(QWidget* parent) : - QWidget{parent} { - - // TODO: Better ranges? - mMagnetPowerSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mMagnetPosSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); - mEnabledCheckBox.setText("Enabled"); - - mControlsWidget = new QWidget(this); - auto* controlsLayout = new QFormLayout(mControlsWidget); - controlsLayout->addRow("Magnet Power:", &mMagnetPowerSpinBox); - controlsLayout->addRow("Magnet Position:", &mMagnetPosSpinBox); - controlsLayout->addRow("Target X-Axis:", &mAxisXCheckBox); - controlsLayout->addRow("Target Y-Axis:", &mAxisYCheckBox); - controlsLayout->addRow("Target Z-Axis:", &mAxisZCheckBox); - - auto* mainLayout = new QFormLayout(this); - mainLayout->addRow("Magnetic Force:", &mEnabledCheckBox); - mainLayout->addRow(mControlsWidget); - - setupConnections(); -} - -void FieldEditorWidget::MagnetDataWidget::setupConnections() { - // Is Enabled - connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit isEnabledUpdated(checked); - mControlsWidget->setEnabled(checked); - }); - - // Magnet Power - connect(&mMagnetPowerSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.magnetPower = static_cast(value); - emit dataUpdated(mData); - }); - - // Magnet pos - connect(&mMagnetPosSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mData.magnetPos = mMagnetPosSpinBox.getVector(); - emit dataUpdated(mData); - }); - - // Axis X - connect(&mAxisXCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mData.magnetFlag.set(Ptcl::FieldMagnetFlag::AxisTargetX, checked); - emit dataUpdated(mData); - }); - - // Axis Y - connect(&mAxisYCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mData.magnetFlag.set(Ptcl::FieldMagnetFlag::AxisTargetY, checked); - emit dataUpdated(mData); - }); - - // Axis Z - connect(&mAxisZCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mData.magnetFlag.set(Ptcl::FieldMagnetFlag::AxisTargetZ, checked); - emit dataUpdated(mData); - }); -} - -void FieldEditorWidget::MagnetDataWidget::setData(const Ptcl::FieldData::FieldMagnetData& data, bool isEnabled) { - QSignalBlocker b1(mMagnetPowerSpinBox); - QSignalBlocker b2(mMagnetPosSpinBox); - QSignalBlocker b3(mAxisXCheckBox); - QSignalBlocker b4(mAxisYCheckBox); - QSignalBlocker b5(mAxisZCheckBox); - QSignalBlocker b6(mEnabledCheckBox); - - mData = data; - - mMagnetPowerSpinBox.setValue(mData.magnetPower); - mMagnetPosSpinBox.setVector(mData.magnetPos); - mAxisXCheckBox.setChecked(mData.magnetFlag.isSet(Ptcl::FieldMagnetFlag::AxisTargetX)); - mAxisYCheckBox.setChecked(mData.magnetFlag.isSet(Ptcl::FieldMagnetFlag::AxisTargetY)); - mAxisZCheckBox.setChecked(mData.magnetFlag.isSet(Ptcl::FieldMagnetFlag::AxisTargetZ)); - mEnabledCheckBox.setChecked(isEnabled); - mControlsWidget->setEnabled(isEnabled); -} - - -// ========================================================================== // - - -} // namespace PtclEditor diff --git a/src/editor/inspector/alphaAnimInspector.cpp b/src/editor/inspector/alphaAnimInspector.cpp new file mode 100644 index 0000000..6828bbf --- /dev/null +++ b/src/editor/inspector/alphaAnimInspector.cpp @@ -0,0 +1,118 @@ +#include "editor/inspector/alphaAnimInspector.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +AlphaAnimInspector::AlphaAnimInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + mGraphA.setLineColor(QColor{20, 40, 60}); + mGraphA.setTickStepSize(0.1f); + mGraphA.setValueSnap(0.1f); + mGraphA.setValueRange(0.0f, 1.0f); + + auto* mainLayout = new QFormLayout(this); + mainLayout->addRow("Alpha Anim:", &mGraphA); + + connect(&mGraphA, &AnimGraph::pointEdited, this, [this](s32 pointIndex, const AnimGraph::GraphPoint& point) { + updateAnimPoint(pointIndex, point); + }); +} + +void AlphaAnimInspector::updateAnimPoint(s32 pointIndex, const AnimGraph::GraphPoint& point) { + auto anim = mEmitter->alphaAnim(); + + const f32 oldP0 = anim.initAlpha; + const f32 oldP1 = oldP0 + anim.diffAlpha21; + const f32 oldP2 = oldP1; + const f32 oldP3 = oldP2 + anim.diffAlpha32; + + auto updateAlphaSection = [&](s32* section, bool isSection2 = false) { + anim.diffAlpha21 = point.value - oldP0; + anim.diffAlpha32 = oldP3 - point.value; + + const f32 sec1 = mGraphA.getPoints()[1].position; + const f32 sec2 = mGraphA.getPoints()[2].position; + + if (std::abs(sec1 - sec2) < std::numeric_limits::epsilon()) { + anim.alphaSection1 = -127; // Disable section1 if handles overlap + if (isSection2) { *section = static_cast(point.position); } + } else { + *section = (std::abs(sec2 - 100.0f) < std::numeric_limits::epsilon()) ? 128 : static_cast(point.position); + } + }; + + switch (pointIndex) { + case 0: + anim.initAlpha = point.value; + anim.diffAlpha21 = oldP1 - point.value; + break; + case 1: + updateAlphaSection(&anim.alphaSection1); + break; + case 2: + updateAlphaSection(&anim.alphaSection2, true); + break; + case 3: + anim.diffAlpha32 = point.value - oldP1; + break; + } + + QString handleName; + switch (pointIndex) { + case 0: handleName = "Start"; break; + case 1: handleName = "Section1"; break; + case 2: handleName = "Section2"; break; + case 3: handleName = "End"; break; + } + + const auto label = QString("Move Alpha %1").arg(handleName); + const auto key = QString("AlphaGraph_%1").arg(pointIndex); + + setEmitterProperty( + label, + key, + &Ptcl::Emitter::alphaAnim, + &Ptcl::Emitter::setAlphaAnim, + anim + ); +} + +void AlphaAnimInspector::populateProperties() { + QSignalBlocker blocker(mGraphA); + + const auto& anim = mEmitter->alphaAnim(); + + const f32 p0 = anim.initAlpha; + const f32 p1 = p0 + anim.diffAlpha21; + const f32 p2 = p1; + const f32 p3 = p2 + anim.diffAlpha32; + + const bool disabled = anim.alphaSection1 == -127; + const bool fullLife = anim.alphaSection2 == 128; + + const f32 sec2 = fullLife ? 100.0f : static_cast(anim.alphaSection2); + const f32 sec1 = disabled ? sec2 : static_cast(anim.alphaSection1); + + AnimGraph::PointList points = { + { 0.0f, p0, AnimGraph::HandleType::Locked }, + { sec1, p1, AnimGraph::HandleType::HoldStart }, + { sec2, p2, AnimGraph::HandleType::HoldEnd }, + { 100.0f, p3, AnimGraph::HandleType::Locked } + }; + mGraphA.setControlPoints(points); + + update(); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/childEditor/alphaPropertiesWidget.cpp b/src/editor/inspector/child/childAlphaInspector.cpp similarity index 50% rename from src/editor/childEditor/alphaPropertiesWidget.cpp rename to src/editor/inspector/child/childAlphaInspector.cpp index 91a5118..6b732d1 100644 --- a/src/editor/childEditor/alphaPropertiesWidget.cpp +++ b/src/editor/inspector/child/childAlphaInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/childEditor/alphaPropertiesWidget.h" +#include "editor/inspector/child/childAlphaInspector.h" #include @@ -9,8 +9,8 @@ namespace PtclEditor { // ========================================================================== // -ChildEditorWidget::AlphaPropertiesWidget::AlphaPropertiesWidget(QWidget* parent) : - QWidget{parent} { +ChildAlphaInspector::ChildAlphaInspector(QWidget* parent) : + InspectorWidgetBase{parent} { mAlphaSpinBox.setRange(0.0f, 1.0f); mAlphaSpinBox.setSingleStep(0.1f); @@ -38,44 +38,75 @@ ChildEditorWidget::AlphaPropertiesWidget::AlphaPropertiesWidget(QWidget* parent) setupConnections(); } -void ChildEditorWidget::AlphaPropertiesWidget::setupConnections() { +void ChildAlphaInspector::setupConnections() { // Inherit Alpha connect(&mInheritAlphaCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit inheritAlphaUpdated(checked); + setEmitterProperty( + "Toggle Child Inherit Alpha", + "ToggleChildInheritAlpha", + &Ptcl::Emitter::isChildInheritAlpha, + &Ptcl::Emitter::setChildInheritAlpha, + checked + ); }); // Alpha connect(&mAlphaSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.alpha = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Alpha", + "SetChildAlpha", + &Ptcl::Emitter::childAlpha, + &Ptcl::Emitter::setChildAlpha, + static_cast(value) + ); }); // Alpha Target connect(&mAlphaTargetSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.alphaTarget = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Alpha Target", + "SetChildAlphaTarget", + &Ptcl::Emitter::childAlphaTarget, + &Ptcl::Emitter::setChildAlphaTarget, + static_cast(value) + ); }); // Alpha Init connect(&mAlphaInitSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.alphaInit = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Alpha Init", + "SetChildAlphaInit", + &Ptcl::Emitter::childAlphaInit, + &Ptcl::Emitter::setChildAlphaInit, + static_cast(value) + ); }); // Start Frame connect(&mStartFrameSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mProps.alphaStartFrame = value; - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Alpha Start Frame", + "SetChildAlphaStartFrame", + &Ptcl::Emitter::childAlphaStartFrame, + &Ptcl::Emitter::setChildAlphaStartFrame, + value + ); }); // Base Frame connect(&mBaseFrameSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mProps.alphaBaseFrame = value; - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Alpha Base Frame", + "SetChildAlphaBaseFrame", + &Ptcl::Emitter::childAlphaBaseFrame, + &Ptcl::Emitter::setChildAlphaBaseFrame, + value + ); }); } -void ChildEditorWidget::AlphaPropertiesWidget::setProperties(const Ptcl::ChildData::AlphaProperties& properties, bool inheritAlpha) { +void ChildAlphaInspector::populateProperties() { QSignalBlocker b1(mAlphaSpinBox); QSignalBlocker b2(mAlphaTargetSpinBox); QSignalBlocker b3(mAlphaInitSpinBox); @@ -83,15 +114,13 @@ void ChildEditorWidget::AlphaPropertiesWidget::setProperties(const Ptcl::ChildDa QSignalBlocker b5(mBaseFrameSpinBox); QSignalBlocker b6(mInheritAlphaCheckBox); - mProps = properties; + mAlphaSpinBox.setValue(mEmitter->childAlpha()); + mAlphaTargetSpinBox.setValue(mEmitter->childAlphaTarget()); + mAlphaInitSpinBox.setValue(mEmitter->childAlphaInit()); + mStartFrameSpinBox.setValue(mEmitter->childAlphaStartFrame()); + mBaseFrameSpinBox.setValue(mEmitter->childAlphaBaseFrame()); - mAlphaSpinBox.setValue(mProps.alpha); - mAlphaTargetSpinBox.setValue(mProps.alphaTarget); - mAlphaInitSpinBox.setValue(mProps.alphaInit); - mStartFrameSpinBox.setValue(mProps.alphaStartFrame); - mBaseFrameSpinBox.setValue(mProps.alphaBaseFrame); - - mInheritAlphaCheckBox.setChecked(inheritAlpha); + mInheritAlphaCheckBox.setChecked(mEmitter->isChildInheritAlpha()); } diff --git a/src/editor/inspector/child/childColorInspector.cpp b/src/editor/inspector/child/childColorInspector.cpp new file mode 100644 index 0000000..dee0bdc --- /dev/null +++ b/src/editor/inspector/child/childColorInspector.cpp @@ -0,0 +1,96 @@ +#include "editor/inspector/child/childColorInspector.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +ChildColorInspector::ChildColorInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + auto* mainLayout = new QFormLayout(this); + + mInheritColorCheckBox.setText("Inherit Parent Primary Color"); + mColor1Widget.enableAlpha(false); + + mainLayout->addRow("Color:", &mInheritColorCheckBox); + mainLayout->addRow("Primary Color:", &mColor0Widget); + mainLayout->addRow("Secondary Color:", &mColor1Widget); + + setLayout(mainLayout); + setupConnections(); +} + +void ChildColorInspector::setupConnections() { + // Inherit Color + connect(&mInheritColorCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Child Inherit Parent Color", + "ToggleChildInheritColor", + &Ptcl::Emitter::isChildInheritParentColor, + &Ptcl::Emitter::setChildInheritParentColor, + checked + ); + }); + + // Color 0 + connect(&mColor0Widget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto newColor = mColor0Widget.color(); + setEmitterProperty( + "Set Child Primary Color", + "SetChildPrimaryColor", + &Ptcl::Emitter::childPrimaryColor, + &Ptcl::Emitter::setChildPrimaryColor, + newColor + ); + }); + + // Color 1 + connect(&mColor1Widget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto color = mColor1Widget.color(); + + Ptcl::binColor3f newColor{ + color.r * 255.0f, + color.g * 255.0f, + color.b * 255.0f + }; + + setEmitterProperty( + "Set Child Secondary Color", + "SetChildSecondaryColor", + &Ptcl::Emitter::childSecondaryColor, + &Ptcl::Emitter::setChildSecondaryColor, + newColor + ); + }); +} + +void ChildColorInspector::populateProperties() { + QSignalBlocker b1(mColor0Widget); + QSignalBlocker b2(mColor1Widget); + QSignalBlocker b3(mInheritColorCheckBox); + + const bool inheritParentColor = mEmitter->isChildInheritParentColor(); + + mColor0Widget.setColor(mEmitter->childPrimaryColor()); + mColor0Widget.setDisabled(inheritParentColor); + + Ptcl::binColor4f color1{ + std::clamp(mEmitter->childSecondaryColor().r / 255.0f, 0.0f, 1.0f), + std::clamp(mEmitter->childSecondaryColor().g / 255.0f, 0.0f, 1.0f), + std::clamp(mEmitter->childSecondaryColor().b / 255.0f, 0.0f, 1.0f), + 1.0f + }; + mColor1Widget.setColor(color1); + mInheritColorCheckBox.setChecked(inheritParentColor); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/inspector/child/childCombinerInspector.cpp b/src/editor/inspector/child/childCombinerInspector.cpp new file mode 100644 index 0000000..efbabdb --- /dev/null +++ b/src/editor/inspector/child/childCombinerInspector.cpp @@ -0,0 +1,78 @@ +#include "editor/inspector/child/childCombinerInspector.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +ChildCombinerInspector::ChildCombinerInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + auto* mainLayout = new QFormLayout(this); + + mainLayout->addRow("Blend Function:", &mBlendFuncComboBox); + mainLayout->addRow("Depth Function:", &mDepthFuncComboBox); + mainLayout->addRow("Combiner Function:", &mCombinerFuncComboBox); + mainLayout->addWidget(&mCombinerPreview); + + setupConnections(); +} + +void ChildCombinerInspector::setupConnections() { + connect(&mBlendFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { + const auto func = mBlendFuncComboBox.currentEnum(); + setEmitterProperty( + "Set Child Blend Function", + "SetChildBlendFunc", + &Ptcl::Emitter::childBlendFunc, + &Ptcl::Emitter::setChildBlendFunc, + func + ); + }); + + connect(&mDepthFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { + const auto func = mDepthFuncComboBox.currentEnum(); + setEmitterProperty( + "Set Child Depth Function", + "SetChildDepthFunc", + &Ptcl::Emitter::childDepthFunc, + &Ptcl::Emitter::setChildDepthFunc, + func + ); + }); + + connect(&mCombinerFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { + const auto func = mCombinerFuncComboBox.currentEnum(); + setEmitterProperty( + "Set Child Combiner Function", + "SetChildCombinerFunc", + &Ptcl::Emitter::childCombinerFunc, + &Ptcl::Emitter::setChildCombinerFunc, + func + ); + }); +} + +void ChildCombinerInspector::populateProperties() { + QSignalBlocker b1(mBlendFuncComboBox); + QSignalBlocker b2(mDepthFuncComboBox); + QSignalBlocker b3(mCombinerFuncComboBox); + + mBlendFuncComboBox.setCurrentEnum(mEmitter->childBlendFunc()); + mDepthFuncComboBox.setCurrentEnum(mEmitter->childDepthFunc()); + mCombinerFuncComboBox.setCurrentEnum(mEmitter->childCombinerFunc()); + mCombinerPreview.setConfig(static_cast(mEmitter->childCombinerFunc())); + + mCombinerPreview.setCombinerSrc(&mEmitter->childTextureHandle(), &mEmitter->childSecondaryColor(), &mEmitter->childPrimaryColor()); + mCombinerPreview.updateStages(); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/childEditor/emissionPropertiesWidget.cpp b/src/editor/inspector/child/childEmissionInspector.cpp similarity index 58% rename from src/editor/childEditor/emissionPropertiesWidget.cpp rename to src/editor/inspector/child/childEmissionInspector.cpp index cc92752..015afe0 100644 --- a/src/editor/childEditor/emissionPropertiesWidget.cpp +++ b/src/editor/inspector/child/childEmissionInspector.cpp @@ -1,15 +1,16 @@ -#include "editor/childEditor/emissionPropertiesWidget.h" +#include "editor/inspector/child/childEmissionInspector.h" #include + namespace PtclEditor { // ========================================================================== // -ChildEditorWidget::EmissionPropertiesWidget::EmissionPropertiesWidget(QWidget* parent) : - QWidget{parent} { +ChildEmissionInspector::ChildEmissionInspector(QWidget* parent) : + InspectorWidgetBase{parent} { // Emission Rate mEmitRateSpinBox.setRange(0, std::numeric_limits::max()); @@ -47,55 +48,75 @@ ChildEditorWidget::EmissionPropertiesWidget::EmissionPropertiesWidget(QWidget* p setupConnections(); } -void ChildEditorWidget::EmissionPropertiesWidget::setupConnections() { +void ChildEmissionInspector::setupConnections() { // Emission Rate connect(&mEmitRateSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mProps.emitRate = value; - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Emission Rate", + "SetChildEmissionRate", + &Ptcl::Emitter::childEmitRate, + &Ptcl::Emitter::setChildEmitRate, + value + ); }); // Emission Timing connect(&mEmitTimingSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mProps.emitTiming = value; - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Emission Start Time", + "SetChildEmissionStartTime", + &Ptcl::Emitter::childEmitTiming, + &Ptcl::Emitter::setChildEmitTiming, + value + ); }); // Lifespan connect(&mLifeSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mProps.life = value; - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Lifespan", + "SetChildLifespan", + &Ptcl::Emitter::childLife, + &Ptcl::Emitter::setChildLife, + value + ); }); // Infinite Life connect(&mInfiniteLifeCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - QSignalBlocker b1(mLifeSpinBox); - - mProps.life = checked ? sLifeInfinite : 100; - mLifeSpinBox.setValue(mProps.life); - mLifeSpinBox.setEnabled(!checked); - emit propertiesUpdated(mProps); + const s32 newLife = checked ? sLifeInfinite : 100; + setEmitterProperty( + "Toggle Child Infinite Life", + "ToggleChildInfiniteLife", + &Ptcl::Emitter::childLife, + &Ptcl::Emitter::setChildLife, + newLife + ); }); // Emission Step connect(&mEmitStepSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mProps.emitStep = value; - emit propertiesUpdated(mProps); + setEmitterProperty( + "Toggle Child Emission Interval", + "ToggleChildEmitStep", + &Ptcl::Emitter::childEmitStep, + &Ptcl::Emitter::setChildEmitStep, + value + ); }); } -void ChildEditorWidget::EmissionPropertiesWidget::setProperties(const Ptcl::ChildData::EmissionProperties& properties) { +void ChildEmissionInspector::populateProperties() { QSignalBlocker b1(mEmitRateSpinBox); QSignalBlocker b2(mEmitTimingSpinBox); QSignalBlocker b3(mLifeSpinBox); QSignalBlocker b4(mEmitStepSpinBox); - mProps = properties; - - mEmitRateSpinBox.setValue(mProps.emitRate); - mEmitTimingSpinBox.setValue(mProps.emitTiming); - mEmitStepSpinBox.setValue(mProps.emitStep); + mEmitRateSpinBox.setValue(mEmitter->childEmitRate()); + mEmitTimingSpinBox.setValue(mEmitter->childEmitTiming()); + mEmitStepSpinBox.setValue(mEmitter->childEmitStep()); - const s32 lifeSpan = mProps.life; + const s32 lifeSpan = mEmitter->childLife(); const bool infiniteLife = (lifeSpan == sLifeInfinite); mLifeSpinBox.setValue(lifeSpan); mLifeSpinBox.setDisabled(infiniteLife); diff --git a/src/editor/childEditor/basicPropertiesWidget.cpp b/src/editor/inspector/child/childGeneralInspector.cpp similarity index 52% rename from src/editor/childEditor/basicPropertiesWidget.cpp rename to src/editor/inspector/child/childGeneralInspector.cpp index 6802618..da9e0d5 100644 --- a/src/editor/childEditor/basicPropertiesWidget.cpp +++ b/src/editor/inspector/child/childGeneralInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/childEditor/basicPropertiesWidget.h" +#include "editor/inspector/child/childGeneralInspector.h" #include @@ -8,13 +8,14 @@ namespace PtclEditor { // ========================================================================== // -ChildEditorWidget::BasicPropertiesWidget::BasicPropertiesWidget(QWidget* parent) : - QWidget{parent} { +ChildGeneralInspector::ChildGeneralInspector(QWidget* parent) : + InspectorWidgetBase{parent} { for (Ptcl::BillboardType type : sChildBillboardTypes) { mBillboardComboBox.addItem(Ptcl::toString(type), QVariant::fromValue(type)); } + mEnabledCheckBox.setText("Enable Child Emitter"); mFollowCheckBox.setText("Follow Parent Emitter"); mParentFieldCheckBox.setText("Apply Parent's Field"); @@ -23,6 +24,7 @@ ChildEditorWidget::BasicPropertiesWidget::BasicPropertiesWidget(QWidget* parent) auto* mainLayout = new QFormLayout(this); + mainLayout->addRow("Child:", &mEnabledCheckBox); mainLayout->addRow("Billboard Type:", &mBillboardComboBox); mainLayout->addRow("Follow Type:", &mFollowCheckBox); mainLayout->addRow("Field Type:", &mParentFieldCheckBox); @@ -31,63 +33,85 @@ ChildEditorWidget::BasicPropertiesWidget::BasicPropertiesWidget(QWidget* parent) setupConnections(); } -void ChildEditorWidget::BasicPropertiesWidget::setupConnections() { +void ChildGeneralInspector::setupConnections() { + // Is Enabled + connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Child", + "ToggleChild", + &Ptcl::Emitter::isChildEnabled, + &Ptcl::Emitter::setChildEnabled, + checked + ); + }); + // Is Follow connect(&mFollowCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit isFollowUpdated(checked); + setEmitterProperty( + "Toggle Child Follow Parent", + "ToggleChildFollowParent", + &Ptcl::Emitter::isChildFollow, + &Ptcl::Emitter::setChildFollow, + checked + ); }); // Is Parent Field connect(&mParentFieldCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit isParentFieldUpdated(checked); + setEmitterProperty( + "Toggle Child Apply Parent Field", + "ToggleChildParentField", + &Ptcl::Emitter::isChildParentField, + &Ptcl::Emitter::setChildParentField, + checked + ); }); // Billboard Type connect(&mBillboardComboBox, &QComboBox::currentIndexChanged, this, [this]() { const auto type = mBillboardComboBox.currentData().value(); - - // TODO: - // mProps.isVelLook = (type == Ptcl::BillboardType::VelLook || type == Ptcl::BillboardType::VelLookPolygon); - // mProps.isEmitterBillboardMtx = mProps.isVelLook; - - mProps.billboardType = type; - - const bool isPolygon = (type == Ptcl::BillboardType::PolygonXY || type == Ptcl::BillboardType::PolygonXZ); - emit isPolygonUpdated(isPolygon); - - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Child Billboard Type", + "SetChildBillboardType", + &Ptcl::Emitter::childBillboardType, + &Ptcl::Emitter::setChildBillboardType, + type + ); }); // Draw Order connect(&mDrawOrderComboBox, &QComboBox::currentIndexChanged, this, [this]() { const auto order = mDrawOrderComboBox.currentData().value(); const bool isPreDraw = (order == DrawOrder::BelowParent); - emit isPreDrawUpdated(isPreDraw); + setEmitterProperty( + "Set Child Draw Order", + "SetChildDrawOrder", + &Ptcl::Emitter::isChildPreDraw, + &Ptcl::Emitter::setChildPreDraw, + isPreDraw + ); }); } -void ChildEditorWidget::BasicPropertiesWidget::setProperties(const Ptcl::ChildData::BasicProperties& properties, bool isFollow, bool isParentField, bool isPreDraw) { +void ChildGeneralInspector::populateProperties() { QSignalBlocker b1(mBillboardComboBox); QSignalBlocker b2(mFollowCheckBox); QSignalBlocker b3(mParentFieldCheckBox); QSignalBlocker b4(mDrawOrderComboBox); - mProps = properties; - - const s32 billboardIndex = mBillboardComboBox.findData(QVariant::fromValue(mProps.billboardType)); + const s32 billboardIndex = mBillboardComboBox.findData(QVariant::fromValue(mEmitter->childBillboardType())); mBillboardComboBox.setCurrentIndex(billboardIndex); - mFollowCheckBox.setChecked(isFollow); - mParentFieldCheckBox.setChecked(isParentField); + mEnabledCheckBox.setChecked(mEmitter->isChildEnabled()); + + mFollowCheckBox.setChecked(mEmitter->isChildFollow()); + mParentFieldCheckBox.setChecked(mEmitter->isChildParentField()); - const auto drawOrder = isPreDraw ? DrawOrder::BelowParent : DrawOrder::AboveParent; + const auto drawOrder = mEmitter->isChildPreDraw() ? DrawOrder::BelowParent : DrawOrder::AboveParent; const s32 drawIndex = mDrawOrderComboBox.findData(QVariant::fromValue(drawOrder)); mDrawOrderComboBox.setCurrentIndex(drawIndex); } -void ChildEditorWidget::BasicPropertiesWidget::populateBillboardType() { -} - // ========================================================================== // diff --git a/src/editor/childEditor/rotationPropertiesWidget.cpp b/src/editor/inspector/child/childRotationInspector.cpp similarity index 57% rename from src/editor/childEditor/rotationPropertiesWidget.cpp rename to src/editor/inspector/child/childRotationInspector.cpp index 6283f61..00fe15a 100644 --- a/src/editor/childEditor/rotationPropertiesWidget.cpp +++ b/src/editor/inspector/child/childRotationInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/childEditor/rotationPropertiesWidget.h" +#include "editor/inspector/child/childRotationInspector.h" #include "math/util.h" @@ -11,8 +11,8 @@ namespace PtclEditor { // ========================================================================== // -ChildEditorWidget::RotationPropertiesWidget::RotationPropertiesWidget(QWidget* parent) : - QWidget{parent} { +ChildRotationInspector::ChildRotationInspector(QWidget* parent) : + InspectorWidgetBase{parent} { auto* mainLayout = new QFormLayout(this); @@ -29,7 +29,7 @@ ChildEditorWidget::RotationPropertiesWidget::RotationPropertiesWidget(QWidget* p setupConnections(); } -void ChildEditorWidget::RotationPropertiesWidget::setupConnections() { +void ChildRotationInspector::setupConnections() { auto deg2idxVec = [](const Math::Vector3f& v) { Math::Vector3i result { Math::Util::deg2idx(v.getX()), @@ -41,48 +41,89 @@ void ChildEditorWidget::RotationPropertiesWidget::setupConnections() { // Inherit Rotation connect(&mInheritRotCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit inheritRotationUpdated(checked); + setEmitterProperty( + "Toggle Child Inherit Rotation", + "ToggleChildInheritRot", + &Ptcl::Emitter::isChildInheritRotation, + &Ptcl::Emitter::setChildInheritRotation, + checked + ); }); // RotType connect(&mRotTypeSpinBox, &QComboBox::currentIndexChanged, this, [this]() { - mProps.rotType = mRotTypeSpinBox.currentEnum(); - updateAxis(); - emit propertiesUpdated(mProps); + const auto type = mRotTypeSpinBox.currentEnum(); + setEmitterProperty( + "Set Child Rotation Type", + "SetChildRotationType", + &Ptcl::Emitter::childRotationType, + &Ptcl::Emitter::setChildRotationType, + type + ); }); // Initial Rotation connect(&mInitRotSpinBox, &VectorSpinBoxBase::valueChanged, this, [this, deg2idxVec]() { - mProps.initRot = deg2idxVec(mInitRotSpinBox.getVector()); - emit propertiesUpdated(mProps); + const auto rot = deg2idxVec(mInitRotSpinBox.getVector()); + setEmitterProperty( + "Set Child Initial Rotation", + "SetChildInitRotation", + &Ptcl::Emitter::childInitialRotation, + &Ptcl::Emitter::setChildInitialRotation, + rot + ); }); // Initial Rotation Rand connect(&mInitRotRandSpinBox, &VectorSpinBoxBase::valueChanged, this, [this, deg2idxVec]() { - mProps.initRotRand = deg2idxVec(mInitRotRandSpinBox.getVector()); - emit propertiesUpdated(mProps); + const auto rot = deg2idxVec(mInitRotRandSpinBox.getVector()); + setEmitterProperty( + "Set Child Initial Rotation Random", + "SetChildInitRotationRand", + &Ptcl::Emitter::childInitialRotationRandom, + &Ptcl::Emitter::setChildInitialRotationRandom, + rot + ); }); // Rotation Speed connect(&mRotVelSpinBox, &VectorSpinBoxBase::valueChanged, this, [this, deg2idxVec]() { - mProps.rotVel = deg2idxVec(mRotVelSpinBox.getVector()); - emit propertiesUpdated(mProps); + const auto speed = deg2idxVec(mRotVelSpinBox.getVector()); + setEmitterProperty( + "Set Child Rotation Speed", + "SetChildRotVel", + &Ptcl::Emitter::childRotationVelocity, + &Ptcl::Emitter::setChildRotationVelocity, + speed + ); }); // Rotation Speed Rand connect(&mRotVelRandSpinBox, &VectorSpinBoxBase::valueChanged, this, [this, deg2idxVec]() { - mProps.rotVelRand = deg2idxVec(mRotVelRandSpinBox.getVector()); - emit propertiesUpdated(mProps); + const auto vel = deg2idxVec(mRotVelRandSpinBox.getVector()); + setEmitterProperty( + "Set Child Rotation Speed Rand", + "SetChildRotVelRand", + &Ptcl::Emitter::childRotationVelocityRandom, + &Ptcl::Emitter::setChildRotationVelocityRandom, + vel + ); }); // Rotation Pivot connect(&mRotBasisSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.rotBasis = mRotBasisSpinBox.getVector(); - emit propertiesUpdated(mProps); + const auto pivot = mRotBasisSpinBox.getVector(); + setEmitterProperty( + "Set Child Rotation Pivot", + "SetChildRotBasis", + &Ptcl::Emitter::childRotationBasis, + &Ptcl::Emitter::setChildRotationBasis, + pivot + ); }); } -void ChildEditorWidget::RotationPropertiesWidget::setProperties(const Ptcl::ChildData::RotationProperties& properties, bool inheritRotation) { +void ChildRotationInspector::populateProperties() { QSignalBlocker b1(mRotTypeSpinBox); QSignalBlocker b2(mInitRotSpinBox); QSignalBlocker b3(mInitRotRandSpinBox); @@ -91,8 +132,6 @@ void ChildEditorWidget::RotationPropertiesWidget::setProperties(const Ptcl::Chil QSignalBlocker b6(mRotBasisSpinBox); QSignalBlocker b7(mInheritRotCheckBox); - mProps = properties; - auto idx2degVec = [](const Math::Vector3i& v) { return Math::Vector3f { Math::Util::to180(Math::Util::idx2deg(v.getX())), @@ -101,21 +140,21 @@ void ChildEditorWidget::RotationPropertiesWidget::setProperties(const Ptcl::Chil }; }; - mRotTypeSpinBox.setCurrentEnum(mProps.rotType); - mInitRotSpinBox.setVector(idx2degVec(mProps.initRot)); - mInitRotRandSpinBox.setVector(idx2degVec(mProps.initRotRand)); - mRotVelSpinBox.setVector(idx2degVec(mProps.rotVel)); - mRotVelRandSpinBox.setVector(idx2degVec(mProps.rotVelRand)); - mRotBasisSpinBox.setVector(mProps.rotBasis); - mInheritRotCheckBox.setChecked(inheritRotation); + mRotTypeSpinBox.setCurrentEnum(mEmitter->childRotationType()); + mInitRotSpinBox.setVector(idx2degVec(mEmitter->childInitialRotation())); + mInitRotRandSpinBox.setVector(idx2degVec(mEmitter->childInitialRotationRandom())); + mRotVelSpinBox.setVector(idx2degVec(mEmitter->childRotationVelocity())); + mRotVelRandSpinBox.setVector(idx2degVec(mEmitter->childRotationVelocityRandom())); + mRotBasisSpinBox.setVector(mEmitter->childRotationBasis()); + mInheritRotCheckBox.setChecked(mEmitter->isChildInheritRotation()); updateAxis(); } -void ChildEditorWidget::RotationPropertiesWidget::updateAxis() { +void ChildRotationInspector::updateAxis() { using Axis = VectorSpinBoxBase::Axis; - switch (mProps.rotType) { + switch (mEmitter->childRotationType()) { case Ptcl::RotType::None: mInitRotSpinBox.setEnabledAxis(Axis::None); mInitRotRandSpinBox.setEnabledAxis(Axis::None); diff --git a/src/editor/inspector/child/childScaleInspector.cpp b/src/editor/inspector/child/childScaleInspector.cpp new file mode 100644 index 0000000..b685871 --- /dev/null +++ b/src/editor/inspector/child/childScaleInspector.cpp @@ -0,0 +1,110 @@ +#include "editor/inspector/child/childScaleInspector.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +ChildScaleInspector::ChildScaleInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + auto* mainLayout = new QFormLayout(this); + + mInheritScaleCheckBox.setText("Inherit Parent Scale"); + mInheritRateSpinBox.setRange(0.0f, 1.0f); + mInheritRateSpinBox.setSingleStep(0.1f); + mScaleSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mScaleTargetSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mStartFrameSpinBox.setRange(0, std::numeric_limits::max()); + + mainLayout->addRow("Scale:", &mInheritScaleCheckBox); + mainLayout->addRow("Inherit Rate:", &mInheritRateSpinBox); + mainLayout->addRow("Initial Scale:", &mScaleSpinBox); + mainLayout->addRow("Target Scale:", &mScaleTargetSpinBox); + mainLayout->addRow("Start Frame:", &mStartFrameSpinBox); + + setupConnections(); +} + +void ChildScaleInspector::setupConnections() { + // Inherit Scale + connect(&mInheritScaleCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Child Inherit Scale", + "ToggleChildInheritScale", + &Ptcl::Emitter::isChildInheritScale, + &Ptcl::Emitter::setChildInheritScale, + checked + ); + }); + + // Scale + connect(&mScaleSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto scale = mScaleSpinBox.getVector(); + setEmitterProperty( + "Set Child Scale", + "SetChildScale", + &Ptcl::Emitter::childScale, + &Ptcl::Emitter::setChildScale, + scale + ); + }); + + // Scale Target + connect(&mScaleTargetSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto target = mScaleTargetSpinBox.getVector(); + setEmitterProperty( + "Set Child Target Scale", + "SetChildScaleTarget", + &Ptcl::Emitter::childScaleTarget, + &Ptcl::Emitter::setChildScaleTarget, + target + ); + }); + + // Inherit Rate + connect(&mInheritRateSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Child Scale Inherit Rate", + "SetChildScaleInheritRate", + &Ptcl::Emitter::childScaleInheritRate, + &Ptcl::Emitter::setChildScaleInheritRate, + static_cast(value) + ); + }); + + // Start Frame + connect(&mStartFrameSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { + setEmitterProperty( + "Set Child Scale Start Frame", + "SetChildScaleStartFrame", + &Ptcl::Emitter::childScaleStartFrame, + &Ptcl::Emitter::setChildScaleStartFrame, + value + ); + }); +} + +void ChildScaleInspector::populateProperties() { + QSignalBlocker b1(mScaleSpinBox); + QSignalBlocker b2(mScaleTargetSpinBox); + QSignalBlocker b3(mInheritRateSpinBox); + QSignalBlocker b4(mStartFrameSpinBox); + QSignalBlocker b5(mInheritScaleCheckBox); + + mScaleSpinBox.setVector(mEmitter->childScale()); + mScaleTargetSpinBox.setVector(mEmitter->childScaleTarget()); + mInheritRateSpinBox.setValue(mEmitter->childScaleInheritRate()); + mStartFrameSpinBox.setValue(mEmitter->childScaleStartFrame()); + mInheritScaleCheckBox.setChecked(mEmitter->isChildInheritScale()); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/childEditor/texturePropertiesWidget.cpp b/src/editor/inspector/child/childTextureInspector.cpp similarity index 50% rename from src/editor/childEditor/texturePropertiesWidget.cpp rename to src/editor/inspector/child/childTextureInspector.cpp index a03d0ca..24bcef3 100644 --- a/src/editor/childEditor/texturePropertiesWidget.cpp +++ b/src/editor/inspector/child/childTextureInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/childEditor/texturePropertiesWidget.h" +#include "editor/inspector/child/childTextureInspector.h" #include "editor/textureSelectDialog.h" @@ -17,8 +17,8 @@ namespace PtclEditor { // ========================================================================== // -ChildEditorWidget::TexturePropertiesWidget::TexturePropertiesWidget(QWidget* parent) : - QWidget{parent} { +ChildTextureInspector::ChildTextureInspector(QWidget* parent) : + InspectorWidgetBase{parent} { mUVScaleSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); @@ -53,53 +53,89 @@ ChildEditorWidget::TexturePropertiesWidget::TexturePropertiesWidget(QWidget* par setupConnections(); } -void ChildEditorWidget::TexturePropertiesWidget::setupConnections() { +void ChildTextureInspector::setupConnections() { // Wrap T connect(&mWrapTComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { Q_UNUSED(index); - mProps.textureWrapT = mWrapTComboBox.currentEnum(); - emit propertiesUpdated(mProps); + const auto wrap = mWrapTComboBox.currentEnum(); + setEmitterProperty( + "Set Child Texture Wrap U", + "SetChildTexWrapU", + &Ptcl::Emitter::childTextureWrapT, + &Ptcl::Emitter::setChildTextureWrapT, + wrap + ); }); // Wrap S connect(&mWrapSComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { Q_UNUSED(index); - mProps.textureWrapS = mWrapSComboBox.currentEnum(); - emit propertiesUpdated(mProps); + const auto wrap = mWrapSComboBox.currentEnum(); + setEmitterProperty( + "Set Child Texture Wrap V", + "SetChildTexWrapV", + &Ptcl::Emitter::childTextureWrapS, + &Ptcl::Emitter::setChildTextureWrapS, + wrap + ); }); // Mag Filter connect(&mMagFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { Q_UNUSED(index); - mProps.textureMagFilter = mMagFilterComboBox.currentEnum(); - emit propertiesUpdated(mProps); + const auto filter = mMagFilterComboBox.currentEnum(); + setEmitterProperty( + "Set Child Texture Mag Filter", + "SetChildTexMagFilter", + &Ptcl::Emitter::childTextureMagFilter, + &Ptcl::Emitter::setChildTextureMagFilter, + filter + ); }); // Min Filter connect(&mMinFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { Q_UNUSED(index); - mProps.textureMinFilter = mMinFilterComboBox.currentEnum(); - emit propertiesUpdated(mProps); + const auto filter = mMinFilterComboBox.currentEnum(); + setEmitterProperty( + "Set Child Texture Min Filter", + "SetChildTexMinFilter", + &Ptcl::Emitter::childTextureMinFilter, + &Ptcl::Emitter::setChildTextureMinFilter, + filter + ); }); // Mipmap Filter connect(&mMipFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { Q_UNUSED(index); - mProps.textureMipFilter = mMipFilterComboBox.currentEnum(); - emit propertiesUpdated(mProps); + const auto filter = mMipFilterComboBox.currentEnum(); + setEmitterProperty( + "Set Child Texture Mip Filter", + "SetChildTexMipFilter", + &Ptcl::Emitter::childTextureMipFilter, + &Ptcl::Emitter::setChildTextureMipFilter, + filter + ); }); // UV Scale connect(&mUVScaleSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.texUVScale = mUVScaleSpinBox.getVector(); - emit propertiesUpdated(mProps); + const auto scale = mUVScaleSpinBox.getVector(); + setEmitterProperty( + "Set Child Texture UV Scale", + "SetChildTexUVScale", + &Ptcl::Emitter::childTextureUVScale, + &Ptcl::Emitter::setChildTextureUVScale, + scale + ); }); // Texture Preview - connect(&mTexturePreview, &ThumbnailWidget::clicked, this, &TexturePropertiesWidget::changeTexture); + connect(&mTexturePreview, &ThumbnailWidget::clicked, this, &ChildTextureInspector::changeTexture); } -void ChildEditorWidget::TexturePropertiesWidget::setProperties(const Ptcl::ChildData::TextureProperties& properties, const std::shared_ptr& texture) { +void ChildTextureInspector::populateProperties() { QSignalBlocker b1(mWrapTComboBox); QSignalBlocker b2(mWrapSComboBox); QSignalBlocker b3(mMagFilterComboBox); @@ -107,39 +143,33 @@ void ChildEditorWidget::TexturePropertiesWidget::setProperties(const Ptcl::Child QSignalBlocker b5(mMipFilterComboBox); QSignalBlocker b6(mUVScaleSpinBox); - mProps = properties; - mTexture = texture; - - if (mTexture) { - mTexturePreview.setPixmap(QPixmap::fromImage(mTexture->textureData())); + if (mEmitter->childTextureHandle().isValid()) { + mTexturePreview.setPixmap(QPixmap::fromImage(mEmitter->childTexture()->textureData())); } - mWrapTComboBox.setCurrentEnum(mProps.textureWrapT); - mWrapSComboBox.setCurrentEnum(mProps.textureWrapS); - mMagFilterComboBox.setCurrentEnum(mProps.textureMagFilter); - mMinFilterComboBox.setCurrentEnum(mProps.textureMinFilter); - mMipFilterComboBox.setCurrentEnum(mProps.textureMipFilter); - mUVScaleSpinBox.setVector(mProps.texUVScale); -} - -void ChildEditorWidget::TexturePropertiesWidget::setTextureList(const Ptcl::TextureList* textureList) { - mTextureList = textureList; + mWrapTComboBox.setCurrentEnum(mEmitter->childTextureWrapT()); + mWrapSComboBox.setCurrentEnum(mEmitter->childTextureWrapS()); + mMagFilterComboBox.setCurrentEnum(mEmitter->childTextureMagFilter()); + mMinFilterComboBox.setCurrentEnum(mEmitter->childTextureMinFilter()); + mMipFilterComboBox.setCurrentEnum(mEmitter->childTextureMipFilter()); + mUVScaleSpinBox.setVector(mEmitter->childTextureUVScale()); } -void ChildEditorWidget::TexturePropertiesWidget::changeTexture() { - if (!mTextureList) { - return; - } - - auto oldTexture = mTexture; +void ChildTextureInspector::changeTexture() { + const auto& textureList = mDocument->textures(); - TextureSelectDialog dialog(*mTextureList, this); + TextureSelectDialog dialog(textureList, this); if (dialog.exec() == QDialog::Accepted) { s32 selectedInded = dialog.selectedIndex(); - if (selectedInded >= 0 && static_cast(selectedInded) < mTextureList->size()) { - mTexture = mTextureList->at(selectedInded); - mTexturePreview.setPixmap(QPixmap::fromImage(mTexture->textureData())); - emit textureUpdated(oldTexture, mTexture); + if (selectedInded >= 0 && static_cast(selectedInded) < textureList.size()) { + const auto texture = textureList.at(selectedInded).get(); + setEmitterProperty( + "Set Child Texture", + "SetChildTexture", + &Ptcl::Emitter::childTexture, + &Ptcl::Emitter::setChildTexture, + texture + ); } } } diff --git a/src/editor/inspector/child/childVelocityInspector.cpp b/src/editor/inspector/child/childVelocityInspector.cpp new file mode 100644 index 0000000..3f0c9d9 --- /dev/null +++ b/src/editor/inspector/child/childVelocityInspector.cpp @@ -0,0 +1,139 @@ +#include "editor/inspector/child/childVelocityInspector.h" + +#include + +namespace PtclEditor { + + +// ========================================================================== // + + +ChildVelocityInspector::ChildVelocityInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + // TODO: Determine better ranges? + mRandVelSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mGravitySpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mVelInheritSpinBox.setRange(0.0f, 1.0f); + mInitPosRandSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mFigureVelSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mAirResistSpinBox.setRange(0.0f, 1.0f); + + auto* mainLayout = new QFormLayout(this); + + mainLayout->addRow("Random Velocity:", &mRandVelSpinBox); + mainLayout->addRow("Gravity:", &mGravitySpinBox); + mainLayout->addRow("Inherit Parent Velocity:", &mInheritVelCheckBox); + mainLayout->addRow("Velocity Inherit Rate:", &mVelInheritSpinBox); + mainLayout->addRow("Inital Position Random:", &mInitPosRandSpinBox); + mainLayout->addRow("Figure Velocity:", &mFigureVelSpinBox); + mainLayout->addRow("Air Resistance:", &mAirResistSpinBox); + + setupConnections(); +} + +void ChildVelocityInspector::setupConnections() { + // Rand Velocity + connect(&mRandVelSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto vel = mRandVelSpinBox.getVector(); + setEmitterProperty( + "Set Child Random Velocity", + "SetChildRandVel", + &Ptcl::Emitter::childRandVelocity, + &Ptcl::Emitter::setChildRandVelocity, + vel + ); + }); + + // Gravity + connect(&mGravitySpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto gravity = mGravitySpinBox.getVector(); + setEmitterProperty( + "Set Child Gravity", + "SetChildGravity", + &Ptcl::Emitter::childGravity, + &Ptcl::Emitter::setChildGravity, + gravity + ); + }); + + // Inherit Velocity + connect(&mInheritVelCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Child Inherit Velocity", + "ToggleChildInheritVel", + &Ptcl::Emitter::isChildInheritVelocity, + &Ptcl::Emitter::setChildInheritVelocity, + checked + ); + }); + + // Inherit Rate + connect(&mVelInheritSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Child Velocity Inherit Rate", + "SetChildVelInheritRate", + &Ptcl::Emitter::childVelocityInheritRate, + &Ptcl::Emitter::setChildVelocityInheritRate, + static_cast(value) + ); + }); + + // Init Pos Rand + connect(&mInitPosRandSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Child Initial Position Random", + "SetChildInitPosRand", + &Ptcl::Emitter::childInitalPositionRand, + &Ptcl::Emitter::setChildInitialPositionRand, + static_cast(value) + ); + }); + + // Figure Velocity + connect(&mFigureVelSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Child Figure Velocity", + "SetChildFigureVel", + &Ptcl::Emitter::childFigureVelocity, + &Ptcl::Emitter::setChildFigureVelocity, + static_cast(value) + ); + }); + + // Air Resistance + connect(&mAirResistSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Child Air Resistance", + "SetChildAirResit", + &Ptcl::Emitter::childAirResistance, + &Ptcl::Emitter::setChildAirResistance, + static_cast(value) + ); + }); +} + +void ChildVelocityInspector::populateProperties() { + QSignalBlocker b1(mRandVelSpinBox); + QSignalBlocker b2(mGravitySpinBox); + QSignalBlocker b3(mVelInheritSpinBox); + QSignalBlocker b4(mInitPosRandSpinBox); + QSignalBlocker b5(mFigureVelSpinBox); + QSignalBlocker b6(mAirResistSpinBox); + QSignalBlocker b7(mInheritVelCheckBox); + + mRandVelSpinBox.setVector(mEmitter->childRandVelocity()); + mGravitySpinBox.setVector(mEmitter->childGravity()); + mVelInheritSpinBox.setValue(mEmitter->childVelocityInheritRate()); + mVelInheritSpinBox.setEnabled(mEmitter->isChildInheritVelocity()); + mInitPosRandSpinBox.setValue(mEmitter->childInitalPositionRand()); + mFigureVelSpinBox.setValue(mEmitter->childFigureVelocity()); + mAirResistSpinBox.setValue(mEmitter->childAirResistance()); + mInheritVelCheckBox.setChecked(mEmitter->isChildInheritVelocity()); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/inspector/colorInspector.cpp b/src/editor/inspector/colorInspector.cpp new file mode 100644 index 0000000..35a866f --- /dev/null +++ b/src/editor/inspector/colorInspector.cpp @@ -0,0 +1,368 @@ +#include "editor/inspector/colorInspector.h" + +#include +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +ColorInspector::ColorInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + // Color Behavior Type + auto colorBehaviorLayout = new QHBoxLayout; + mColorBehavior.addItem("Constant", QVariant::fromValue(Behavior::Constant)); + mColorBehavior.addItem("Random", QVariant::fromValue(Behavior::Random)); + mColorBehavior.addItem("Animation", QVariant::fromValue(Behavior::Animation)); + colorBehaviorLayout->addWidget(new QLabel("Color Behavior")); + colorBehaviorLayout->addWidget(&mColorBehavior); + colorBehaviorLayout->addStretch(); + + // Primary Color Ui + mPrimaryColorUi = new QWidget(this); + auto* mPrimaryColorLayout = new QVBoxLayout(mPrimaryColorUi); + mPrimaryColorLayout->addWidget(new QLabel("Primary Color")); + mPrimaryColorLayout->addWidget(&mPrimaryColorWidget); + + // Random Color Ui + mRandomColorUi = new QWidget(this); + auto* mRandomColorLayout = new QVBoxLayout(mRandomColorUi); + mRandomColorLayout->addWidget(new QLabel("Random Color A")); + mRandomColorLayout->addWidget(&mRandomColorAWidget); + mRandomColorLayout->addWidget(new QLabel("Random Color B")); + mRandomColorLayout->addWidget(&mRandomColorBWidget); + mRandomColorLayout->addWidget(new QLabel("Random Color C")); + mRandomColorLayout->addWidget(&mRandomColorCWidget); + + // Color Repetition + auto colorRepeatLayout = new QHBoxLayout; + mRepetitionCountLabel.setText("Repetition Count"); + colorRepeatLayout->addWidget(&mRepetitionCountLabel); + colorRepeatLayout->addWidget(&mColorNumRepeatSpinBox); + colorRepeatLayout->addStretch(); + + // Anim Color Ui + mAnimColorUi = new QWidget(this); + auto* mAnimColorLayout = new QVBoxLayout(mAnimColorUi); + mAnimColorLayout->addWidget(new QLabel("Anim Start Color")); + mAnimColorLayout->addWidget(&mStartColorWidget); + mAnimColorLayout->addWidget(new QLabel("Anim Mid Color")); + mAnimColorLayout->addWidget(&mMidColorWidget); + mAnimColorLayout->addWidget(new QLabel("Anim End Color")); + mAnimColorLayout->addWidget(&mEndColorWidget); + mAnimColorLayout->addWidget(&mColorSections); + mAnimColorLayout->addLayout(colorRepeatLayout); + + // Secondary Color + mSecondaryColorWidget.enableAlpha(false); + + // Main Layout + auto mainLayout = new QVBoxLayout(this); + mainLayout->addLayout(colorBehaviorLayout); + + mainLayout->addWidget(mPrimaryColorUi); + mainLayout->addWidget(mRandomColorUi); + mainLayout->addWidget(mAnimColorUi); + + mainLayout->addWidget(new QLabel("Secondary Color")); + mainLayout->addWidget(&mSecondaryColorWidget); + mainLayout->addWidget(new QLabel("Color Calc Type")); + mainLayout->addWidget(&mColorCalcTypeSpinBox); + + setLayout(mainLayout); + setupConnections(); +} + +void ColorInspector::setupConnections() { + // Behavior Type + connect(&mColorBehavior, &QComboBox::currentIndexChanged, this, &ColorInspector::handleBehaviorChanged); + + // Color Sections + connect(&mColorSections, &ColorGradientEditor::handleMoved, this, &ColorInspector::updateColorSection); + + // Color Repeat + connect(&mColorNumRepeatSpinBox, &SizedSpinBoxBase::valueChanged, this, [this](s32 value) { + setEmitterProperty( + "Set Color Repetitions", + "SetColorRepetitions", + &Ptcl::Emitter::colorNumRepeat, + &Ptcl::Emitter::setColorNumRepeat, + value + ); + }); + + // Color Calc Type + connect(&mColorCalcTypeSpinBox, &QComboBox::currentIndexChanged, this, [this]() { + const auto type = mColorCalcTypeSpinBox.currentEnum(); + setEmitterProperty( + "Set Color Calc Type", + "SetColorCalcType", + &Ptcl::Emitter::colorCalcType, + &Ptcl::Emitter::setColorCalcType, + type + ); + }); + + // Primary Color + connect(&mPrimaryColorWidget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto& color = mPrimaryColorWidget.color(); + setEmitterProperty( + "Set Primary Color", + "SetPrimaryColor", + &Ptcl::Emitter::primaryColor, + &Ptcl::Emitter::setPrimaryColor, + color + ); + }); + + // Random Color A + connect(&mRandomColorAWidget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto& color = mRandomColorAWidget.color(); + setEmitterProperty( + "Set Random Color A", + "SetRandomColorA", + &Ptcl::Emitter::randomColorA, + &Ptcl::Emitter::setRandomColorA, + color + ); + }); + + // Random Color B + connect(&mRandomColorBWidget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto& color = mRandomColorBWidget.color(); + setEmitterProperty( + "Set Random Color B", + "SetRandomColorB", + &Ptcl::Emitter::randomColorB, + &Ptcl::Emitter::setRandomColorB, + color + ); + }); + + // Random Color C + connect(&mRandomColorCWidget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto& color = mRandomColorCWidget.color(); + setEmitterProperty( + "Set Random Color C", + "SetRandomColorC", + &Ptcl::Emitter::randomColorC, + &Ptcl::Emitter::setRandomColorC, + color + ); + }); + + // Anim Start Color + connect(&mStartColorWidget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto& color = mStartColorWidget.color(); + setEmitterProperty( + "Set Start Color", + "SetStartColor", + &Ptcl::Emitter::startColor, + &Ptcl::Emitter::setStartColor, + color + ); + }); + + // Anim Mid Color + connect(&mMidColorWidget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto& color = mMidColorWidget.color(); + setEmitterProperty( + "Set Mid Color", + "SetMidColor", + &Ptcl::Emitter::midColor, + &Ptcl::Emitter::setMidColor, + color + ); + }); + + // Anim End Color + connect(&mEndColorWidget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto& color = mEndColorWidget.color(); + setEmitterProperty( + "Set End Color", + "SetEndColor", + &Ptcl::Emitter::endColor, + &Ptcl::Emitter::setEndColor, + color + ); + }); + + // Secondary Color + connect(&mSecondaryColorWidget, &RGBAColorWidget::colorChanged, this, [this]() { + const auto& color = mSecondaryColorWidget.color(); + + Ptcl::binColor3f newColor{ + color.r * 255.0f, + color.g * 255.0f, + color.b * 255.0f + }; + + setEmitterProperty( + "Set Secondary Color", + "SetSecondaryColor", + &Ptcl::Emitter::secondaryColor, + &Ptcl::Emitter::setSecondaryColor, + newColor + ); + }); +} + +void ColorInspector::populateProperties() { + QSignalBlocker b1(mColorSections); + QSignalBlocker b2(mColorNumRepeatSpinBox); + QSignalBlocker b3(mColorCalcTypeSpinBox); + QSignalBlocker b4(mPrimaryColorWidget); + QSignalBlocker b5(mRandomColorAWidget); + QSignalBlocker b6(mRandomColorBWidget); + QSignalBlocker b7(mRandomColorCWidget); + QSignalBlocker b8(mStartColorWidget); + QSignalBlocker b9(mMidColorWidget); + QSignalBlocker b10(mEndColorWidget); + QSignalBlocker b11(mColorBehavior); + + mPrimaryColorWidget.setColor(mEmitter->primaryColor()); + + mRandomColorAWidget.setColor(mEmitter->randomColorA()); + mRandomColorBWidget.setColor(mEmitter->randomColorB()); + mRandomColorCWidget.setColor(mEmitter->randomColorC()); + + mStartColorWidget.setColor(mEmitter->startColor()); + mMidColorWidget.setColor(mEmitter->midColor()); + mEndColorWidget.setColor(mEmitter->endColor()); + + mColorSections.setTimings( + mEmitter->colorSection1(), + mEmitter->colorSection2(), + mEmitter->colorSection3() + ); + + const auto& startColor = mEmitter->startColor(); + mColorSections.setInitialColor(QColor::fromRgbF(startColor.r, startColor.g, startColor.b)); + + const auto& midColor = mEmitter->midColor(); + mColorSections.setPeakColor(QColor::fromRgbF(midColor.r, midColor.g, midColor.b)); + + const auto& endColor = mEmitter->endColor(); + mColorSections.setEndColor(QColor::fromRgbF(endColor.r, endColor.g, endColor.b)); + + mColorSections.setRepetitionCount(mEmitter->colorNumRepeat()); + mColorNumRepeatSpinBox.setValue(mEmitter->colorNumRepeat()); + mColorCalcTypeSpinBox.setCurrentEnum(mEmitter->colorCalcType()); + + Ptcl::binColor4f secondaryColor{ + std::clamp(mEmitter->secondaryColor().r / 255.0f, 0.0f, 1.0f), + std::clamp(mEmitter->secondaryColor().g / 255.0f, 0.0f, 1.0f), + std::clamp(mEmitter->secondaryColor().b / 255.0f, 0.0f, 1.0f), + 1.0f + }; + mSecondaryColorWidget.setColor(secondaryColor); + + Behavior behavior = Behavior::Constant; + if (mEmitter->isColorRandom()) { + behavior = Behavior::Random; + mPrimaryColorUi->setVisible(false); + mRandomColorUi->setVisible(true); + mAnimColorUi->setVisible(false); + } else if (mEmitter->isColorAnimation()) { + behavior = Behavior::Animation; + mPrimaryColorUi->setVisible(false); + mRandomColorUi->setVisible(false); + mAnimColorUi->setVisible(true); + } else { + mPrimaryColorUi->setVisible(true); + mRandomColorUi->setVisible(false); + mAnimColorUi->setVisible(false); + } + + mColorBehavior.setCurrentIndex(behaviorToIndex(behavior)); +} + +void ColorInspector::handleBehaviorChanged(s32 index) { + auto behavior = behaviorFromIndex(index); + + bool isColorRandom; + bool isColorAnim; + QString label; + + switch (behavior) { + case Behavior::Constant: + label = "Set Color Behavior Constant"; + isColorRandom = false; + isColorAnim = false; + break; + case Behavior::Random: + label = "Set Color Behavior Random"; + isColorRandom = true; + isColorAnim = false; + break; + case Behavior::Animation: + label = "Set Color Behavior Animation"; + isColorRandom = false; + isColorAnim = true; + break; + } + + mDocument->undoStack()->beginMacro(formatHistoryLabel(label)); + + setEmitterProperty( + "Set Color Random", + "SetColorRandom", + &Ptcl::Emitter::isColorRandom, + &Ptcl::Emitter::setIsColorRandom, + isColorRandom + ); + + setEmitterProperty( + "Set Color Anim", + "SetColorAnim", + &Ptcl::Emitter::isColorAnimation, + &Ptcl::Emitter::setIsColorAnimation, + isColorAnim + ); + + mDocument->undoStack()->endMacro(); +} + +void ColorInspector::updateColorSection(ColorGradientEditor::HandleType handleType) { + switch (handleType) { + case ColorGradientEditor::HandleType::InCompletedHandle: { + setEmitterProperty( + "Set Color Anim In Timing", + "SetColorAnimSection1", + &Ptcl::Emitter::colorSection1, + &Ptcl::Emitter::setColorSection1, + mColorSections.inCompletedTiming() + ); + } + break; + case ColorGradientEditor::HandleType::PeakHandle: { + setEmitterProperty( + "Set Color Anim Peak Timing", + "SetColorAnimSection2", + &Ptcl::Emitter::colorSection2, + &Ptcl::Emitter::setColorSection2, + mColorSections.peakTiming() + ); + } + break; + case ColorGradientEditor::HandleType::OutStartHandle: { + setEmitterProperty( + "Set Color Anim Out Timing", + "SetColorAnimSection3", + &Ptcl::Emitter::colorSection3, + &Ptcl::Emitter::setColorSection3, + mColorSections.outStartTiming() + ); + } + break; + } +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/inspector/combinerInspector.cpp b/src/editor/inspector/combinerInspector.cpp new file mode 100644 index 0000000..5511e41 --- /dev/null +++ b/src/editor/inspector/combinerInspector.cpp @@ -0,0 +1,90 @@ +#include "editor/inspector/combinerInspector.h" + +#include + +namespace PtclEditor { + + +// ========================================================================== // + + +CombinerInspector::CombinerInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + auto* mainLayout = new QFormLayout(this); + + mFogCheckBox.setText("Enable Fog"); + + mainLayout->addRow("Fog:", &mFogCheckBox); + mainLayout->addRow("Blend Function:", &mBlendFuncComboBox); + mainLayout->addRow("Depth Function:", &mDepthFuncComboBox); + mainLayout->addRow("Combiner Function:", &mCombinerFuncComboBox); + mainLayout->addWidget(&mCombinerPreview); + + setupConnections(); +} + +void CombinerInspector::setupConnections() { + connect(&mFogCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Set Fog Enabled", + "SetFogEnabled", + &Ptcl::Emitter::isFogEnabled, + &Ptcl::Emitter::setIsFogEnabled, + checked + ); + }); + + connect(&mBlendFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { + const auto func = mBlendFuncComboBox.currentEnum(); + setEmitterProperty( + "Set Blend Function", + "SetBlendFunction", + &Ptcl::Emitter::blendFunction, + &Ptcl::Emitter::setBlendFunction, + func + ); + }); + + connect(&mDepthFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { + const auto func = mDepthFuncComboBox.currentEnum(); + setEmitterProperty( + "Set Depth Function", + "SetDepthFunction", + &Ptcl::Emitter::depthFunction, + &Ptcl::Emitter::setDepthFunction, + func + ); + }); + + connect(&mCombinerFuncComboBox, &QComboBox::currentIndexChanged, this, [this]() { + const auto func = mCombinerFuncComboBox.currentEnum(); + setEmitterProperty( + "Set Combiner Function", + "SetCombinerFunction", + &Ptcl::Emitter::combinerFunction, + &Ptcl::Emitter::setCombinerFunction, + func + ); + }); +} + +void CombinerInspector::populateProperties() { + QSignalBlocker b1(mBlendFuncComboBox); + QSignalBlocker b2(mDepthFuncComboBox); + QSignalBlocker b3(mCombinerFuncComboBox); + QSignalBlocker b4(mFogCheckBox); + + mFogCheckBox.setChecked(mEmitter->isFogEnabled()); + mBlendFuncComboBox.setCurrentEnum(mEmitter->blendFunction()); + mDepthFuncComboBox.setCurrentEnum(mEmitter->depthFunction()); + mCombinerFuncComboBox.setCurrentEnum(mEmitter->combinerFunction()); + mCombinerPreview.setConfig(static_cast(mEmitter->combinerFunction())); + mCombinerPreview.setCombinerSrc(&mEmitter->textureHandle(), &mEmitter->secondaryColor(), &mEmitter->primaryColor()); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/emitterWidget/emissionPropertiesWidget.cpp b/src/editor/inspector/emissionInspector.cpp similarity index 55% rename from src/editor/emitterWidget/emissionPropertiesWidget.cpp rename to src/editor/inspector/emissionInspector.cpp index 7a696b7..efd6576 100644 --- a/src/editor/emitterWidget/emissionPropertiesWidget.cpp +++ b/src/editor/inspector/emissionInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/emitterWidget/emissionPropertiesWidget.h" +#include "editor/inspector/emissionInspector.h" #include #include @@ -10,8 +10,8 @@ namespace PtclEditor { // ========================================================================== // -EmitterWidget::EmissionPropertiesWidget::EmissionPropertiesWidget(QWidget* parent) : - QWidget{parent} { +EmissionInspector::EmissionInspector(QWidget* parent) : + InspectorWidgetBase{parent} { auto* mainLayout = new QGridLayout(this); @@ -21,66 +21,95 @@ EmitterWidget::EmissionPropertiesWidget::EmissionPropertiesWidget(QWidget* paren mLifeStepRndSpinBox.setRange(0, std::numeric_limits::max()); mEmitRateSpinBox.setRange(0, std::numeric_limits::max()); - // Row 0: Infinite Emission mainLayout->addWidget(&mInfiniteEmitCheckBox, 0, 1); mainLayout->addWidget(new QLabel("Infinite Emission:"), 0, 0); - // Row 1: Start and End Frame mainLayout->addWidget(new QLabel("Emission Start Frame:"), 1, 0); mainLayout->addWidget(&mStartFrameSpinBox, 1, 1); mainLayout->addWidget(new QLabel("Emission End Frame:"), 1, 2); mainLayout->addWidget(&mEndFrameSpinBox, 1, 3); - // Row 2: Interval and Interval Rand mainLayout->addWidget(new QLabel("Emission Interval:"), 2, 0); mainLayout->addWidget(&mLifeStepSpinBox, 2, 1); mainLayout->addWidget(new QLabel("Random Emission Interval:"), 2, 2); mainLayout->addWidget(&mLifeStepRndSpinBox, 2, 3); - // Row 3: Emission Rate mainLayout->addWidget(new QLabel("Emission Rate:"), 3, 0); mainLayout->addWidget(&mEmitRateSpinBox, 3, 1); mainLayout->setColumnStretch(1, 1); mainLayout->setColumnStretch(3, 1); + setupConnections(); +} + +void EmissionInspector::setupConnections() { connect(&mStartFrameSpinBox, &QSpinBox::valueChanged, this, [this](u64 value) { - mProps.startFrame = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Emission Start Frame", + "SetEmitStartFrame", + &Ptcl::Emitter::emitStartFrame, + &Ptcl::Emitter::setEmitStartFrame, + static_cast(value) + ); }); connect(&mEndFrameSpinBox, &QSpinBox::valueChanged, this, [this](u64 value) { - mProps.endFrame = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Emission End Frame", + "SetEmitEndFrame", + &Ptcl::Emitter::emitEndFrame, + &Ptcl::Emitter::setEmitEndFrame, + static_cast(value) + ); }); - connect(&mInfiniteEmitCheckBox, &QCheckBox::checkStateChanged, this, [this](Qt::CheckState state) { + connect(&mInfiniteEmitCheckBox, &QCheckBox::checkStateChanged, this, [this](bool checked) { QSignalBlocker b1(mEndFrameSpinBox); - const bool isInfinite = (state == Qt::CheckState::Checked); - mProps.endFrame = isInfinite ? sEmitInfinite : 1; - mEndFrameSpinBox.setValue(mProps.endFrame); - mEndFrameSpinBox.setEnabled(!isInfinite); - emit propertiesUpdated(mProps); + const s32 endFrame = checked ? sEmitInfinite : 1; + + setEmitterProperty( + "Toggle Infinite Emission", + "SetEmitInfinite", + &Ptcl::Emitter::emitEndFrame, + &Ptcl::Emitter::setEmitEndFrame, + endFrame + ); }); connect(&mLifeStepSpinBox, &QSpinBox::valueChanged, this, [this](u64 value) { - mProps.lifeStep = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Emission Interval", + "SetEmitLifeStep", + &Ptcl::Emitter::lifeStep, + &Ptcl::Emitter::setLifeStep, + static_cast(value) + ); }); connect(&mLifeStepRndSpinBox, &QSpinBox::valueChanged, this, [this](u64 value) { - mProps.lifeStepRnd = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Emission Random Interval", + "SetEmitLifeStepRandom", + &Ptcl::Emitter::lifeStepRandom, + &Ptcl::Emitter::setLifeStepRandom, + static_cast(value) + ); }); connect(&mEmitRateSpinBox, &QSpinBox::valueChanged, this, [this](u64 value) { - mProps.emitRate = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Emission Rate", + "SetEmitRate", + &Ptcl::Emitter::emitRate, + &Ptcl::Emitter::setEmitRate, + static_cast(value) + ); }); } -void EmitterWidget::EmissionPropertiesWidget::setProperties(const Ptcl::Emitter::EmissionProperties& properties) { +void EmissionInspector::populateProperties() { QSignalBlocker b1(mStartFrameSpinBox); QSignalBlocker b2(mEndFrameSpinBox); QSignalBlocker b3(mLifeStepSpinBox); @@ -88,21 +117,19 @@ void EmitterWidget::EmissionPropertiesWidget::setProperties(const Ptcl::Emitter: QSignalBlocker b5(mInfiniteEmitCheckBox); QSignalBlocker b6(mEmitRateSpinBox); - mProps = properties; - - mStartFrameSpinBox.setValue(mProps.startFrame); + mStartFrameSpinBox.setValue(mEmitter->emitStartFrame()); - const s32 endFrame = mProps.endFrame; + const s32 endFrame = mEmitter->emitEndFrame(); const bool infiniteEmission = (endFrame == sEmitInfinite); mEndFrameSpinBox.setValue(endFrame); mEndFrameSpinBox.setDisabled(infiniteEmission); mInfiniteEmitCheckBox.setChecked(infiniteEmission); - mLifeStepSpinBox.setValue(mProps.lifeStep); - mLifeStepRndSpinBox.setValue(mProps.lifeStepRnd); + mLifeStepSpinBox.setValue(mEmitter->lifeStep()); + mLifeStepRndSpinBox.setValue(mEmitter->lifeStepRandom()); - mEmitRateSpinBox.setValue(mProps.emitRate); + mEmitRateSpinBox.setValue(mEmitter->emitRate()); } diff --git a/src/editor/inspector/emitterSetInspector.cpp b/src/editor/inspector/emitterSetInspector.cpp new file mode 100644 index 0000000..baff759 --- /dev/null +++ b/src/editor/inspector/emitterSetInspector.cpp @@ -0,0 +1,127 @@ +#include "editor/inspector/emitterSetInspector.h" +#include "util/nameValidator.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +EmitterSetInspector::EmitterSetInspector(QWidget* parent) : + QWidget{parent} { + mNameLineEdit.setPlaceholderText("EmitterSetName"); + mNameLineEdit.setValidator(new EmitterNameValidator(&mNameLineEdit)); + // TODO: Check these + mUserDataSpinBox.setRange(std::numeric_limits::min(), std::numeric_limits::max()); + mLastUpdateSpinBox.setRange(std::numeric_limits::min(), std::numeric_limits::max()); + + auto* mainLayout = new QFormLayout(this); + mainLayout->addRow("EmitterSet Name:", &mNameLineEdit); + mainLayout->addRow("UserData:", &mUserDataSpinBox); + mainLayout->addRow("LastUpdate:", &mLastUpdateSpinBox); + + setupConnections(); +} + +void EmitterSetInspector::setupConnections() { + // Name Edit + connect(&mNameLineEdit, &QLineEdit::textEdited, this, [this](const QString& text) { + mDocument->setEmitterSetProperty( + mSelection->emitterSetIndex(), + "Set EmitterSet Name", + "SetEmitterSetName", + &Ptcl::EmitterSet::name, + &Ptcl::EmitterSet::setName, + text + ); + }); + + // User Data + connect(&mUserDataSpinBox, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + mDocument->setEmitterSetProperty( + mSelection->emitterSetIndex(), + "Set EmitterSet UserData", + "SetEmitterSetUserData", + &Ptcl::EmitterSet::userData, + &Ptcl::EmitterSet::setUserData, + static_cast(value) + ); + }); + + // Last Update + connect(&mLastUpdateSpinBox, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + mDocument->setEmitterSetProperty( + mSelection->emitterSetIndex(), + "Set EmitterSet LastUpdate", + "SetEmitterSetLastUpdate", + &Ptcl::EmitterSet::lastUpdateDate, + &Ptcl::EmitterSet::setLastUpdateDate, + static_cast(value) + ); + }); +} + +void EmitterSetInspector::setDocument(Ptcl::Document* document) { + if (mDocument) { + mDocument->disconnect(this); + } + + mDocument = document; + + if (mDocument) { + connect(mDocument, &Ptcl::Document::emitterSetChanged, this, [this](s32 setIndex) { + if (!mEmitterSet) { + return; + } + + if (setIndex != mSelection->emitterSetIndex()) { + return; + } + + populateProperties(); + }); + } +} + +void EmitterSetInspector::setSelection(Ptcl::Selection* selection) { + if (mSelection) { + mSelection->disconnect(this); + } + + mSelection = selection; + + if (mSelection) { + connect(selection, &Ptcl::Selection::selectionChanged, this, [this](s32 setIndex, s32 emitterIndex) { + Q_UNUSED(emitterIndex); + + if (!mDocument) { + mEmitterSet = nullptr; + setEnabled(false); + return; + } + + mEmitterSet = mDocument->emitterSet(setIndex); + setEnabled(true); + populateProperties(); + }); + } +} + +void EmitterSetInspector::populateProperties() { + QSignalBlocker b1(mNameLineEdit); + QSignalBlocker b2(mUserDataSpinBox); + QSignalBlocker b3(mLastUpdateSpinBox); + + mNameLineEdit.setText(mEmitterSet->name()); + mUserDataSpinBox.setValue(mEmitterSet->userData()); + mLastUpdateSpinBox.setValue(mEmitterSet->lastUpdateDate()); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/fieldEditor/collisionDataWidget.cpp b/src/editor/inspector/field/fieldCollisionInspector.cpp similarity index 50% rename from src/editor/fieldEditor/collisionDataWidget.cpp rename to src/editor/inspector/field/fieldCollisionInspector.cpp index 001e8da..73cae0b 100644 --- a/src/editor/fieldEditor/collisionDataWidget.cpp +++ b/src/editor/inspector/field/fieldCollisionInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/fieldEditor/collisionDataWidget.h" +#include "editor/inspector/field/fieldCollisionInspector.h" #include @@ -9,8 +9,8 @@ namespace PtclEditor { // ========================================================================== // -FieldEditorWidget::CollisionDataWidget::CollisionDataWidget(QWidget* parent) : - QWidget{parent} { +FieldCollisionInspector::FieldCollisionInspector(QWidget* parent) : + InspectorWidgetBase{parent} { // TODO: Better ranges? mIsWorldCheckBox.setText("Collision in world coordinates"); @@ -32,51 +32,77 @@ FieldEditorWidget::CollisionDataWidget::CollisionDataWidget(QWidget* parent) : setupConnections(); } -void FieldEditorWidget::CollisionDataWidget::setupConnections() { +void FieldCollisionInspector::setupConnections() { // Is Enabled connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit isEnabledUpdated(checked); - mControlsWidget->setEnabled(checked); + setEmitterProperty( + "Toggle Field Collision", + "ToggleFieldCollision", + &Ptcl::Emitter::isFieldCollisionEnabled, + &Ptcl::Emitter::setFieldCollisionEnabled, + checked + ); }); // CollisionType connect(&mCollisionTypeSpinBox, &QComboBox::currentIndexChanged, this, [this]() { - mData.collisionType = mCollisionTypeSpinBox.currentEnum(); - emit dataUpdated(mData); + const auto type = mCollisionTypeSpinBox.currentEnum(); + setEmitterProperty( + "Set Field Collision Type", + "SetFieldCollisionType", + &Ptcl::Emitter::fieldCollisionType, + &Ptcl::Emitter::setFieldCollisionType, + type + ); }); // Is World connect(&mIsWorldCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mData.collisionIsWorld = checked; - emit dataUpdated(mData); + setEmitterProperty( + "Toggle Field Collision WorldCoords", + "ToggleFieldCollisionInWorld", + &Ptcl::Emitter::fieldCollisionIsWorld, + &Ptcl::Emitter::setFieldCollisionIsWorld, + checked + ); }); // Coef - connect(&mCoefSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.collisionCoef = static_cast(value); - emit dataUpdated(mData); + connect(&mCoefSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Field Collision Bounce Rate", + "SetFieldCollisionCoef", + &Ptcl::Emitter::fieldCollisionCoef, + &Ptcl::Emitter::setFieldCollisionCoef, + static_cast(value) + ); }); // Coord connect(&mCoordSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.collisionCoord = static_cast(value); - emit dataUpdated(mData); + setEmitterProperty( + "Set Field Collision Plane Coord", + "SetFieldCollisionCoord", + &Ptcl::Emitter::fieldCollisionCoord, + &Ptcl::Emitter::setFieldCollisionCoord, + static_cast(value) + ); }); } -void FieldEditorWidget::CollisionDataWidget::setData(const Ptcl::FieldData::FieldCollisionData& data, bool isEnabled) { +void FieldCollisionInspector::populateProperties() { QSignalBlocker b1(mCollisionTypeSpinBox); QSignalBlocker b2(mIsWorldCheckBox); QSignalBlocker b3(mCoefSpinBox); QSignalBlocker b4(mCoordSpinBox); QSignalBlocker b5(mEnabledCheckBox); - mData = data; + mCollisionTypeSpinBox.setCurrentEnum(mEmitter->fieldCollisionType()); + mIsWorldCheckBox.setChecked(mEmitter->fieldCollisionIsWorld()); + mCoefSpinBox.setValue(mEmitter->fieldCollisionCoef()); + mCoordSpinBox.setValue(mEmitter->fieldCollisionCoord()); - mCollisionTypeSpinBox.setCurrentEnum(mData.collisionType); - mIsWorldCheckBox.setChecked(mData.collisionIsWorld); - mCoefSpinBox.setValue(mData.collisionCoef); - mCoordSpinBox.setValue(mData.collisionCoord); + const bool isEnabled = mEmitter->isFieldCollisionEnabled(); mEnabledCheckBox.setChecked(isEnabled); mControlsWidget->setEnabled(isEnabled); } diff --git a/src/editor/fieldEditor/convergenceDataWidget.cpp b/src/editor/inspector/field/fieldConvergenceInspector.cpp similarity index 50% rename from src/editor/fieldEditor/convergenceDataWidget.cpp rename to src/editor/inspector/field/fieldConvergenceInspector.cpp index 7890a03..7e2d29e 100644 --- a/src/editor/fieldEditor/convergenceDataWidget.cpp +++ b/src/editor/inspector/field/fieldConvergenceInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/fieldEditor/convergenceDataWidget.h" +#include "editor/inspector/field/fieldConvergenceInspector.h" #include @@ -9,8 +9,8 @@ namespace PtclEditor { // ========================================================================== // -FieldEditorWidget::ConvergenceDataWidget::ConvergenceDataWidget(QWidget* parent) : - QWidget{parent} { +FieldConvergenceInspector::FieldConvergenceInspector(QWidget* parent) : + InspectorWidgetBase{parent} { // TODO: Better ranges? mPosSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); @@ -28,35 +28,52 @@ FieldEditorWidget::ConvergenceDataWidget::ConvergenceDataWidget(QWidget* parent) setupConnections(); } -void FieldEditorWidget::ConvergenceDataWidget::setupConnections() { +void FieldConvergenceInspector::setupConnections() { // Is Enabled connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit isEnabledUpdated(checked); - mControlsWidget->setEnabled(checked); + setEmitterProperty( + "Toggle Field Convergence", + "ToggleFieldConvergence", + &Ptcl::Emitter::isFieldConvergenceEnabled, + &Ptcl::Emitter::setFieldConvergenceEnabled, + checked + ); }); // Type connect(&mTypeSpinBox, &QComboBox::currentIndexChanged, this, [this]() { - mData.convergenceType = mTypeSpinBox.currentEnum(); - emit dataUpdated(mData); + const auto type = mTypeSpinBox.currentEnum(); + setEmitterProperty( + "Set Field Convergence Type", + "SetFieldConvergenceType", + &Ptcl::Emitter::fieldConvergenceType, + &Ptcl::Emitter::setFieldConvergenceType, + type + ); }); // Position connect(&mPosSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mData.convergencePos = mPosSpinBox.getVector(); - emit dataUpdated(mData); + const auto pos = mPosSpinBox.getVector(); + setEmitterProperty( + "Set Field Convergence Pos", + "SetFieldConvergencePos", + &Ptcl::Emitter::fieldConvergencePos, + &Ptcl::Emitter::setFieldConvergencePos, + pos + ); }); } -void FieldEditorWidget::ConvergenceDataWidget::setData(const Ptcl::FieldData::FieldConvergenceData& data, bool isEnabled) { +void FieldConvergenceInspector::populateProperties() { QSignalBlocker b1(mTypeSpinBox); QSignalBlocker b2(mPosSpinBox); QSignalBlocker b3(mEnabledCheckBox); - mData = data; + mTypeSpinBox.setCurrentEnum(mEmitter->fieldConvergenceType()); + mPosSpinBox.setVector(mEmitter->fieldConvergencePos()); - mTypeSpinBox.setCurrentEnum(mData.convergenceType); - mPosSpinBox.setVector(mData.convergencePos); + const bool isEnabled = mEmitter->isFieldConvergenceEnabled(); mEnabledCheckBox.setChecked(isEnabled); mControlsWidget->setEnabled(isEnabled); } diff --git a/src/editor/inspector/field/fieldMagnetInspector.cpp b/src/editor/inspector/field/fieldMagnetInspector.cpp new file mode 100644 index 0000000..2bae27d --- /dev/null +++ b/src/editor/inspector/field/fieldMagnetInspector.cpp @@ -0,0 +1,126 @@ +#include "editor/inspector/field/fieldMagnetInspector.h" + +#include + +namespace PtclEditor { + + +// ========================================================================== // + + +FieldMagnetInspector::FieldMagnetInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + // TODO: Better ranges? + mMagnetPowerSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mMagnetPosSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mEnabledCheckBox.setText("Enabled"); + + mControlsWidget = new QWidget(this); + auto* controlsLayout = new QFormLayout(mControlsWidget); + controlsLayout->addRow("Magnet Power:", &mMagnetPowerSpinBox); + controlsLayout->addRow("Magnet Position:", &mMagnetPosSpinBox); + controlsLayout->addRow("Target X-Axis:", &mAxisXCheckBox); + controlsLayout->addRow("Target Y-Axis:", &mAxisYCheckBox); + controlsLayout->addRow("Target Z-Axis:", &mAxisZCheckBox); + + auto* mainLayout = new QFormLayout(this); + mainLayout->addRow("Magnetic Force:", &mEnabledCheckBox); + mainLayout->addRow(mControlsWidget); + + setupConnections(); +} + +void FieldMagnetInspector::setupConnections() { + // Is Enabled + connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Field Magnet", + "ToggleFieldMagnet", + &Ptcl::Emitter::isFieldMagnetEnabled, + &Ptcl::Emitter::setFieldMagnetEnabled, + checked + ); + }); + + // Magnet Power + connect(&mMagnetPowerSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Field Magnet Power", + "SetFieldMagnetPower", + &Ptcl::Emitter::fieldMagnetPower, + &Ptcl::Emitter::setFieldMagnetPower, + static_cast(value) + ); + }); + + // Magnet pos + connect(&mMagnetPosSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto pos = mMagnetPosSpinBox.getVector(); + setEmitterProperty( + "Set Field Magnet Pos", + "SetFieldMagnetPos", + &Ptcl::Emitter::fieldMagnetPos, + &Ptcl::Emitter::setFieldMagnetPos, + pos + ); + }); + + // Axis X + connect(&mAxisXCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Field Magnet X-Target", + "ToggleFieldMagnetTargetX", + &Ptcl::Emitter::isFieldMagnetAxisTargetX, + &Ptcl::Emitter::setFieldMagnetAxisTargetX, + checked + ); + }); + + // Axis Y + connect(&mAxisYCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Field Magnet Y-Target", + "ToggleFieldMagnetTargetY", + &Ptcl::Emitter::isFieldMagnetAxisTargetY, + &Ptcl::Emitter::setFieldMagnetAxisTargetY, + checked + ); + }); + + // Axis Z + connect(&mAxisZCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Field Magnet Z-Target", + "ToggleFieldMagnetTargetZ", + &Ptcl::Emitter::isFieldMagnetAxisTargetZ, + &Ptcl::Emitter::setFieldMagnetAxisTargetZ, + checked + ); + }); +} + +void FieldMagnetInspector::populateProperties() { + QSignalBlocker b1(mMagnetPowerSpinBox); + QSignalBlocker b2(mMagnetPosSpinBox); + QSignalBlocker b3(mAxisXCheckBox); + QSignalBlocker b4(mAxisYCheckBox); + QSignalBlocker b5(mAxisZCheckBox); + QSignalBlocker b6(mEnabledCheckBox); + + mMagnetPowerSpinBox.setValue(mEmitter->fieldMagnetPower()); + mMagnetPosSpinBox.setVector(mEmitter->fieldMagnetPos()); + mAxisXCheckBox.setChecked(mEmitter->isFieldMagnetAxisTargetX()); + mAxisYCheckBox.setChecked(mEmitter->isFieldMagnetAxisTargetY()); + mAxisZCheckBox.setChecked(mEmitter->isFieldMagnetAxisTargetZ()); + + const bool isEnabled = mEmitter->isFieldMagnetEnabled(); + mEnabledCheckBox.setChecked(isEnabled); + mControlsWidget->setEnabled(isEnabled); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/fieldEditor/posAddDataWidget.cpp b/src/editor/inspector/field/fieldPosAddInspector.cpp similarity index 56% rename from src/editor/fieldEditor/posAddDataWidget.cpp rename to src/editor/inspector/field/fieldPosAddInspector.cpp index 1fa4296..898d164 100644 --- a/src/editor/fieldEditor/posAddDataWidget.cpp +++ b/src/editor/inspector/field/fieldPosAddInspector.cpp @@ -1,17 +1,16 @@ -#include "editor/fieldEditor/posAddDataWidget.h" - -#include "math/util.h" +#include "editor/inspector/field/fieldPosAddInspector.h" #include + namespace PtclEditor { // ========================================================================== // -FieldEditorWidget::PosAddDataWidget::PosAddDataWidget(QWidget* parent) : - QWidget{parent} { +FieldPosAddInspector::FieldPosAddInspector(QWidget* parent) : + InspectorWidgetBase{parent} { // TODO: Set better limits? mPosSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); @@ -28,27 +27,38 @@ FieldEditorWidget::PosAddDataWidget::PosAddDataWidget(QWidget* parent) : setupConnections(); } -void FieldEditorWidget::PosAddDataWidget::setupConnections() { +void FieldPosAddInspector::setupConnections() { // Is Enabled connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit isEnabledUpdated(checked); - mControlsWidget->setEnabled(checked); + setEmitterProperty( + "Toggle Field PosAdd", + "ToggleFieldPosAdd", + &Ptcl::Emitter::isFieldPosAddEnabled, + &Ptcl::Emitter::setFieldPosAddEnabled, + checked + ); }); // Pos Add connect(&mPosSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mData.posAdd = mPosSpinBox.getVector(); - emit dataUpdated(mData); + const auto pos = mPosSpinBox.getVector(); + setEmitterProperty( + "Set Field PosAdd Position", + "SetFieldPosAdd", + &Ptcl::Emitter::fieldPosAddPosition, + &Ptcl::Emitter::setFieldPosAddPosition, + pos + ); }); } -void FieldEditorWidget::PosAddDataWidget::setData(const Ptcl::FieldData::FieldPosAddData& data, bool isEnabled) { +void FieldPosAddInspector::populateProperties() { QSignalBlocker b1(mPosSpinBox); QSignalBlocker b2(mEnabledCheckBox); - mData = data; + mPosSpinBox.setVector(mEmitter->fieldPosAddPosition()); - mPosSpinBox.setVector(mData.posAdd); + const bool isEnabled = mEmitter->isFieldPosAddEnabled(); mEnabledCheckBox.setChecked(isEnabled); mControlsWidget->setEnabled(isEnabled); } diff --git a/src/editor/fieldEditor/randomDataWidget.cpp b/src/editor/inspector/field/fieldRandomInspector.cpp similarity index 55% rename from src/editor/fieldEditor/randomDataWidget.cpp rename to src/editor/inspector/field/fieldRandomInspector.cpp index a53a081..9a7629b 100644 --- a/src/editor/fieldEditor/randomDataWidget.cpp +++ b/src/editor/inspector/field/fieldRandomInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/fieldEditor/randomDataWidget.h" +#include "editor/inspector/field/fieldRandomInspector.h" #include @@ -8,8 +8,8 @@ namespace PtclEditor { // ========================================================================== // -FieldEditorWidget::RandomDataWidget::RandomDataWidget(QWidget* parent) : - QWidget{parent} { +FieldRandomInspector::FieldRandomInspector(QWidget* parent) : + InspectorWidgetBase{parent} { // TODO: Better ranges? mRandomVelAddSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); @@ -28,35 +28,51 @@ FieldEditorWidget::RandomDataWidget::RandomDataWidget(QWidget* parent) : setupConnections(); } -void FieldEditorWidget::RandomDataWidget::setupConnections() { +void FieldRandomInspector::setupConnections() { // Is Enabled connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit isEnabledUpdated(checked); - mControlsWidget->setEnabled(checked); + setEmitterProperty( + "Toggle Field Random", + "ToggleFieldRandom", + &Ptcl::Emitter::isFieldRandomEnabled, + &Ptcl::Emitter::setFieldRandomEnabled, + checked + ); }); // Random Vel Add connect(&mRandomVelAddSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mData.randomVelAdd = mRandomVelAddSpinBox.getVector(); - emit dataUpdated(mData); + const auto velocity = mRandomVelAddSpinBox.getVector(); + setEmitterProperty( + "Set Field Random Velocity", + "SetFieldRandomVelAdd", + &Ptcl::Emitter::fieldRandomVelAdd, + &Ptcl::Emitter::setFieldRandomVelAdd, + velocity + ); }); // Random Blank connect(&mRandomBlankSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mData.randomBlank = value; - emit dataUpdated(mData); + setEmitterProperty( + "Set Field Random Blank", + "SetFieldRandomBlank", + &Ptcl::Emitter::fieldRandomBlank, + &Ptcl::Emitter::setFieldRandomBlank, + value + ); }); } -void FieldEditorWidget::RandomDataWidget::setData(const Ptcl::FieldData::FieldRandomData& data, bool isEnabled) { +void FieldRandomInspector::populateProperties() { QSignalBlocker b1(mRandomBlankSpinBox); QSignalBlocker b2(mRandomVelAddSpinBox); QSignalBlocker b3(mEnabledCheckBox); - mData = data; + mRandomBlankSpinBox.setValue(mEmitter->fieldRandomBlank()); + mRandomVelAddSpinBox.setVector(mEmitter->fieldRandomVelAdd()); - mRandomBlankSpinBox.setValue(mData.randomBlank); - mRandomVelAddSpinBox.setVector(mData.randomVelAdd); + const bool isEnabled = mEmitter->isFieldRandomEnabled(); mEnabledCheckBox.setChecked(isEnabled); mControlsWidget->setEnabled(isEnabled); } diff --git a/src/editor/fieldEditor/spinDataWidget.cpp b/src/editor/inspector/field/fieldSpinInspector.cpp similarity index 53% rename from src/editor/fieldEditor/spinDataWidget.cpp rename to src/editor/inspector/field/fieldSpinInspector.cpp index 0e82596..499c0bd 100644 --- a/src/editor/fieldEditor/spinDataWidget.cpp +++ b/src/editor/inspector/field/fieldSpinInspector.cpp @@ -1,17 +1,16 @@ -#include "editor/fieldEditor/spinDataWidget.h" - -#include "math/util.h" +#include "editor/inspector/field/fieldSpinInspector.h" #include + namespace PtclEditor { // ========================================================================== // -FieldEditorWidget::SpinDataWidget::SpinDataWidget(QWidget* parent) : - QWidget{parent} { +FieldSpinInspector::FieldSpinInspector(QWidget* parent) : + InspectorWidgetBase{parent} { mSpinRotateSpinBox.setRange(-180.0f, 180.0f); mEnabledCheckBox.setText("Enabled"); @@ -28,35 +27,52 @@ FieldEditorWidget::SpinDataWidget::SpinDataWidget(QWidget* parent) : setupConnections(); } -void FieldEditorWidget::SpinDataWidget::setupConnections() { +void FieldSpinInspector::setupConnections() { // Is Enabled connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - emit isEnabledUpdated(checked); - mControlsWidget->setEnabled(checked); + setEmitterProperty( + "Toggle Field Spin", + "ToggleFieldSpin", + &Ptcl::Emitter::isFieldSpinEnabled, + &Ptcl::Emitter::setFieldSpinEnabled, + checked + ); }); // Spin Rotate connect(&mSpinRotateSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.spinRotate = Math::Util::deg2idx(static_cast(value)); - emit dataUpdated(mData); + const f32 rotate = Math::Util::deg2idx(static_cast(value)); + setEmitterProperty( + "Set Field Spin Rotation", + "SetFieldSpinRotation", + &Ptcl::Emitter::fieldSpinRotate, + &Ptcl::Emitter::setFieldSpinRotate, + rotate + ); }); // Spin Axis connect(&mSpinAxisSpinBox, &QComboBox::currentIndexChanged, this, [this]() { - mData.spinAxis = mSpinAxisSpinBox.currentEnum(); - emit dataUpdated(mData); + const auto axis = mSpinAxisSpinBox.currentEnum(); + setEmitterProperty( + "Set Field Spin Axis", + "SetFieldSpinAxis", + &Ptcl::Emitter::fieldSpinAxis, + &Ptcl::Emitter::setFieldSpinAxis, + axis + ); }); } -void FieldEditorWidget::SpinDataWidget::setData(const Ptcl::FieldData::FieldSpinData& data, bool isEnabled) { +void FieldSpinInspector::populateProperties() { QSignalBlocker b1(mSpinRotateSpinBox); QSignalBlocker b2(mSpinAxisSpinBox); QSignalBlocker b3(mEnabledCheckBox); - mData = data; + mSpinRotateSpinBox.setValue(Math::Util::to180(Math::Util::idx2deg(mEmitter->fieldSpinRotate()))); + mSpinAxisSpinBox.setCurrentEnum(mEmitter->fieldSpinAxis()); - mSpinRotateSpinBox.setValue(Math::Util::to180(Math::Util::idx2deg(mData.spinRotate))); - mSpinAxisSpinBox.setCurrentEnum(mData.spinAxis); + const bool isEnabled = mEmitter->isFieldSpinEnabled(); mEnabledCheckBox.setChecked(isEnabled); mControlsWidget->setEnabled(isEnabled); } diff --git a/src/editor/fluctuationEditorWidget.cpp b/src/editor/inspector/fluctuationInspector.cpp similarity index 52% rename from src/editor/fluctuationEditorWidget.cpp rename to src/editor/inspector/fluctuationInspector.cpp index 7289e64..f9088e4 100644 --- a/src/editor/fluctuationEditorWidget.cpp +++ b/src/editor/inspector/fluctuationInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/fluctuationEditorWidget.h" +#include "editor/inspector/fluctuationInspector.h" #include @@ -8,8 +8,8 @@ namespace PtclEditor { // ========================================================================== // -FluctuationEditorWidget::FluctuationEditorWidget(QWidget* parent) : - QWidget{parent} { +FluctuationInspector::FluctuationInspector(QWidget* parent) : + InspectorWidgetBase{parent} { // TODO: Determine better ranges? mScaleSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); mFreqSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); @@ -35,46 +35,75 @@ FluctuationEditorWidget::FluctuationEditorWidget(QWidget* parent) : setupConnections(); } -void FluctuationEditorWidget::setupConnections() { +void FluctuationInspector::setupConnections() { // Enabled connect(&mEnabledCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mControlsContainer->setEnabled(checked); - mFluxFlag.set(Ptcl::FluctuationFlag::Enabled, checked); - emit flagsUpdated(mFluxFlag); + setEmitterProperty( + "Toggle Fluctuation", + "SetFluxEnable", + &Ptcl::Emitter::isFluctuationEnabled, + &Ptcl::Emitter::setFluctuationEnabled, + checked + ); }); // Apply to alpha connect(&mApplyAlphaCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mFluxFlag.set(Ptcl::FluctuationFlag::ApplyAlpha, checked); - emit flagsUpdated(mFluxFlag); + setEmitterProperty( + "Toggle Fluctuation Apply Alpha", + "SetFluxApplyAlpha", + &Ptcl::Emitter::isFluctuationApplyAlpha, + &Ptcl::Emitter::setFluctuationApplyAlpha, + checked + ); }); // Apply to scale connect(&mApplyScaleCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mFluxFlag.set(Ptcl::FluctuationFlag::ApplyScale, checked); - emit flagsUpdated(mFluxFlag); + setEmitterProperty( + "Toggle Fluctuation Apply Scale", + "SetFluxApplyScale", + &Ptcl::Emitter::isFluctuationApplyScale, + &Ptcl::Emitter::setFluctuationApplyScale, + checked + ); }); // Scale connect(&mScaleSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.fluctuationScale = static_cast(value); - emit dataUpdated(mData); + setEmitterProperty( + "Set Fluctuation Scale", + "SetFluxScale", + &Ptcl::Emitter::fluctuationScale, + &Ptcl::Emitter::setFluctuationScale, + static_cast(value) + ); }); // Freq connect(&mFreqSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.fluctuationFreq = static_cast(value); - emit dataUpdated(mData); + setEmitterProperty( + "Set Fluctuation Frequency", + "SetFluxFreq", + &Ptcl::Emitter::fluctuationFrequency, + &Ptcl::Emitter::setFluctuationFrequency, + static_cast(value) + ); }); // Phase Rnd connect(&mPhaseRndCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mData.fluctuationPhaseRnd = checked; - emit dataUpdated(mData); + setEmitterProperty( + "Toggle Fluctuation Phase Randomness", + "SetFluxRandom", + &Ptcl::Emitter::isFluctuationPhaseRandom, + &Ptcl::Emitter::setFluctuationPhaseRandom, + checked + ); }); } -void FluctuationEditorWidget::setData(const Ptcl::FluctuationData& data, const BitFlag& fluxFlag) { +void FluctuationInspector::populateProperties() { QSignalBlocker b1(mScaleSpinBox); QSignalBlocker b2(mFreqSpinBox); QSignalBlocker b3(mPhaseRndCheckBox); @@ -82,17 +111,14 @@ void FluctuationEditorWidget::setData(const Ptcl::FluctuationData& data, const B QSignalBlocker b5(mApplyScaleCheckBox); QSignalBlocker b6(mEnabledCheckBox); - mData = data; - mFluxFlag = fluxFlag; + mScaleSpinBox.setValue(mEmitter->fluctuationScale()); + mFreqSpinBox.setValue(mEmitter->fluctuationFrequency()); + mPhaseRndCheckBox.setChecked(mEmitter->isFluctuationPhaseRandom()); - mScaleSpinBox.setValue(mData.fluctuationScale); - mFreqSpinBox.setValue(mData.fluctuationFreq); - mPhaseRndCheckBox.setChecked(mData.fluctuationPhaseRnd); + mApplyAlphaCheckBox.setChecked(mEmitter->isFluctuationApplyAlpha()); + mApplyScaleCheckBox.setChecked(mEmitter->isFluctuationApplyScale()); - mApplyAlphaCheckBox.setChecked(mFluxFlag.isSet(Ptcl::FluctuationFlag::ApplyAlpha)); - mApplyScaleCheckBox.setChecked( mFluxFlag.isSet(Ptcl::FluctuationFlag::ApplyScale)); - - const bool isEnabled = mFluxFlag.isSet(Ptcl::FluctuationFlag::Enabled); + const bool isEnabled = mEmitter->isFluctuationEnabled(); mEnabledCheckBox.setChecked(isEnabled); mControlsContainer->setEnabled(isEnabled); } diff --git a/src/editor/emitterWidget/basicPropertiesWidget.cpp b/src/editor/inspector/generalEmitterInspector.cpp similarity index 62% rename from src/editor/emitterWidget/basicPropertiesWidget.cpp rename to src/editor/inspector/generalEmitterInspector.cpp index 9a717e1..3312527 100644 --- a/src/editor/emitterWidget/basicPropertiesWidget.cpp +++ b/src/editor/inspector/generalEmitterInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/emitterWidget/basicPropertiesWidget.h" +#include "editor/inspector/generalEmitterInspector.h" #include "util/nameValidator.h" #include @@ -9,8 +9,8 @@ namespace PtclEditor { // ========================================================================== // -EmitterWidget::BasicPropertiesWidget::BasicPropertiesWidget(QWidget* parent) : - QWidget{parent} { +GeneralEmitterInspector::GeneralEmitterInspector(QWidget* parent) : + InspectorWidgetBase{parent} { for (Ptcl::BillboardType type : sBillboardTypes) { mBillboardComboBox.addItem(Ptcl::toString(type), QVariant::fromValue(type)); @@ -57,104 +57,141 @@ EmitterWidget::BasicPropertiesWidget::BasicPropertiesWidget(QWidget* parent) : setupConnections(); } -void EmitterWidget::BasicPropertiesWidget::setupConnections() { +void GeneralEmitterInspector::setupConnections() { // Emitter Name connect(&mNameLineEdit, &QLineEdit::textChanged, this, [this](const QString& text) { - mProps.name = text; - emit propertiesUpdated(mProps); - emit emitterNameChanged(); + setEmitterProperty( + "Set Name", + "EmitterName", + &Ptcl::Emitter::name, + &Ptcl::Emitter::setName, + text + ); }); // Emitter Type connect(&mTypeComboBox, &QComboBox::currentIndexChanged, this, [this]() { - mProps.type = mTypeComboBox.currentEnum(); - - if (mProps.type == Ptcl::EmitterType::Simple) { - if (!isBillboardAllowedForShape(mProps.billboardType, ShapeType::Particle)) { - applyBillboardType(Ptcl::BillboardType::Billboard); + auto* stack = mDocument->undoStack(); + stack->beginMacro(formatHistoryLabel("Set Type")); + + setEmitterProperty( + "Set Type", + "EmitterType", + &Ptcl::Emitter::type, + &Ptcl::Emitter::setType, + mTypeComboBox.currentEnum() + ); + + if (mEmitter->type() == Ptcl::EmitterType::Simple) { + if (!isBillboardAllowedForShape(mEmitter->billboardType(), ShapeType::Particle)) { + setBillboardType(Ptcl::BillboardType::Billboard, "Auto Fix Billboard Type", "BillboardType"); syncBillboardSelection(); } } + stack->endMacro(); + updateShapeRowVisibility(); updateBillboardRowVisibility(); - emit propertiesUpdated(mProps); - emit emitterTypeChanged(); }); // Random Seed Mode connect(&mRandomSeedMode, &QComboBox::currentIndexChanged, this, [this]() { - auto& seed = mProps.randomSeed; + auto seed = mEmitter->randomSeed(); auto mode = static_cast(mRandomSeedMode.currentData().toUInt()); seed.setMode(mode); + + setEmitterProperty( + "Set Random Seed Mode", + "RandomSeedMode", + &Ptcl::Emitter::randomSeed, + &Ptcl::Emitter::setRandomSeed, + seed + ); + mRandomSeedSpinBox.setEnabled(mode == PtclSeed::Mode::ConstantSeed); - emit propertiesUpdated(mProps); }); // Random Seed connect(&mRandomSeedSpinBox, &SizedSpinBoxBase::valueChanged, this, [this](int value) { - auto& seed = mProps.randomSeed; + auto seed = mEmitter->randomSeed(); if (seed.mode() == PtclSeed::Mode::ConstantSeed) { seed.setConstantSeed(static_cast(value)); } - emit propertiesUpdated(mProps); + + setEmitterProperty( + "Set Random Seed", + "RandomSeed", + &Ptcl::Emitter::randomSeed, + &Ptcl::Emitter::setRandomSeed, + seed + ); }); // Follow Type connect(&mFollowTypeComboBox, &QComboBox::currentIndexChanged, this, [this]() { const auto type = mFollowTypeComboBox.currentEnum(); - mProps.followType = type; - // TODO: Check if this should also be set for Ptcl::FollowType::PosOnly - mProps.isFollow = (type == Ptcl::FollowType::All); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Follow Type", + "FollowType", + &Ptcl::Emitter::followType, + &Ptcl::Emitter::setFollowType, + type + ); }); // Billboard Type connect(&mBillboardComboBox, &QComboBox::currentIndexChanged, this, [this]() { - applyBillboardType(mBillboardComboBox.currentData().value()); - emit propertiesUpdated(mProps); + setBillboardType(mBillboardComboBox.currentData().value(), "Set Billboard Type", "BillboardType"); }); - // Shape Type + // Shape Type connect(&mShapeComboBox, &QComboBox::currentIndexChanged, this, [this]() { const auto type = mShapeComboBox.currentData().value(); - if (type == ShapeType::Particle) { - applyBillboardType(Ptcl::BillboardType::Billboard); - } else if (type == ShapeType::Primitive) { - applyBillboardType(Ptcl::BillboardType::Primitive); - } else { - applyBillboardType(Ptcl::BillboardType::Stripe); + Ptcl::BillboardType newBillboard; + switch (type) { + case ShapeType::Particle: newBillboard = Ptcl::BillboardType::Billboard; break; + case ShapeType::Primitive: newBillboard = Ptcl::BillboardType::Primitive; break; + case ShapeType::Stripe: newBillboard = Ptcl::BillboardType::Stripe; break; } + setBillboardType(newBillboard, "Set Shape Type", "ShapeType"); syncBillboardSelection(); updateBillboardRowVisibility(); updateShapeRowVisibility(); - emit propertiesUpdated(mProps); }); // Stripe Type connect(&mStripeTypeComboBox, &QComboBox::currentIndexChanged, this, [this]() { - applyBillboardType(mStripeTypeComboBox.currentData().value()); - emit propertiesUpdated(mProps); + setBillboardType(mStripeTypeComboBox.currentData().value(), "Set Stripe Type", "StripeType"); }); // Is Billboard Mtx connect(&mIsBillboardMtxCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mProps.isEmitterBillboardMtx = checked; - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Billboard Matrix", + "IsBillboardMtx", + &Ptcl::Emitter::isEmitterBillboardMtx, + &Ptcl::Emitter::setIsEmitterBillboardMtx, + checked + ); }); } -void EmitterWidget::BasicPropertiesWidget::applyBillboardType(Ptcl::BillboardType type) { - mProps.billboardType = type; - mProps.isPolygon = (type == Ptcl::BillboardType::PolygonXY || type == Ptcl::BillboardType::PolygonXZ); - mProps.isVelLook = (type == Ptcl::BillboardType::VelLook || type == Ptcl::BillboardType::VelLookPolygon); +void GeneralEmitterInspector::setBillboardType(Ptcl::BillboardType type, const QString& label, const QString& key) { + setEmitterProperty( + label, + key, + &Ptcl::Emitter::billboardType, + &Ptcl::Emitter::setBillboardType, + type + ); } -bool EmitterWidget::BasicPropertiesWidget::isBillboardAllowedForShape(Ptcl::BillboardType billboard, ShapeType shape) { +bool GeneralEmitterInspector::isBillboardAllowedForShape(Ptcl::BillboardType billboard, ShapeType shape) { switch (shape) { case ShapeType::Particle: return billboard != Ptcl::BillboardType::Stripe && @@ -169,7 +206,7 @@ bool EmitterWidget::BasicPropertiesWidget::isBillboardAllowedForShape(Ptcl::Bill return false; } -EmitterWidget::BasicPropertiesWidget::ShapeType EmitterWidget::BasicPropertiesWidget::shapeFromBillboard(Ptcl::BillboardType type) { +GeneralEmitterInspector::ShapeType GeneralEmitterInspector::shapeFromBillboard(Ptcl::BillboardType type) { if (type == Ptcl::BillboardType::Stripe || type == Ptcl::BillboardType::ComplexStripe) { return ShapeType::Stripe; } @@ -181,7 +218,7 @@ EmitterWidget::BasicPropertiesWidget::ShapeType EmitterWidget::BasicPropertiesWi return ShapeType::Particle; } -void EmitterWidget::BasicPropertiesWidget::setProperties(const Ptcl::Emitter::BasicProperties& properties) { +void GeneralEmitterInspector::populateProperties() { QSignalBlocker b1(mNameLineEdit); QSignalBlocker b2(mTypeComboBox); QSignalBlocker b3(mRandomSeedMode); @@ -192,52 +229,50 @@ void EmitterWidget::BasicPropertiesWidget::setProperties(const Ptcl::Emitter::Ba QSignalBlocker b8(mStripeTypeComboBox); QSignalBlocker b9(mIsBillboardMtxCheckBox); - mProps = properties; - - mNameLineEdit.setText(mProps.name); - mTypeComboBox.setCurrentEnum(mProps.type); + mNameLineEdit.setText(mEmitter->name()); + mTypeComboBox.setCurrentEnum(mEmitter->type()); - auto& randomSeed = mProps.randomSeed; + auto& randomSeed = mEmitter->randomSeed(); auto seedMode = randomSeed.mode(); - int index = mRandomSeedMode.findData(static_cast(seedMode)); + s32 index = mRandomSeedMode.findData(static_cast(seedMode)); if (index != -1) { mRandomSeedMode.setCurrentIndex(index); } mRandomSeedSpinBox.setValue(randomSeed.constantSeed()); mRandomSeedSpinBox.setEnabled(seedMode == PtclSeed::Mode::ConstantSeed); - mFollowTypeComboBox.setCurrentEnum(mProps.followType); + mFollowTypeComboBox.setCurrentEnum(mEmitter->followType()); - const auto shapeType = shapeFromBillboard(mProps.billboardType); + const auto shapeType = shapeFromBillboard(mEmitter->billboardType()); const s32 shapeIndex = mShapeComboBox.findData(QVariant::fromValue(shapeType)); mShapeComboBox.setCurrentIndex(shapeIndex); - mIsBillboardMtxCheckBox.setChecked(mProps.isEmitterBillboardMtx); + mIsBillboardMtxCheckBox.setChecked(mEmitter->isEmitterBillboardMtx()); syncBillboardSelection(); updateBillboardRowVisibility(); updateShapeRowVisibility(); } -void EmitterWidget::BasicPropertiesWidget::updateShapeRowVisibility() { - if (mProps.type == Ptcl::EmitterType::Simple) { +void GeneralEmitterInspector::updateShapeRowVisibility() { + if (mEmitter->type() == Ptcl::EmitterType::Simple) { mMainLayout->setRowVisible(&mShapeComboBox, false); } else { mMainLayout->setRowVisible(&mShapeComboBox, true); } } -void EmitterWidget::BasicPropertiesWidget::updateBillboardRowVisibility() { +void GeneralEmitterInspector::updateBillboardRowVisibility() { const auto shape = mShapeComboBox.currentData().value(); mMainLayout->setRowVisible(&mBillboardComboBox, shape == ShapeType::Particle); mMainLayout->setRowVisible(&mStripeTypeComboBox, shape == ShapeType::Stripe); } -void EmitterWidget::BasicPropertiesWidget::syncBillboardSelection() { +void GeneralEmitterInspector::syncBillboardSelection() { QSignalBlocker b1(mBillboardComboBox); QSignalBlocker b2(mStripeTypeComboBox); - const QVariant value = QVariant::fromValue(mProps.billboardType); + const QVariant value = QVariant::fromValue(mEmitter->billboardType()); const s32 billboardIndex = mBillboardComboBox.findData(value); if (billboardIndex != -1) { @@ -250,6 +285,7 @@ void EmitterWidget::BasicPropertiesWidget::syncBillboardSelection() { } } + // ========================================================================== // diff --git a/src/editor/inspector/gravityInspector.cpp b/src/editor/inspector/gravityInspector.cpp new file mode 100644 index 0000000..57cd43e --- /dev/null +++ b/src/editor/inspector/gravityInspector.cpp @@ -0,0 +1,62 @@ +#include "editor/inspector/gravityInspector.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +GravityInspector::GravityInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + auto* mainLayout = new QFormLayout(this); + + mIsDirectionalCheckBox.setText("Apply gravity in world coords"); + + mainLayout->addRow("Coordinates:", &mIsDirectionalCheckBox); + mainLayout->addRow("Gravity Direction:", &mGravitySpinBox); + + setupConnections(); +} + +void GravityInspector::setupConnections() { + // Is Directional + connect(&mIsDirectionalCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Set Gravity Directional", + "GravDirectional", + &Ptcl::Emitter::isDirectional, + &Ptcl::Emitter::setDirectional, + checked + ); + }); + + // Gravity + connect(&mGravitySpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto gravity = mGravitySpinBox.getVector(); + setEmitterProperty( + "Set Gravity Direction", + "GravDir", + &Ptcl::Emitter::gravity, + &Ptcl::Emitter::setGravity, + gravity + ); + }); +} + +void GravityInspector::populateProperties() { + QSignalBlocker b1(mIsDirectionalCheckBox); + QSignalBlocker b2(mGravitySpinBox); + + mIsDirectionalCheckBox.setChecked(mEmitter->isDirectional()); + mGravitySpinBox.setVector(mEmitter->gravity()); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/inspector/inspectorPanel.cpp b/src/editor/inspector/inspectorPanel.cpp new file mode 100644 index 0000000..38b8cbf --- /dev/null +++ b/src/editor/inspector/inspectorPanel.cpp @@ -0,0 +1,356 @@ + +#include "editor/inspector/inspectorPanel.h" + +#include "editor/inspector/emitterSetInspector.h" + +#include "editor/inspector/alphaAnimInspector.h" +#include "editor/inspector/generalEmitterInspector.h" +#include "editor/inspector/colorInspector.h" +#include "editor/inspector/combinerInspector.h" +#include "editor/inspector/emissionInspector.h" +#include "editor/inspector/gravityInspector.h" +#include "editor/inspector/lifespanInspector.h" +#include "editor/inspector/rotationInspector.h" +#include "editor/inspector/scaleAnimInspector.h" +#include "editor/inspector/stripeInspector.h" +#include "editor/inspector/terminationInspector.h" +#include "editor/inspector/textureInspector.h" +#include "editor/inspector/transformInspector.h" +#include "editor/inspector/velocityInspector.h" +#include "editor/inspector/volumeInspector.h" + +#include "editor/inspector/fluctuationInspector.h" + +#include "editor/inspector/child/childAlphaInspector.h" +#include "editor/inspector/child/childColorInspector.h" +#include "editor/inspector/child/childCombinerInspector.h" +#include "editor/inspector/child/childEmissionInspector.h" +#include "editor/inspector/child/childGeneralInspector.h" +#include "editor/inspector/child/childRotationInspector.h" +#include "editor/inspector/child/childScaleInspector.h" +#include "editor/inspector/child/childTextureInspector.h" +#include "editor/inspector/child/childVelocityInspector.h" + +#include "editor/inspector/field/fieldCollisionInspector.h" +#include "editor/inspector/field/fieldConvergenceInspector.h" +#include "editor/inspector/field/fieldMagnetInspector.h" +#include "editor/inspector/field/fieldPosAddInspector.h" +#include "editor/inspector/field/fieldRandomInspector.h" +#include "editor/inspector/field/fieldSpinInspector.h" +#include "util/nameValidator.h" + +#include + +namespace PtclEditor { + + +// ========================================================================== // + + +InspectorPanel::InspectorPanel(QWidget* parent) : + QWidget{parent} { + + mProjNameLineEdit = new QLineEdit(this); + mProjNameLineEdit->setPlaceholderText("PTCLProject"); + mProjNameLineEdit->setValidator(new EmitterNameValidator(mProjNameLineEdit)); + + connect(mProjNameLineEdit, &QLineEdit::textChanged, this, [this](const QString& text) { + mDocument->setProjectName(text); + }); + + mEmitterSetInspector = new EmitterSetInspector(this); + + mGeneralInspector = new GeneralEmitterInspector(this); + mGravityInspector = new GravityInspector(this); + mTransformInspector = new TransformInspector(this); + mLifespanInspector = new LifespanInspector(this); + mTerminationInspector = new TerminationInspector(this); + mEmissionInspector = new EmissionInspector(this); + mVelocityInspector = new VelocityInspector(this); + mVolumeInspector = new VolumeInspector(this); + mColorInspector = new ColorInspector(this); + mAlphaAnimInspector = new AlphaAnimInspector(this); + mRotationInspector = new RotationInspector(this); + mScaleAnimInspector = new ScaleAnimInspector(this); + mTextureInspector = new TextureInspector(this); + mCombinerInspector = new CombinerInspector(this); + mStripeInspector = new StripeInspector(this); + + mFieldCollisionInspector = new FieldCollisionInspector(this); + mFieldConvergenceInspector = new FieldConvergenceInspector(this); + mFieldMagnetInspector = new FieldMagnetInspector(this); + mFieldPosAddInspector = new FieldPosAddInspector(this); + mFieldRandomInspector = new FieldRandomInspector(this); + mFieldSpinInspector = new FieldSpinInspector(this); + + mChildAlphaInspector = new ChildAlphaInspector(this); + mChildColorInspector = new ChildColorInspector(this); + mChildCombinerInspector = new ChildCombinerInspector(this); + mChildEmissionInspector = new ChildEmissionInspector(this); + mChildGeneralInspector = new ChildGeneralInspector(this); + mChildRotationInspector = new ChildRotationInspector(this); + mChildScaleInspector = new ChildScaleInspector(this); + mChildTextureInspector = new ChildTextureInspector(this); + mChildVelocityInspector = new ChildVelocityInspector(this); + + mFluctuationInspector = new FluctuationInspector(this); + + // Project Properties + auto* projectPropertiesLayout = new QHBoxLayout; + projectPropertiesLayout->addWidget(new QLabel("Project Name")); + projectPropertiesLayout->addWidget(mProjNameLineEdit); + + mTabStack = new QStackedWidget(this); + + mEmitterSetTabs = new QTabWidget(this); + mEmitterSetTabs->setTabPosition(QTabWidget::West); + mTabStack->addWidget(mEmitterSetTabs); + + mEmitterTabs = new QTabWidget(this); + mEmitterTabs->setTabPosition(QTabWidget::West); + mTabStack->addWidget(mEmitterTabs); + + mChildTabs = new QTabWidget(this); + mChildTabs->setTabPosition(QTabWidget::West); + mTabStack->addWidget(mChildTabs); + + mFieldTabs = new QTabWidget(this); + mFieldTabs->setTabPosition(QTabWidget::West); + mTabStack->addWidget(mFieldTabs); + + mFluxTabs = new QTabWidget(this); + mFluxTabs->setTabPosition(QTabWidget::West); + mTabStack->addWidget(mFluxTabs); + + auto* layout = new QVBoxLayout(this); + layout->addLayout(projectPropertiesLayout); + layout->addWidget(mTabStack); + layout->setContentsMargins(0, 0, 0, 0); + + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + buildTabs(); +} + +void InspectorPanel::buildTabs() { + // This is dumb, but fixes some issues with some tabs being incorrectly sized + // Individual inspector widgets should probably be adjusted instead so this can be removed + auto wrapInScroll = [this](QWidget* content) { + auto* scroll = new QScrollArea; + scroll->setWidget(content); + scroll->setWidgetResizable(true); + scroll->setFrameShape(QFrame::NoFrame); + scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + return scroll; + }; + + // EmitterSet + mEmitterSetTabs->addTab(mEmitterSetInspector, "EmitterSet"); + + // Emitter + mEmitterTabs->addTab(wrapInScroll(mGeneralInspector), "General"); + mEmitterTabs->addTab(mStripeInspector, "Stripe"); + mEmitterTabs->addTab(wrapInScroll(mLifespanInspector), "Life"); + mEmitterTabs->addTab(wrapInScroll(mTerminationInspector), "Termination"); + mEmitterTabs->addTab(wrapInScroll(mGravityInspector), "Gravity"); + mEmitterTabs->addTab(wrapInScroll(mEmissionInspector), "Emission"); + mEmitterTabs->addTab(wrapInScroll(mVolumeInspector), "Volume"); + mEmitterTabs->addTab(wrapInScroll(mVelocityInspector), "Velocity"); + mEmitterTabs->addTab(wrapInScroll(mTextureInspector), "Texture"); + mEmitterTabs->addTab(wrapInScroll(mColorInspector), "Color"); + mEmitterTabs->addTab(wrapInScroll(mCombinerInspector), "Combiner"); + mEmitterTabs->addTab(wrapInScroll(mAlphaAnimInspector), "Alpha"); + mEmitterTabs->addTab(wrapInScroll(mTransformInspector), "Transform"); + mEmitterTabs->addTab(wrapInScroll(mRotationInspector), "Rotation"); + mEmitterTabs->addTab(wrapInScroll(mScaleAnimInspector), "Scale"); + + // Fluctuation + mFluxTabs->addTab(mFluctuationInspector, "Fluctuation"); + + // Field + mFieldTabs->addTab(mFieldCollisionInspector, "Collision"); + mFieldTabs->addTab(mFieldConvergenceInspector, "Convergence"); + mFieldTabs->addTab(mFieldMagnetInspector, "Magnet"); + mFieldTabs->addTab(mFieldPosAddInspector, "Pos Add"); + mFieldTabs->addTab(mFieldRandomInspector, "Random"); + mFieldTabs->addTab(mFieldSpinInspector, "Spin"); + + // Child + mChildTabs->addTab(mChildGeneralInspector, "General"); + mChildTabs->addTab(mChildColorInspector, "Color"); + mChildTabs->addTab(mChildAlphaInspector, "Alpha"); + mChildTabs->addTab(mChildCombinerInspector, "Combiner"); + mChildTabs->addTab(mChildEmissionInspector, "Emission"); + mChildTabs->addTab(mChildRotationInspector, "Rotation"); + mChildTabs->addTab(mChildScaleInspector, "Scale"); + mChildTabs->addTab(mChildTextureInspector, "Texture"); + mChildTabs->addTab(mChildVelocityInspector, "Velocity"); +} + +void InspectorPanel::updateTabVisibility() { + if (!mSelection) { + return; + } + + const auto type = mSelection->type(); + + switch (type) { + case Ptcl::Selection::Type::EmitterSet: + mTabStack->setCurrentWidget(mEmitterSetTabs); + break; + case Ptcl::Selection::Type::Emitter: + mTabStack->setCurrentWidget(mEmitterTabs); + break; + case Ptcl::Selection::Type::EmitterChild: + mTabStack->setCurrentWidget(mChildTabs); + break; + case Ptcl::Selection::Type::EmitterFlux: + mTabStack->setCurrentWidget(mFluxTabs); + break; + case Ptcl::Selection::Type::EmitterField: + mTabStack->setCurrentWidget(mFieldTabs); + break; + default: + break; + } +} + +void InspectorPanel::setDocument(Ptcl::Document* document) { + if (mDocument) { + mDocument->disconnect(this); + } + + mDocument = document; + + mEmitterSetInspector->setDocument(document); + + mGeneralInspector->setDocument(document); + mGravityInspector->setDocument(document); + mTransformInspector->setDocument(document); + mLifespanInspector->setDocument(document); + mScaleAnimInspector->setDocument(document); + mTerminationInspector->setDocument(document); + mEmissionInspector->setDocument(document); + mVelocityInspector->setDocument(document); + mVolumeInspector->setDocument(document); + mRotationInspector->setDocument(document); + mAlphaAnimInspector->setDocument(document); + mCombinerInspector->setDocument(document); + mColorInspector->setDocument(document); + mTextureInspector->setDocument(document); + mStripeInspector->setDocument(document); + + mFluctuationInspector->setDocument(document); + + mFieldCollisionInspector->setDocument(document); + mFieldConvergenceInspector->setDocument(document); + mFieldMagnetInspector->setDocument(document); + mFieldPosAddInspector->setDocument(document); + mFieldRandomInspector->setDocument(document); + mFieldSpinInspector->setDocument(document); + + mChildAlphaInspector->setDocument(document); + mChildColorInspector->setDocument(document); + mChildCombinerInspector->setDocument(document); + mChildEmissionInspector->setDocument(document); + mChildGeneralInspector->setDocument(document); + mChildRotationInspector->setDocument(document); + mChildScaleInspector->setDocument(document); + mChildTextureInspector->setDocument(document); + mChildVelocityInspector->setDocument(document); + + if (mDocument) { + QSignalBlocker b1(mProjNameLineEdit); + mProjNameLineEdit->setText(document->projectName()); + + connect(mDocument, &Ptcl::Document::emitterChanged, this, [this](s32 setIndex, s32 emitterIndex) { + if (!mEmitter || setIndex != mSelection->emitterSetIndex() || emitterIndex != mSelection->emitterIndex()) { + return; + } + + populateProperties(); + }); + + connect(mDocument, &Ptcl::Document::projectChanged, this, [this]() { + QSignalBlocker b1(mProjNameLineEdit); + mProjNameLineEdit->setText(mDocument->projectName()); + }); + + } +} + +void InspectorPanel::setSelection(Ptcl::Selection* selection) { + if (mSelection) { + mSelection->disconnect(this); + } + + mSelection = selection; + + mEmitterSetInspector->setSelection(selection); + + mGeneralInspector->setSelection(selection); + mGravityInspector->setSelection(selection); + mTransformInspector->setSelection(selection); + mLifespanInspector->setSelection(selection); + mScaleAnimInspector->setSelection(selection); + mTerminationInspector->setSelection(selection); + mEmissionInspector->setSelection(selection); + mVelocityInspector->setSelection(selection); + mVolumeInspector->setSelection(selection); + mRotationInspector->setSelection(selection); + mAlphaAnimInspector->setSelection(selection); + mCombinerInspector->setSelection(selection); + mColorInspector->setSelection(selection); + mTextureInspector->setSelection(selection); + mFluctuationInspector->setSelection(selection); + mStripeInspector->setSelection(selection); + + mFieldCollisionInspector->setSelection(selection); + mFieldConvergenceInspector->setSelection(selection); + mFieldMagnetInspector->setSelection(selection); + mFieldPosAddInspector->setSelection(selection); + mFieldRandomInspector->setSelection(selection); + mFieldSpinInspector->setSelection(selection); + + mChildAlphaInspector->setSelection(selection); + mChildColorInspector->setSelection(selection); + mChildCombinerInspector->setSelection(selection); + mChildEmissionInspector->setSelection(selection); + mChildGeneralInspector->setSelection(selection); + mChildRotationInspector->setSelection(selection); + mChildScaleInspector->setSelection(selection); + mChildTextureInspector->setSelection(selection); + mChildVelocityInspector->setSelection(selection); + + if (mSelection) { + connect(selection, &Ptcl::Selection::selectionChanged, this, [this](s32 setIndex, s32 emitterIndex, Ptcl::Selection::Type type) { + if (!mDocument) { + mEmitter = nullptr; + setEnabled(false); + return; + } + + mEmitter = mDocument->emitter(setIndex, emitterIndex); + setEnabled(true); + populateProperties(); + }); + } +} + +void InspectorPanel::populateProperties() { + if (mLastSelectionType != mSelection->type()) { + mLastSelectionType = mSelection->type(); + updateTabVisibility(); + } + + // TODO - Stripe should be combined some other tab, this shouldn't be handled by the inspector + const s32 stripeIdx = mEmitterTabs->indexOf(mStripeInspector); + const bool hasStripe = mEmitter->hasStripeData(); + mEmitterTabs->setTabVisible(stripeIdx, hasStripe); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/inspector/inspectorWidgetBase.cpp b/src/editor/inspector/inspectorWidgetBase.cpp new file mode 100644 index 0000000..01c9add --- /dev/null +++ b/src/editor/inspector/inspectorWidgetBase.cpp @@ -0,0 +1,73 @@ +#include "editor/inspector/inspectorWidgetBase.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +InspectorWidgetBase::InspectorWidgetBase(QWidget* parent) : + QWidget{parent} {} + +void InspectorWidgetBase::setDocument(Ptcl::Document* document) { + if (mDocument) { + mDocument->disconnect(this); + } + + mDocument = document; + + if (mDocument) { + connect(mDocument, &Ptcl::Document::emitterChanged, this, &InspectorWidgetBase::onEmitterChanged); + } +} + +void InspectorWidgetBase::setSelection(Ptcl::Selection* selection) { + if (mSelection) { + mSelection->disconnect(this); + } + + mSelection = selection; + + if (mSelection) { + connect(selection, &Ptcl::Selection::selectionChanged, this, [this](s32 setIndex, s32 emitterIndex, Ptcl::Selection::Type type) { + if (!mDocument) { + mEmitter = nullptr; + setEnabled(false); + return; + } + + mEmitter = mDocument->emitter(setIndex, emitterIndex); + + setEnabled(true); + populateProperties(); + }); + } +} + +QString InspectorWidgetBase::formatHistoryLabel(const QString& label) const { + return QString("Set %1, Emitter %2 - %3") + .arg(mSelection->emitterSetIndex()) + .arg(mSelection->emitterIndex()) + .arg(label); +} + + +void InspectorWidgetBase::onEmitterChanged(s32 setIndex, s32 emitterIndex) { + if (!mEmitter) { + return; + } + + if (setIndex != mSelection->emitterSetIndex() || emitterIndex != mSelection->emitterIndex()) { + return; + } + + populateProperties(); +} + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/emitterWidget/lifespanPropertiesWidget.cpp b/src/editor/inspector/lifespanInspector.cpp similarity index 53% rename from src/editor/emitterWidget/lifespanPropertiesWidget.cpp rename to src/editor/inspector/lifespanInspector.cpp index 802cebd..b25e06e 100644 --- a/src/editor/emitterWidget/lifespanPropertiesWidget.cpp +++ b/src/editor/inspector/lifespanInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/emitterWidget/lifespanPropertiesWidget.h" +#include "editor/inspector/lifespanInspector.h" #include @@ -9,8 +9,8 @@ namespace PtclEditor { // ========================================================================== // -EmitterWidget::LifespanPropertiesWidget::LifespanPropertiesWidget(QWidget* parent) : - QWidget{parent} { +LifespanInspector::LifespanInspector(QWidget* parent) : + InspectorWidgetBase{parent} { auto* mainLayout = new QFormLayout(this); @@ -27,42 +27,56 @@ EmitterWidget::LifespanPropertiesWidget::LifespanPropertiesWidget(QWidget* paren mainLayout->addRow("Lifespan:", &mLifeSpanSpinBox); mainLayout->addRow("Lifespan Randomness:", &mLifeSpanRndSpinBox); + setupConnections(); +} + +void LifespanInspector::setupConnections() { connect(&mLifeSpanSpinBox, &QSpinBox::valueChanged, this, [this](u64 value) { - mProps.ptclLife = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Lifespan", + "SetLifeSpan", + &Ptcl::Emitter::ptclLife, + &Ptcl::Emitter::setPtclLife, + static_cast(value) + ); }); - connect(&mInfiniteLifeCheckBox, &QCheckBox::checkStateChanged, this, [this](Qt::CheckState state) { - QSignalBlocker b1(mLifeSpanSpinBox); + connect(&mInfiniteLifeCheckBox, &QCheckBox::clicked, this, [this](bool checked) { + const s32 newLife = checked ? sLifeInfinite : 100; - const bool isInfinite = (state == Qt::CheckState::Checked); - mProps.ptclLife = isInfinite ? sLifeInfinite : 100; - mLifeSpanSpinBox.setValue(mProps.ptclLife); - mLifeSpanSpinBox.setEnabled(!isInfinite); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Toggle Infinite Life", + "SetParticleLife", + &Ptcl::Emitter::ptclLife, + &Ptcl::Emitter::setPtclLife, + newLife + ); }); connect(&mLifeSpanRndSpinBox, &QSpinBox::valueChanged, this, [this](u64 value) { - mProps.ptclLifeRnd = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set LifeSpan Random", + "SetLifeSpanRand", + &Ptcl::Emitter::ptclLifeRandom, + &Ptcl::Emitter::setPtclLifeRandom, + static_cast(value) + ); }); } -void EmitterWidget::LifespanPropertiesWidget::setProperties(const Ptcl::Emitter::LifespanProperties& properties) { +void LifespanInspector::populateProperties() { QSignalBlocker b1(mInfiniteLifeCheckBox); QSignalBlocker b2(mLifeSpanSpinBox); QSignalBlocker b3(mLifeSpanRndSpinBox); - mProps = properties; - - const s32 lifeSpan = mProps.ptclLife; + const s32 lifeSpan = mEmitter->ptclLife(); const bool infiniteLife = (lifeSpan == sLifeInfinite); mLifeSpanSpinBox.setValue(lifeSpan); mLifeSpanSpinBox.setDisabled(infiniteLife); mInfiniteLifeCheckBox.setChecked(infiniteLife); - mLifeSpanRndSpinBox.setValue(mProps.ptclLifeRnd); + mLifeSpanRndSpinBox.setValue(mEmitter->ptclLifeRandom()); } diff --git a/src/editor/emitterWidget/rotationPropertiesWidget.cpp b/src/editor/inspector/rotationInspector.cpp similarity index 58% rename from src/editor/emitterWidget/rotationPropertiesWidget.cpp rename to src/editor/inspector/rotationInspector.cpp index 3fb038f..3a747f6 100644 --- a/src/editor/emitterWidget/rotationPropertiesWidget.cpp +++ b/src/editor/inspector/rotationInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/emitterWidget/rotationPropertiesWidget.h" +#include "editor/inspector/rotationInspector.h" #include "math/util.h" @@ -11,17 +11,33 @@ namespace PtclEditor { // ========================================================================== // -EmitterWidget::RotationPropertiesWidget::RotationPropertiesWidget(QWidget* parent) : - QWidget{parent} { +RotationInspector::RotationInspector(QWidget* parent) : + InspectorWidgetBase{parent} { auto* mainLayout = new QFormLayout(this); - // RotType mainLayout->addRow("Rotation Type", &mRotTypeSpinBox); + mainLayout->addRow("Initial Rotation", &mInitRotSpinBox); + mainLayout->addRow("Initial Rotation Random", &mInitRotRandSpinBox); + mainLayout->addRow("Rotation Speed", &mRotVelSpinBox); + mainLayout->addRow("Rotation Speed Random", &mRotVelRandSpinBox); + mainLayout->addRow("Rotation Pivot Offset", &mRotBasisSpinBox); + + setLayout(mainLayout); + setupConnections(); +} + +void RotationInspector::setupConnections() { connect(&mRotTypeSpinBox, &QComboBox::currentIndexChanged, this, [this]() { - mProps.rotType = mRotTypeSpinBox.currentEnum(); - updateAxis(); - emit propertiesUpdated(mProps); + const auto type = mRotTypeSpinBox.currentEnum(); + + setEmitterProperty( + "Set Rotation type", + "SetRotType", + &Ptcl::Emitter::rotationType, + &Ptcl::Emitter::setRotationType, + type + ); }); auto deg2idxVec = [](const Math::Vector3f& v) { @@ -33,51 +49,76 @@ EmitterWidget::RotationPropertiesWidget::RotationPropertiesWidget(QWidget* paren return result; }; - // Initial Rotation - mainLayout->addRow("Initial Rotation", &mInitRotSpinBox); connect(&mInitRotSpinBox, &VectorSpinBoxBase::valueChanged, this, [this, deg2idxVec]() { - mProps.initRot = deg2idxVec(mInitRotSpinBox.getVector()); - emit propertiesUpdated(mProps); + const auto rotation = deg2idxVec(mInitRotSpinBox.getVector()); + + setEmitterProperty( + "Set Initial Rotation", + "SetInitRot", + &Ptcl::Emitter::initialRotation, + &Ptcl::Emitter::setInitialRotation, + rotation + ); }); - // Initial Rotation Rand - mainLayout->addRow("Initial Rotation Random", &mInitRotRandSpinBox); connect(&mInitRotRandSpinBox, &VectorSpinBoxBase::valueChanged, this, [this, deg2idxVec]() { - mProps.initRotRand = deg2idxVec(mInitRotRandSpinBox.getVector()); - emit propertiesUpdated(mProps); + const auto rand = deg2idxVec(mInitRotRandSpinBox.getVector()); + + setEmitterProperty( + "Set Initial Rotation Random", + "SetInitRotRand", + &Ptcl::Emitter::initialRotationRandom, + &Ptcl::Emitter::setInitialRotationRandom, + rand + ); }); - // Rotation Speed - mainLayout->addRow("Rotation Speed", &mRotVelSpinBox); connect(&mRotVelSpinBox, &VectorSpinBoxBase::valueChanged, this, [this, deg2idxVec]() { - mProps.rotVel = deg2idxVec(mRotVelSpinBox.getVector()); - emit propertiesUpdated(mProps); + const auto velocity = deg2idxVec(mRotVelSpinBox.getVector()); + + setEmitterProperty( + "Set Rotation Speed", + "SetRotVel", + &Ptcl::Emitter::rotationVelocity, + &Ptcl::Emitter::setRotationVelocity, + velocity + ); }); - // Rotation Speed Rand - mainLayout->addRow("Rotation Speed Random", &mRotVelRandSpinBox); connect(&mRotVelRandSpinBox, &VectorSpinBoxBase::valueChanged, this, [this, deg2idxVec]() { - mProps.rotVelRand = deg2idxVec(mRotVelRandSpinBox.getVector()); - emit propertiesUpdated(mProps); + const auto rand = deg2idxVec(mRotVelRandSpinBox.getVector()); + + setEmitterProperty( + "Set Rotation Speed Random", + "SetRotVelRand", + &Ptcl::Emitter::rotationVelocityRandom, + &Ptcl::Emitter::setRotationVelocityRandom, + rand + ); }); - // Rotation Pivot - mainLayout->addRow("Rotation Pivot Offset", &mRotBasisSpinBox); connect(&mRotBasisSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mProps.rotBasis = mRotBasisSpinBox.getVector(); - emit propertiesUpdated(mProps); + const auto basis = mRotBasisSpinBox.getVector(); + + setEmitterProperty( + "Set Rotation Pivot", + "SetRotBasis", + &Ptcl::Emitter::rotationBasis, + &Ptcl::Emitter::setRotationBasis, + basis + ); }); - - setLayout(mainLayout); - } -void EmitterWidget::RotationPropertiesWidget::setProperties(const Ptcl::Emitter::RotationProperties& properties) { - mProps = properties; - populateWidgets(); -} -void EmitterWidget::RotationPropertiesWidget::populateWidgets() { +void RotationInspector::populateProperties() { + QSignalBlocker b1(mRotTypeSpinBox); + QSignalBlocker b2(mInitRotSpinBox); + QSignalBlocker b3(mInitRotRandSpinBox); + QSignalBlocker b4(mRotVelSpinBox); + QSignalBlocker b5(mRotVelRandSpinBox); + QSignalBlocker b6(mRotBasisSpinBox); + auto idx2degVec = [](const Math::Vector3i& v) { return Math::Vector3f { Math::Util::to180(Math::Util::idx2deg(v.getX())), @@ -86,31 +127,20 @@ void EmitterWidget::RotationPropertiesWidget::populateWidgets() { }; }; - QSignalBlocker b1(mRotTypeSpinBox); - mRotTypeSpinBox.setCurrentEnum(mProps.rotType); - - QSignalBlocker b2(mInitRotSpinBox); - mInitRotSpinBox.setVector(idx2degVec(mProps.initRot)); - - QSignalBlocker b3(mInitRotRandSpinBox); - mInitRotRandSpinBox.setVector(idx2degVec(mProps.initRotRand)); - - QSignalBlocker b4(mRotVelSpinBox); - mRotVelSpinBox.setVector(idx2degVec(mProps.rotVel)); - - QSignalBlocker b5(mRotVelRandSpinBox); - mRotVelRandSpinBox.setVector(idx2degVec(mProps.rotVelRand)); - - QSignalBlocker b6(mRotBasisSpinBox); - mRotBasisSpinBox.setVector(mProps.rotBasis); + mRotTypeSpinBox.setCurrentEnum(mEmitter->rotationType()); + mInitRotSpinBox.setVector(idx2degVec(mEmitter->initialRotation())); + mInitRotRandSpinBox.setVector(idx2degVec(mEmitter->initialRotationRandom())); + mRotVelSpinBox.setVector(idx2degVec(mEmitter->rotationVelocity())); + mRotVelRandSpinBox.setVector(idx2degVec(mEmitter->rotationVelocityRandom())); + mRotBasisSpinBox.setVector(mEmitter->rotationBasis()); updateAxis(); } -void EmitterWidget::RotationPropertiesWidget::updateAxis() { +void RotationInspector::updateAxis() { using Axis = VectorSpinBoxBase::Axis; - switch (mProps.rotType) { + switch (mEmitter->rotationType()) { case Ptcl::RotType::None: mInitRotSpinBox.setEnabledAxis(Axis::None); mInitRotRandSpinBox.setEnabledAxis(Axis::None); diff --git a/src/editor/emitterWidget/scalePropertiesWidget.cpp b/src/editor/inspector/scaleAnimInspector.cpp similarity index 50% rename from src/editor/emitterWidget/scalePropertiesWidget.cpp rename to src/editor/inspector/scaleAnimInspector.cpp index 6a4b36f..8d627af 100644 --- a/src/editor/emitterWidget/scalePropertiesWidget.cpp +++ b/src/editor/inspector/scaleAnimInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/emitterWidget/scalePropertiesWidget.h" +#include "editor/inspector/scaleAnimInspector.h" #include @@ -9,13 +9,13 @@ namespace PtclEditor { // ========================================================================== // -EmitterWidget::ScalePropertiesWidget::ScalePropertiesWidget(QWidget* parent) : - QWidget{parent} { +ScaleAnimInspector::ScaleAnimInspector(QWidget* parent) : + InspectorWidgetBase{parent} { // TODO: Move these somewhere else static constexpr QColor sColorAxisX = { 238, 51, 79 }; static constexpr QColor sColorAxisY = { 42, 125, 212 }; - static constexpr QColor sColorAxisZ = { 137, 214, 1 }; + // static constexpr QColor sColorAxisZ = { 137, 214, 1 }; mGraphX.setLineColor(sColorAxisX); mGraphY.setLineColor(sColorAxisY); @@ -28,6 +28,10 @@ EmitterWidget::ScalePropertiesWidget::ScalePropertiesWidget(QWidget* parent) : // TODO: Check this is valid mRandSpinbox.setRange(0.0f, 1.0f); + setupConnections(); +} + +void ScaleAnimInspector::setupConnections() { connect(&mGraphX, &AnimGraph::pointEdited, this, [this](s32 pointIndex, const AnimGraph::GraphPoint& point) { updateAnimPoint(pointIndex, point, &Math::Vector2f::getX); }); @@ -37,12 +41,19 @@ EmitterWidget::ScalePropertiesWidget::ScalePropertiesWidget(QWidget* parent) : }); connect(&mRandSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mProps.scaleRand = static_cast(value); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Scale Random", + "SetScaleRand", + &Ptcl::Emitter::scaleRand, + &Ptcl::Emitter::setScaleRand, + static_cast(value) + ); }); } -void EmitterWidget::ScalePropertiesWidget::updateAnimPoint(s32 pointIndex, const AnimGraph::GraphPoint& point, f32 (Math::Vector2f::*get)() const) { +void ScaleAnimInspector::updateAnimPoint(s32 pointIndex, const AnimGraph::GraphPoint& point, f32 (Math::Vector2f::*get)() const) { + auto anim = mEmitter->scaleAnim(); + auto set = [&](Math::Vector2f& v, f32 val) { if (get == &Math::Vector2f::getX) { v.setX(val); @@ -57,20 +68,20 @@ void EmitterWidget::ScalePropertiesWidget::updateAnimPoint(s32 pointIndex, const mGraphY.getPoints(); }; - const f32 oldP0 = (mProps.initScale.*get)(); - const f32 oldP1 = oldP0 + (mProps.diffScale21.*get)(); + const f32 oldP0 = (anim.initScale.*get)(); + const f32 oldP1 = oldP0 + (anim.diffScale21.*get)(); const f32 oldP2 = oldP1; - const f32 oldP3 = oldP2 + (mProps.diffScale32.*get)(); + const f32 oldP3 = oldP2 + (anim.diffScale32.*get)(); auto updateScaleSection = [&](s32* section, bool isSection2 = false) { - set(mProps.diffScale21, point.value - oldP0); - set(mProps.diffScale32, oldP3 - point.value); + set(anim.diffScale21, point.value - oldP0); + set(anim.diffScale32, oldP3 - point.value); const f32 sec1 = getGraphPoints()[1].position; const f32 sec2 = getGraphPoints()[2].position; if (std::abs(sec1 - sec2) < std::numeric_limits::epsilon()) { - mProps.scaleSection1 = -127; // Disable section1 if handles overlap + anim.scaleSection1 = -127; // Disable section1 if handles overlap if (isSection2) { *section = static_cast(point.position); } } else { *section = static_cast(point.position); @@ -79,37 +90,66 @@ void EmitterWidget::ScalePropertiesWidget::updateAnimPoint(s32 pointIndex, const switch (pointIndex) { case 0: - set(mProps.initScale, point.value); - set(mProps.diffScale21, oldP1 - point.value); + set(anim.initScale, point.value); + set(anim.diffScale21, oldP1 - point.value); break; case 1: - updateScaleSection(&mProps.scaleSection1); + updateScaleSection(&anim.scaleSection1); break; case 2: - updateScaleSection(&mProps.scaleSection2, true); + updateScaleSection(&anim.scaleSection2, true); break; case 3: - set(mProps.diffScale32, point.value - oldP1); + set(anim.diffScale32, point.value - oldP1); break; } - emit propertiesUpdated(mProps); + const QString axis = (get == &Math::Vector2f::getX) ? "X" : "Y"; + + QString handleName; + switch (pointIndex) { + case 0: handleName = "Start"; break; + case 1: handleName = "Section1"; break; + case 2: handleName = "Section2"; break; + case 3: handleName = "End"; break; + } + + QString key; + QString label; + if (pointIndex == 1 || pointIndex == 2) { + label = QString("Move Scale %1").arg(handleName); + key = QString("ScaleGraph_%1").arg(pointIndex); + } else { + label = QString("Move Scale %1 (%2)").arg(handleName, axis); + key = QString("ScaleAnim_%1_%2").arg(pointIndex).arg(axis); + } + + setEmitterProperty( + label, + key, + &Ptcl::Emitter::scaleAnim, + &Ptcl::Emitter::setScaleAnim, + anim + ); + updateGraphs(); } -void EmitterWidget::ScalePropertiesWidget::updateGraphs() { - auto updateGraph = [this](AnimGraph& graph, f32 (Math::Vector2f::*get)() const) { +void ScaleAnimInspector::updateGraphs() { + const auto& anim = mEmitter->scaleAnim(); + + auto updateGraph = [&](AnimGraph& graph, f32 (Math::Vector2f::*get)() const) { QSignalBlocker blocker(graph); - const f32 p0 = (mProps.initScale.*get)(); - const f32 p1 = p0 + (mProps.diffScale21.*get)(); + const f32 p0 = (anim.initScale.*get)(); + const f32 p1 = p0 + (anim.diffScale21.*get)(); const f32 p2 = p1; - const f32 p3 = p2 + (mProps.diffScale32.*get)(); + const f32 p3 = p2 + (anim.diffScale32.*get)(); - const bool disabled = mProps.scaleSection1 == -127; + const bool disabled = anim.scaleSection1 == -127; - const f32 sec1 = disabled ? static_cast(mProps.scaleSection2) : static_cast(mProps.scaleSection1); - const f32 sec2 = static_cast(mProps.scaleSection2); + const f32 sec1 = disabled ? static_cast(anim.scaleSection2) : static_cast(anim.scaleSection1); + const f32 sec2 = static_cast(anim.scaleSection2); AnimGraph::PointList points = { { 0.0f, p0, AnimGraph::HandleType::Locked }, @@ -124,13 +164,11 @@ void EmitterWidget::ScalePropertiesWidget::updateGraphs() { updateGraph(mGraphY, &Math::Vector2f::getY); } -void EmitterWidget::ScalePropertiesWidget::setProperties(const Ptcl::Emitter::ScaleProperties& properties) { - mProps = properties; - +void ScaleAnimInspector::populateProperties() { updateGraphs(); QSignalBlocker blockerRand(mRandSpinbox); - mRandSpinbox.setValue(mProps.scaleRand); + mRandSpinbox.setValue(mEmitter->scaleRand()); update(); } diff --git a/src/editor/stripeEditorWidget.cpp b/src/editor/inspector/stripeInspector.cpp similarity index 52% rename from src/editor/stripeEditorWidget.cpp rename to src/editor/inspector/stripeInspector.cpp index 710e70a..c21d0ac 100644 --- a/src/editor/stripeEditorWidget.cpp +++ b/src/editor/inspector/stripeInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/stripeEditorWidget.h" +#include "editor/inspector/stripeInspector.h" #include @@ -8,8 +8,8 @@ namespace PtclEditor { // ========================================================================== // -StripeEditorWidget::StripeEditorWidget(QWidget* parent) : - QWidget{parent} { +StripeInspector::StripeInspector(QWidget* parent) : + InspectorWidgetBase{parent} { mTypeComboBox.addItem("Billboard Stripe", QVariant::fromValue(Ptcl::StripeType::Billboard)); mTypeComboBox.addItem("Emitter Maxtrix", QVariant::fromValue(Ptcl::StripeType::EmitterMatrix)); @@ -36,58 +36,100 @@ StripeEditorWidget::StripeEditorWidget(QWidget* parent) : setupConnections(); } -void StripeEditorWidget::setupConnections() { +void StripeInspector::setupConnections() { // Type connect(&mTypeComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { + Q_UNUSED(index); const auto type = mTypeComboBox.currentData().value(); - mData.type = type; - emit dataUpdated(mData); + setEmitterProperty( + "Set Stripe Type", + "SetStripeType", + &Ptcl::Emitter::stripeType, + &Ptcl::Emitter::setStripeType, + type + ); }); // Num Hist connect(&mNumHistSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mData.numHistory = value; - emit dataUpdated(mData); + setEmitterProperty( + "Set Stripe History Size", + "SetStripeNumHist", + &Ptcl::Emitter::stripeNumHistory, + &Ptcl::Emitter::setStripeNumHistory, + value + ); }); // Start Alpha connect(&mStartAlphaSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.startAlpha = static_cast(value); - emit dataUpdated(mData); + setEmitterProperty( + "Set Stripe Start Alpha", + "SetStripeStartAlpha", + &Ptcl::Emitter::stripeStartAlpha, + &Ptcl::Emitter::setStripeStartAlpha, + static_cast(value) + ); }); // End Alpha connect(&mEndAlphaSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.endAlpha = static_cast(value); - emit dataUpdated(mData); + setEmitterProperty( + "Set Stripe End Alpha", + "SetStripeEndAlpha", + &Ptcl::Emitter::stripeEndAlpha, + &Ptcl::Emitter::setStripeEndAlpha, + static_cast(value) + ); }); // UV Scroll Speed connect(&mUVScrollSpeedSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - mData.uvScrollSpeed = mUVScrollSpeedSpinBox.getVector(); - emit dataUpdated(mData); + const auto speed = mUVScrollSpeedSpinBox.getVector(); + setEmitterProperty( + "Set Stripe UV Scroll Speed", + "SetStripeUVSpeed", + &Ptcl::Emitter::stripeUVScrollSpeed, + &Ptcl::Emitter::setStripeUVScrollSpeed, + speed + ); }); // Hist Step connect(&mHistStepSpinBox, &QSpinBox::valueChanged, this, [this](s32 value) { - mData.historyStep = value; - emit dataUpdated(mData); + setEmitterProperty( + "Set Stripe History Spacing", + "SetStripeHistStep", + &Ptcl::Emitter::stripeHistoryStep, + &Ptcl::Emitter::setStripeHistoryStep, + value + ); }); // Dir Interpolate connect(&mDirIntepolateSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { - mData.dirInterpolate = static_cast(value); - emit dataUpdated(mData); + setEmitterProperty( + "Set Stripe Interpolation Ratio", + "SetStripeDirInterp", + &Ptcl::Emitter::stripeDirInterpolate, + &Ptcl::Emitter::setStripeDirInterpolate, + static_cast(value) + ); }); // Emitter Coord connect(&mEmitterCoordCheckBox, &QCheckBox::clicked, this, [this](bool checked) { - mStripeFlag.set(Ptcl::StripeFlag::EmitterCoord, checked); - emit flagsUpdated(mStripeFlag); + setEmitterProperty( + "Toggle Stripe Follow Emitter", + "SetStripeEmitterCoord", + &Ptcl::Emitter::isStripeEmitterCoord, + &Ptcl::Emitter::setStripeEmitterCoord, + checked + ); }); } -void StripeEditorWidget::setData(const Ptcl::StripeData& data, const BitFlag& stripeFlag) { +void StripeInspector::populateProperties() { QSignalBlocker b1(mTypeComboBox); QSignalBlocker b2(mNumHistSpinBox); QSignalBlocker b3(mStartAlphaSpinBox); @@ -97,19 +139,16 @@ void StripeEditorWidget::setData(const Ptcl::StripeData& data, const BitFlagstripeType())); mTypeComboBox.setCurrentIndex(typeIndex); - mNumHistSpinBox.setValue(mData.numHistory); - mStartAlphaSpinBox.setValue(mData.startAlpha); - mEndAlphaSpinBox.setValue(mData.endAlpha); - mUVScrollSpeedSpinBox.setVector(mData.uvScrollSpeed); - mHistStepSpinBox.setValue(mData.historyStep); - mDirIntepolateSpinBox.setValue(mData.dirInterpolate); - mEmitterCoordCheckBox.setChecked(stripeFlag.isSet(Ptcl::StripeFlag::EmitterCoord)); + mNumHistSpinBox.setValue(mEmitter->stripeNumHistory()); + mStartAlphaSpinBox.setValue(mEmitter->stripeStartAlpha()); + mEndAlphaSpinBox.setValue(mEmitter->stripeEndAlpha()); + mUVScrollSpeedSpinBox.setVector(mEmitter->stripeUVScrollSpeed()); + mHistStepSpinBox.setValue(mEmitter->stripeHistoryStep()); + mDirIntepolateSpinBox.setValue(mEmitter->stripeDirInterpolate()); + mEmitterCoordCheckBox.setChecked(mEmitter->isStripeEmitterCoord()); } diff --git a/src/editor/inspector/terminationInspector.cpp b/src/editor/inspector/terminationInspector.cpp new file mode 100644 index 0000000..14dd8d6 --- /dev/null +++ b/src/editor/inspector/terminationInspector.cpp @@ -0,0 +1,59 @@ +#include "editor/inspector/terminationInspector.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +TerminationInspector::TerminationInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + auto* mainLayout = new QFormLayout(this); + + mAlphaAddInSpinBox.setRange(0.0f, 1.0f); + + mainLayout->addRow("Stop Emission During Fade:", &mIsStopEmitCheckBox); + mainLayout->addRow("Alpha Add During Fade:", &mAlphaAddInSpinBox); + + setupConnections(); +} + +void TerminationInspector::setupConnections() { + connect(&mIsStopEmitCheckBox, &QCheckBox::checkStateChanged, this, [this](bool checked) { + setEmitterProperty( + "Set Stop Emission", + "SetStopEmission", + &Ptcl::Emitter::isStopEmitInFade, + &Ptcl::Emitter::setIsStopEmitInFade, + checked + ); + }); + + connect(&mAlphaAddInSpinBox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Alpha Add In Fade", + "SetAlphaAddIn", + &Ptcl::Emitter::alphaAddInFade, + &Ptcl::Emitter::setAlphaAddInFade, + value + ); + }); +} + +void TerminationInspector::populateProperties() { + QSignalBlocker b1(mIsStopEmitCheckBox); + QSignalBlocker b2(mAlphaAddInSpinBox); + + mIsStopEmitCheckBox.setChecked(mEmitter->isStopEmitInFade()); + mAlphaAddInSpinBox.setValue(mEmitter->alphaAddInFade()); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/emitterWidget/texturePropertiesWidget.cpp b/src/editor/inspector/textureInspector.cpp similarity index 59% rename from src/editor/emitterWidget/texturePropertiesWidget.cpp rename to src/editor/inspector/textureInspector.cpp index e07c101..6be00ad 100644 --- a/src/editor/emitterWidget/texturePropertiesWidget.cpp +++ b/src/editor/inspector/textureInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/emitterWidget/texturePropertiesWidget.h" +#include "editor/inspector/textureInspector.h" #include "editor/textureSelectDialog.h" @@ -17,85 +17,16 @@ namespace PtclEditor { // ========================================================================== // -EmitterWidget::TexturePropertiesWidget::TexturePropertiesWidget(QWidget* parent) : - QWidget{parent} { - // Wrap T - connect(&mWrapTComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { - Q_UNUSED(index); - mProps.textureWrapT = mWrapTComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - // Wrap S - connect(&mWrapSComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { - Q_UNUSED(index); - mProps.textureWrapS = mWrapSComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - // Mag Filter - connect(&mMagFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { - Q_UNUSED(index); - mProps.textureMagFilter = mMagFilterComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - // Min Filter - connect(&mMinFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { - Q_UNUSED(index); - mProps.textureMinFilter = mMinFilterComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); - - // Mipmap Filter - connect(&mMipFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { - Q_UNUSED(index); - mProps.textureMipFilter = mMipFilterComboBox.currentEnum(); - emit propertiesUpdated(mProps); - }); +TextureInspector::TextureInspector(QWidget* parent) : + InspectorWidgetBase{parent} { // Texture Preview mTexturePreview.setThumbnailSize(QSize(64, 64)); - connect(&mTexturePreview, &ThumbnailWidget::clicked, this, &TexturePropertiesWidget::changeTexture); - - // Texture pattern count - connect(&mNumTexPat, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - mProps.numTexPat = value; - emit propertiesUpdated(mProps); - }); - - // Texture Division X mTexDivX.setRange(1, 4); - connect(&mTexDivX, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - mProps.numTexDivX = value; - updateUVScale(); - updateTexPatTblColumns(); - emit propertiesUpdated(mProps); - }); - - // Texture Division Y mTexDivY.setRange(1, 4); - connect(&mTexDivY, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - mProps.numTexDivY = value; - updateUVScale(); - updateTexPatTblColumns(); - emit propertiesUpdated(mProps); - }); - - // Texture pattern Frequency mTexPatFreq.setMinimum(1); - connect(&mTexPatFreq, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - mProps.texPatFreq = value; - emit propertiesUpdated(mProps); - }); - - // Texture pattern table use mTexPatTblUse.setRange(2, 16); - connect(&mTexPatTblUse, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - mProps.texPatTblUse = value; - updateTexPatTblColumns(); - emit propertiesUpdated(mProps); - }); + // Texture pattern table const s32 referenceHeight = mWrapTComboBox.sizeHint().height(); // Make TexPat table same hight as a comboBox @@ -112,51 +43,11 @@ EmitterWidget::TexturePropertiesWidget::TexturePropertiesWidget(QWidget* parent) for (s32 i = 0; i < 16; ++i) { auto* item = new QTableWidgetItem("0"); item->setTextAlignment(Qt::AlignCenter); - - if (i < mProps.numTexPat) { - item->setIcon(QIcon(createFramePreview(mProps.texPatTbl[i]))); - } - mTexPatTbl.setItem(0, i, item); } - connect(&mTexPatTbl, &QTableWidget::itemChanged, this, [this](QTableWidgetItem* item) { - QSignalBlocker b1(mTexPatTbl); - - bool ok = false; - s32 value = item->text().toInt(&ok); - - const bool valid = ok && value >= 0 && value < maxFrameCount(); - - if (!valid) { - value = 0; - item->setText("0"); - } - - mProps.texPatTbl[item->column()] = value; - item->setIcon(valid ? QIcon(createFramePreview(value)) : QIcon()); - - emit propertiesUpdated(mProps); - }); - - // Texture Repetitions X mTexRepetitionsX.setMinimum(1); - connect(&mTexRepetitionsX, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - f32 uvX = static_cast(value) / static_cast(mProps.numTexDivX); - mProps.texUVScale.setX(uvX); - updateTexPatTblColumns(); - emit propertiesUpdated(mProps); - }); - - // Texture Repetitions Y mTexRepetitionsY.setMinimum(1); - connect(&mTexRepetitionsY, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { - f32 uvY = static_cast(value) / static_cast(mProps.numTexDivY); - mProps.texUVScale.setY(uvY); - updateTexPatTblColumns(); - emit propertiesUpdated(mProps); - }); - // Texture Settings Layout auto settingsLayout = new QGridLayout; @@ -181,27 +72,10 @@ EmitterWidget::TexturePropertiesWidget::TexturePropertiesWidget(QWidget* parent) // Anim Mode mAnimModeComboBox.addItems({"Fit to Speed", "Fit to Life"}); - connect(&mAnimModeComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { - auto mode = static_cast(index); - - if (mode == AnimMode::FitToLife) { - mTexPatFreq.setDisabled(true); - mProps.texPatFreq = 0; - } else { - mTexPatFreq.setDisabled(false); - mProps.texPatFreq = 1; - } - - emit propertiesUpdated(mProps); - }); // Texture Pattern Anim mTexPatGroupBox.setTitle("Texture Pattern Animation"); mTexPatGroupBox.setCheckable(true); - connect(&mTexPatGroupBox, &QGroupBox::clicked, this, [this](bool checked) { - mProps.isTexPatAnim = checked; - emit propertiesUpdated(mProps); - }); auto texPatSettingsLayout = new QGridLayout; texPatSettingsLayout->addWidget(new QLabel("Animation Mode:"), 0, 0); @@ -225,16 +99,209 @@ EmitterWidget::TexturePropertiesWidget::TexturePropertiesWidget(QWidget* parent) mainLayout->addWidget(&mNumTexPat, 3, 1, 1, 1); setLayout(mainLayout); - + setupConnections(); } -void EmitterWidget::TexturePropertiesWidget::setProperties(const Ptcl::Emitter::TextureProperties& properties, const std::shared_ptr& texture) { - mProps = properties; - mTexture = texture; - populateWidgets(); +void TextureInspector::setupConnections() { + connect(&mTexturePreview, &ThumbnailWidget::clicked, this, &TextureInspector::changeTexture); + + // Wrap T + connect(&mWrapTComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { + Q_UNUSED(index); + const auto wrap = mWrapTComboBox.currentEnum(); + setEmitterProperty( + "Set Texture Wrap U", + "SetTexWrapU", + &Ptcl::Emitter::textureWrapT, + &Ptcl::Emitter::setTextureWrapT, + wrap + ); + }); + + // Wrap S + connect(&mWrapSComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { + Q_UNUSED(index); + const auto wrap = mWrapSComboBox.currentEnum(); + setEmitterProperty( + "Set Texture Wrap V", + "SetTexWrapV", + &Ptcl::Emitter::textureWrapS, + &Ptcl::Emitter::setTextureWrapS, + wrap + ); + }); + + // Mag Filter + connect(&mMagFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { + Q_UNUSED(index); + const auto filter = mMagFilterComboBox.currentEnum(); + setEmitterProperty( + "Set Texture Mag Filter", + "SetTexMagFilter", + &Ptcl::Emitter::textureMagFilter, + &Ptcl::Emitter::setTextureMagFilter, + filter + ); + }); + + // Min Filter + connect(&mMinFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { + Q_UNUSED(index); + const auto filter = mMinFilterComboBox.currentEnum(); + setEmitterProperty( + "Set Texture Min Filter", + "SetTexMinFilter", + &Ptcl::Emitter::textureMinFilter, + &Ptcl::Emitter::setTextureMinFilter, + filter + ); + }); + + // Mipmap Filter + connect(&mMipFilterComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { + Q_UNUSED(index); + const auto filter = mMipFilterComboBox.currentEnum(); + setEmitterProperty( + "Set Texture Mipmap Filter", + "SetTexMipFilter", + &Ptcl::Emitter::textureMipFilter, + &Ptcl::Emitter::setTextureMipFilter, + filter + ); + }); + + // Texture pattern count + connect(&mNumTexPat, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + setEmitterProperty( + "Set Texture Pattern Count", + "SetNumTexPat", + &Ptcl::Emitter::numTexturePattern, + &Ptcl::Emitter::setNumTexturePattern, + static_cast(value) + ); + }); + + connect(&mTexDivX, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + setEmitterProperty( + "Set Texture Divisions X", + "SetTexDivX", + &Ptcl::Emitter::numTextureDivisionX, + &Ptcl::Emitter::setNumTextureDivisionX, + static_cast(value) + ); + }); + + connect(&mTexDivY, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + setEmitterProperty( + "Set Texture Divisions Y", + "SetTexDivY", + &Ptcl::Emitter::numTextureDivisionY, + &Ptcl::Emitter::setNumTextureDivisionY, + static_cast(value) + ); + }); + + connect(&mTexPatFreq, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + setEmitterProperty( + "Set Texture Anim Frame Step", + "SetTexPatFreq", + &Ptcl::Emitter::texturePatternFrequency, + &Ptcl::Emitter::setTexturePatternFrequency, + static_cast(value) + ); + }); + + connect(&mTexPatTblUse, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + setEmitterProperty( + "Set Texture Anim Frame Count", + "SetTexPatTblUse", + &Ptcl::Emitter::texturePatternTableUse, + &Ptcl::Emitter::setTexturePatternTableUse, + static_cast(value) + ); + }); + + connect(&mTexPatTbl, &QTableWidget::itemChanged, this, [this](QTableWidgetItem* item) { + QSignalBlocker b1(mTexPatTbl); + + bool ok = false; + s32 value = item->text().toInt(&ok); + + const bool valid = ok && value >= 0 && value < maxFrameCount(); + if (!valid) { + value = 0; + item->setText("0"); + } + + auto table = mEmitter->texturePatternTable(); + const s32 col = item->column(); + + if (table[col] == value) { + return; + } + + table[col] = value; + + setEmitterProperty( + "Set Texture Anim Frame Order", + QString("SetTexPatTbl_%1").arg(col), + &Ptcl::Emitter::texturePatternTable, + &Ptcl::Emitter::setTexturePatternTable, + table + ); + }); + + connect(&mTexRepetitionsX, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + setEmitterProperty( + "Set Texture X Repetition", + "SetTexRepX", + &Ptcl::Emitter::numTextureRepetitionsX, + &Ptcl::Emitter::setNumTextureRepetitionsX, + static_cast(value) + ); + }); + + connect(&mTexRepetitionsY, &SizedSpinBoxBase::valueChanged, this, [this](u64 value) { + setEmitterProperty( + "Set Texture Y Repetition", + "SetTexRepY", + &Ptcl::Emitter::numTextureRepetitionsY, + &Ptcl::Emitter::setNumTextureRepetitionsY, + static_cast(value) + ); + }); + + connect(&mAnimModeComboBox, &QComboBox::currentIndexChanged, this, [this](s32 index) { + auto mode = static_cast(index); + + u16 freq; + if (mode == AnimMode::FitToLife) { + freq = 0; + } else { + freq = 1; + } + + setEmitterProperty( + "Set Texture Anim Mode", + "SetTexAnimMode", + &Ptcl::Emitter::texturePatternFrequency, + &Ptcl::Emitter::setTexturePatternFrequency, + freq + ); + }); + + connect(&mTexPatGroupBox, &QGroupBox::clicked, this, [this](bool checked) { + setEmitterProperty( + "Toggle Texture Anim", + "ToggleTexAnim", + &Ptcl::Emitter::isTexturePatternAnim, + &Ptcl::Emitter::setIsTexturePatternAnim, + checked + ); + }); } -void EmitterWidget::TexturePropertiesWidget::populateWidgets() { +void TextureInspector::populateProperties() { QSignalBlocker b1(mWrapTComboBox); QSignalBlocker b2(mWrapSComboBox); QSignalBlocker b3(mMagFilterComboBox); @@ -249,25 +316,24 @@ void EmitterWidget::TexturePropertiesWidget::populateWidgets() { QSignalBlocker b12(mTexPatGroupBox); QSignalBlocker b13(mTexRepetitionsX); QSignalBlocker b14(mTexRepetitionsY); + QSignalBlocker b15(mAnimModeComboBox); - if (mTexture) { - mTexturePreview.setPixmap(QPixmap::fromImage(mTexture->textureData())); - } + mTexturePreview.setPixmap(QPixmap::fromImage(mEmitter->textureHandle()->textureData())); - mWrapTComboBox.setCurrentEnum(mProps.textureWrapT); - mWrapSComboBox.setCurrentEnum(mProps.textureWrapS); - mMagFilterComboBox.setCurrentEnum(mProps.textureMagFilter); - mMinFilterComboBox.setCurrentEnum(mProps.textureMinFilter); - mMipFilterComboBox.setCurrentEnum(mProps.textureMipFilter); + mWrapTComboBox.setCurrentEnum(mEmitter->textureWrapT()); + mWrapSComboBox.setCurrentEnum(mEmitter->textureWrapS()); + mMagFilterComboBox.setCurrentEnum(mEmitter->textureMagFilter()); + mMinFilterComboBox.setCurrentEnum(mEmitter->textureMinFilter()); + mMipFilterComboBox.setCurrentEnum(mEmitter->textureMipFilter()); - mNumTexPat.setValue(mProps.numTexPat); - mTexDivX.setValue(mProps.numTexDivX); - mTexDivY.setValue(mProps.numTexDivY); + mNumTexPat.setValue(mEmitter->numTexturePattern()); + mTexDivX.setValue(mEmitter->numTextureDivisionX()); + mTexDivY.setValue(mEmitter->numTextureDivisionY()); - const auto freq = mProps.texPatFreq; + const auto freq = mEmitter->texturePatternFrequency(); const auto mode = freqToAnimMode(freq); - mTexPatFreq.setValue(mProps.texPatFreq); + mTexPatFreq.setValue(freq); mAnimModeComboBox.setCurrentIndex(static_cast(mode)); if (mode == AnimMode::FitToLife) { @@ -276,38 +342,27 @@ void EmitterWidget::TexturePropertiesWidget::populateWidgets() { mTexPatFreq.setDisabled(false); } - mTexPatTblUse.setValue(mProps.texPatTblUse); + mTexPatTblUse.setValue(mEmitter->texturePatternTableUse()); - const auto& tbl = mProps.texPatTbl; + const auto& tbl = mEmitter->texturePatternTable(); for (s32 i = 0; i < tbl.size(); ++i) { QTableWidgetItem* item = mTexPatTbl.item(0, i); item->setText(QString::number(tbl[i])); - if (i < mProps.numTexPat) { - item->setIcon(QIcon(createFramePreview(mProps.texPatTbl[i]))); + if (i < mEmitter->numTexturePattern()) { + item->setIcon(QIcon(createFramePreview(tbl[i]))); } } - mTexPatGroupBox.setChecked(mProps.isTexPatAnim); + mTexPatGroupBox.setChecked(mEmitter->isTexturePatternAnim()); - const f32 divX = static_cast(mProps.numTexDivX); - const f32 divY = static_cast(mProps.numTexDivY); - - mTexRepetitionsX.setValue(static_cast(std::round(mProps.texUVScale.getX() * divX))); - mTexRepetitionsY.setValue(static_cast(std::round(mProps.texUVScale.getY() * divY))); + mTexRepetitionsX.setValue(mEmitter->numTextureRepetitionsX()); + mTexRepetitionsY.setValue(mEmitter->numTextureRepetitionsY()); updateTexPatTblColumns(); } -void EmitterWidget::TexturePropertiesWidget::setTextureList(const Ptcl::TextureList* textureList) { - mTextureList = textureList; -} - -void EmitterWidget::TexturePropertiesWidget::updateTextureDetails() { - mTexturePreview.setPixmap(QPixmap::fromImage(mTexture->textureData())); -} - -void EmitterWidget::TexturePropertiesWidget::updateTexPatTblColumns() { +void TextureInspector::updateTexPatTblColumns() { const QPalette& palette = mTexPatTbl.palette(); for (s32 i = 0; i < 16; ++i) { @@ -316,12 +371,12 @@ void EmitterWidget::TexturePropertiesWidget::updateTexPatTblColumns() { continue; } - if (i >= mProps.texPatTblUse) { + if (i >= mEmitter->texturePatternTableUse()) { item->setFlags(Qt::NoItemFlags); item->setBackground(palette.color(QPalette::Disabled, QPalette::Base)); item->setForeground(palette.color(QPalette::Disabled, QPalette::Text)); - s32 frame = mProps.texPatTbl[i]; + s32 frame = mEmitter->texturePatternTable()[i]; item->setText(QString::number(frame)); item->setIcon(QIcon()); } else { @@ -329,46 +384,39 @@ void EmitterWidget::TexturePropertiesWidget::updateTexPatTblColumns() { item->setBackground(palette.color(QPalette::Base)); item->setForeground(palette.color(QPalette::Text)); - s32 frame = mProps.texPatTbl[i]; + s32 frame = mEmitter->texturePatternTable()[i]; item->setText(QString::number(frame)); item->setIcon(QIcon(createFramePreview(frame))); } } } -void EmitterWidget::TexturePropertiesWidget::updateUVScale() { - mProps.texUVScale.setX(static_cast(mTexRepetitionsX.value()) / static_cast(mProps.numTexDivX)); - mProps.texUVScale.setY(static_cast(mTexRepetitionsY.value()) / static_cast(mProps.numTexDivY)); - -} - -void EmitterWidget::TexturePropertiesWidget::changeTexture() { - if (!mTextureList) { - return; - } - - auto oldTexture = mTexture; +void TextureInspector::changeTexture() { + const auto& textureList = mDocument->textures(); - TextureSelectDialog dialog(*mTextureList, this); + TextureSelectDialog dialog(textureList, this); if (dialog.exec() == QDialog::Accepted) { - s32 selectedInded = dialog.selectedIndex(); - if (selectedInded >= 0 && static_cast(selectedInded) < mTextureList->size()) { - mTexture = mTextureList->at(selectedInded); - updateTextureDetails(); - emit textureUpdated(oldTexture, mTexture); + s32 selectedIndex = dialog.selectedIndex(); + if (selectedIndex >= 0 && static_cast(selectedIndex) < textureList.size()) { + const auto texture = textureList.at(selectedIndex).get(); + setEmitterProperty( + "Set Texture", + "SetEmitterTexture", + &Ptcl::Emitter::texture, + &Ptcl::Emitter::setTexture, + texture + ); } } - - updateTexPatTblColumns(); } -s32 EmitterWidget::TexturePropertiesWidget::maxFrameCount() const { - return mProps.numTexDivX * mProps.numTexDivY; +s32 TextureInspector::maxFrameCount() const { + return mEmitter->numTextureDivisionX() * mEmitter->numTextureDivisionY(); } -std::optional EmitterWidget::TexturePropertiesWidget::calcFrameUVOffset(s32 frame) const { - const auto divX = mProps.numTexDivX; - const auto divY = mProps.numTexDivY; +std::optional TextureInspector::calcFrameUVOffset(s32 frame) const { + const auto divX = mEmitter->numTextureDivisionX(); + const auto divY = mEmitter->numTextureDivisionY(); if (frame < 0 || divX <= 0 || divY <= 0) { return std::nullopt; @@ -378,7 +426,7 @@ std::optional EmitterWidget::TexturePropertiesWidget::calcFrameU return std::nullopt; } - const auto& uvScale = mProps.texUVScale; + const auto& uvScale = mEmitter->textureUVScale(); const s32 frameX = frame % divX; const s32 frameY = frame / divX; @@ -391,8 +439,8 @@ std::optional EmitterWidget::TexturePropertiesWidget::calcFrameU return uvOffset; } -QImage EmitterWidget::TexturePropertiesWidget::getFrameTexture(s32 frame) const { - if (!mTexture) { +QImage TextureInspector::getFrameTexture(s32 frame) const { + if (!mEmitter->textureHandle().isValid()) { return {}; } @@ -402,8 +450,8 @@ QImage EmitterWidget::TexturePropertiesWidget::getFrameTexture(s32 frame) const } const auto& uvOffset = *uv; - const auto& uvScale = mProps.texUVScale; - const auto& src = mTexture->textureData(); + const auto& uvScale = mEmitter->textureUVScale(); + const auto& src = mEmitter->textureHandle()->textureData(); const f32 texW = static_cast(src.width()); const f32 texH = static_cast(src.height()); @@ -419,7 +467,7 @@ QImage EmitterWidget::TexturePropertiesWidget::getFrameTexture(s32 frame) const return rect.isValid() ? src.copy(rect) : QImage{}; } -QImage EmitterWidget::TexturePropertiesWidget::applyUVRepetition(const QImage& image, f32 repeatX, f32 repeatY) const { +QImage TextureInspector::applyUVRepetition(const QImage& image, f32 repeatX, f32 repeatY) const { if (image.isNull()) { return {}; } @@ -454,7 +502,7 @@ QImage EmitterWidget::TexturePropertiesWidget::applyUVRepetition(const QImage& i return out; } -QPixmap EmitterWidget::TexturePropertiesWidget::createFramePreview(s32 frame) const { +QPixmap TextureInspector::createFramePreview(s32 frame) const { QImage base = getFrameTexture(frame); if (base.isNull()) { return {}; diff --git a/src/editor/inspector/transformInspector.cpp b/src/editor/inspector/transformInspector.cpp new file mode 100644 index 0000000..8aef2d2 --- /dev/null +++ b/src/editor/inspector/transformInspector.cpp @@ -0,0 +1,73 @@ +#include "editor/inspector/transformInspector.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +TransformInspector::TransformInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + auto* mainLayout = new QFormLayout(this); + + mainLayout->addRow("Translation", &mTranslationSpinBox); + mainLayout->addRow("Rotation", &mRotationSpinBox); + mainLayout->addRow("Scale", &mScaleSpinBox); + + setupConnections(); +} + +void TransformInspector::setupConnections() { + connect(&mTranslationSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto translation = mTranslationSpinBox.getVector(); + setEmitterProperty( + "Set Translation", + "SetTranslation", + &Ptcl::Emitter::translation, + &Ptcl::Emitter::setTranslation, + translation + ); + }); + + connect(&mRotationSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto rotation = mRotationSpinBox.getVector(); + setEmitterProperty( + "Set Rotation", + "SetRotation", + &Ptcl::Emitter::rotation, + &Ptcl::Emitter::setRotation, + rotation + ); + }); + + connect(&mScaleSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto scale = mScaleSpinBox.getVector(); + setEmitterProperty( + "Set Scale", + "SetScale", + &Ptcl::Emitter::scale, + &Ptcl::Emitter::setScale, + scale + ); + }); +} + +void TransformInspector::populateProperties() { + QSignalBlocker b1(mTranslationSpinBox); + QSignalBlocker b2(mRotationSpinBox); + QSignalBlocker b3(mScaleSpinBox); + + mTranslationSpinBox.setVector(mEmitter->translation()); + mRotationSpinBox.setVector(mEmitter->rotation()); + mScaleSpinBox.setVector(mEmitter->scale()); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/inspector/velocityInspector.cpp b/src/editor/inspector/velocityInspector.cpp new file mode 100644 index 0000000..19ed428 --- /dev/null +++ b/src/editor/inspector/velocityInspector.cpp @@ -0,0 +1,120 @@ +#include "editor/inspector/velocityInspector.h" + +#include + + +namespace PtclEditor { + + +// ========================================================================== // + + +VelocityInspector::VelocityInspector(QWidget* parent) : + InspectorWidgetBase{parent} { + + auto* mainLayout = new QFormLayout(this); + + mFigureVelSpinbox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mInitVelSpinbox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mVelRandomSpinbox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + mAirResistanceSpinbox.setRange(0.0f, 1.0f); + + mainLayout->addRow("Figure Velocity:", &mFigureVelSpinbox); + mainLayout->addRow("Velocity Direction:", &mVelDirSpinbox); + mainLayout->addRow("Initial Velocity:", &mInitVelSpinbox); + mainLayout->addRow("Initial Velocity Random:", &mVelRandomSpinbox); + mainLayout->addRow("Spread Vector:", &mSpreadVecSpinbox); + mainLayout->addRow("Air Resistance:", &mAirResistanceSpinbox); + + setupConnections(); +} + +void VelocityInspector::setupConnections() { + connect(&mFigureVelSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Figure Velocity", + "SetFigureVelocity", + &Ptcl::Emitter::figureVelocity, + &Ptcl::Emitter::setFigureVelocity, + static_cast(value) + ); + }); + + connect(&mVelDirSpinbox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto direction = mVelDirSpinbox.getVector(); + + setEmitterProperty( + "Set Velocity Direction", + "SetVelocityDir", + &Ptcl::Emitter::velocityDirection, + &Ptcl::Emitter::setVelocityDirection, + direction + ); + }); + + connect(&mInitVelSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Initial Velocity", + "SetInitialVelocity", + &Ptcl::Emitter::initialVelocity, + &Ptcl::Emitter::setInitialVelocity, + static_cast(value) + ); + }); + + connect(&mVelRandomSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Initial Velocity Random", + "SetInitVelocityRand", + &Ptcl::Emitter::initialVelocityRandom, + &Ptcl::Emitter::setInitialVelocityRandom, + static_cast(value) + ); + }); + + connect(&mSpreadVecSpinbox, &VectorSpinBoxBase::valueChanged, this, [this]() { + const auto spread = mSpreadVecSpinbox.getVector(); + + setEmitterProperty( + "Set Spread Vector", + "SetSpreadVector", + &Ptcl::Emitter::spreadVector, + &Ptcl::Emitter::setSpreadVector, + spread + ); + }); + + connect(&mAirResistanceSpinbox, &QDoubleSpinBox::valueChanged, this, [this](double value) { + setEmitterProperty( + "Set Air Resistance", + "SetAirResistance", + &Ptcl::Emitter::airResistance, + &Ptcl::Emitter::setAirResistance, + static_cast(value) + ); + }); +} + +void VelocityInspector::populateProperties() { + QSignalBlocker b1(mFigureVelSpinbox); + QSignalBlocker b2(mVelDirSpinbox); + QSignalBlocker b3(mInitVelSpinbox); + QSignalBlocker b4(mVelRandomSpinbox); + QSignalBlocker b5(mSpreadVecSpinbox); + QSignalBlocker b6(mAirResistanceSpinbox); + + mFigureVelSpinbox.setValue(mEmitter->figureVelocity()); + mVelDirSpinbox.setVector(mEmitter->velocityDirection()); + mInitVelSpinbox.setValue(mEmitter->initialVelocity()); + mVelRandomSpinbox.setValue(mEmitter->initialVelocityRandom()); + mSpreadVecSpinbox.setVector(mEmitter->spreadVector()); + mAirResistanceSpinbox.setValue(mEmitter->airResistance()); + + update(); +} + + +// ========================================================================== // + + +} // namespace PtclEditor diff --git a/src/editor/emitterWidget/volumePropertiesWidget.cpp b/src/editor/inspector/volumeInspector.cpp similarity index 67% rename from src/editor/emitterWidget/volumePropertiesWidget.cpp rename to src/editor/inspector/volumeInspector.cpp index 0390a35..3e97ea6 100644 --- a/src/editor/emitterWidget/volumePropertiesWidget.cpp +++ b/src/editor/inspector/volumeInspector.cpp @@ -1,4 +1,4 @@ -#include "editor/emitterWidget/volumePropertiesWidget.h" +#include "editor/inspector/volumeInspector.h" #include "math/util.h" @@ -11,14 +11,14 @@ namespace PtclEditor { // ========================================================================== // -EmitterWidget::VolumePropertiesWidget::VolumePropertiesWidget(QWidget* parent) : - QWidget{parent} { +VolumeInspector::VolumeInspector(QWidget* parent) : + InspectorWidgetBase{parent} { setupUi(); - setupSignals(); + setupConnections(); } -void EmitterWidget::VolumePropertiesWidget::setupUi() { +void VolumeInspector::setupUi() { mRadiusSpinBox.setOrientation(Qt::Vertical); mSweepStartSpinBox.setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); @@ -106,57 +106,80 @@ void EmitterWidget::VolumePropertiesWidget::setupUi() { } } -void EmitterWidget::VolumePropertiesWidget::setupSignals() { - connect(&mTypeComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this]() { - auto type = mTypeComboBox.currentEnum(); - mProps.volumeType = type; - updateFieldVisibility(type); - emit propertiesUpdated(mProps); +void VolumeInspector::setupConnections() { + connect(&mTypeComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this]() { + const auto type = mTypeComboBox.currentEnum(); + + setEmitterProperty( + "Set Volume Type", + "SetVolumeType", + &Ptcl::Emitter::volumeType, + &Ptcl::Emitter::setVolumeType, + type + ); }); - connect(&mVolumeTblIndexComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) { - mProps.volumeTblIndex = index; - emit propertiesUpdated(mProps); + connect(&mVolumeTblIndexComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](s32 index) { + setEmitterProperty( + "Set Volume Table Index", + "SetVolumeTblIdx", + &Ptcl::Emitter::volumeTblIndex, + &Ptcl::Emitter::setVolumeTblIndex, + index + ); }); connect(&mRadiusSpinBox, &VectorSpinBoxBase::valueChanged, this, [this]() { - auto radius = mRadiusSpinBox.getVector(); - - mProps.volumeRadius = radius; - // Keep length spinbox in sync - const QSignalBlocker block(&mLengthSpinBox); - mLengthSpinBox.setValue(radius.getZ()); - emit propertiesUpdated(mProps); + const auto radius = mRadiusSpinBox.getVector(); + + setEmitterProperty( + "Set Volume Radius", + "SetVolumeRadius", + &Ptcl::Emitter::volumeRadius, + &Ptcl::Emitter::setVolumeRadius, + radius + ); }); - connect(&mLengthSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](double value) { + connect(&mLengthSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](f64 value) { auto radius = mRadiusSpinBox.getVector(); radius.setZ(static_cast(value)); - mProps.volumeRadius = radius; - // Keep radius spinbox in sync - const QSignalBlocker block(&mRadiusSpinBox); - mRadiusSpinBox.setVector(radius); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Volume Length", + "SetVolumeLength", + &Ptcl::Emitter::volumeRadius, + &Ptcl::Emitter::setVolumeRadius, + radius + ); }); - connect(&mSweepStartSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](double value) { - mProps.volumeSweepStart = Math::Util::deg2idx(Math::Util::to180(static_cast(value))); - emit propertiesUpdated(mProps); - }); + connect(&mSweepStartSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](f64 value) { + const auto sweepStart = Math::Util::deg2idx(Math::Util::to180(static_cast(value))); - connect(&mSweepParamSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](double value) { - mProps.volumeSweepParam = Math::Util::deg2idx(Math::Util::to180(static_cast(value))); - emit propertiesUpdated(mProps); + setEmitterProperty( + "Set Sweep Start", + "SetSweepStart", + &Ptcl::Emitter::volumeSweepStart, + &Ptcl::Emitter::setVolumeSweepStart, + sweepStart + ); }); -} -void EmitterWidget::VolumePropertiesWidget::setProperties(const Ptcl::Emitter::VolumeProperties& properties) { - mProps = properties; - populateWidgets(); + connect(&mSweepParamSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](f64 value) { + const auto sweepParam = Math::Util::deg2idx(Math::Util::to180(static_cast(value))); + + setEmitterProperty( + "Set Sweep Param", + "SetSweepParam", + &Ptcl::Emitter::volumeSweepParam, + &Ptcl::Emitter::setVolumeSweepParam, + sweepParam + ); + }); } -void EmitterWidget::VolumePropertiesWidget::populateWidgets() { +void VolumeInspector::populateProperties() { QSignalBlocker b1(mVolumeTblIndexComboBox); QSignalBlocker b2(mTypeComboBox); QSignalBlocker b3(mRadiusSpinBox); @@ -164,22 +187,22 @@ void EmitterWidget::VolumePropertiesWidget::populateWidgets() { QSignalBlocker b5(mSweepStartSpinBox); QSignalBlocker b6(mSweepParamSpinBox); - auto volumeType = mProps.volumeType; + auto volumeType = mEmitter->volumeType(); - mVolumeTblIndexComboBox.setCurrentIndex(mProps.volumeTblIndex); + mVolumeTblIndexComboBox.setCurrentIndex(mEmitter->volumeTblIndex()); mTypeComboBox.setCurrentEnum(volumeType); - auto& radius = mProps.volumeRadius; + auto& radius = mEmitter->volumeRadius(); mRadiusSpinBox.setVector(radius); mLengthSpinBox.setValue(radius.getZ()); - mSweepStartSpinBox.setValue(Math::Util::to360(Math::Util::idx2deg(mProps.volumeSweepStart))); - mSweepParamSpinBox.setValue(Math::Util::to360(Math::Util::idx2deg(mProps.volumeSweepParam))); + mSweepStartSpinBox.setValue(Math::Util::to360(Math::Util::idx2deg(mEmitter->volumeSweepStart()))); + mSweepParamSpinBox.setValue(Math::Util::to360(Math::Util::idx2deg(mEmitter->volumeSweepParam()))); updateFieldVisibility(volumeType); } -void EmitterWidget::VolumePropertiesWidget::updateFieldVisibility(Ptcl::VolumeType type) { +void VolumeInspector::updateFieldVisibility(Ptcl::VolumeType type) { for (const auto& field : mFields) { bool visible = field.isVisible(type); QWidget* widget = field.widget; diff --git a/src/editor/mainWindow.cpp b/src/editor/mainWindow.cpp index bcedb86..55d742b 100644 --- a/src/editor/mainWindow.cpp +++ b/src/editor/mainWindow.cpp @@ -1,5 +1,4 @@ #include "editor/mainWindow.h" -#include "util/nameValidator.h" #include "util/settingsUtil.h" #include @@ -25,7 +24,6 @@ namespace PtclEditor { MainWindow::MainWindow(QWidget* parent) : QMainWindow{parent} { setupUi(); - setupConnections(); updateRecentFileList(); } @@ -33,57 +31,34 @@ void MainWindow::setupUi() { // MainWindow setAcceptDrops(true); - // Properties - mPropertiesStack = new QStackedWidget(this); - mPropertiesStack->addWidget(&mEmitterSetWidget); - mPropertiesStack->addWidget(&mEmitterWidget); - mPropertiesStack->setCurrentIndex(0); - - mPropertiesGroup.setFlat(false); - auto* emitterGroupLayout = new QVBoxLayout(&mPropertiesGroup); - emitterGroupLayout->setContentsMargins(0, 0, 0, 0); - emitterGroupLayout->addWidget(mPropertiesStack); - - // Project Name - mProjNameLineEdit.setPlaceholderText("PTCLProject"); - mProjNameLineEdit.setValidator(new EmitterNameValidator(&mProjNameLineEdit)); - mProjNameLineEdit.setEnabled(false); - - auto* projectSettingsLayout = new QFormLayout; - projectSettingsLayout->setContentsMargins(0, 0, 0, 0); - projectSettingsLayout->addRow("Project Name:", &mProjNameLineEdit); - - auto* propertiesContainer = new QWidget(this); - auto* propertiesLayout = new QVBoxLayout(propertiesContainer); - propertiesLayout->setContentsMargins(0, 0, 0, 0); - propertiesLayout->setSpacing(4); - - propertiesLayout->addLayout(projectSettingsLayout); - propertiesLayout->addWidget(&mPropertiesGroup); - // Top Splitter mTopSplitter = new QSplitter(Qt::Horizontal, this); mTopSplitter->addWidget(&mPtclList); - mTopSplitter->addWidget(propertiesContainer); + mTopSplitter->addWidget(&mInspector); mTopSplitter->setStretchFactor(0, 0); mTopSplitter->setStretchFactor(1, 1); + // Bottom Container + auto* bottomContainer = new QWidget(this); + auto* bottomLayout = new QHBoxLayout(bottomContainer); + bottomLayout->addWidget(&mUndoView, 0); + bottomLayout->addWidget(&mTextureWidget, 1); + // Bottom Splitter mBottomSplitter = new QSplitter(Qt::Vertical, this); mBottomSplitter->addWidget(mTopSplitter); - mBottomSplitter->addWidget(&mTextureWidget); + mBottomSplitter->addWidget(bottomContainer); mBottomSplitter->setStretchFactor(0, 1); mBottomSplitter->setStretchFactor(1, 0); // Ptcl List mPtclList.setEnabled(false); mPtclList.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + mPtclList.setSelection(&mSelection); - // Emitter Widget - mEmitterWidget.setEnabled(false); - - // EmitterSet Widget - mEmitterSetWidget.setEnabled(false); + // Inspector + mInspector.setEnabled(false); + mInspector.setSelection(&mSelection); // Texture Widget mTextureWidget.setEnabled(false); @@ -91,6 +66,9 @@ void MainWindow::setupUi() { setCentralWidget(mBottomSplitter); setupMenus(); + // Undo View + mUndoView.setEmptyLabel(""); + // StatusBar auto* status = statusBar(); mStatusLabel = new QLabel("No file loaded", status); @@ -103,78 +81,10 @@ void MainWindow::setupUi() { updateWindowTitle(); } -void MainWindow::setupConnections() { - // Proj Name - connect(&mProjNameLineEdit, &QLineEdit::textChanged, this, [this](const QString& text) { - mPtclRes->setName(text); - setDirty(true); - }); - - // Ptcl List - connect(&mPtclList, &PtclList::selectedEmitterSetChanged, this, [this](s32 index) { - selectEmitterSet(index); - setPropertiesView(PropertiesView::EmitterSet); - updatePropertiesStatus(); - }); - - connect(&mPtclList, &PtclList::selectedEmitterChanged, this, [this](s32 setIndex, s32 emitterIndex) { - selectEmitter(setIndex, emitterIndex); - setPropertiesView(PropertiesView::Emitter); - updatePropertiesStatus(); - }); - - connect(&mPtclList, &PtclList::selectedChildData, this, [this](s32 setIndex, s32 emitterIndex) { - selectEmitter(setIndex, emitterIndex); - setPropertiesView(PropertiesView::EmitterChild); - updatePropertiesStatus(); - }); - - connect(&mPtclList, &PtclList::selectedFluctuation, this, [this](s32 setIndex, s32 emitterIndex) { - selectEmitter(setIndex, emitterIndex); - setPropertiesView(PropertiesView::EmitterFlux); - updatePropertiesStatus(); - }); - - connect(&mPtclList, &PtclList::selectedField, this, [this](s32 setIndex, s32 emitterIndex) { - selectEmitter(setIndex, emitterIndex); - setPropertiesView(PropertiesView::EmitterField); - updatePropertiesStatus(); - }); - - connect(&mPtclList, &PtclList::itemAdded, this, [this]() { - setDirty(true); - }); - - connect(&mPtclList, &PtclList::itemRemoved, this, [this]() { - setDirty(true); - }); - - connect(&mEmitterWidget, &EmitterWidget::emitterNameChanged, this, [this]() { - mPtclList.updateEmitterName(mCurEmitterSetIdx, mCurEmitterIdx); - updatePropertiesStatus(); - }); - - connect(&mEmitterWidget, &EmitterWidget::emitterTypeChanged, this, [this]() { - mPtclList.updateEmitter(mCurEmitterSetIdx, mCurEmitterIdx); - }); - - connect(&mEmitterWidget, &EmitterWidget::complexFlagsChanged, this, [this]() { - mPtclList.updateEmitter(mCurEmitterSetIdx, mCurEmitterIdx); - }); - - connect(&mEmitterWidget, &EmitterWidget::propertiesChanged, this, [this]() { - setDirty(true); - }); - - // EmitterSet Widget - connect(&mEmitterSetWidget, &EmitterSetWidget::emitterSetNamedChanged, this, [this]() { - mPtclList.updateEmitterSetName(mCurEmitterSetIdx); - updatePropertiesStatus(); - }); - - connect(&mEmitterSetWidget, &EmitterSetWidget::propertiesChanged, this, [this]() { - setDirty(true); - }); +MainWindow::~MainWindow() { + mPtclList.setDocument(nullptr); + mInspector.setDocument(nullptr); + mTextureWidget.setDocument(nullptr); } void MainWindow::setupMenus() { @@ -198,13 +108,23 @@ void MainWindow::setupMenus() { mSaveAsAction.setEnabled(false); connect(&mSaveAsAction, &QAction::triggered, this, &MainWindow::saveFileAs); + // Undo + mUndoAction = new QAction("Undo", this); + mUndoAction->setShortcut(QKeySequence::Undo); + mUndoAction->setEnabled(false); + + // Redo + mRedoAction = new QAction("Redo", this); + mRedoAction->setShortcut(QKeySequence::Redo); + mRedoAction->setEnabled(false); + // Recent Files Menu mRecentFilesMenu.setTitle("Recent Files"); mRecentFilesMenu.setIcon(QIcon(":/res/icons/recent.png")); // Recent Files Actions - int maxRecentFiles = SettingsUtil::SettingsMgr::instance().maxRecentFiles(); - for (int i = 0; i < maxRecentFiles; ++i) { + s32 maxRecentFiles = SettingsUtil::SettingsMgr::instance().maxRecentFiles(); + for (s32 i = 0; i < maxRecentFiles; ++i) { QAction* recentFileAction = mRecentFilesMenu.addAction(""); recentFileAction->setVisible(false); connect(recentFileAction, &QAction::triggered, this, &MainWindow::openRecentFile); @@ -219,12 +139,18 @@ void MainWindow::setupMenus() { mFileMenu.addSeparator(); mFileMenu.addMenu(&mRecentFilesMenu); + // Edit Menu + mEditMenu.setTitle("Edit"); + mEditMenu.addAction(mUndoAction); + mEditMenu.addAction(mRedoAction); + // Menu Bar menuBar()->addMenu(&mFileMenu); + menuBar()->addMenu(&mEditMenu); } void MainWindow::closeEvent(QCloseEvent* event) { - if (!mPtclRes || !mHasUnsavedChanges) { + if (!mDocument || !mDocument->isDirty()) { auto& settings = SettingsUtil::SettingsMgr::instance(); settings.setWindowGeometry(saveGeometry()); settings.setWindowState(saveState()); @@ -303,26 +229,25 @@ void MainWindow::openFile() { } void MainWindow::saveFile() { - if (!mPtclRes) { + if (!mDocument) { return; } - if (mCurrentFilePath.isEmpty()) { + if (mDocument->filePath().isEmpty()) { saveFileAs(); return; } - mPtclRes->save(mCurrentFilePath); + mDocument->save(mDocument->filePath()); - setDirty(false); statusBar()->showMessage("File Saved", 2000); - SettingsUtil::SettingsMgr::instance().addRecentFile(mCurrentFilePath); + SettingsUtil::SettingsMgr::instance().addRecentFile(mDocument->filePath()); updateRecentFileList(); } void MainWindow::saveFileAs() { - if (!mPtclRes) { + if (!mDocument) { return; } @@ -346,12 +271,11 @@ void MainWindow::saveFileAs() { filePath += ".ptcl"; } - mPtclRes->save(filePath); + mDocument->save(filePath); - setDirty(false); statusBar()->showMessage("File Saved", 2000); - mCurrentFilePath = filePath; + mDocument->filePath() = filePath; SettingsUtil::SettingsMgr::instance().addRecentFile(filePath); SettingsUtil::SettingsMgr::instance().setLastSavePath(QFileInfo(filePath).absolutePath()); updateRecentFileList(); @@ -372,10 +296,10 @@ void MainWindow::openRecentFile() { void MainWindow::updateRecentFileList() { const auto recentFiles = SettingsUtil::SettingsMgr::instance().recentFiles(); - int maxRecentFiles = SettingsUtil::SettingsMgr::instance().maxRecentFiles(); + s32 maxRecentFiles = SettingsUtil::SettingsMgr::instance().maxRecentFiles(); qsizetype numRecentFiles = qMin(recentFiles.size(), maxRecentFiles); - for (int i = 0; i < numRecentFiles; ++i) { + for (s32 i = 0; i < numRecentFiles; ++i) { auto& file = recentFiles[i]; auto& action = mRecentFileActions[i]; @@ -393,198 +317,101 @@ void MainWindow::updateRecentFileList() { } void MainWindow::loadPtclRes(const QString& path) { - mEmitterSetWidget.clear(); - mPtclList.setEnabled(false); - mTextureWidget.setEnabled(false); - mProjNameLineEdit.setEnabled(false); + mPtclList.setDocument(nullptr); + mInspector.setDocument(nullptr); + mTextureWidget.setDocument(nullptr); + mSaveAsAction.setEnabled(false); - mPtclRes = std::make_unique(); - if (!mPtclRes->load(path)) { - mPtclRes.reset(); + mDocument = std::make_unique(); + if (!mDocument->load(path)) { + mDocument.reset(); + bindUndoStack(); return; } - mCurrentFilePath = path; - setDirty(false); + bindUndoStack(); SettingsUtil::SettingsMgr::instance().addRecentFile(path); SettingsUtil::SettingsMgr::instance().setLastOpenPath(QFileInfo(path).absolutePath()); updateRecentFileList(); - mPtclList.setPtclRes(mPtclRes.get()); - mTextureWidget.setTextures(&mPtclRes->textures()); - mEmitterWidget.setTextureList(&mPtclRes->textures()); - - QSignalBlocker b1(mProjNameLineEdit); - mProjNameLineEdit.setText(mPtclRes->name()); + mPtclList.setDocument(mDocument.get()); + mInspector.setDocument(mDocument.get()); + mTextureWidget.setDocument(mDocument.get()); - const auto& sets = mPtclRes->getEmitterSets(); - if (!sets.empty()) { - selectEmitter(0, 0); + if (mDocument->emitterSetCount() != 0) { + mSelection.set(0, 0, Ptcl::Selection::Type::EmitterSet); } updateStatusBar(); updateWindowTitle(); - mPtclList.setEnabled(true); - mTextureWidget.setEnabled(true); - mProjNameLineEdit.setEnabled(true); mSaveAsAction.setEnabled(true); } -void MainWindow::selectEmitterSet(s32 setIndex) { - mCurEmitterSetIdx = setIndex; - mCurEmitterIdx = 0; - - if (!mPtclRes || mCurEmitterIdx < 0 || mCurEmitterIdx < 0) { - return; - } - - const auto& emitterSets = mPtclRes->getEmitterSets(); - if (mCurEmitterSetIdx >= emitterSets.size()) { - return; - } - const auto& emitterSet = emitterSets[mCurEmitterSetIdx]; - - mEmitterSetWidget.setEmitterSet(emitterSet.get()); - - if (!mEmitterSetWidget.isEnabled()) { - mEmitterSetWidget.setEnabled(true); - } -} - -void MainWindow::selectEmitter(s32 setIndex, s32 emitterIndex) { - mCurEmitterSetIdx = setIndex; - mCurEmitterIdx = emitterIndex; - - if (!mPtclRes || mCurEmitterIdx < 0 || mCurEmitterIdx < 0) { - return; - } - - const auto& emitterSets = mPtclRes->getEmitterSets(); - if (mCurEmitterSetIdx >= emitterSets.size()) { - return; - } - const auto& emitterSet = emitterSets[mCurEmitterSetIdx]; - - const auto& emitters = emitterSet->emitters(); - if (mCurEmitterIdx >= emitters.size()) { - return; +void MainWindow::updateWindowTitle() { + QString title = "PTCLTool"; + if (mDocument && !mDocument->filePath().isEmpty()) { + title += " - " + QFileInfo(mDocument->filePath()).fileName(); } - const auto& emitter = emitters[mCurEmitterIdx]; - - mEmitterWidget.setEmitter(emitter.get()); - - if (!mEmitterWidget.isEnabled()) { - mEmitterWidget.setEnabled(true); + if (mDocument && mDocument->isDirty()) { + title += " *"; } + setWindowTitle(title); } -void MainWindow::setPropertiesView(PropertiesView view) { - if (view == mCurPropertiesView) { +void MainWindow::updateStatusBar() { + if (!mStatusLabel) { return; } - mCurPropertiesView = view; - - switch (mCurPropertiesView) { - case PropertiesView::EmitterSet: - mPropertiesStack->setCurrentWidget(&mEmitterSetWidget); - break; - case PropertiesView::Emitter: - mPropertiesStack->setCurrentWidget(&mEmitterWidget); - mEmitterWidget.showStandardEditor(); - break; - case PropertiesView::EmitterChild: - mPropertiesStack->setCurrentWidget(&mEmitterWidget); - mEmitterWidget.showChildEditor(); - break; - case PropertiesView::EmitterFlux: - mPropertiesStack->setCurrentWidget(&mEmitterWidget); - mEmitterWidget.showFluctuationEditor(); - break; - case PropertiesView::EmitterField: - mPropertiesStack->setCurrentWidget(&mEmitterWidget); - mEmitterWidget.showFieldEditor(); - break; + if (!mDocument) { + mStatusLabel->setText("No file loaded"); + } else if (mDocument->isDirty()) { + mStatusLabel->setText("Unsaved changes"); + } else { + mStatusLabel->setText("All changes saved"); } } -void MainWindow::updatePropertiesStatus() { - mPropertiesGroup.setTitle({}); - - if (!mPtclRes || mCurEmitterIdx < 0 || mCurEmitterIdx < 0) { +void MainWindow::bindUndoStack() { + if (!mDocument) { + mUndoAction->setEnabled(false); + mRedoAction->setEnabled(false); return; } - const auto& emitterSets = mPtclRes->getEmitterSets(); - if (mCurEmitterSetIdx >= emitterSets.size()) { - return; - } - const auto& emitterSet = emitterSets[mCurEmitterSetIdx]; + auto* stack = mDocument->undoStack(); - const auto& emitters = emitterSet->emitters(); - if (mCurEmitterIdx >= emitters.size()) { - return; - } - const auto& emitter = emitters[mCurEmitterIdx]; + mUndoAction->disconnect(); + mRedoAction->disconnect(); - QString title = emitterSet->name(); + connect(mUndoAction, &QAction::triggered, stack, &QUndoStack::undo); + connect(mRedoAction, &QAction::triggered, stack, &QUndoStack::redo); - if (mCurPropertiesView != PropertiesView::EmitterSet) { - title += QStringLiteral(" > %1").arg(emitter->name()); - } + connect(stack, &QUndoStack::canUndoChanged, mUndoAction, &QAction::setEnabled); + connect(stack, &QUndoStack::canRedoChanged, mRedoAction, &QAction::setEnabled); - switch (mCurPropertiesView) { - case PropertiesView::EmitterChild: - title += QStringLiteral(" > Child Properties:"); - break; - case PropertiesView::EmitterFlux: - title += QStringLiteral(" > Fluctuation Properties:"); - break; - case PropertiesView::EmitterField: - title += QStringLiteral(" > Field Properties:"); - break; - case PropertiesView::Emitter: - case PropertiesView::EmitterSet: - title += QStringLiteral(" Properties:"); - break; - } - - mPropertiesGroup.setTitle(title); -} + connect(stack, &QUndoStack::undoTextChanged, this, [this](const QString& text) { + mUndoAction->setText(text.isEmpty() ? "Undo" : "Undo " + text); + }); -void MainWindow::updateWindowTitle() { - QString title = "PTCLTool"; - if (!mCurrentFilePath.isEmpty()) { - title += " - " + QFileInfo(mCurrentFilePath).fileName(); - } - if (mHasUnsavedChanges) { - title += " *"; - } - setWindowTitle(title); -} + connect(stack, &QUndoStack::redoTextChanged, this, [this](const QString& text) { + mRedoAction->setText(text.isEmpty() ? "Redo" : "Redo " + text); + }); -void MainWindow::updateStatusBar() { - if (!mStatusLabel) { - return; - } + connect(stack, &QUndoStack::cleanChanged, this, [this](bool clean) { + const bool dirty = !clean; + mSaveAction.setEnabled(dirty); + updateStatusBar(); + updateWindowTitle(); + }); - if (!mPtclRes) { - mStatusLabel->setText("No file loaded"); - } else if (mHasUnsavedChanges) { - mStatusLabel->setText("Unsaved changes"); - } else { - mStatusLabel->setText("All changes saved"); - } -} + mUndoAction->setEnabled(stack->canUndo()); + mRedoAction->setEnabled(stack->canRedo()); -void MainWindow::setDirty(bool dirty) { - mHasUnsavedChanges = dirty; - mSaveAction.setEnabled(dirty); - updateStatusBar(); - updateWindowTitle(); + mUndoView.setStack(stack); } diff --git a/src/editor/ptclListWidget.cpp b/src/editor/ptclListWidget.cpp index 17577c4..43d26cf 100644 --- a/src/editor/ptclListWidget.cpp +++ b/src/editor/ptclListWidget.cpp @@ -172,7 +172,41 @@ PtclList::PtclList(QWidget* parent) : // Tree View mTreeView.setModel(&mProxyModel); mTreeView.setHeaderHidden(true); - connect(mTreeView.selectionModel(), &QItemSelectionModel::selectionChanged, this, &PtclList::selectionChanged); + connect(&mTreeView, &QTreeView::clicked, this, [this](const QModelIndex& proxyIndex) { + const QModelIndex sourceIndex = mProxyModel.mapToSource(proxyIndex); + QStandardItem* item = mListModel.itemFromIndex(sourceIndex); + + if (!item || !mSelection || !mDocument) { + return; + } + + updateToolbarForSelection(item); + + const auto type = static_cast(item->data(sRoleNodeType).toUInt()); + + const s32 setIndex = item->data(sRoleSetIdx).toInt(); + const s32 emitterIndex = item->data(sRoleEmitterIdx).toInt(); + + switch (type) { + case NodeType::EmitterSet: + mSelection->set(setIndex, 0, Ptcl::Selection::Type::EmitterSet); + break; + case NodeType::Emitter: + mSelection->set(setIndex, emitterIndex, Ptcl::Selection::Type::Emitter); + break; + case NodeType::ChildData: + mSelection->set(setIndex, emitterIndex, Ptcl::Selection::Type::EmitterChild); + break; + case NodeType::Fluctuation: + mSelection->set(setIndex, emitterIndex, Ptcl::Selection::Type::EmitterFlux); + break; + case NodeType::Field: + mSelection->set(setIndex, emitterIndex, Ptcl::Selection::Type::EmitterField); + break; + default: + break; + } + }); // Search Layout auto* searchLayout = new QHBoxLayout; @@ -223,14 +257,82 @@ void PtclList::setupFilterMenu() { connect(compactAction, &QAction::toggled, this, updateFilter); } -void PtclList::setPtclRes(Ptcl::PtclRes* ptclRes) { - if (mResPtr == ptclRes) { +void PtclList::setDocument(Ptcl::Document* document) { + if (mDocument) { + mDocument->disconnect(this); + } + + mDocument = document; + + if (!mDocument) { + mListModel.clear(); + setEnabled(false); return; } + connect(mDocument, &Ptcl::Document::emitterAdded, this, [this](s32 setIndex, s32 emitterIndex) { + QStandardItem* setItem = mListModel.item(setIndex); + if (!setItem) { + return; + } + + insertEmitterNode(setItem, setIndex, emitterIndex); + reindexEmitters(setItem, setIndex); + }); + + connect(mDocument, &Ptcl::Document::emitterRemoved, this, [this](s32 setIndex, s32 emitterIndex) { + QStandardItem* setItem = mListModel.item(setIndex); + if (!setItem) { + return; + } + + setItem->removeRow(emitterIndex); + reindexEmitters(setItem, setIndex); + }); + + connect(mDocument, &Ptcl::Document::emitterSetAdded, this, [this](s32 setIndex) { + insertEmitterSetNode(setIndex); + reindexEmitterSets(); + }); + + connect(mDocument, &Ptcl::Document::emitterSetRemoved, this, [this](s32 setIndex) { + mListModel.removeRow(setIndex); + reindexEmitterSets(); + }); + mListModel.clear(); - mResPtr = ptclRes; populateList(); + setEnabled(true); +} + +void PtclList::setSelection(Ptcl::Selection* selection) { + mSelection = selection; + + connect(selection, &Ptcl::Selection::selectionChanged, this, [this](s32 setIndex, s32 emitterIndex, Ptcl::Selection::Type type) { + if (!mDocument) { + return; + } + + QSignalBlocker b(mTreeView.selectionModel()); + + const QStandardItem* item = findItem(setIndex, emitterIndex, type); + if (!item) { + mTreeView.clearSelection(); + return; + } + + const QModelIndex sourceIndex = mListModel.indexFromItem(item); + const QModelIndex proxyIndex = mProxyModel.mapFromSource(sourceIndex); + + if (!proxyIndex.isValid()) { + mTreeView.clearSelection(); + return; + } + + auto* selectionModel = mTreeView.selectionModel(); + selectionModel->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + mTreeView.scrollTo(proxyIndex); + }); } void PtclEditor::PtclList::refresh() { @@ -238,13 +340,13 @@ void PtclEditor::PtclList::refresh() { } void PtclList::populateList() { - if (!mResPtr) { + if (!mDocument) { return; } mListModel.clear(); - const auto& sets = mResPtr->getEmitterSets(); - for (u32 setIndex = 0; setIndex < sets.size(); ++setIndex) { + const auto& sets = mDocument->emitterSets(); + for (s32 setIndex = 0; setIndex < sets.size(); ++setIndex) { insertEmitterSetNode(setIndex); } @@ -253,7 +355,7 @@ void PtclList::populateList() { } void PtclList::insertEmitterSetNode(s32 setIndex) { - const auto& set = mResPtr->getEmitterSets()[setIndex]; + const auto& set = mDocument->emitterSet(setIndex); QString setName = QString("%1: %2").arg(setIndex).arg(set->name()); auto* setItem = new QStandardItem(setName); @@ -263,14 +365,14 @@ void PtclList::insertEmitterSetNode(s32 setIndex) { setItem->setIcon(QIcon(":/res/icons/emitterset.png")); // Emitters - for (u32 emitterIndex = 0; emitterIndex < set->emitters().size(); ++emitterIndex) { + for (s32 emitterIndex = 0; emitterIndex < mDocument->emitterCount(setIndex); ++emitterIndex) { insertEmitterNode(setItem, setIndex, emitterIndex); } mListModel.appendRow(setItem); } void PtclList::insertEmitterNode(QStandardItem* setItem, s32 setIndex, s32 emitterIndex) { - const auto& emitter = mResPtr->getEmitterSets()[setIndex]->emitters()[emitterIndex]; + const auto& emitter = mDocument->emitter(setIndex, emitterIndex); QString emitterName = QString("%1: %2").arg(emitterIndex).arg(emitter->name()); auto* emitterItem = new QStandardItem(emitterName); @@ -292,59 +394,39 @@ void PtclList::filterList(const QString& text) { mProxyModel.setFilterFixedString(text); } -void PtclList::selectionChanged(const QItemSelection& selection) { - if (selection.indexes().isEmpty()) { +void PtclList::selectNearestValidEmitter(s32 setIndex, s32 prefferedEmitter) { + if (!mDocument || !mSelection) { return; } - QModelIndex proxyIndex = selection.indexes().first(); - QModelIndex sourceIndex = mProxyModel.mapToSource(proxyIndex); - QStandardItem* item = mListModel.itemFromIndex(sourceIndex); - - updateToolbarForSelection(item); + const auto& set = mDocument->emitterSet(setIndex); + const s32 count = set ? set->emitterCount() : 0; - if (!item) { + if (count <= 0) { + mSelection->set(setIndex, 0, Ptcl::Selection::Type::EmitterSet); return; } - auto type = static_cast(item->data(sRoleNodeType).toUInt()); + const s32 clamped = std::clamp(prefferedEmitter, 0, count - 1); + mSelection->set(setIndex, clamped, Ptcl::Selection::Type::Emitter); +} - switch (type) { - case NodeType::EmitterSet: { - const u32 setIndex = sourceIndex.row(); - emit selectedEmitterSetChanged(setIndex); - break; - } - case NodeType::Emitter: { - const u32 emitterIndex = sourceIndex.row(); - const u32 setIndex = sourceIndex.parent().row(); - emit selectedEmitterChanged(setIndex, emitterIndex); - break; - } - case NodeType::ChildData: { - const u32 emitterIndex = sourceIndex.parent().row(); - const u32 setIndex = sourceIndex.parent().parent().row(); - emit selectedChildData(setIndex, emitterIndex); - break; - } - case NodeType::Fluctuation: { - const u32 emitterIndex = sourceIndex.parent().row(); - const u32 setIndex = sourceIndex.parent().parent().row(); - emit selectedFluctuation(setIndex, emitterIndex); - break; - } - case NodeType::Field: { - const u32 emitterIndex = sourceIndex.parent().row(); - const u32 setIndex = sourceIndex.parent().parent().row(); - emit selectedField(setIndex, emitterIndex); - break; - } +void PtclList::selectNearestValidEmitterSet(s32 prefferedEmitterSet) { + if (!mDocument || !mSelection) { + return; + } + const s32 count = mDocument->emitterSetCount(); + + if (count <= 0) { + return; } + + const s32 clamped = std::clamp(prefferedEmitterSet, 0, count - 1); + mSelection->set(clamped, 0, Ptcl::Selection::Type::EmitterSet); } void PtclList::addComplexNodes(QStandardItem* emitterItem, s32 setIndex, s32 emitterIndex) { - const auto& emitter = mResPtr->getEmitterSets()[setIndex]->emitters()[emitterIndex]; - const auto& props = emitter->complexProperties(); + const auto& emitter = mDocument->emitter(setIndex, emitterIndex); // ChildData ensureComplexNode( @@ -353,7 +435,7 @@ void PtclList::addComplexNodes(QStandardItem* emitterItem, s32 setIndex, s32 emi "ChildData", setIndex, emitterIndex, - props.childFlags.isSet(Ptcl::ChildFlag::Enabled) + emitter->isChildEnabled() ); // Fluctuation @@ -363,7 +445,7 @@ void PtclList::addComplexNodes(QStandardItem* emitterItem, s32 setIndex, s32 emi "Fluctuation", setIndex, emitterIndex, - props.fluctuationFlags.isSet(Ptcl::FluctuationFlag::Enabled) + emitter->isFluctuationEnabled() ); // Field @@ -373,10 +455,39 @@ void PtclList::addComplexNodes(QStandardItem* emitterItem, s32 setIndex, s32 emi "Field", setIndex, emitterIndex, - props.fieldFlags.isSet(Ptcl::FieldFlag::Enabled) + emitter->isFieldEnabled() ); } +QStandardItem* PtclList::findItem(s32 setIndex, s32 emitterIndex, Ptcl::Selection::Type type) const { + auto* setItem = mListModel.item(setIndex); + if (!setItem) { + return nullptr; + } + + if (type == Ptcl::Selection::Type::EmitterSet) { + return setItem; + } + + auto* emitterItem = setItem->child(emitterIndex); + if (!emitterItem) { + return nullptr; + } + + switch (type) { + case Ptcl::Selection::Type::Emitter: + return emitterItem; + case Ptcl::Selection::Type::EmitterChild: + return findChildByType(emitterItem, NodeType::ChildData); + case Ptcl::Selection::Type::EmitterFlux: + return findChildByType(emitterItem, NodeType::Fluctuation); + case Ptcl::Selection::Type::EmitterField: + return findChildByType(emitterItem, NodeType::Field); + default: + return nullptr; + } +} + QStandardItem* PtclList::findChildByType(QStandardItem* parent, NodeType type) { if (!parent) { return nullptr; @@ -410,51 +521,6 @@ void PtclList::ensureComplexNode(QStandardItem* emitterItem, NodeType type, cons item->setData(enabled, sRoleEnabled); } -void PtclList::selectEmitter(s32 setIndex, s32 emitterIndex) { - const QStandardItem* setItem = mListModel.item(setIndex); - if (!setItem) { - return; - } - - const QStandardItem* emitterItem = setItem->child(emitterIndex); - if (!emitterItem) { - return; - } - - const QModelIndex sourceIndex = mListModel.indexFromItem(emitterItem); - const QModelIndex proxyIndex = mProxyModel.mapFromSource(sourceIndex); - - if (!proxyIndex.isValid()) { - return; - } - - auto* selection = mTreeView.selectionModel(); - - selection->clearSelection(); - selection->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); - mTreeView.scrollTo(proxyIndex); -} - -void PtclList::selectEmitterSet(s32 setIndex) { - const QStandardItem* setItem = mListModel.item(setIndex); - if (!setItem) { - return; - } - - const QModelIndex sourceIndex = mListModel.indexFromItem(setItem); - const QModelIndex proxyIndex = mProxyModel.mapFromSource(sourceIndex); - - if (!proxyIndex.isValid()) { - return; - } - - auto* selection = mTreeView.selectionModel(); - - selection->clearSelection(); - selection->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); - mTreeView.scrollTo(proxyIndex); -} - void PtclList::updateEmitter(s32 setIndex, s32 emitterIndex) { const QStandardItem* setItem = mListModel.item(setIndex); if (!setItem) { @@ -466,7 +532,7 @@ void PtclList::updateEmitter(s32 setIndex, s32 emitterIndex) { return; } - const auto& emitter = mResPtr->getEmitterSets()[setIndex]->emitters()[emitterIndex]; + const auto& emitter = mDocument->emitter(setIndex, emitterIndex); emitterItem->setData(static_cast(emitter->type()), sRoleEmitterType); if (emitter->type() == Ptcl::EmitterType::Simple) { @@ -481,9 +547,7 @@ void PtclList::updateEmitterName(s32 setIndex, s32 emitterIndex) { const QStandardItem* setItem = mListModel.item(setIndex); QStandardItem* emitterItem = setItem->child(emitterIndex); - const auto& sets = mResPtr->getEmitterSets(); - const auto& set = sets[setIndex]; - const auto* emitter = set->emitters()[emitterIndex].get(); + const auto& emitter = mDocument->emitter(setIndex, emitterIndex); QString emitterName = QString("%1: %2").arg(emitterIndex).arg(emitter->name()); emitterItem->setText(emitterName); @@ -492,8 +556,7 @@ void PtclList::updateEmitterName(s32 setIndex, s32 emitterIndex) { void PtclList::updateEmitterSetName(s32 setIndex) { QStandardItem* setItem = mListModel.item(setIndex); - const auto& sets = mResPtr->getEmitterSets(); - const auto& set = sets[setIndex]; + const auto& set = mDocument->emitterSet(setIndex); QString setName = QString("%1: %2").arg(setIndex).arg(set->name()); setItem->setText(setName); @@ -554,13 +617,11 @@ void PtclList::addEmitterSet() { return; } - const s32 setIndex = mResPtr->emitterSetCount(); - mResPtr->addNewEmitterSet(); + const s32 setIndex = mDocument->emitterSetCount(); + mDocument->addEmitterSet("Add New EmitterSet"); - insertEmitterSetNode(setIndex); - selectEmitterSet(setIndex); + mSelection->set(setIndex, 0, Ptcl::Selection::Type::EmitterSet); expandSourceIndex(mListModel.index(setIndex, 0)); - emit itemAdded(); } void PtclList::addEmitter() { @@ -578,16 +639,13 @@ void PtclList::addEmitter() { setItem = item->parent(); } - u32 setIndex = setItem->data(sRoleSetIdx).toUInt(); - auto& emitterSet = mResPtr->getEmitterSets()[setIndex]; + s32 setIndex = setItem->data(sRoleSetIdx).toInt(); + const auto& emitterSet = mDocument->emitterSet(setIndex); const s32 emitterIndex = emitterSet->emitterCount(); - emitterSet->addNewEmitter(); - - insertEmitterNode(setItem, setIndex, emitterIndex); - selectEmitter(setIndex, emitterIndex); + mDocument->addEmitter("Add New Emitter", setIndex); + mSelection->set(setIndex, emitterIndex, Ptcl::Selection::Type::Emitter); expandSourceIndex(mListModel.indexFromItem(setItem)); - emit itemAdded(); } void PtclList::removeItem() { @@ -606,7 +664,6 @@ void PtclList::removeItem() { } else if (type == NodeType::EmitterSet) { removeEmitterSet(item); } - emit itemRemoved(); } @@ -615,26 +672,20 @@ void PtclList::removeEmitter(QStandardItem* setItem, QStandardItem* emitterItem) return; } - const s32 setIndex = setItem->data(sRoleSetIdx).toUInt(); - const s32 emitterIndex = emitterItem->data(sRoleEmitterIdx).toUInt(); + const s32 setIndex = setItem->data(sRoleSetIdx).toInt(); + const s32 emitterIndex = emitterItem->data(sRoleEmitterIdx).toInt(); - const auto& emitterSet = mResPtr->getEmitterSets()[setIndex]; - const auto& emitter = mResPtr->getEmitterSets()[setIndex]->emitters()[emitterIndex]; + const auto& emitterSet = mDocument->emitterSet(setIndex); + const auto& emitter = mDocument->emitter(setIndex, emitterIndex); const auto confirmationMessage = QString("Are you sure you want to remove the Emitter '%1'?").arg(emitter->name()); if (QMessageBox::question(this, "Remove Emitter", confirmationMessage) != QMessageBox::Yes) { return; } - emitterSet->removeEmitter(emitterIndex); - setItem->removeRow(emitterIndex); - reindexEmitters(setItem, setIndex); - - const s32 remainingCount = setItem->rowCount(); - if (remainingCount > 0) { - const s32 nextIndex = std::min(emitterIndex, remainingCount - 1); - selectEmitter(setIndex, nextIndex); - } + const s32 nextPreferred = emitterIndex; + mDocument->removeEmitter(setIndex, emitterIndex); + selectNearestValidEmitter(setIndex, nextPreferred); } void PtclList::removeEmitterSet(QStandardItem* setItem) { @@ -642,24 +693,17 @@ void PtclList::removeEmitterSet(QStandardItem* setItem) { return; } - const s32 setIndex = setItem->data(sRoleSetIdx).toUInt(); - const auto& emitterSet = mResPtr->getEmitterSets()[setIndex]; + const s32 setIndex = setItem->data(sRoleSetIdx).toInt(); + const auto& emitterSet = mDocument->emitterSet(setIndex); const auto confirmationMessage = QString("Are you sure you want to remove the EmitterSet '%1'?").arg(emitterSet->name()); if (QMessageBox::question(this, "Remove EmitterSet", confirmationMessage) != QMessageBox::Yes) { return; } - mResPtr->removeEmitterSet(setIndex); - mListModel.removeRow(setIndex); - reindexEmitterSets(); - - const s32 remainingCount = mListModel.rowCount(); - - if (remainingCount > 0) { - const s32 nextIndex = std::min(setIndex, remainingCount - 1); - selectEmitterSet(nextIndex); - } + const s32 nextPreferred = setIndex; + mDocument->removeEmitterSet(setIndex); + selectNearestValidEmitterSet(nextPreferred); } void PtclList::reindexEmitters(QStandardItem* setItem, s32 setIndex) { @@ -674,7 +718,7 @@ void PtclList::reindexEmitters(QStandardItem* setItem, s32 setIndex) { } emitterItem->setData(i, sRoleEmitterIdx); - const auto& emitter = mResPtr->getEmitterSets()[setIndex]->emitters()[i]; + const auto& emitter = mDocument->emitter(setIndex, i); emitterItem->setText(QString("%1: %2").arg(i).arg(emitter->name())); for (s32 c = 0; c < emitterItem->rowCount(); ++c) { @@ -694,7 +738,7 @@ void PtclList::reindexEmitterSets() { } setItem->setData(i, sRoleSetIdx); - const auto& set = mResPtr->getEmitterSets()[i]; + const auto& set = mDocument->emitterSet(i); setItem->setText(QString("%1: %2").arg(i).arg(set->name())); reindexEmitters(setItem, i); } @@ -721,12 +765,12 @@ void PtclList::copyItem() { mClipboardEmitter.reset(); if (type == NodeType::EmitterSet) { - const s32 setIndex = item->data(sRoleSetIdx).toUInt(); - mClipboardSet = mResPtr->getEmitterSets()[setIndex]->clone(); + const s32 setIndex = item->data(sRoleSetIdx).toInt(); + mClipboardSet = mDocument->emitterSet(setIndex)->clone(); } else if (type == NodeType::Emitter) { - const s32 setIndex = item->parent()->data(sRoleSetIdx).toUInt(); - const s32 emitterIndex = item->data(sRoleEmitterIdx).toUInt(); - mClipboardEmitter = mResPtr->getEmitterSets()[setIndex]->emitters()[emitterIndex]->clone(); + const s32 setIndex = item->parent()->data(sRoleSetIdx).toInt(); + const s32 emitterIndex = item->data(sRoleEmitterIdx).toInt(); + mClipboardEmitter = mDocument->emitter(setIndex, emitterIndex)->clone(); } updateToolbarForSelection(item); @@ -737,32 +781,27 @@ void PtclList::pasteItem() { QModelIndex sourceIndex = mProxyModel.mapToSource(proxyModel); QStandardItem* item = mListModel.itemFromIndex(sourceIndex); - if (!item) { + if (!item || !mDocument || !mSelection) { return; } const auto type = static_cast(item->data(sRoleNodeType).toUInt()); - if (mClipboardSet && type == NodeType::EmitterSet) { - auto& newSet = mResPtr->appendEmitterSet(mClipboardSet); - mClipboardSet = newSet->clone(); + if (mClipboardSet && type == NodeType::EmitterSet) { + mDocument->addEmitterSet("Paste EmitterSet", mClipboardSet->clone()); - const s32 setIndex = mResPtr->emitterSetCount() - 1; - insertEmitterSetNode(setIndex); - selectEmitterSet(setIndex); + const s32 setIndex = mDocument->emitterSetCount() - 1; + mSelection->set(setIndex, 0, Ptcl::Selection::Type::EmitterSet); } else if (mClipboardEmitter && type == NodeType::Emitter) { const auto& setItem = item->parent(); - const s32 setIndex = item->data(sRoleSetIdx).toUInt(); - auto& set = mResPtr->getEmitterSets()[setIndex]; + const s32 setIndex = item->data(sRoleSetIdx).toInt(); + auto set = mDocument->emitterSet(setIndex); - auto& newEmitter = set->appendEmitter(mClipboardEmitter); - mClipboardEmitter = newEmitter->clone(); + mDocument->addEmitter("Paste Emitter", setIndex, mClipboardEmitter->clone()); const s32 emitterIndex = set->emitterCount() - 1; - insertEmitterNode(setItem, setIndex, emitterIndex); - selectEmitter(setIndex, emitterIndex); + mSelection->set(setIndex, emitterIndex, Ptcl::Selection::Type::Emitter); } - } // ========================================================================== // diff --git a/src/editor/textureListWidget.cpp b/src/editor/textureListWidget.cpp index 62e63fe..25b73d3 100644 --- a/src/editor/textureListWidget.cpp +++ b/src/editor/textureListWidget.cpp @@ -83,7 +83,7 @@ QSize TextureItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QM TextureListModel::TextureListModel(QObject* parent) : QAbstractListModel{parent} {} -void TextureListModel::setTextures(Ptcl::TextureList* textures) { +void TextureListModel::setTextures(const Ptcl::TextureList* textures) { beginResetModel(); mTextures = textures; @@ -153,14 +153,39 @@ void TextureListModel::emitRowChangedFor(Ptcl::Texture* texture) { } } +void TextureListModel::onTextureAdded(s32 index) { + if (!mTextures) { + return; + } + + beginInsertRows(QModelIndex(), index, index); + + auto* texture = (*mTextures)[index].get(); + texture->setUserCountCallback([this, texture]() { + emitRowChangedFor(texture); + }); + + endInsertRows(); +} + +void TextureListModel::onTextureRemoved(s32 index) { + if (!mTextures) { + return; + } + + beginRemoveRows(QModelIndex(), index, index); + endRemoveRows(); +} + // ========================================================================== // TextureDetailsPanel::TextureDetailsPanel(QWidget* parent) : QWidget{parent} { mThumbnailWidget.setThumbnailSize({256, 256}); - mExportButton.setText("Export Texture"); - mReplaceButton.setText("Replace Texture"); + mExportButton.setText("Export"); + mReplaceButton.setText("Replace"); + mDeleteButton.setText("Delete"); auto* mainLayout = new QVBoxLayout(this); mainLayout->setContentsMargins(0, 0, 0, 0); @@ -170,6 +195,7 @@ TextureDetailsPanel::TextureDetailsPanel(QWidget* parent) : auto* buttonLayout = new QHBoxLayout; buttonLayout->addWidget(&mExportButton); buttonLayout->addWidget(&mReplaceButton); + buttonLayout->addWidget(&mDeleteButton); mainLayout->addLayout(buttonLayout); mainLayout->addStretch(1); @@ -182,16 +208,24 @@ TextureDetailsPanel::TextureDetailsPanel(QWidget* parent) : connect(&mReplaceButton, &QPushButton::clicked, this, [this](bool checked) { Q_UNUSED(checked); - if (mTexturePtr) { - emit replaceRequested(mTexturePtr); + if (mIndex.isValid()) { + emit replaceRequested(mIndex); + } + }); + + connect(&mDeleteButton, &QPushButton::clicked, this, [this](bool checked) { + Q_UNUSED(checked); + if (mIndex.isValid()) { + emit deleteRequested(mIndex); } }); setEnabled(false); } -void TextureDetailsPanel::setTexture(Ptcl::Texture* texture) { +void TextureDetailsPanel::setTexture(const QModelIndex& index, Ptcl::Texture* texture) { mTexturePtr = texture; + mIndex = index; if (!mTexturePtr) { setEnabled(false); @@ -217,6 +251,7 @@ TextureListWidget::TextureListWidget(QWidget *parent) : connect(&mDetailsPanel, &TextureDetailsPanel::exportRequested, this, &TextureListWidget::exportTexture); connect(&mDetailsPanel, &TextureDetailsPanel::replaceRequested, this, &TextureListWidget::replaceTexture); + connect(&mDetailsPanel, &TextureDetailsPanel::deleteRequested, this, &TextureListWidget::deleteTexture); } void TextureListWidget::setupToolbar() { @@ -257,8 +292,11 @@ void TextureListWidget::setupContextMenu() { menu.addAction("Export", this, [this, texture] { exportTexture(texture); }); - menu.addAction("Replace", this, [this, texture] { - replaceTexture(texture); + menu.addAction("Replace", this, [this, index] { + replaceTexture(index); + }); + menu.addAction("Delete", this, [this, index] { + deleteTexture(index); }); menu.exec(mView.viewport()->mapToGlobal(pos)); @@ -284,30 +322,50 @@ void TextureListWidget::setupSelectionHandling() { if (current.isValid()) { texture = static_cast(current.data(TextureListModel::Roles::TexturePtrRole).value()); } - mDetailsPanel.setTexture(texture); + mDetailsPanel.setTexture(current, texture); }); } -void TextureListWidget::setTextures(Ptcl::TextureList* textures) { - if (mTexturesPtr == textures) { +void TextureListWidget::setDocument(Ptcl::Document* document) { + if (mDocument) { + mDocument->disconnect(this); + } + + mDocument = document; + + if (!mDocument) { + mModel.setTextures(nullptr); + + mActionExportAll->setEnabled(false); + mActionImportTexture->setEnabled(false); + + setEnabled(false); return; } - mTexturesPtr = textures; - mModel.setTextures(textures); + connect(mDocument, &Ptcl::Document::textureChanged, this, [this](s32 index) { + QModelIndex idx = mModel.index(index); + emit mModel.dataChanged(idx, idx); + }); - const bool hasData = (textures != nullptr); - mActionExportAll->setEnabled(hasData); - mActionImportTexture->setEnabled(hasData); -} + connect(mDocument, &Ptcl::Document::textureAdded, this, [this](s32 index) { + mModel.onTextureAdded(index); + }); + + connect(mDocument, &Ptcl::Document::textureRemoved, this, [this](s32 index) { + mModel.onTextureRemoved(index); + }); -void TextureListWidget::clear() { - setTextures(nullptr); - mDetailsPanel.setTexture(nullptr); + mModel.setTextures(&mDocument->textures()); + + mActionExportAll->setEnabled(true); + mActionImportTexture->setEnabled(true); + + setEnabled(true); } void TextureListWidget::exportAll() { - if (!mTexturesPtr) { + if (!mDocument) { return; } @@ -327,8 +385,9 @@ void TextureListWidget::exportAll() { return; } - for (s32 idx = 0; idx < mTexturesPtr->size(); ++idx) { - const auto& texture = (*mTexturesPtr)[idx]; + const auto& textures = mDocument->textures(); + for (s32 idx = 0; idx < textures.size(); ++idx) { + const auto& texture = textures[idx]; texture->textureData().save(QString("%1/tex_%2.png").arg(dirPath).arg(idx)); } @@ -336,7 +395,7 @@ void TextureListWidget::exportAll() { } void TextureListWidget::importTexture() { - if (!mTexturesPtr) { + if (!mDocument) { return; } @@ -360,8 +419,7 @@ void TextureListWidget::importTexture() { dialog.setFilePath(filePath); if (dialog.exec() == QDialog::Accepted) { - mTexturesPtr->push_back(std::move(dialog.getTexture())); - mModel.setTextures(mTexturesPtr); + mDocument->addTexture(dialog.getTexture()); } SettingsUtil::SettingsMgr::instance().setLastImportPath(QFileInfo(filePath).absolutePath()); @@ -397,11 +455,13 @@ void TextureListWidget::exportTexture(Ptcl::Texture* texture) { SettingsUtil::SettingsMgr::instance().setLastExportPath(QFileInfo(filePath).absolutePath()); } -void TextureListWidget::replaceTexture(Ptcl::Texture* texture) { - if (!texture) { +void TextureListWidget::replaceTexture(const QModelIndex& index) { + if (!mDocument || !index.isValid()) { return; } + const s32 textureIndex = index.row(); + QString basePath = SettingsUtil::SettingsMgr::instance().lastImportPath(); if (basePath.isEmpty()) { QString lastOpenPath = SettingsUtil::SettingsMgr::instance().lastOpenPath(); @@ -422,14 +482,20 @@ void TextureListWidget::replaceTexture(Ptcl::Texture* texture) { dialog.setFilePath(filePath); if (dialog.exec() == QDialog::Accepted) { - texture->replaceTexture(*dialog.getTexture()); - mModel.setTextures(mTexturesPtr); - mDetailsPanel.setTexture(texture); + auto newTexture = dialog.getTexture(); + mDocument->replaceTexture(textureIndex, std::move(newTexture)); } SettingsUtil::SettingsMgr::instance().setLastImportPath(QFileInfo(filePath).absolutePath()); +} - texture->textureData().save(filePath); +void TextureListWidget::deleteTexture(const QModelIndex& index) { + if (!mDocument || !index.isValid()) { + return; + } + + const s32 textureIndex = index.row(); + mDocument->removeTexture(textureIndex); } diff --git a/src/ptcl/ptcl.cpp b/src/ptcl/ptcl.cpp index 8c3af77..69171c9 100644 --- a/src/ptcl/ptcl.cpp +++ b/src/ptcl/ptcl.cpp @@ -52,12 +52,12 @@ EmitterSetList PtclBinaryReader::readEmitterSets() { return std::move(setList); } -std::shared_ptr PtclBinaryReader::loadTexture(u32 texturePos, u32 size, u32 width, u32 height, TextureFormat format) { +Texture* PtclBinaryReader::loadTexture(u32 texturePos, u32 size, u32 width, u32 height, TextureFormat format) { const u32 offset = mTextureTblPos + texturePos; auto it = mTextureOffsetMap.find(offset); if (it != mTextureOffsetMap.end()) { - return mTextures[it->second]; + return mTextures[it->second].get(); } mFile.seek(offset); @@ -69,13 +69,13 @@ std::shared_ptr PtclBinaryReader::loadTexture(u32 texturePos, u32 size, qWarning() << "Expected to read" << size << "bytes, got" << bytesRead << "bytes."; } - auto texture = std::make_shared(&textureData, width, height, format); + auto texture = std::make_unique(&textureData, width, height, format); const u32 idx = static_cast(mTextures.size()); - mTextures.push_back(texture); + mTextures.push_back(std::move(texture)); mTextureOffsetMap.emplace(offset, idx); - return texture; + return mTextures.back().get(); } std::unique_ptr PtclBinaryReader::readEmitterSet(s32 index) { @@ -142,9 +142,9 @@ void PtclBinaryReader::readComplexData(Emitter& emitter, const BinCommonEmitterD if (complex.childFlag.isSet(ChildFlag::Enabled)) { BinChildData childData{}; mStream >> childData; - emitter.childData().initFromBinary(childData); + emitter.initChild(childData); - emitter.childData().setTexture( + emitter.setChildTexture( loadTexture( childData.childTexturePos, childData.childTextureSize, @@ -156,38 +156,36 @@ void PtclBinaryReader::readComplexData(Emitter& emitter, const BinCommonEmitterD } // FieldData - Ptcl::FieldData fieldData; if (complex.fieldFlag.isSet(FieldFlag::Random)) { BinFieldRandomData randomData{}; mStream >> randomData; - fieldData.initRandomData(randomData); + emitter.initFieldRandom(randomData); } if (complex.fieldFlag.isSet(FieldFlag::Magnet)) { BinFieldMagnetData magnetData{}; mStream >> magnetData; - fieldData.initMagnetData(magnetData); + emitter.initFieldMagnet(magnetData); } if (complex.fieldFlag.isSet(FieldFlag::Spin)) { BinFieldSpinData spinData{}; mStream >> spinData; - fieldData.initSpinData(spinData); + emitter.initFieldSpin(spinData); } if (complex.fieldFlag.isSet(FieldFlag::Collision)) { BinFieldCollisionData collisionData{}; mStream >> collisionData; - fieldData.initCollisionData(collisionData); + emitter.initFieldCollision(collisionData); } if (complex.fieldFlag.isSet(FieldFlag::Convergence)) { BinFieldConvergenceData convergenceData{}; mStream >> convergenceData; - fieldData.initConvergenceData(convergenceData); + emitter.initFieldConvergence(convergenceData); } if (complex.fieldFlag.isSet(FieldFlag::PosAdd)) { BinFieldPosAddData posAddData{}; mStream >> posAddData; - fieldData.initPosAddData(posAddData); + emitter.initFieldPosAdd(posAddData); } - emitter.setFieldData(fieldData); // FluctuationData if (complex.fluctuationFlag.isSet(FluctuationFlag::Enabled)) { @@ -265,7 +263,7 @@ void PtclBinaryWriter::buildHeader(const PtclRes& res) { constexpr u32 headerBasePos = 0; constexpr u32 emitterSetsBasePos = headerBasePos + sizeof(BinHeaderData); const u32 emitterTblDataBasePos = emitterSetsBasePos + (res.emitterSetCount() * sizeof(BinEmitterSetData)); - const u32 emitterDataBasePos = emitterTblDataBasePos + (res.emitterCount() * sizeof(BinEmitterTblData)); + const u32 emitterDataBasePos = emitterTblDataBasePos + (res.totalEmitterCount() * sizeof(BinEmitterTblData)); mEmitterSetsCurOffset = emitterSetsBasePos; mEmitterTblCurOffset = emitterTblDataBasePos; @@ -276,7 +274,7 @@ void PtclBinaryWriter::buildHeader(const PtclRes& res) { mHeader = { .magic = {'S', 'P', 'B', 'D'}, .version = 11, - .numEmitterSet = res.emitterSetCount(), + .numEmitterSet = static_cast(res.emitterSetCount()), .namePos = appendName(res.name()), .nameTblPos = 0, .textureTblPos = 0, @@ -334,12 +332,12 @@ void PtclBinaryWriter::writeComplexEmitter(const Emitter& emitter) { // Child const bool hasChild = emitterData.childFlag.isSet(ChildFlag::Enabled); - BinChildData childData(emitter.childData()); + BinChildData childData(emitter); emitterData.childDataOffset = emitterDataSize; if (hasChild) { emitterDataSize += sizeof(BinChildData); - childData.childTexturePos = appendTexture(emitter.childData().textureHandle(), childData.childTextureSize); + childData.childTexturePos = appendTexture(emitter.childTextureHandle(), childData.childTextureSize); } // Main Texture @@ -348,7 +346,7 @@ void PtclBinaryWriter::writeComplexEmitter(const Emitter& emitter) { // Field emitterData.fieldDataOffset = emitterDataSize; - const auto& fieldFlags = emitter.complexProperties().fieldFlags; + const auto& fieldFlags = emitter.fieldFlags(); const bool hasRandom = fieldFlags.isSet(FieldFlag::Random); const bool hasMagnet = fieldFlags.isSet(FieldFlag::Magnet); @@ -365,7 +363,7 @@ void PtclBinaryWriter::writeComplexEmitter(const Emitter& emitter) { if (hasPosAdd) { emitterDataSize += sizeof(BinFieldPosAddData); } // Fluctuation - const bool hasFluctuation = emitter.complexProperties().fluctuationFlags.isSet(FluctuationFlag::Enabled); + const bool hasFluctuation = emitter.fluctuationFlags().isSet(FluctuationFlag::Enabled); if (hasFluctuation) { emitterData.fluctuationDataOffset = emitterDataSize; @@ -387,14 +385,14 @@ void PtclBinaryWriter::writeComplexEmitter(const Emitter& emitter) { // Sub-Blocks if (hasChild) { mEmitterData.emplace_back(childData); } - if (hasRandom) { mEmitterData.emplace_back(BinFieldRandomData{emitter.fieldData().randomData()}); } - if (hasMagnet) { mEmitterData.emplace_back(BinFieldMagnetData{emitter.fieldData().magnetData()}); } - if (hasSpin) { mEmitterData.emplace_back(BinFieldSpinData{emitter.fieldData().spinData()}); } - if (hasCollision) { mEmitterData.emplace_back(BinFieldCollisionData{emitter.fieldData().collisionData()}); } - if (hasConvergence) { mEmitterData.emplace_back(BinFieldConvergenceData{emitter.fieldData().convergenceData()}); } - if (hasPosAdd) { mEmitterData.emplace_back(BinFieldPosAddData{emitter.fieldData().posAddData()}); } - if (hasFluctuation) { mEmitterData.emplace_back(BinFluctuationData{emitter.fluctuationData()}); } - if (hasStripe) { mEmitterData.emplace_back(BinStripeData{emitter.stripeData()}); } + if (hasRandom) { mEmitterData.emplace_back(BinFieldRandomData{emitter}); } + if (hasMagnet) { mEmitterData.emplace_back(BinFieldMagnetData{emitter}); } + if (hasSpin) { mEmitterData.emplace_back(BinFieldSpinData{emitter}); } + if (hasCollision) { mEmitterData.emplace_back(BinFieldCollisionData{emitter}); } + if (hasConvergence) { mEmitterData.emplace_back(BinFieldConvergenceData{emitter}); } + if (hasPosAdd) { mEmitterData.emplace_back(BinFieldPosAddData{emitter}); } + if (hasFluctuation) { mEmitterData.emplace_back(BinFluctuationData{emitter}); } + if (hasStripe) { mEmitterData.emplace_back(BinStripeData{emitter}); } } void PtclBinaryWriter::writeFile() { @@ -445,11 +443,19 @@ bool PtclRes::load(const QString& filePath) { return true; } -u32 PtclRes::emitterSetCount() const { +s32 PtclRes::emitterSetCount() const { return mEmitterSets.size(); } -u32 PtclRes::emitterCount() const { +s32 PtclRes::emitterCount(s32 setIndex) const { + if (setIndex < 0 || setIndex >= mEmitterSets.size()) { + return 0; + } + + return mEmitterSets[setIndex]->emitterCount(); +} + +u32 PtclRes::totalEmitterCount() const { u32 count = 0; for (auto& emitterSet : mEmitterSets) { @@ -458,6 +464,10 @@ u32 PtclRes::emitterCount() const { return count; } +s32 PtclRes::textureCount() const { + return mTextures.size(); +} + bool PtclRes::save(const QString& filePath) { PtclBinaryWriter writer(filePath); writer.write(*this); @@ -474,14 +484,56 @@ void PtclRes::setName(const QString& name) { mName = name; } -const EmitterSetList& PtclRes::getEmitterSets() const { +EmitterSetList& PtclRes::getEmitterSets() { return mEmitterSets; } -EmitterSetList& PtclRes::getEmitterSets() { +const EmitterSetList& PtclRes::getEmitterSets() const { return mEmitterSets; } +EmitterSet* PtclRes::emitterSet(s32 index) { + if (index < 0 || index >= mEmitterSets.size()) { + return nullptr; + } + + return mEmitterSets[index].get(); +} + +const EmitterSet* PtclRes::emitterSet(s32 index) const { + if (index < 0 || index >= mEmitterSets.size()) { + return nullptr; + } + + return mEmitterSets[index].get(); +} + +Emitter* PtclRes::emitter(s32 setIndex, s32 emitterIndex) { + if (setIndex < 0 || setIndex >= mEmitterSets.size()) { + return nullptr; + } + + auto& set = mEmitterSets[setIndex]; + if (emitterIndex < 0 || emitterIndex >= set->emitters().size()) { + return nullptr; + } + + return set->emitters()[emitterIndex].get(); +} + +const Emitter* PtclRes::emitter(s32 setIndex, s32 emitterIndex) const { + if (setIndex < 0 || setIndex >= mEmitterSets.size()) { + return nullptr; + } + + auto& set = mEmitterSets[setIndex]; + if (emitterIndex < 0 || emitterIndex >= set->emitters().size()) { + return nullptr; + } + + return set->emitters()[emitterIndex].get(); +} + const TextureList& PtclRes::textures() const { return mTextures; } @@ -490,24 +542,32 @@ TextureList& PtclRes::textures() { return mTextures; } -void PtclRes::addNewEmitterSet() { - auto newSet = std::make_unique(); - newSet->setName("New_EmitterSet_" + QString::number(emitterSetCount())); - newSet->addNewEmitter(); - mEmitterSets.push_back(std::move(newSet)); +void PtclRes::insertEmitterSet(s32 setIndex, std::unique_ptr emitterSet) { + mEmitterSets.insert(mEmitterSets.begin() + setIndex, std::move(emitterSet)); } -void PtclRes::removeEmitterSet(s32 setIndex) { - if (setIndex >= mEmitterSets.size()) { - return; - } +std::unique_ptr PtclRes::removeEmitterSet(s32 setIndex) { + auto it = mEmitterSets.begin() + setIndex; - mEmitterSets.erase(mEmitterSets.begin() + setIndex); + std::unique_ptr removed = std::move(*it); + mEmitterSets.erase(it); + return removed; } -const std::unique_ptr& PtclRes::appendEmitterSet(std::unique_ptr& newSet) { - mEmitterSets.push_back(std::move(newSet)); - return mEmitterSets.at(emitterSetCount() - 1); +void PtclRes::insertTexture(s32 index, std::unique_ptr texture) { + mTextures.insert(mTextures.begin() + index, std::move(texture)); +} + +void PtclRes::swapTexture(s32 index, std::unique_ptr& texture) { + mTextures[index]->swapTexture(*texture); +} + +std::unique_ptr PtclRes::removeTexture(s32 index) { + auto it = mTextures.begin() + index; + + std::unique_ptr removed = std::move(*it); + mTextures.erase(it); + return removed; } diff --git a/src/ptcl/ptclBinary.cpp b/src/ptcl/ptclBinary.cpp index 009e0a8..34f0bfd 100644 --- a/src/ptcl/ptclBinary.cpp +++ b/src/ptcl/ptclBinary.cpp @@ -1,7 +1,6 @@ #include "ptcl/ptclBinary.h" #include "ptcl/ptclEmitter.h" #include "util/printUtil.h" -#include "ptcl/ptclFieldData.h" namespace Ptcl { @@ -312,9 +311,9 @@ void BinTextureRes::printData(u32 indentationLevel) { BinCommonEmitterData::BinCommonEmitterData(const Ptcl::Emitter& emitter) { - type = emitter.basicProperties().type; + type = emitter.type(); flag = emitter.flags(); - randomSeed = emitter.basicProperties().randomSeed.raw(); + randomSeed = emitter.randomSeed().raw(); namePos = 0; // To be assigned after construction... namePtr = 0; @@ -322,83 +321,83 @@ BinCommonEmitterData::BinCommonEmitterData(const Ptcl::Emitter& emitter) { .width = static_cast(emitter.textureHandle()->textureData().width()), .height = static_cast(emitter.textureHandle()->textureData().height()), .format = emitter.textureHandle()->textureFormat(), - .wrapT = emitter.textureProperties().textureWrapT, - .wrapS = emitter.textureProperties().textureWrapS, - .magFilter = emitter.textureProperties().textureMagFilter, - .minMipFilter = static_cast((static_cast(emitter.textureProperties().textureMinFilter) & 0x1) | ((static_cast(emitter.textureProperties().textureMipFilter) & 0x3) << 1)), + .wrapT = emitter.textureWrapT(), + .wrapS = emitter.textureWrapS(), + .magFilter = emitter.textureMagFilter(), + .minMipFilter = static_cast((static_cast(emitter.textureMinFilter()) & 0x1) | ((static_cast(emitter.textureMipFilter()) & 0x3) << 1)), }; textureSize = 0; // To be assigned after construction... texturePos = 0; // To be assigned after construction... textureHandlePtr = 0; - isPolygon = emitter.basicProperties().isPolygon; - isFollow = emitter.basicProperties().isFollow; - isEmitterBillboardMtx = emitter.basicProperties().isEmitterBillboardMtx; - isDirectional = emitter.gravityProperties().isDirectional; - isTexPatAnim = emitter.textureProperties().isTexPatAnim; - isVelLook = emitter.basicProperties().isVelLook; - volumeTblIndex = emitter.volumeProperties().volumeTblIndex; - isStopEmitInFade = emitter.terminationProperties().isStopEmitInFade; - volumeType = emitter.volumeProperties().volumeType; - volumeRadius = emitter.volumeProperties().volumeRadius; - volumeSweepStart = emitter.volumeProperties().volumeSweepStart; - volumeSweepParam = emitter.volumeProperties().volumeSweepParam; - figureVel = emitter.velocityProperties().figureVel; - emitterVelDir = emitter.velocityProperties().emitterVelDir; - initVel = emitter.velocityProperties().initVel; - initVelRnd = emitter.velocityProperties().initVelRnd; - spreadVec = emitter.velocityProperties().spreadVec; - - startFrame = emitter.emissionProperties().startFrame; - endFrame = emitter.emissionProperties().endFrame; - lifeStep = emitter.emissionProperties().lifeStep; - lifeStepRnd = emitter.emissionProperties().lifeStepRnd; - - emitRate = emitter.emissionProperties().emitRate; - ptclLife = emitter.lifespanProperties().ptclLife; - ptclLifeRnd = emitter.lifespanProperties().ptclLifeRnd; - airResistance = emitter.velocityProperties().airResistance; - blendFunc = emitter.combinerProperties().blendFunc; - billboardType = emitter.basicProperties().billboardType; - depthFunc = emitter.combinerProperties().depthFunc; - gravity = emitter.gravityProperties().gravity; - color0 = emitter.colorProperties().color0; - color1 = emitter.colorProperties().color1; - colorSection1 = emitter.colorProperties().colorSection1; - colorSection2 = emitter.colorProperties().colorSection2; - colorSection3 = emitter.colorProperties().colorSection3; - colorNumRepeat = emitter.colorProperties().colorNumRepeat; - initAlpha = emitter.alphaProperties().initAlpha; - diffAlpha21 = emitter.alphaProperties().diffAlpha21; - diffAlpha32 = emitter.alphaProperties().diffAlpha32; - alphaSection1 = emitter.alphaProperties().alphaSection1; - alphaSection2 = emitter.alphaProperties().alphaSection2; - - initScale = emitter.scaleProperties().initScale; - diffScale21 = emitter.scaleProperties().diffScale21; - diffScale32 = emitter.scaleProperties().diffScale32; - scaleSection1 = emitter.scaleProperties().scaleSection1; - scaleSection2 = emitter.scaleProperties().scaleSection2; - scaleRand = emitter.scaleProperties().scaleRand; - - rotCalcType = static_cast(emitter.rotationProperties().rotType) + 5 * static_cast(emitter.colorProperties().colorCalcType); - followType = emitter.basicProperties().followType; - colorCombinerFunc = emitter.combinerProperties().combinerFunc; - initRot = emitter.rotationProperties().initRot; - initRotRand = emitter.rotationProperties().initRotRand; - rotVel = emitter.rotationProperties().rotVel; - rotVelRand = emitter.rotationProperties().rotVelRand; - rotBasis = emitter.rotationProperties().rotBasis; - transformSRT = emitter.transformProperties().transformSRT; - transformRT = emitter.transformProperties().transformRT; - alphaAddInFade = emitter.terminationProperties().alphaAddInFade; - numTexPat = emitter.textureProperties().numTexPat; - numTexDivX = emitter.textureProperties().numTexDivX; - numTexDivY = emitter.textureProperties().numTexDivY; - texUVScale = emitter.textureProperties().texUVScale; - std::copy(emitter.textureProperties().texPatTbl.begin(), emitter.textureProperties().texPatTbl.end(), texPatTbl.data()); - texPatFreq = emitter.textureProperties().texPatFreq; - texPatTblUse = emitter.textureProperties().texPatTblUse; + isPolygon = emitter.isPolygon(); + isFollow = emitter.isFollow(); + isEmitterBillboardMtx = emitter.isEmitterBillboardMtx(); + isDirectional = emitter.isDirectional(); + isTexPatAnim = emitter.isTexturePatternAnim(); + isVelLook = emitter.isVelLook(); + volumeTblIndex = emitter.volumeTblIndex(); + isStopEmitInFade = emitter.isStopEmitInFade(); + volumeType = emitter.volumeType(); + volumeRadius = emitter.volumeRadius(); + volumeSweepStart = emitter.volumeSweepStart(); + volumeSweepParam = emitter.volumeSweepParam(); + figureVel = emitter.figureVelocity(); + emitterVelDir = emitter.velocityDirection(); + initVel = emitter.initialVelocity(); + initVelRnd = emitter.initialVelocityRandom(); + spreadVec = emitter.spreadVector(); + + startFrame = emitter.emitStartFrame(); + endFrame = emitter.emitEndFrame(); + lifeStep = emitter.lifeStep(); + lifeStepRnd = emitter.lifeStepRandom(); + + emitRate = emitter.emitRate(); + ptclLife = emitter.ptclLife(); + ptclLifeRnd = emitter.ptclLifeRandom(); + airResistance = emitter.airResistance(); + blendFunc = emitter.blendFunction(); + billboardType = emitter.billboardType(); + depthFunc = emitter.depthFunction(); + gravity = emitter.gravity(); + color0 = emitter.color0(); + color1 = emitter.secondaryColor(); + colorSection1 = emitter.colorSection1(); + colorSection2 = emitter.colorSection2(); + colorSection3 = emitter.colorSection3(); + colorNumRepeat = emitter.colorNumRepeat(); + initAlpha = emitter.alphaAnim().initAlpha; + diffAlpha21 = emitter.alphaAnim().diffAlpha21; + diffAlpha32 = emitter.alphaAnim().diffAlpha32; + alphaSection1 = emitter.alphaAnim().alphaSection1; + alphaSection2 = emitter.alphaAnim().alphaSection2; + + initScale = emitter.scaleAnim().initScale; + diffScale21 = emitter.scaleAnim().diffScale21; + diffScale32 = emitter.scaleAnim().diffScale32; + scaleSection1 = emitter.scaleAnim().scaleSection1; + scaleSection2 = emitter.scaleAnim().scaleSection2; + scaleRand = emitter.scaleRand(); + + rotCalcType = static_cast(emitter.rotationType()) + 5 * static_cast(emitter.colorCalcType()); + followType = emitter.followType(); + colorCombinerFunc = emitter.combinerFunction(); + initRot = emitter.initialRotation(); + initRotRand = emitter.initialRotationRandom(); + rotVel = emitter.rotationVelocity(); + rotVelRand = emitter.rotationVelocityRandom(); + rotBasis = emitter.rotationBasis(); + transformSRT = emitter.transformSRT(); + transformRT = emitter.transformRT(); + alphaAddInFade = emitter.alphaAddInFade(); + numTexPat = emitter.numTexturePattern(); + numTexDivX = emitter.numTextureDivisionX(); + numTexDivY = emitter.numTextureDivisionY(); + texUVScale = emitter.textureUVScale(); + std::copy(emitter.texturePatternTable().begin(), emitter.texturePatternTable().end(), texPatTbl.data()); + texPatFreq = emitter.texturePatternFrequency(); + texPatTblUse = emitter.texturePatternTableUse(); } QDataStream& operator>>(QDataStream& in, BinCommonEmitterData& item) { @@ -652,10 +651,10 @@ void BinCommonEmitterData::printData(u32 indentationLevel) { BinComplexEmitterData::BinComplexEmitterData(const Ptcl::Emitter& emitter) : BinCommonEmitterData{emitter} { - childFlag = emitter.complexProperties().childFlags; - fieldFlag = emitter.complexProperties().fieldFlags; - fluctuationFlag = emitter.complexProperties().fluctuationFlags; - stripeFlag = emitter.complexProperties().stripeFlags; + childFlag = emitter.childFlags(); + fieldFlag = emitter.fieldFlags(); + fluctuationFlag = emitter.fluctuationFlags(); + stripeFlag = emitter.stripeFlags(); childDataOffset = 0; fieldDataOffset = 0; @@ -709,29 +708,29 @@ void BinComplexEmitterData::printData(u32 indentationLevel) { // ========================================================================== // -BinChildData::BinChildData(const Ptcl::ChildData& childData) { - childEmitRate = childData.emissionProperties().emitRate; - childEmitTiming = childData.emissionProperties().emitTiming; - childLife = childData.emissionProperties().life; - childEmitStep = childData.emissionProperties().emitStep; - childVelInheritRate = childData.velocityProperties().velInheritRate; - childFigurVel = childData.velocityProperties().figurVel; - childRandVel = childData.velocityProperties().randVel; - childInitPosRand = childData.velocityProperties().initPosRand; +BinChildData::BinChildData(const Ptcl::Emitter& emitterData) { + childEmitRate = emitterData.childEmitRate(); + childEmitTiming = emitterData.childEmitTiming(); + childLife = emitterData.childLife(); + childEmitStep = emitterData.childEmitStep(); + childVelInheritRate = emitterData.childVelocityInheritRate(); + childFigurVel = emitterData.childFigureVelocity(); + childRandVel = emitterData.childRandVelocity(); + childInitPosRand = emitterData.childInitalPositionRand(); - childBlendType = childData.combinerProperties().blendFunc; - childBillboardType = childData.basicProperties().billboardType; - childDepthType = childData.combinerProperties().depthFunc; + childBlendType = emitterData.childBlendFunc(); + childBillboardType = emitterData.childBillboardType(); + childDepthType = emitterData.childDepthFunc(); - if (childData.textureHandle().isValid()) { + if (emitterData.childTextureHandle().isValid()) { childTextureRes = { - .width = static_cast(childData.textureHandle()->textureData().width()), - .height = static_cast(childData.textureHandle()->textureData().height()), - .format = childData.textureHandle()->textureFormat(), - .wrapT = childData.textureProperties().textureWrapT, - .wrapS = childData.textureProperties().textureWrapS, - .magFilter = childData.textureProperties().textureMagFilter, - .minMipFilter = static_cast((static_cast(childData.textureProperties().textureMinFilter) & 0x1) | ((static_cast(childData.textureProperties().textureMipFilter) & 0x3) << 1)), + .width = static_cast(emitterData.childTextureHandle()->textureData().width()), + .height = static_cast(emitterData.childTextureHandle()->textureData().height()), + .format = emitterData.childTextureHandle()->textureFormat(), + .wrapT = emitterData.childTextureWrapT(), + .wrapS = emitterData.childTextureWrapS(), + .magFilter = emitterData.childTextureMagFilter(), + .minMipFilter = static_cast((static_cast(emitterData.childTextureMinFilter()) & 0x1) | ((static_cast(emitterData.childTextureMipFilter()) & 0x3) << 1)), }; } else { childTextureRes = {}; @@ -741,28 +740,28 @@ BinChildData::BinChildData(const Ptcl::ChildData& childData) { childTexturePos = 0; // To be assigned after construction... childTextureHandlePtr = 0; - childColor0 = childData.colorProperties().color0; - childColor1 = childData.colorProperties().color1; - childAlpha = childData.alphaProperties().alpha; - childAlphaTarget = childData.alphaProperties().alphaTarget; - childAlphaInit = childData.alphaProperties().alphaInit; - childScaleInheritRate = childData.scaleProperties().scaleInheritRate; - childScale = childData.scaleProperties().scale; - childRotType = childData.rotationProperties().rotType; - childInitRot = childData.rotationProperties().initRot; - childInitRotRand = childData.rotationProperties().initRotRand; - childRotVel = childData.rotationProperties().rotVel; - childRotVelRand = childData.rotationProperties().rotVelRand; - childRotBasis = childData.rotationProperties().rotBasis; - childGravity = childData.velocityProperties().gravity; - childAlphaStartFrame = childData.alphaProperties().alphaStartFrame; - childAlphaBaseFrame = childData.alphaProperties().alphaBaseFrame; - childScaleStartFrame = childData.scaleProperties().scaleStartFrame; - childScaleTarget = childData.scaleProperties().scaleTarget; - childTexUScale = childData.textureProperties().texUVScale.getX(); - childTexVScale = childData.textureProperties().texUVScale.getY(); - childCombinerType = childData.combinerProperties().combinerFunc; - childAirResist = childData.velocityProperties().airResist; + childColor0 = emitterData.childPrimaryColor(); + childColor1 = emitterData.childSecondaryColor(); + childAlpha = emitterData.childAlpha(); + childAlphaTarget = emitterData.childAlphaTarget(); + childAlphaInit = emitterData.childAlphaInit(); + childScaleInheritRate = emitterData.childScaleInheritRate(); + childScale = emitterData.childScale(); + childRotType = emitterData.childRotationType(); + childInitRot = emitterData.childInitialRotation(); + childInitRotRand = emitterData.childInitialRotationRandom(); + childRotVel = emitterData.childRotationVelocity(); + childRotVelRand = emitterData.childRotationVelocityRandom(); + childRotBasis = emitterData.childRotationBasis(); + childGravity = emitterData.childGravity(); + childAlphaStartFrame = emitterData.childAlphaStartFrame(); + childAlphaBaseFrame = emitterData.childAlphaBaseFrame(); + childScaleStartFrame = emitterData.childScaleStartFrame(); + childScaleTarget = emitterData.childScaleTarget(); + childTexUScale = emitterData.childTextureUVScale().getX(); + childTexVScale = emitterData.childTextureUVScale().getY(); + childCombinerType = emitterData.childCombinerFunc(); + childAirResist = emitterData.childAirResistance(); } @@ -852,9 +851,9 @@ QDataStream& operator<<(QDataStream& out, const BinChildData& item) { // ========================================================================== // -BinFieldRandomData::BinFieldRandomData(const Ptcl::FieldData::FieldRandomData& fieldRandomData) { - fieldRandomBlank = fieldRandomData.randomBlank; - fieldRandomVelAdd = fieldRandomData.randomVelAdd; +BinFieldRandomData::BinFieldRandomData(const Ptcl::Emitter& emitterData) { + fieldRandomBlank = emitterData.fieldRandomBlank(); + fieldRandomVelAdd = emitterData.fieldRandomVelAdd(); } QDataStream& operator>>(QDataStream& in, BinFieldRandomData& item) { @@ -873,10 +872,10 @@ QDataStream& operator<<(QDataStream& out, const BinFieldRandomData& item) { // ========================================================================== // -BinFieldMagnetData::BinFieldMagnetData(const Ptcl::FieldData::FieldMagnetData& fieldMagnetData) { - fieldMagnetPower = fieldMagnetData.magnetPower; - fieldMagnetPos = fieldMagnetData.magnetPos; - fieldMagnetFlag = fieldMagnetData.magnetFlag; +BinFieldMagnetData::BinFieldMagnetData(const Ptcl::Emitter& emitterData) { + fieldMagnetPower = emitterData.fieldMagnetPower(); + fieldMagnetPos = emitterData.fieldMagnetPos(); + fieldMagnetFlag = emitterData.fieldMagnetFlag(); } QDataStream& operator>>(QDataStream& in, BinFieldMagnetData& item) { @@ -897,9 +896,9 @@ QDataStream& operator<<(QDataStream& out, const BinFieldMagnetData& item) { // ========================================================================== // -BinFieldSpinData::BinFieldSpinData(const Ptcl::FieldData::FieldSpinData& fieldSpinData) { - fieldSpinRotate = fieldSpinData.spinRotate; - fieldSpinAxis = fieldSpinData.spinAxis; +BinFieldSpinData::BinFieldSpinData(const Ptcl::Emitter& emitterData) { + fieldSpinRotate = emitterData.fieldSpinRotate(); + fieldSpinAxis = emitterData.fieldSpinAxis(); } QDataStream& operator>>(QDataStream& in, BinFieldSpinData& item) { @@ -918,11 +917,11 @@ QDataStream& operator<<(QDataStream& out, const BinFieldSpinData& item) { // ========================================================================== // -BinFieldCollisionData::BinFieldCollisionData(const Ptcl::FieldData::FieldCollisionData& fieldCollisionData) { - fieldCollisionType = fieldCollisionData.collisionType; - fieldCollisionIsWorld = fieldCollisionData.collisionIsWorld; - fieldCollisionCoord = fieldCollisionData.collisionCoord; - fieldCollisionCoef = fieldCollisionData.collisionCoef; +BinFieldCollisionData::BinFieldCollisionData(const Ptcl::Emitter& emitterData) { + fieldCollisionType = emitterData.fieldCollisionType(); + fieldCollisionIsWorld = emitterData.fieldCollisionIsWorld(); + fieldCollisionCoord = emitterData.fieldCollisionCoord(); + fieldCollisionCoef = emitterData.fieldCollisionCoef(); } QDataStream& operator>>(QDataStream& in, BinFieldCollisionData& item) { @@ -945,9 +944,9 @@ QDataStream& operator<<(QDataStream& out, const BinFieldCollisionData& item) { // ========================================================================== // -BinFieldConvergenceData::BinFieldConvergenceData(const Ptcl::FieldData::FieldConvergenceData& fieldConvergenceData) { - fieldConvergenceType = fieldConvergenceData.convergenceType; - fieldConvergencePos = fieldConvergenceData.convergencePos; +BinFieldConvergenceData::BinFieldConvergenceData(const Ptcl::Emitter& emitterData) { + fieldConvergenceType = emitterData.fieldConvergenceType(); + fieldConvergencePos = emitterData.fieldConvergencePos(); } QDataStream& operator>>(QDataStream& in, BinFieldConvergenceData& item) { @@ -966,8 +965,8 @@ QDataStream& operator<<(QDataStream& out, const BinFieldConvergenceData& item) { // ========================================================================== // -BinFieldPosAddData::BinFieldPosAddData(const Ptcl::FieldData::FieldPosAddData& fieldPosAddData) { - fieldPosAdd = fieldPosAddData.posAdd; +BinFieldPosAddData::BinFieldPosAddData(const Ptcl::Emitter& emitterData) { + fieldPosAdd = emitterData.fieldPosAddPosition(); } QDataStream& operator>>(QDataStream& in, BinFieldPosAddData& item) { @@ -984,10 +983,10 @@ QDataStream& operator<<(QDataStream& out, const BinFieldPosAddData& item) { // ========================================================================== // -BinFluctuationData::BinFluctuationData(const Ptcl::FluctuationData& fluctuationData) { - fluctuationScale = fluctuationData.fluctuationScale; - fluctuationFreq = fluctuationData.fluctuationFreq; - fluctuationPhaseRnd = fluctuationData.fluctuationPhaseRnd; +BinFluctuationData::BinFluctuationData(const Ptcl::Emitter& emitterData) { + fluctuationScale = emitterData.fluctuationScale(); + fluctuationFreq = emitterData.fluctuationFrequency(); + fluctuationPhaseRnd = emitterData.isFluctuationPhaseRandom(); } QDataStream& operator>>(QDataStream& in, BinFluctuationData& item) { @@ -1008,14 +1007,14 @@ QDataStream& operator<<(QDataStream& out, const BinFluctuationData& item) { // ========================================================================== // -BinStripeData::BinStripeData(const Ptcl::StripeData& stripeData) { - stripeType = stripeData.type; - stripeNumHistory = stripeData.numHistory; - stripeStartAlpha = stripeData.startAlpha; - stripeEndAlpha = stripeData.endAlpha; - uvScrollSpeed = stripeData.uvScrollSpeed; - stripeHistoryStep = stripeData.historyStep; - stripeDirInterpolate = stripeData.dirInterpolate; +BinStripeData::BinStripeData(const Ptcl::Emitter& emitterData) { + stripeType = emitterData.stripeType(); + stripeNumHistory = emitterData.stripeNumHistory(); + stripeStartAlpha = emitterData.stripeStartAlpha(); + stripeEndAlpha = emitterData.stripeEndAlpha(); + uvScrollSpeed = emitterData.stripeUVScrollSpeed(); + stripeHistoryStep = emitterData.stripeHistoryStep(); + stripeDirInterpolate = emitterData.stripeDirInterpolate(); } QDataStream& operator>>(QDataStream& in, BinStripeData& item) { diff --git a/src/ptcl/ptclChildData.cpp b/src/ptcl/ptclChildData.cpp deleted file mode 100644 index 6a0af1c..0000000 --- a/src/ptcl/ptclChildData.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include "ptcl/ptclChildData.h" - - -namespace Ptcl { - - -// ========================================================================== // - -std::unique_ptr ChildData::clone() const { - auto newData = std::make_unique(); - - newData->mBasicProperties = mBasicProperties; - newData->mEmissionProperties = mEmissionProperties; - newData->mVelocityProperties = mVelocityProperties; - newData->mTextureProperties = mTextureProperties; - newData->mColorProperties = mColorProperties; - newData->mAlphaProperties = mAlphaProperties; - newData->mCombinerProperties = mCombinerProperties; - newData->mRotationProperties = mRotationProperties; - newData->mScaleProperties = mScaleProperties; - newData->mTextureHandle = mTextureHandle.clone(); - return newData; -} - -TextureHandle& ChildData::textureHandle() { - return mTextureHandle; -} - -const TextureHandle& ChildData::textureHandle() const { - return mTextureHandle; -} - -void ChildData::setTexture(const std::shared_ptr& texture) { - mTextureHandle.set(texture); -} - -const ChildData::BasicProperties& ChildData::basicProperties() const { - return mBasicProperties; -} - -void ChildData::setBasicProperties(const BasicProperties& basicProperties) { - mBasicProperties = basicProperties; -} - -const ChildData::EmissionProperties& ChildData::emissionProperties() const { - return mEmissionProperties; -} - -void ChildData::setEmissionProperties(const EmissionProperties& emissionProperties) { - mEmissionProperties = emissionProperties; -} - -const ChildData::VelocityProperties& ChildData::velocityProperties() const { - return mVelocityProperties; -} - -void ChildData::setVelocityProperties(const VelocityProperties& velocityProperties) { - mVelocityProperties = velocityProperties; -} - -const ChildData::TextureProperties& ChildData::textureProperties() const { - return mTextureProperties; -} - -void ChildData::setTextureProperties(const TextureProperties& textureProperties) { - mTextureProperties = textureProperties; -} - -const ChildData::ColorProperties& ChildData::colorProperties() const { - return mColorProperties; -} - -void ChildData::setColorProperties(const ColorProperties& colorProperties) { - mColorProperties = colorProperties; -} - -const ChildData::AlphaProperties& ChildData::alphaProperties() const { - return mAlphaProperties; -} - -void ChildData::setAlphaProperties(const AlphaProperties& alphaProperties) { - mAlphaProperties = alphaProperties; -} - -const ChildData::CombinerProperties& ChildData::combinerProperties() const { - return mCombinerProperties; -} - -void ChildData::setCombinerProperties(const CombinerProperties& combinerProperties) { - mCombinerProperties = combinerProperties; -} - -const ChildData::RotationProperties& ChildData::rotationProperties() const { - return mRotationProperties; -} - -void ChildData::setRotationProperties(const RotationProperties& rotationProperties) { - mRotationProperties = rotationProperties; -} - -const ChildData::ScaleProperties& ChildData::scaleProperties() const { - return mScaleProperties; -} - -void ChildData::setScaleProperties(const ScaleProperties& scaleProperties) { - mScaleProperties = scaleProperties; -} - -void ChildData::initFromBinary(const BinChildData& childData) { - - mBasicProperties = { - .billboardType = childData.childBillboardType - }; - - mEmissionProperties = { - .emitRate = childData.childEmitRate, - .emitTiming = childData.childEmitTiming, - .life = childData.childLife, - .emitStep = childData.childEmitStep - }; - - mVelocityProperties = { - .randVel = { childData.childRandVel.x, childData.childRandVel.y, childData.childRandVel.z }, - .gravity = { childData.childGravity.x, childData.childGravity.y, childData.childGravity.z }, - .velInheritRate = childData.childVelInheritRate, - .initPosRand = childData.childInitPosRand, - .figurVel = childData.childFigurVel, - .airResist = childData.childAirResist - }; - - mRotationProperties = { - .rotType = childData.childRotType, - .initRot = { childData.childInitRot.x, childData.childInitRot.y, childData.childInitRot.z }, - .initRotRand = { childData.childInitRotRand.x, childData.childInitRotRand.y, childData.childInitRotRand.z }, - .rotVel = { childData.childRotVel.x, childData.childRotVel.y, childData.childRotVel.z }, - .rotVelRand = { childData.childRotVelRand.x, childData.childRotVelRand.y, childData.childRotVelRand.z }, - .rotBasis = { childData.childRotBasis.x, childData.childRotBasis.y } - }; - - mScaleProperties = { - .scale = { childData.childScale.x, childData.childScale.y }, - .scaleTarget = { childData.childScaleTarget.x, childData.childScaleTarget.y }, - .scaleInheritRate = childData.childScaleInheritRate, - .scaleStartFrame = childData.childScaleStartFrame - }; - - mTextureProperties = { - .textureWrapT = childData.childTextureRes.wrapT, - .textureWrapS = childData.childTextureRes.wrapS, - .textureMagFilter = childData.childTextureRes.magFilter, - .textureMinFilter = static_cast(childData.childTextureRes.minMipFilter & 0x1), - .textureMipFilter = static_cast((childData.childTextureRes.minMipFilter >> 1) & 0x3), - .texUVScale = { childData.childTexUScale, childData.childTexVScale } - }; - - mColorProperties = { - .color0 = childData.childColor0, - .color1 = childData.childColor1 - }; - - mAlphaProperties = { - .alpha = childData.childAlpha, - .alphaTarget = childData.childAlphaTarget, - .alphaInit = childData.childAlphaInit, - .alphaStartFrame = childData.childAlphaStartFrame, - .alphaBaseFrame = childData.childAlphaBaseFrame - }; - - mCombinerProperties = { - .blendFunc = childData.childBlendType, - .depthFunc = childData.childDepthType, - .combinerFunc = childData.childCombinerType - }; -} - - -// ========================================================================== // - - -} // namespace ptcl diff --git a/src/ptcl/ptclCommand.cpp b/src/ptcl/ptclCommand.cpp new file mode 100644 index 0000000..3eec9eb --- /dev/null +++ b/src/ptcl/ptclCommand.cpp @@ -0,0 +1,25 @@ +#include "ptcl/ptclCommand.h" +#include "ptcl/ptclDocument.h" + +namespace Ptcl { + + +// ========================================================================== // + +template +Emitter& SetEmitterPropertyCommand::getEmitter() const { + return *mDocument->emitter(mSetIndex, mEmitterIndex); +} + +template +void SetEmitterPropertyCommand::apply(const T& value) { + auto& emitter = getEmitter(); + mSetter(emitter, value); + mDocument->notifyEmitterChanged(mSetIndex, mEmitterIndex); +} + + +// ========================================================================== // + + +} // namespace Ptcl diff --git a/src/ptcl/ptclDocument.cpp b/src/ptcl/ptclDocument.cpp new file mode 100644 index 0000000..0b53efa --- /dev/null +++ b/src/ptcl/ptclDocument.cpp @@ -0,0 +1,79 @@ +#include "ptcl/ptclCommand.h" +#include "ptcl/ptclDocument.h" + +#include + + +namespace Ptcl { + + +// ========================================================================== // + + +Selection::Selection(QObject* parent) : + QObject{parent} {} + +void Selection::set(s32 setIndex, s32 emitterIndex, Type type) { + mSetIndex = setIndex; + mEmitterIndex = emitterIndex; + mType = type; + emit selectionChanged(mSetIndex, mEmitterIndex, mType); +} + + +// ========================================================================== // + + +Document::Document(QObject* parent) : + QObject{parent} {} + +bool Document::load(const QString& filePath) { + mFilePath = filePath; + mUndoStack.clear(); + mUndoStack.setClean(); + return mData.load(filePath); +} + +bool Document::save(const QString& filePath) { + mFilePath = filePath; + mUndoStack.setClean(); + return mData.save(filePath); +} + +void Document::setProjectName(const QString& name) { + mUndoStack.push(new RenameProjectNameCommand(this, name)); +} + +void Document::addEmitter(QString label, s32 setIndex, std::unique_ptr emitter) { + mUndoStack.push(new AddEmitterCommand(this, setIndex, std::move(label), std::move(emitter))); +} + +void Document::removeEmitter(s32 setIndex, s32 emitterIndex) { + mUndoStack.push(new RemoveEmitterCommand(this, setIndex, emitterIndex)); +} + +void Document::addEmitterSet(QString label, std::unique_ptr emitterSet) { + mUndoStack.push(new AddEmitterSetCommand(this, std::move(label), std::move(emitterSet))); +} + +void Document::removeEmitterSet(s32 setIndex) { + mUndoStack.push(new RemoveEmitterSetCommand(this, setIndex)); +} + +void Document::addTexture(std::unique_ptr texture) { + mUndoStack.push(new AddTextureCommand(this, std::move(texture))); +} + +void Document::removeTexture(s32 index) { + mUndoStack.push(new RemoveTextureCommand(this, index)); +} + +void Document::replaceTexture(s32 index, std::unique_ptr texture) { + mUndoStack.push(new ReplaceTextureCommand(this, index, std::move(texture))); +} + + +// ========================================================================== // + + +} // namespace Ptcl diff --git a/src/ptcl/ptclEmitter.cpp b/src/ptcl/ptclEmitter.cpp index e7395d9..043a4d9 100644 --- a/src/ptcl/ptclEmitter.cpp +++ b/src/ptcl/ptclEmitter.cpp @@ -6,35 +6,137 @@ namespace Ptcl { // ========================================================================== // +Emitter::Emitter(QString name) : + mName{std::move(name)} {} + std::unique_ptr Emitter::clone() const { auto newEmitter = std::make_unique(); newEmitter->mFlag = mFlag; - newEmitter->mBasicProperties = mBasicProperties; - newEmitter->mGravityProperties = mGravityProperties; - newEmitter->mTransformProperties = mTransformProperties; - newEmitter->mLifespanProperties = mLifespanProperties; - newEmitter->mTerminationProperties = mTerminationProperties; - newEmitter->mEmissionProperties = mEmissionProperties; - newEmitter->mVelocityProperties = mVelocityProperties; - newEmitter->mVolumeProperties = mVolumeProperties; - newEmitter->mColorProperties = mColorProperties; - newEmitter->mAlphaProperties = mAlphaProperties; - newEmitter->mScaleProperties = mScaleProperties; - newEmitter->mRotationProperties = mRotationProperties; - newEmitter->mTextureProperties = mTextureProperties; - newEmitter->mCombinerProperties = mCombinerProperties; - newEmitter->mTextureHandle = mTextureHandle.clone(); - newEmitter->mComplexProperties = mComplexProperties; - newEmitter->mChildData = std::move(*mChildData.clone()); - newEmitter->mFluctuationData = mFluctuationData; - newEmitter->mFieldData = mFieldData; - newEmitter->mStripeData = mStripeData; - return newEmitter; -} -EmitterType Emitter::type() const { - return mBasicProperties.type; + // Basic Properties + newEmitter->mType = mType; + newEmitter->mFollowType = mFollowType; + newEmitter->mName = mName; + newEmitter->mRandomSeed = mRandomSeed; + newEmitter->mBillboardType = mBillboardType; + newEmitter->mIsPolygon = mIsPolygon; + newEmitter->mIsVelLook = mIsVelLook; + newEmitter->mIsEmitterBillboardMtx = mIsEmitterBillboardMtx; + newEmitter->mIsFollow = mIsFollow; + + // Gravity Properties + newEmitter->mIsDirectional = mIsDirectional; + newEmitter->mGravity = mGravity; + + // Lifespan Properties + newEmitter->mPtclLife = mPtclLife; + newEmitter->mPtclLifeRnd = mPtclLifeRnd; + + // Transform Properties + newEmitter->mTransformSRT = mTransformSRT; + newEmitter->mTransformRT = mTransformRT; + + // Termination Properties + newEmitter->mIsStopEmitInFade = mIsStopEmitInFade; + newEmitter->mAlphaAddInFade = mAlphaAddInFade; + + // Emission Properties + newEmitter->mEmitStartFrame = mEmitStartFrame; + newEmitter->mEmitEndFrame = mEmitEndFrame; + newEmitter->mLifeStep = mLifeStep; + newEmitter->mLifeStepRnd = mLifeStepRnd; + newEmitter->mEmitRate = mEmitRate; + + // Velocity Properties + newEmitter->mFigureVelocity = mFigureVelocity; + newEmitter->mVelocityDir = mVelocityDir; + newEmitter->mInitVelocity = mInitVelocity; + newEmitter->mInitVelocityRnd = mInitVelocityRnd; + newEmitter->mSpreadVec = mSpreadVec; + newEmitter->mAirResistance = mAirResistance; + + // Volume Properties + newEmitter->mVolumeTblIndex = mVolumeTblIndex; + newEmitter->mVolumeType = mVolumeType; + newEmitter->mVolumeRadius = mVolumeRadius; + newEmitter->mVolumeSweepStart = mVolumeSweepStart; + newEmitter->mVolumeSweepParam = mVolumeSweepParam; + + // Color Properties + newEmitter->mColor0 = mColor0; + newEmitter->mColorSection1 = mColorSection1; + newEmitter->mColorSection2 = mColorSection2; + newEmitter->mColorSection3 = mColorSection3; + newEmitter->mColorNumRepeat = mColorNumRepeat; + newEmitter->mColorCalcType = mColorCalcType; + newEmitter->mColor1 = mColor1; + + // Alpha Properties + newEmitter->mAlphaAnim = mAlphaAnim; + + // Scale Properties + newEmitter->mScaleAnim = mScaleAnim; + newEmitter->mScaleRand = mScaleRand; + + // Rotation Properties + newEmitter->mRotType = mRotType; + newEmitter->mInitRot = mInitRot; + newEmitter->mInitRotRand = mInitRotRand; + newEmitter->mRotVel = mRotVel; + newEmitter->mRotVelRand = mRotVelRand; + newEmitter->mRotBasis = mRotBasis; + + // Combiner Properties + newEmitter->mBlendFunc = mBlendFunc; + newEmitter->mDepthFunc = mDepthFunc; + newEmitter->mCombinerFunc = mCombinerFunc; + + // Texture Properties + newEmitter->mTextureWrapT = mTextureWrapT; + newEmitter->mTextureWrapS = mTextureWrapS; + newEmitter->mTextureMagFilter = mTextureMagFilter; + newEmitter->mTextureMinFilter = mTextureMinFilter; + newEmitter->mTextureMipFilter = mTextureMipFilter; + newEmitter->mNumTexturePattern = mNumTexturePattern; + newEmitter->mNumTextureDivisionX = mNumTextureDivisionX; + newEmitter->mNumTextureDivisionY = mNumTextureDivisionY; + newEmitter->mTextureUVScale = mTextureUVScale; + newEmitter->mTexturePatternTbl = mTexturePatternTbl; + newEmitter->mTexturePatternFrequency = mTexturePatternFrequency; + newEmitter->mTexturePatternTblUse = mTexturePatternTblUse; + newEmitter->mIsTexturePatternAnim = mIsTexturePatternAnim; + newEmitter->mTextureHandle = mTextureHandle; + + newEmitter->mChildFlags = mChildFlags; + newEmitter->mChild = mChild; + + // Fluctuation Properties + newEmitter->mFluctuationFlags = mFluctuationFlags; + newEmitter->mFluctuationScale = mFluctuationScale; + newEmitter->mFluctuationFreq = mFluctuationFreq; + newEmitter->mFluctuationPhaseRnd = mFluctuationPhaseRnd; + + // Stripe Properties + newEmitter->mStripeFlags = mStripeFlags; + newEmitter->mStripeType = mStripeType; + newEmitter->mStripeNumHistory = mStripeNumHistory; + newEmitter->mStripeStartAlpha = mStripeStartAlpha; + newEmitter->mStripeEndAlpha = mStripeEndAlpha; + newEmitter->mStripeUVScrollSpeed = mStripeUVScrollSpeed; + newEmitter->mStripeHistoryStep = mStripeHistoryStep; + newEmitter->mStripeDirInterpolate = mStripeDirInterpolate; + + // Field Properties + newEmitter->mFieldFlags = mFieldFlags; + newEmitter->mFieldRandom = mFieldRandom; + newEmitter->mFieldMagnet = mFieldMagnet; + newEmitter->mFieldSpin = mFieldSpin; + newEmitter->mFieldCollision = mFieldCollision; + newEmitter->mFieldConvergence = mFieldConvergence; + newEmitter->mFieldPosAdd = mFieldPosAdd; + + return newEmitter; } BitFlag& Emitter::flags() { @@ -45,317 +147,200 @@ const BitFlag& Emitter::flags() const { return mFlag; } -const QString& Emitter::name() const { - return mBasicProperties.name; -} - -void Emitter::setName(const QString& name) { - mBasicProperties.name = name; -} - -const TextureHandle& Emitter::textureHandle() const { - return mTextureHandle; -} - -TextureHandle& Emitter::textureHandle() { - return mTextureHandle; -} - -void Emitter::setTexture(const std::shared_ptr& texture) { - mTextureHandle.set(texture); -} - -const Emitter::BasicProperties& Emitter::basicProperties() const { - return mBasicProperties; -} - -void Emitter::setBasicProperties(const BasicProperties& basicProperties) { - mBasicProperties = basicProperties; -} - -const Emitter::GravityProperties& Emitter::gravityProperties() const { - return mGravityProperties; -} - -void Emitter::setGravityProperties(const GravityProperties& gravityProperties) { - mGravityProperties = gravityProperties; -} - -const Emitter::TransformProperties& Emitter::transformProperties() const { - return mTransformProperties; -} - -void Emitter::setTransformProperties(const TransformProperties& transformProperties) { - mTransformProperties = transformProperties; -} - -const Emitter::LifespanProperties& Emitter::lifespanProperties() const { - return mLifespanProperties; -} - -void Emitter::setLifespanProperties(const LifespanProperties& lifespanProperties) { - mLifespanProperties = lifespanProperties; -} - -const Emitter::TerminationProperties& Emitter::terminationProperties() const { - return mTerminationProperties; -} - -void Emitter::setTerminationProperties(const TerminationProperties& terminationProperties) { - mTerminationProperties = terminationProperties; -} - -const Emitter::EmissionProperties& Emitter::emissionProperties() const { - return mEmissionProperties; -} - -void Emitter::setEmissionProperties(const EmissionProperties& emissionProperties) { - mEmissionProperties = emissionProperties; -} - -const Emitter::VelocityProperties& Emitter::velocityProperties() const { - return mVelocityProperties; -} - -void Emitter::setVelocityProperties(const VelocityProperties& velocityProperties) { - mVelocityProperties = velocityProperties; -} - -const Emitter::VolumeProperties& Emitter::volumeProperties() const { - return mVolumeProperties; -} - -void Emitter::setVolumeProperties(const VolumeProperties& volumeProperties) { - mVolumeProperties = volumeProperties; -} - -const Emitter::ColorProperties& Emitter::colorProperties() const { - return mColorProperties; -} - -void Emitter::setColorProperties(const ColorProperties& colorProperties) { - mColorProperties = colorProperties; - // Sync color flags with mFlag - mFlag.set(EmitterFlag::ColorRandom, mColorProperties.colorRandom); - mFlag.set(EmitterFlag::ColorAnimation, mColorProperties.colorAnimation); -} - -const Emitter::AlphaProperties& Emitter::alphaProperties() const { - return mAlphaProperties; -} - -void Emitter::setAlphaProperties(const AlphaProperties& alphaProperties) { - mAlphaProperties = alphaProperties; -} - -const Emitter::ScaleProperties& Emitter::scaleProperties() const { - return mScaleProperties; -} - -void Emitter::setScaleProperties(const ScaleProperties& scaleProperties) { - mScaleProperties = scaleProperties; -} - -const Emitter::TextureProperties& Emitter::textureProperties() const { - return mTextureProperties; -} - -void Emitter::setTextureProperties(const TextureProperties& textureProperties) { - mTextureProperties = textureProperties; -} - -const Emitter::RotationProperties& Emitter::rotationProperties() const { - return mRotationProperties; -} - -void Emitter::setRotationProperties(const RotationProperties& rotationProperties) { - mRotationProperties = rotationProperties; -} - -const Emitter::CombinerProperties& Emitter::combinerProperties() const { - return mCombinerProperties; -} - -void Emitter::setCombinerProperties(const CombinerProperties& combinerProperties) { - mCombinerProperties = combinerProperties; - mFlag.set(EmitterFlag::EnableFog, mCombinerProperties.isFogEnabled); -} - -const Emitter::ComplexProperties& Emitter::complexProperties() const { - return mComplexProperties; -} - -void Emitter::setComplexProperties(const ComplexProperties& complexProperties) { - mComplexProperties = complexProperties; -} - -void Emitter::setChildFlags(const BitFlag& childFlags) { - mComplexProperties.childFlags = childFlags; -} - -void Emitter::setFluctuationFlags(const BitFlag& fluxFlags) { - mComplexProperties.fluctuationFlags = fluxFlags; -} - -void Emitter::setFieldFlags(const BitFlag& fieldFlags) { - mComplexProperties.fieldFlags = fieldFlags; -} - -void Emitter::setStripeFlags(const BitFlag& stripeFlags) { - mComplexProperties.stripeFlags = stripeFlags; -} - -const ChildData& Emitter::childData() const { - return mChildData; -} - -ChildData& Emitter::childData() { - return mChildData; -} - -const FluctuationData& Emitter::fluctuationData() const { - return mFluctuationData; -} - -void Emitter::setFluctuationData(const FluctuationData& fluctuationData) { - mFluctuationData = fluctuationData; +void Emitter::initFieldRandom(const BinFieldRandomData& randomData) { + mFieldRandom = { + .randomBlank = randomData.fieldRandomBlank, + .randomVelAdd = Math::Vector3f(randomData.fieldRandomVelAdd.x, randomData.fieldRandomVelAdd.y, randomData.fieldRandomVelAdd.z) + }; } -void Emitter::initFluctuationData(const BinFluctuationData& fluctuationData) { - mFluctuationData = { - .fluctuationScale = fluctuationData.fluctuationScale, - .fluctuationFreq = fluctuationData.fluctuationFreq, - .fluctuationPhaseRnd = static_cast(fluctuationData.fluctuationPhaseRnd) +void Emitter::initFieldMagnet(const BinFieldMagnetData& magnetData) { + mFieldMagnet = { + .magnetPower = magnetData.fieldMagnetPower, + .magnetPos = Math::Vector3f(magnetData.fieldMagnetPos.x, magnetData.fieldMagnetPos.y, magnetData.fieldMagnetPos.z), + .magnetFlag = magnetData.fieldMagnetFlag, }; } -const FieldData& Emitter::fieldData() const { - return mFieldData; +void Emitter::initFieldSpin(const BinFieldSpinData& spinData) { + mFieldSpin = { + .spinRotate = spinData.fieldSpinRotate, + .spinAxis = spinData.fieldSpinAxis + }; } -FieldData& Emitter::fieldData() { - return mFieldData; +void Emitter::initFieldCollision(const BinFieldCollisionData& collisionData) { + mFieldCollision = { + .collisionType = collisionData.fieldCollisionType, + .collisionIsWorld = collisionData.fieldCollisionIsWorld > 0, + .collisionCoord = collisionData.fieldCollisionCoord, + .collisionCoef = collisionData.fieldCollisionCoef + }; } -void Emitter::setFieldData(const FieldData& fieldData) { - mFieldData = fieldData; +void Emitter::initFieldConvergence(const BinFieldConvergenceData& convergenceData) { + mFieldConvergence = { + .convergenceType = convergenceData.fieldConvergenceType, + .convergencePos = Math::Vector3f(convergenceData.fieldConvergencePos.x, convergenceData.fieldConvergencePos.y, convergenceData.fieldConvergencePos.z) + }; } -const StripeData& Emitter::stripeData() const { - return mStripeData; +void Emitter::initFieldPosAdd(const BinFieldPosAddData& posAddData) { + mFieldPosAdd = { + .posAdd = Math::Vector3f(posAddData.fieldPosAdd.x, posAddData.fieldPosAdd.y, posAddData.fieldPosAdd.z) + }; } -void Emitter::setStripeData(const StripeData& stripeData) { - mStripeData = stripeData; +void Emitter::initFluctuationData(const BinFluctuationData& fluctuationData) { + mFluctuationScale = fluctuationData.fluctuationScale; + mFluctuationFreq = fluctuationData.fluctuationFreq; + mFluctuationPhaseRnd = static_cast(fluctuationData.fluctuationPhaseRnd); } void Emitter::initStripeData(const BinStripeData& stripeData) { - mStripeData = { - .type = stripeData.stripeType, - .numHistory = stripeData.stripeNumHistory, - .startAlpha = stripeData.stripeStartAlpha, - .endAlpha = stripeData.stripeEndAlpha, - .uvScrollSpeed = {stripeData.uvScrollSpeed.x, stripeData.uvScrollSpeed.y}, - .historyStep = stripeData.stripeHistoryStep, - .dirInterpolate = stripeData.stripeDirInterpolate + mStripeType = stripeData.stripeType; + mStripeNumHistory = stripeData.stripeNumHistory; + mStripeStartAlpha = stripeData.stripeStartAlpha; + mStripeEndAlpha = stripeData.stripeEndAlpha; + mStripeUVScrollSpeed = {stripeData.uvScrollSpeed.x, stripeData.uvScrollSpeed.y}; + mStripeHistoryStep = stripeData.stripeHistoryStep; + mStripeDirInterpolate = stripeData.stripeDirInterpolate; +} + +void Emitter::initChild(const BinChildData& childData) { + mChild = { + .billboardType = childData.childBillboardType, + + .emitRate = childData.childEmitRate, + .emitTiming = childData.childEmitTiming, + .life = childData.childLife, + .emitStep = childData.childEmitStep, + + .randVel = { childData.childRandVel.x, childData.childRandVel.y, childData.childRandVel.z }, + .gravity = { childData.childGravity.x, childData.childGravity.y, childData.childGravity.z }, + .velInheritRate = childData.childVelInheritRate, + .initPosRand = childData.childInitPosRand, + .figurVel = childData.childFigurVel, + .airResist = childData.childAirResist, + + .rotType = childData.childRotType, + .initRot = { childData.childInitRot.x, childData.childInitRot.y, childData.childInitRot.z }, + .initRotRand = { childData.childInitRotRand.x, childData.childInitRotRand.y, childData.childInitRotRand.z }, + .rotVel = { childData.childRotVel.x, childData.childRotVel.y, childData.childRotVel.z }, + .rotVelRand = { childData.childRotVelRand.x, childData.childRotVelRand.y, childData.childRotVelRand.z }, + .rotBasis = { childData.childRotBasis.x, childData.childRotBasis.y }, + + .scale = { childData.childScale.x, childData.childScale.y }, + .scaleTarget = { childData.childScaleTarget.x, childData.childScaleTarget.y }, + .scaleInheritRate = childData.childScaleInheritRate, + .scaleStartFrame = childData.childScaleStartFrame, + + .textureWrapT = childData.childTextureRes.wrapT, + .textureWrapS = childData.childTextureRes.wrapS, + .textureMagFilter = childData.childTextureRes.magFilter, + .textureMinFilter = static_cast(childData.childTextureRes.minMipFilter & 0x1), + .textureMipFilter = static_cast((childData.childTextureRes.minMipFilter >> 1) & 0x3), + .texUVScale = { childData.childTexUScale, childData.childTexVScale }, + + .color0 = childData.childColor0, + .color1 = childData.childColor1, + + .alpha = childData.childAlpha, + .alphaTarget = childData.childAlphaTarget, + .alphaInit = childData.childAlphaInit, + .alphaStartFrame = childData.childAlphaStartFrame, + .alphaBaseFrame = childData.childAlphaBaseFrame, + + .blendFunc = childData.childBlendType, + .depthFunc = childData.childDepthType, + .combinerFunc = childData.childCombinerType }; } bool Emitter::hasStripeData() const { - const auto bType = mBasicProperties.billboardType; + const auto bType = mBillboardType; const bool isBillboardStripe = bType == BillboardType::Stripe || bType == BillboardType::ComplexStripe; - return mBasicProperties.type != EmitterType::Simple && isBillboardStripe; + return mType != EmitterType::Simple && isBillboardStripe; } void Emitter::initFromBinary(const BinCommonEmitterData& emitterData) { mFlag = emitterData.flag; - mTextureProperties = { - .textureWrapT = emitterData.textureRes.wrapT, - .textureWrapS = emitterData.textureRes.wrapS, - .textureMagFilter = emitterData.textureRes.magFilter, - .textureMinFilter = static_cast(emitterData.textureRes.minMipFilter & 0x1), - .textureMipFilter = static_cast((emitterData.textureRes.minMipFilter >> 1) & 0x3), - .numTexPat = emitterData.numTexPat, - .numTexDivX = emitterData.numTexDivX, - .numTexDivY = emitterData.numTexDivY, - .texUVScale = { emitterData.texUVScale.x, emitterData.texUVScale.y }, - .texPatTbl = emitterData.texPatTbl, - .texPatFreq = emitterData.texPatFreq, - .texPatTblUse = emitterData.texPatTblUse, - .isTexPatAnim = emitterData.isTexPatAnim - }; - - mBasicProperties = { - .type = emitterData.type, - .followType = emitterData.followType, - // name - must be set after initialization - .randomSeed = PtclSeed{emitterData.randomSeed}, - .billboardType = emitterData.billboardType, - .isPolygon = emitterData.isPolygon, - .isVelLook = emitterData.isVelLook, - .isEmitterBillboardMtx = emitterData.isEmitterBillboardMtx, - .isFollow = emitterData.isFollow - }; - - mGravityProperties = { - .isDirectional = emitterData.isDirectional, - .gravity = Math::Vector3f(emitterData.gravity.x, emitterData.gravity.y, emitterData.gravity.z) - }; - - mTransformProperties = { - .transformSRT = emitterData.transformSRT.toMatrix34f(), - .transformRT = emitterData.transformRT.toMatrix34f() - }; - - mLifespanProperties = { - .ptclLife = emitterData.ptclLife, - .ptclLifeRnd = emitterData.ptclLifeRnd - }; - - mTerminationProperties = { - .isStopEmitInFade = emitterData.isStopEmitInFade, - .alphaAddInFade = emitterData.alphaAddInFade - }; - - mEmissionProperties = { - .startFrame = emitterData.startFrame, - .endFrame = emitterData.endFrame, - .lifeStep = emitterData.lifeStep, - .lifeStepRnd = emitterData.lifeStepRnd, - .emitRate = emitterData.emitRate - }; - - mVelocityProperties = { - .figureVel = emitterData.figureVel, - .emitterVelDir = Math::Vector3f(emitterData.emitterVelDir.x, emitterData.emitterVelDir.y, emitterData.emitterVelDir.z), - .initVel = emitterData.initVel, - .initVelRnd = emitterData.initVelRnd, - .spreadVec = Math::Vector3f(emitterData.spreadVec.x, emitterData.spreadVec.y, emitterData.spreadVec.z), - .airResistance = emitterData.airResistance - }; - - mVolumeProperties = { - .volumeTblIndex = emitterData.volumeTblIndex, - .volumeType = emitterData.volumeType, - .volumeRadius = Math::Vector3f(emitterData.volumeRadius.x, emitterData.volumeRadius.y, emitterData.volumeRadius.z), - .volumeSweepStart = emitterData.volumeSweepStart, - .volumeSweepParam = emitterData.volumeSweepParam, - }; - - mColorProperties = { - .color0 = emitterData.color0, - .colorSection1 = emitterData.colorSection1, - .colorSection2 = emitterData.colorSection2, - .colorSection3 = emitterData.colorSection3, - .colorNumRepeat = emitterData.colorNumRepeat, - .colorRandom = emitterData.flag.isSet(EmitterFlag::ColorRandom), - .colorAnimation = emitterData.flag.isSet(EmitterFlag::ColorAnimation), - .colorCalcType = static_cast(emitterData.rotCalcType / 5), - .color1 = emitterData.color1 - }; - - mAlphaProperties = { + // Texture Properties + mTextureWrapT = emitterData.textureRes.wrapT; + mTextureWrapS = emitterData.textureRes.wrapS; + mTextureMagFilter = emitterData.textureRes.magFilter; + mTextureMinFilter = static_cast(emitterData.textureRes.minMipFilter & 0x1); + mTextureMipFilter = static_cast((emitterData.textureRes.minMipFilter >> 1) & 0x3); + mNumTexturePattern = emitterData.numTexPat; + mNumTextureDivisionX = emitterData.numTexDivX; + mNumTextureDivisionY = emitterData.numTexDivY; + mTextureUVScale = { emitterData.texUVScale.x, emitterData.texUVScale.y }; + mTexturePatternTbl = emitterData.texPatTbl; + mTexturePatternFrequency = emitterData.texPatFreq; + mTexturePatternTblUse = emitterData.texPatTblUse; + mIsTexturePatternAnim = emitterData.isTexPatAnim; + + // Basic Properties + mType = emitterData.type; + mFollowType = emitterData.followType; + // name - must be set after initialization + mRandomSeed = PtclSeed{emitterData.randomSeed}; + mBillboardType = emitterData.billboardType; + mIsPolygon = emitterData.isPolygon; + mIsVelLook = emitterData.isVelLook; + mIsEmitterBillboardMtx = emitterData.isEmitterBillboardMtx; + mIsFollow = emitterData.isFollow; + + // Gravity Properties + mIsDirectional = emitterData.isDirectional; + mGravity = Math::Vector3f(emitterData.gravity.x, emitterData.gravity.y, emitterData.gravity.z); + + // Lifespan Properties + mPtclLife = emitterData.ptclLife; + mPtclLifeRnd = emitterData.ptclLifeRnd; + + // Transform Properties + mTransformSRT = emitterData.transformSRT.toMatrix34f(); + mTransformRT = emitterData.transformRT.toMatrix34f(); + + // Termination Properties + mIsStopEmitInFade = emitterData.isStopEmitInFade; + mAlphaAddInFade = emitterData.alphaAddInFade; + + // Emission Properties + mEmitStartFrame = emitterData.startFrame; + mEmitEndFrame = emitterData.endFrame; + mLifeStep = emitterData.lifeStep; + mLifeStepRnd = emitterData.lifeStepRnd; + mEmitRate = emitterData.emitRate; + + // Velocity Properties + mFigureVelocity = emitterData.figureVel; + mVelocityDir = Math::Vector3f(emitterData.emitterVelDir.x, emitterData.emitterVelDir.y, emitterData.emitterVelDir.z); + mInitVelocity = emitterData.initVel; + mInitVelocityRnd = emitterData.initVelRnd; + mSpreadVec = Math::Vector3f(emitterData.spreadVec.x, emitterData.spreadVec.y, emitterData.spreadVec.z); + mAirResistance = emitterData.airResistance; + + // Volume Properties + mVolumeTblIndex = emitterData.volumeTblIndex; + mVolumeType = emitterData.volumeType; + mVolumeRadius = Math::Vector3f(emitterData.volumeRadius.x, emitterData.volumeRadius.y, emitterData.volumeRadius.z); + mVolumeSweepStart = emitterData.volumeSweepStart; + mVolumeSweepParam = emitterData.volumeSweepParam; + + // Color Properties + mColor0 = emitterData.color0; + mColorSection1 = emitterData.colorSection1; + mColorSection2 = emitterData.colorSection2; + mColorSection3 = emitterData.colorSection3; + mColorNumRepeat = emitterData.colorNumRepeat; + mColorCalcType = static_cast(emitterData.rotCalcType / 5); + mColor1 = emitterData.color1; + + // Alpha Properties + mAlphaAnim = { .initAlpha = emitterData.initAlpha, .diffAlpha21 = emitterData.diffAlpha21, .diffAlpha32 = emitterData.diffAlpha32, @@ -363,39 +348,36 @@ void Emitter::initFromBinary(const BinCommonEmitterData& emitterData) { .alphaSection2 = emitterData.alphaSection2, }; - mScaleProperties = { + // Scale Properties + mScaleAnim = { .initScale = Math::Vector2f(emitterData.initScale.x, emitterData.initScale.y), .diffScale21 = Math::Vector2f(emitterData.diffScale21.x, emitterData.diffScale21.y), .diffScale32 = Math::Vector2f(emitterData.diffScale32.x, emitterData.diffScale32.y), .scaleSection1 = emitterData.scaleSection1, .scaleSection2 = emitterData.scaleSection2, - .scaleRand = emitterData.scaleRand }; - mRotationProperties = { - .rotType = static_cast(emitterData.rotCalcType % 5), - .initRot = Math::Vector3i(emitterData.initRot.x, emitterData.initRot.y, emitterData.initRot.z), - .initRotRand = Math::Vector3i(emitterData.initRotRand.x, emitterData.initRotRand.y, emitterData.initRotRand.z), - .rotVel = Math::Vector3i(emitterData.rotVel.x, emitterData.rotVel.y, emitterData.rotVel.z), - .rotVelRand = Math::Vector3i(emitterData.rotVelRand.x, emitterData.rotVelRand.y, emitterData.rotVelRand.z), - .rotBasis = Math::Vector2f(emitterData.rotBasis.x, emitterData.rotBasis.y) - }; + mScaleRand = emitterData.scaleRand; - mCombinerProperties = { - .blendFunc = emitterData.blendFunc, - .depthFunc = emitterData.depthFunc, - .combinerFunc = emitterData.colorCombinerFunc, - .isFogEnabled = emitterData.flag.isSet(EmitterFlag::EnableFog) - }; + // Rotation Properties + mRotType = static_cast(emitterData.rotCalcType % 5); + mInitRot = Math::Vector3i(emitterData.initRot.x, emitterData.initRot.y, emitterData.initRot.z); + mInitRotRand = Math::Vector3i(emitterData.initRotRand.x, emitterData.initRotRand.y, emitterData.initRotRand.z); + mRotVel = Math::Vector3i(emitterData.rotVel.x, emitterData.rotVel.y, emitterData.rotVel.z); + mRotVelRand = Math::Vector3i(emitterData.rotVelRand.x, emitterData.rotVelRand.y, emitterData.rotVelRand.z); + mRotBasis = Math::Vector2f(emitterData.rotBasis.x, emitterData.rotBasis.y); + + // Combiner Properties + mBlendFunc = emitterData.blendFunc; + mDepthFunc = emitterData.depthFunc; + mCombinerFunc = emitterData.colorCombinerFunc; } void Emitter::initComplexFromBinary(const BinComplexEmitterData& emitterData) { - mComplexProperties = { - .childFlags = emitterData.childFlag, - .fieldFlags = emitterData.fieldFlag, - .fluctuationFlags = emitterData.fluctuationFlag, - .stripeFlags = emitterData.stripeFlag - }; + mChildFlags = emitterData.childFlag, + mFieldFlags = emitterData.fieldFlag, + mFluctuationFlags = emitterData.fluctuationFlag; + mStripeFlags = emitterData.stripeFlag; } diff --git a/src/ptcl/ptclEmitterSet.cpp b/src/ptcl/ptclEmitterSet.cpp index 1758cb0..4f5265b 100644 --- a/src/ptcl/ptclEmitterSet.cpp +++ b/src/ptcl/ptclEmitterSet.cpp @@ -6,6 +6,12 @@ namespace Ptcl { // ========================================================================== // +EmitterSet::EmitterSet(QString name) : + mName{std::move(name)} { + auto emitter = std::make_unique("New_Emitter_0"); + insertEmitter(0, std::move(emitter)); +} + EmitterSet::EmitterSet(const BinEmitterSet& binEmitterSet) {} @@ -41,18 +47,16 @@ void EmitterSet::setUserData(u32 data) { mUserData = data; } -void EmitterSet::addNewEmitter() { - auto newEmitter = std::make_unique(); - newEmitter->setName("New_Emitter_" + QString::number(emitterCount())); - mEmitters.push_back(std::move(newEmitter)); +void EmitterSet::insertEmitter(s32 emitterIndex, std::unique_ptr emitter) { + mEmitters.insert(mEmitters.begin() + emitterIndex, std::move(emitter)); } -void EmitterSet::removeEmitter(s32 emitterIndex) { - if (emitterIndex >= mEmitters.size()) { - return; - } +std::unique_ptr EmitterSet::removeEmitter(s32 emitterIndex) { + auto it = mEmitters.begin() + emitterIndex; - mEmitters.erase(mEmitters.begin() + emitterIndex); + std::unique_ptr removed = std::move(*it); + mEmitters.erase(it); + return removed; } std::unique_ptr EmitterSet::clone() const { @@ -70,11 +74,6 @@ std::unique_ptr EmitterSet::clone() const { return newSet; } -const std::unique_ptr& EmitterSet::appendEmitter(std::unique_ptr& newSet) { - mEmitters.push_back(std::move(newSet)); - return mEmitters.at(emitterCount() - 1); -} - // ========================================================================== // diff --git a/src/ptcl/ptclFieldData.cpp b/src/ptcl/ptclFieldData.cpp deleted file mode 100644 index bc47b2a..0000000 --- a/src/ptcl/ptclFieldData.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "ptcl/ptclFieldData.h" -#include "ptcl/ptclBinary.h" - -namespace Ptcl { - -const FieldData::FieldRandomData& FieldData::randomData() const { - return mRandomData; -} - -void FieldData::setRandomData(const FieldRandomData& randomData) { - mRandomData = randomData; -} - -void FieldData::initRandomData(const BinFieldRandomData& randomData) { - mRandomData = { - .randomBlank = randomData.fieldRandomBlank, - .randomVelAdd = Math::Vector3f(randomData.fieldRandomVelAdd.x, randomData.fieldRandomVelAdd.y, randomData.fieldRandomVelAdd.z) - }; -} - -const FieldData::FieldMagnetData& FieldData::magnetData() const { - return mMagnetData; -} - -void FieldData::setMagnetData(const FieldMagnetData& magnetData) { - mMagnetData = magnetData; -} - -void FieldData::initMagnetData(const BinFieldMagnetData& magnetData) { - mMagnetData = { - .magnetPower = magnetData.fieldMagnetPower, - .magnetPos = Math::Vector3f(magnetData.fieldMagnetPos.x, magnetData.fieldMagnetPos.y, magnetData.fieldMagnetPos.z), - .magnetFlag = magnetData.fieldMagnetFlag, - }; -} - -const FieldData::FieldSpinData& FieldData::spinData() const { - return mSpinData; -} - -void FieldData::setSpinData(const FieldSpinData& spinData) { - mSpinData = spinData; -} - -void FieldData::initSpinData(const BinFieldSpinData& spinData) { - mSpinData = { - .spinRotate = spinData.fieldSpinRotate, - .spinAxis = spinData.fieldSpinAxis - }; -} - -const FieldData::FieldCollisionData& FieldData::collisionData() const { - return mCollisionData; -} - -void FieldData::setCollisionData(const FieldCollisionData& collisionData) { - mCollisionData = collisionData; -} - -void FieldData::initCollisionData(const BinFieldCollisionData& collisionData) { - mCollisionData = { - .collisionType = collisionData.fieldCollisionType, - .collisionIsWorld = collisionData.fieldCollisionIsWorld > 0, - .collisionCoord = collisionData.fieldCollisionCoord, - .collisionCoef = collisionData.fieldCollisionCoef - }; -} - -const FieldData::FieldConvergenceData& FieldData::convergenceData() const { - return mConvergenceData; -} - -void FieldData::setConvergenceData(const FieldConvergenceData& convergenceData) { - mConvergenceData = convergenceData; -} - -void FieldData::initConvergenceData(const BinFieldConvergenceData& convergenceData) { - mConvergenceData = { - .convergenceType = convergenceData.fieldConvergenceType, - .convergencePos = Math::Vector3f(convergenceData.fieldConvergencePos.x, convergenceData.fieldConvergencePos.y, convergenceData.fieldConvergencePos.z) - }; -} - -const FieldData::FieldPosAddData& FieldData::posAddData() const { - return mPosAddData; -} - -void FieldData::setPosAddData(const FieldPosAddData& posAddData) { - mPosAddData = posAddData; -} - -void FieldData::initPosAddData(const BinFieldPosAddData& posAddData) { - mPosAddData = { - .posAdd = Math::Vector3f(posAddData.fieldPosAdd.x, posAddData.fieldPosAdd.y, posAddData.fieldPosAdd.z) - }; -} - - -// ========================================================================== // - - -} // namespace Ptcl diff --git a/src/ptcl/ptclTexture.cpp b/src/ptcl/ptclTexture.cpp index 1145c55..436cf7f 100644 --- a/src/ptcl/ptclTexture.cpp +++ b/src/ptcl/ptclTexture.cpp @@ -1,7 +1,6 @@ #include "ptcl/ptclTexture.h" #include "util/imageUtil.h" -#include #include @@ -44,24 +43,14 @@ bool Texture::isPlaceholder() const { return mIsPlaceholder; } -void Texture::replaceTexture(std::vector* encodedData, s32 width, s32 height, TextureFormat format) { - mEncodedData = std::move(*encodedData); - mTextureFormat = format; - mDecodedTexture = ImageUtil::picaTextureToQImage(mEncodedData, width, height, format); - - if (mDecodedTexture.isNull()) { - throw std::runtime_error("Failed to decode texture from encoded data."); - } +void Texture::swapTexture(Texture& other) { + std::swap(mTextureFormat, other.mTextureFormat); + std::swap(mEncodedData, other.mEncodedData); + std::swap(mDecodedTexture, other.mDecodedTexture); } -void Texture::replaceTexture(const Texture& other) { - mTextureFormat = other.mTextureFormat; - mEncodedData = other.mEncodedData; - mDecodedTexture = other.mDecodedTexture; -} - -const std::shared_ptr& Texture::placeholder() { - static std::shared_ptr sPlaceholder = [] { +Texture* Texture::placeholder() { + static Texture sPlaceholder = [] { constexpr s32 width = 8; constexpr s32 height = 8; constexpr s32 tile = width / 2; @@ -80,12 +69,11 @@ const std::shared_ptr& Texture::placeholder() { } auto encoded = ImageUtil::QImageToPicaTexture(img, TextureFormat::ETC1); - auto tex = std::make_shared(&encoded, width, height, TextureFormat::ETC1); - - tex->mIsPlaceholder = true; + Texture tex(&encoded, width, height, TextureFormat::ETC1); + tex.mIsPlaceholder = true; return tex; }(); - return sPlaceholder; + return &sPlaceholder; } void Texture::setUserCountCallback(Texture::UserCountCallback callback) { @@ -114,7 +102,7 @@ void Texture::doUserCountCallback() const { // ========================================================================== // -TextureHandle::TextureHandle(std::shared_ptr texture) : +TextureHandle::TextureHandle(Texture* texture) : mTexturePtr(std::move(texture)) { incrementCount(); } @@ -151,10 +139,6 @@ TextureHandle& TextureHandle::operator=(TextureHandle&& other) noexcept { return *this; } -TextureHandle TextureHandle::clone() const { - return *this; -} - void TextureHandle::invalidate() { mTexturePtr = nullptr; } @@ -163,11 +147,11 @@ bool TextureHandle::isValid() const { return mTexturePtr != nullptr; } -std::shared_ptr TextureHandle::get() const { +Texture* TextureHandle::get() const { return mTexturePtr ? mTexturePtr : Texture::placeholder(); } -void TextureHandle::set(const std::shared_ptr& texture) { +void TextureHandle::set(Texture* texture) { if (mTexturePtr != texture) { decrementCount(); mTexturePtr = texture; @@ -175,12 +159,12 @@ void TextureHandle::set(const std::shared_ptr& texture) { } } -TextureHandle& TextureHandle::operator=(const std::shared_ptr& texture) { +TextureHandle& TextureHandle::operator=(Texture* texture) { set(std::move(texture)); return *this; } -std::shared_ptr TextureHandle::operator->() const { +Texture* TextureHandle::operator->() const { return get(); }