diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 3aad0000..91115da4 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -90,7 +90,8 @@ jobs: - os: windows-latest artifact: agave-win # note macos-14 is arm64 and macos-13 is x86_64 - - os: macos-15 + # Tensorstore does not support universal builds yet + - os: macos-14 artifact: agave-macos-arm64 - os: macos-15-intel artifact: agave-macos-x86_64 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d9f6c40..b6755316 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ include(FetchContent) # Needed to recognize FetchContent_Declare in renderlib if(APPLE) set(ENV{MACOSX_DEPLOYMENT_TARGET} "10.15") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version" FORCE) + # Tensorstore does not support universal builds yet: + # set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") endif(APPLE) if(POLICY CMP0048) diff --git a/agave_app/AppearanceDockWidget.cpp b/agave_app/AppearanceDockWidget.cpp index f909b54e..0e2aa2a6 100644 --- a/agave_app/AppearanceDockWidget.cpp +++ b/agave_app/AppearanceDockWidget.cpp @@ -5,11 +5,13 @@ QAppearanceWidget::QAppearanceWidget(QWidget* pParent, QRenderSettings* qrs, RenderSettings* rs, + AreaLightObject* alo, + SkyLightObject* slo, QAction* pToggleRotateAction, QAction* pToggleTranslateAction) : QWidget(pParent) , m_MainLayout() - , m_AppearanceSettingsWidget(nullptr, qrs, rs, pToggleRotateAction, pToggleTranslateAction) + , m_AppearanceSettingsWidget(nullptr, qrs, rs, alo, slo, pToggleRotateAction, pToggleTranslateAction) { // Create main layout m_MainLayout.setAlignment(Qt::AlignTop); @@ -25,10 +27,12 @@ QAppearanceWidget::QAppearanceWidget(QWidget* pParent, QAppearanceDockWidget::QAppearanceDockWidget(QWidget* parent, QRenderSettings* qrs, RenderSettings* rs, + AreaLightObject* alo, + SkyLightObject* slo, QAction* pToggleRotateAction, QAction* pToggleTranslateAction) : QDockWidget(parent) - , m_VolumeAppearanceWidget(nullptr, qrs, rs, pToggleRotateAction, pToggleTranslateAction) + , m_VolumeAppearanceWidget(nullptr, qrs, rs, alo, slo, pToggleRotateAction, pToggleTranslateAction) { setWindowTitle("Appearance"); diff --git a/agave_app/AppearanceDockWidget.h b/agave_app/AppearanceDockWidget.h index 88e80368..67b6ff9e 100644 --- a/agave_app/AppearanceDockWidget.h +++ b/agave_app/AppearanceDockWidget.h @@ -15,6 +15,8 @@ class QAppearanceWidget : public QWidget QAppearanceWidget(QWidget* pParent = NULL, QRenderSettings* qrs = nullptr, RenderSettings* rs = nullptr, + AreaLightObject* alo = nullptr, + SkyLightObject* slo = nullptr, QAction* pToggleRotateAction = nullptr, QAction* pToggleTranslateAction = nullptr); @@ -33,6 +35,8 @@ class QAppearanceDockWidget : public QDockWidget QAppearanceDockWidget(QWidget* pParent = NULL, QRenderSettings* qrs = nullptr, RenderSettings* rs = nullptr, + AreaLightObject* alo = nullptr, + SkyLightObject* slo = nullptr, QAction* pToggleRotateAction = nullptr, QAction* pToggleTranslateAction = nullptr); diff --git a/agave_app/AppearanceDockWidget2.cpp b/agave_app/AppearanceDockWidget2.cpp index 1c25f68c..7523a385 100644 --- a/agave_app/AppearanceDockWidget2.cpp +++ b/agave_app/AppearanceDockWidget2.cpp @@ -5,7 +5,7 @@ QAppearanceDockWidget2::QAppearanceDockWidget2(QWidget* pParent, ViewerWindow* vw, AppearanceObject* ado) : QDockWidget(pParent) - , m_AppearanceWidget(nullptr, rs, vw, ado) + , m_AppearanceWidget(nullptr, rs, ado) { setWindowTitle("Appearance"); diff --git a/agave_app/AppearanceSettingsWidget.cpp b/agave_app/AppearanceSettingsWidget.cpp index 78ae4a9d..b8f8b423 100644 --- a/agave_app/AppearanceSettingsWidget.cpp +++ b/agave_app/AppearanceSettingsWidget.cpp @@ -1,13 +1,17 @@ #include "AppearanceSettingsWidget.h" + #include "QRenderSettings.h" #include "RangeWidget.h" #include "qtControls/Section.h" +#include "qtControls/controlFactory.h" #include "ImageXYZC.h" #include "renderlib/AppScene.h" +#include "renderlib/AreaLightObject.hpp" #include "renderlib/Colormap.h" #include "renderlib/Logging.h" #include "renderlib/RenderSettings.h" +#include "renderlib/SkyLightObject.hpp" #include "tfeditor/gradients.h" #include @@ -95,11 +99,15 @@ static const int MAX_CHANNELS_CHECKED = 4; QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, QRenderSettings* qrs, RenderSettings* rs, + AreaLightObject* alo, + SkyLightObject* slo, QAction* pToggleRotateAction, QAction* pToggleTranslateAction) : QGroupBox(pParent) , m_MainLayout() , m_qrendersettings(qrs) + , m_arealightObject(alo) + , m_skylightObject(slo) , m_scene(nullptr) { Controls::initFormLayout(m_MainLayout); @@ -343,73 +351,15 @@ QAppearanceSettingsWidget::createAreaLightingControls(QAction* pRotationAction) m_lt0gui.m_RotateButton->setToolTip(tr("Show interactive controls in viewport for area light rotation angle")); btnLayout->addWidget(m_lt0gui.m_RotateButton); QObject::connect(m_lt0gui.m_RotateButton, &QPushButton::clicked, [this, pRotationAction]() { - toggleActionForObject(pRotationAction, this->m_scene->SceneAreaLight()); + toggleActionForObject(pRotationAction, m_arealightObject->getSceneLight().get()); }); // dummy widget to fill space (TODO: Translate button?) btnLayout->addWidget(new QWidget()); sectionLayout->addLayout(btnLayout, sectionLayout->rowCount(), 0, 1, 2); - m_lt0gui.m_thetaSlider = new QNumericSlider(); - m_lt0gui.m_thetaSlider->setStatusTip(tr("Set angle theta for area light")); - m_lt0gui.m_thetaSlider->setToolTip(tr("Set angle theta for area light")); - m_lt0gui.m_thetaSlider->setRange(0.0, TWO_PI_F); - m_lt0gui.m_thetaSlider->setSingleStep(TWO_PI_F / 100.0); - m_lt0gui.m_thetaSlider->setValue(0.0); - sectionLayout->addRow("Theta", m_lt0gui.m_thetaSlider); - QObject::connect( - m_lt0gui.m_thetaSlider, &QNumericSlider::valueChanged, this, &QAppearanceSettingsWidget::OnSetAreaLightTheta); - - m_lt0gui.m_phiSlider = new QNumericSlider(); - m_lt0gui.m_phiSlider->setStatusTip(tr("Set angle phi for area light")); - m_lt0gui.m_phiSlider->setToolTip(tr("Set angle phi for area light")); - m_lt0gui.m_phiSlider->setRange(0.0, PI_F); - m_lt0gui.m_phiSlider->setSingleStep(PI_F / 100.0); - m_lt0gui.m_phiSlider->setValue(HALF_PI_F); - sectionLayout->addRow("Phi", m_lt0gui.m_phiSlider); - QObject::connect( - m_lt0gui.m_phiSlider, &QNumericSlider::valueChanged, this, &QAppearanceSettingsWidget::OnSetAreaLightPhi); - - m_lt0gui.m_sizeSlider = new QNumericSlider(); - m_lt0gui.m_sizeSlider->setStatusTip(tr("Set size for area light")); - m_lt0gui.m_sizeSlider->setToolTip(tr("Set size for area light")); - m_lt0gui.m_sizeSlider->setRange(0.1, 5.0); - m_lt0gui.m_sizeSlider->setSingleStep(5.0 / 100.0); - m_lt0gui.m_sizeSlider->setValue(1.0); - sectionLayout->addRow("Size", m_lt0gui.m_sizeSlider); - QObject::connect( - m_lt0gui.m_sizeSlider, &QNumericSlider::valueChanged, this, &QAppearanceSettingsWidget::OnSetAreaLightSize); - - m_lt0gui.m_distSlider = new QNumericSlider(); - m_lt0gui.m_distSlider->setStatusTip(tr("Set distance for area light")); - m_lt0gui.m_distSlider->setToolTip(tr("Set distance for area light")); - m_lt0gui.m_distSlider->setRange(0.1, 10.0); - m_lt0gui.m_distSlider->setSingleStep(1.0); - m_lt0gui.m_distSlider->setValue(10.0); - sectionLayout->addRow("Distance", m_lt0gui.m_distSlider); - QObject::connect( - m_lt0gui.m_distSlider, &QNumericSlider::valueChanged, this, &QAppearanceSettingsWidget::OnSetAreaLightDistance); - - auto* arealightLayout = new QHBoxLayout(); - m_lt0gui.m_intensitySlider = new QNumericSlider(); - m_lt0gui.m_intensitySlider->setStatusTip(tr("Set intensity for area light")); - m_lt0gui.m_intensitySlider->setToolTip(tr("Set intensity for area light")); - m_lt0gui.m_intensitySlider->setRange(0.0, 1000.0); - m_lt0gui.m_intensitySlider->setSingleStep(10.0); - m_lt0gui.m_intensitySlider->setValue(100.0); - m_lt0gui.m_intensitySlider->setDecimals(1); - arealightLayout->addWidget(m_lt0gui.m_intensitySlider, 1); - m_lt0gui.m_areaLightColorButton = new QColorPushButton(); - m_lt0gui.m_areaLightColorButton->setStatusTip(tr("Set color for area light")); - m_lt0gui.m_areaLightColorButton->setToolTip(tr("Set color for area light")); - arealightLayout->addWidget(m_lt0gui.m_areaLightColorButton, 0); - arealightLayout->setContentsMargins(0, 0, 0, 0); - sectionLayout->addRow("Intensity", arealightLayout); - QObject::connect(m_lt0gui.m_areaLightColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { - this->OnSetAreaLightColor(this->m_lt0gui.m_intensitySlider->value(), c); - }); - QObject::connect(m_lt0gui.m_intensitySlider, &QNumericSlider::valueChanged, [this](double v) { - this->OnSetAreaLightColor(v, this->m_lt0gui.m_areaLightColorButton->GetColor()); - }); + if (m_arealightObject) { + createFlatList(sectionLayout, m_arealightObject); + } section->setContentLayout(*sectionLayout); return section; @@ -421,62 +371,9 @@ QAppearanceSettingsWidget::createSkyLightingControls() Section* section = new Section("Sky Light", 0); auto* sectionLayout = Controls::createAgaveFormLayout(); - auto* skylightTopLayout = new QHBoxLayout(); - m_lt1gui.m_stintensitySlider = new QNumericSlider(); - m_lt1gui.m_stintensitySlider->setStatusTip(tr("Set intensity for top of skylight sphere")); - m_lt1gui.m_stintensitySlider->setToolTip(tr("Set intensity for top of skylight sphere")); - m_lt1gui.m_stintensitySlider->setRange(0.0, 10.0); - m_lt1gui.m_stintensitySlider->setValue(1.0); - skylightTopLayout->addWidget(m_lt1gui.m_stintensitySlider, 1); - m_lt1gui.m_stColorButton = new QColorPushButton(); - m_lt1gui.m_stColorButton->setStatusTip(tr("Set color for top of skylight sphere")); - m_lt1gui.m_stColorButton->setToolTip(tr("Set color for top of skylight sphere")); - skylightTopLayout->addWidget(m_lt1gui.m_stColorButton); - sectionLayout->addRow("Top", skylightTopLayout); - QObject::connect(m_lt1gui.m_stColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { - this->OnSetSkyLightTopColor(this->m_lt1gui.m_stintensitySlider->value(), c); - }); - QObject::connect(m_lt1gui.m_stintensitySlider, &QNumericSlider::valueChanged, [this](double v) { - this->OnSetSkyLightTopColor(v, this->m_lt1gui.m_stColorButton->GetColor()); - }); - - auto* skylightMidLayout = new QHBoxLayout(); - m_lt1gui.m_smintensitySlider = new QNumericSlider(); - m_lt1gui.m_smintensitySlider->setStatusTip(tr("Set intensity for middle of skylight sphere")); - m_lt1gui.m_smintensitySlider->setToolTip(tr("Set intensity for middle of skylight sphere")); - m_lt1gui.m_smintensitySlider->setRange(0.0, 10.0); - m_lt1gui.m_smintensitySlider->setValue(1.0); - skylightMidLayout->addWidget(m_lt1gui.m_smintensitySlider, 1); - m_lt1gui.m_smColorButton = new QColorPushButton(); - m_lt1gui.m_smColorButton->setStatusTip(tr("Set color for middle of skylight sphere")); - m_lt1gui.m_smColorButton->setToolTip(tr("Set color for middle of skylight sphere")); - skylightMidLayout->addWidget(m_lt1gui.m_smColorButton); - sectionLayout->addRow("Mid", skylightMidLayout); - QObject::connect(m_lt1gui.m_smColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { - this->OnSetSkyLightMidColor(this->m_lt1gui.m_smintensitySlider->value(), c); - }); - QObject::connect(m_lt1gui.m_smintensitySlider, &QNumericSlider::valueChanged, [this](double v) { - this->OnSetSkyLightMidColor(v, this->m_lt1gui.m_smColorButton->GetColor()); - }); - - auto* skylightBotLayout = new QHBoxLayout(); - m_lt1gui.m_sbintensitySlider = new QNumericSlider(); - m_lt1gui.m_sbintensitySlider->setStatusTip(tr("Set intensity for bottom of skylight sphere")); - m_lt1gui.m_sbintensitySlider->setToolTip(tr("Set intensity for bottom of skylight sphere")); - m_lt1gui.m_sbintensitySlider->setRange(0.0, 10.0); - m_lt1gui.m_sbintensitySlider->setValue(1.0); - skylightBotLayout->addWidget(m_lt1gui.m_sbintensitySlider, 1); - m_lt1gui.m_sbColorButton = new QColorPushButton(); - m_lt1gui.m_sbColorButton->setStatusTip(tr("Set color for bottom of skylight sphere")); - m_lt1gui.m_sbColorButton->setToolTip(tr("Set color for bottom of skylight sphere")); - skylightBotLayout->addWidget(m_lt1gui.m_sbColorButton); - sectionLayout->addRow("Bot", skylightBotLayout); - QObject::connect(m_lt1gui.m_sbColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { - this->OnSetSkyLightBotColor(this->m_lt1gui.m_sbintensitySlider->value(), c); - }); - QObject::connect(m_lt1gui.m_sbintensitySlider, &QNumericSlider::valueChanged, [this](double v) { - this->OnSetSkyLightBotColor(v, this->m_lt1gui.m_sbColorButton->GetColor()); - }); + if (m_skylightObject) { + createFlatList(sectionLayout, m_skylightObject); + } section->setContentLayout(*sectionLayout); return section; @@ -871,46 +768,17 @@ QAppearanceSettingsWidget::initClipPlaneControls(Scene* scene) void QAppearanceSettingsWidget::initLightingControls(Scene* scene) { - m_lt0gui.m_thetaSlider->setValue(scene->AreaLight().m_Theta); - m_lt0gui.m_phiSlider->setValue(scene->AreaLight().m_Phi); - m_lt0gui.m_sizeSlider->setValue(scene->AreaLight().m_Width); - m_lt0gui.m_distSlider->setValue(scene->AreaLight().m_Distance); - // split color into color and intensity. - QColor c; - float i; - normalizeColorForGui(scene->AreaLight().m_Color, c, i); - m_lt0gui.m_intensitySlider->setValue(i * scene->AreaLight().m_ColorIntensity); - m_lt0gui.m_areaLightColorButton->SetColor(c); + m_arealightObject->updatePropsFromSceneLight(); // attach light observer to scene's area light source, to receive updates from viewport controls // TODO FIXME clean this up - it's not removed anywhere so if light(i.e. scene) outlives "this" then we have problems. // Currently in AGAVE this is not an issue.. - scene->SceneAreaLight()->m_observers.push_back([this](const Light& light) { + m_arealightObject->getSceneLight()->m_observers.push_back([this](const Light& light) { // update gui controls - - // bring theta into 0..2pi - m_lt0gui.m_thetaSlider->setValue(light.m_Theta < 0 ? light.m_Theta + TWO_PI_F : light.m_Theta); - // bring phi into 0..pi - m_lt0gui.m_phiSlider->setValue(light.m_Phi < 0 ? light.m_Phi + PI_F : light.m_Phi); - m_lt0gui.m_sizeSlider->setValue(light.m_Width); - m_lt0gui.m_distSlider->setValue(light.m_Distance); - // split color into color and intensity. - QColor c; - float i; - normalizeColorForGui(light.m_Color, c, i); - m_lt0gui.m_intensitySlider->setValue(i * light.m_ColorIntensity); - m_lt0gui.m_areaLightColorButton->SetColor(c); + m_arealightObject->updatePropsFromSceneLight(); }); - normalizeColorForGui(scene->SphereLight().m_ColorTop, c, i); - m_lt1gui.m_stintensitySlider->setValue(i * scene->SphereLight().m_ColorTopIntensity); - m_lt1gui.m_stColorButton->SetColor(c); - normalizeColorForGui(scene->SphereLight().m_ColorMiddle, c, i); - m_lt1gui.m_smintensitySlider->setValue(i * scene->SphereLight().m_ColorMiddleIntensity); - m_lt1gui.m_smColorButton->SetColor(c); - normalizeColorForGui(scene->SphereLight().m_ColorBottom, c, i); - m_lt1gui.m_sbintensitySlider->setValue(i * scene->SphereLight().m_ColorBottomIntensity); - m_lt1gui.m_sbColorButton->SetColor(c); + m_skylightObject->updatePropsFromSceneLight(); } void diff --git a/agave_app/AppearanceSettingsWidget.h b/agave_app/AppearanceSettingsWidget.h index 93d1079a..4d7a3e80 100644 --- a/agave_app/AppearanceSettingsWidget.h +++ b/agave_app/AppearanceSettingsWidget.h @@ -12,6 +12,8 @@ #include +class AreaLightObject; +class SkyLightObject; class QRenderSettings; class ImageXYZC; class RangeWidget; @@ -35,6 +37,8 @@ class QAppearanceSettingsWidget : public QGroupBox QAppearanceSettingsWidget(QWidget* pParent = NULL, QRenderSettings* qrs = nullptr, RenderSettings* rs = nullptr, + AreaLightObject* alo = nullptr, + SkyLightObject* slo = nullptr, QAction* pToggleRotateAction = nullptr, QAction* pToggleTranslateAction = nullptr); @@ -89,6 +93,8 @@ public slots: QFormLayout m_MainLayout; QRenderSettings* m_qrendersettings; + AreaLightObject* m_arealightObject; + SkyLightObject* m_skylightObject; Section* m_clipRoiSection; RangeWidget* m_roiX; @@ -121,8 +127,9 @@ public slots: QNumericSlider* m_phiSlider; QNumericSlider* m_sizeSlider; QNumericSlider* m_distSlider; - QNumericSlider* m_intensitySlider; - QColorPushButton* m_areaLightColorButton; + // QNumericSlider* m_intensitySlider; + // QColorPushButton* m_areaLightColorButton; + QColorWithIntensity* m_areaLightColor; } m_lt0gui; struct lt1 diff --git a/agave_app/AppearanceWidget.cpp b/agave_app/AppearanceWidget.cpp index c57e9546..87b825a9 100644 --- a/agave_app/AppearanceWidget.cpp +++ b/agave_app/AppearanceWidget.cpp @@ -32,40 +32,33 @@ QAppearanceWidget2::QAppearanceWidget2(QWidget* pParent, RenderSettings* rs, Vie // } // } - // QComboBox* rendererType = addRow(*m_appearanceDataObject->getRendererTypeUiInfo()); - // m_MainLayout.addRow("Renderer", rendererType); - // QComboBox* shadingType = addRow(*m_appearanceDataObject->getShadingTypeUiInfo()); - // m_MainLayout.addRow("Shading Type", shadingType); - // QNumericSlider* densityScale = addRow(*m_appearanceDataObject->getDensityScaleUiInfo()); - // m_MainLayout.addRow("Scattering Density", densityScale); - // QNumericSlider* gradientFactor = addRow(*m_appearanceDataObject->getGradientFactorUiInfo()); - // m_MainLayout.addRow("Shading Type Mixture", gradientFactor); - // QNumericSlider* stepSizePrimaryRay = addRow(*m_appearanceDataObject->getStepSizePrimaryRayUiInfo()); - // m_MainLayout.addRow("Step Size Primary Ray", stepSizePrimaryRay); - // QNumericSlider* stepSizeSecondaryRay = addRow(*m_appearanceDataObject->getStepSizeSecondaryRayUiInfo()); - // m_MainLayout.addRow("Step Size Secondary Ray", stepSizeSecondaryRay); - // QCheckBox* interpolateCheckBox = addRow(*m_appearanceDataObject->getInterpolateUiInfo()); - // m_MainLayout.addRow("Interpolate", interpolateCheckBox); - // QColorPushButton* backgroundColorButton = addRow(*m_appearanceDataObject->getBackgroundColorUiInfo()); - // m_MainLayout.addRow("Background Color", backgroundColorButton); - // QCheckBox* showBoundingBoxCheckBox = addRow(*m_appearanceDataObject->getShowBoundingBoxUiInfo()); - // m_MainLayout.addRow("Show Bounding Box", showBoundingBoxCheckBox); - // QColorPushButton* boundingBoxColorButton = addRow(*m_appearanceDataObject->getBoundingBoxColorUiInfo()); - // m_MainLayout.addRow("Bounding Box Color", boundingBoxColorButton); - // QCheckBox* showScaleBarCheckBox = addRow(*m_appearanceDataObject->getShowScaleBarUiInfo()); - // m_MainLayout.addRow("Show Scale Bar", showScaleBarCheckBox); + QComboBox* rendererType = addRow(*m_appearanceDataObject->getRendererTypeUiInfo()); + m_MainLayout.addRow("Renderer", rendererType); + QComboBox* shadingType = addRow(*m_appearanceDataObject->getShadingTypeUiInfo()); + m_MainLayout.addRow("Shading Type", shadingType); + QNumericSlider* densityScale = addRow(*m_appearanceDataObject->getDensityScaleUiInfo()); + m_MainLayout.addRow("Scattering Density", densityScale); + QNumericSlider* gradientFactor = addRow(*m_appearanceDataObject->getGradientFactorUiInfo()); + m_MainLayout.addRow("Shading Type Mixture", gradientFactor); + QNumericSlider* stepSizePrimaryRay = addRow(*m_appearanceDataObject->getStepSizePrimaryRayUiInfo()); + m_MainLayout.addRow("Step Size Primary Ray", stepSizePrimaryRay); + QNumericSlider* stepSizeSecondaryRay = addRow(*m_appearanceDataObject->getStepSizeSecondaryRayUiInfo()); + m_MainLayout.addRow("Step Size Secondary Ray", stepSizeSecondaryRay); + QCheckBox* interpolateCheckBox = addRow(*m_appearanceDataObject->getInterpolateUiInfo()); + m_MainLayout.addRow("Interpolate", interpolateCheckBox); + QColorPushButton* backgroundColorButton = addRow(*m_appearanceDataObject->getBackgroundColorUiInfo()); + m_MainLayout.addRow("Background Color", backgroundColorButton); + QCheckBox* showBoundingBoxCheckBox = addRow(*m_appearanceDataObject->getShowBoundingBoxUiInfo()); + m_MainLayout.addRow("Show Bounding Box", showBoundingBoxCheckBox); + QColorPushButton* boundingBoxColorButton = addRow(*m_appearanceDataObject->getBoundingBoxColorUiInfo()); + m_MainLayout.addRow("Bounding Box Color", boundingBoxColorButton); + QCheckBox* showScaleBarCheckBox = addRow(*m_appearanceDataObject->getShowScaleBarUiInfo()); + m_MainLayout.addRow("Show Scale Bar", showScaleBarCheckBox); - // QObject::connect(rendererType, &QComboBox::currentIndexChanged, [this, vw](int index) { vw->setRenderer(index); }); - // QObject::connect(shadingType, &QComboBox::currentIndexChanged, [this, gradientFactor](int index) { - // gradientFactor->setEnabled(index == 2); - // }); - m_appearanceObject->getRendererTypeUiInfo()->GetProperty(0)->AddCallback( - new prtyCallbackLambda([this, vw](prtyProperty* i_Property, bool i_bDirty) { - if (i_bDirty) { - const int newvalue = (static_cast(i_Property))->GetValue(); - vw->setRenderer(newvalue); - } - })); + QObject::connect(rendererType, &QComboBox::currentIndexChanged, [this, vw](int index) { vw->setRenderer(index); }); + QObject::connect(shadingType, &QComboBox::currentIndexChanged, [this, gradientFactor](int index) { + gradientFactor->setEnabled(index == 2); + }); } QSize diff --git a/agave_app/AppearanceWidget.h b/agave_app/AppearanceWidget.h index a0fa71ac..6e943119 100644 --- a/agave_app/AppearanceWidget.h +++ b/agave_app/AppearanceWidget.h @@ -32,5 +32,5 @@ class QAppearanceWidget2 : public QWidget RenderSettings* m_renderSettings; private: - AppearanceObject* m_appearanceObject; + AppearanceObject* m_appearanceDataObject; }; diff --git a/agave_app/ArealightDockWidget.cpp b/agave_app/ArealightDockWidget.cpp new file mode 100644 index 00000000..5d26f7e6 --- /dev/null +++ b/agave_app/ArealightDockWidget.cpp @@ -0,0 +1,16 @@ +#include "ArealightDockWidget.h" + +QAreaLightDockWidget::QAreaLightDockWidget(QWidget* pParent, RenderSettings* rs, AreaLightObject* arealightObject) + : QDockWidget(pParent) + , m_ArealightWidget(nullptr, rs, arealightObject) +{ + setWindowTitle("Area Light"); + + setWidget(&m_ArealightWidget); + + QSizePolicy SizePolicy; + + SizePolicy.setVerticalPolicy(QSizePolicy::Maximum); + + setSizePolicy(SizePolicy); +} diff --git a/agave_app/ArealightDockWidget.h b/agave_app/ArealightDockWidget.h new file mode 100644 index 00000000..f3d67c75 --- /dev/null +++ b/agave_app/ArealightDockWidget.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "ArealightWidget.h" + +class QAreaLightDockWidget : public QDockWidget +{ + Q_OBJECT + +public: + QAreaLightDockWidget(QWidget* pParent = NULL, RenderSettings* rs = NULL, AreaLightObject* arealightObject = NULL); + +private: + QAreaLightWidget m_ArealightWidget; +}; diff --git a/agave_app/ArealightWidget.cpp b/agave_app/ArealightWidget.cpp new file mode 100644 index 00000000..cbaf5e35 --- /dev/null +++ b/agave_app/ArealightWidget.cpp @@ -0,0 +1,30 @@ +#include "ArealightWidget.h" +#include "RenderSettings.h" + +#include "qtControls/controlFactory.h" + +#include "renderlib/uiInfo.hpp" +#include "renderlib/AreaLightObject.hpp" +#include "renderlib/ViewerWindow.h" + +#include + +QAreaLightWidget::QAreaLightWidget(QWidget* pParent, RenderSettings* rs, AreaLightObject* arealightObject) + : QWidget(pParent) + , m_MainLayout() + , m_renderSettings(rs) + , m_arealightObject(arealightObject) +{ + Controls::initFormLayout(m_MainLayout); + setLayout(&m_MainLayout); + + if (m_arealightObject) { + createFlatList(&m_MainLayout, m_arealightObject); + } +} + +QSize +QAreaLightWidget::sizeHint() const +{ + return QSize(20, 20); +} diff --git a/agave_app/ArealightWidget.h b/agave_app/ArealightWidget.h new file mode 100644 index 00000000..fd80b455 --- /dev/null +++ b/agave_app/ArealightWidget.h @@ -0,0 +1,27 @@ +#pragma once + +#include "qtControls/Controls.h" + +#include "renderlib/AreaLightObject.hpp" +#include "renderlib/Logging.h" + +#include +#include + +class RenderSettings; +class ViewerWindow; + +class QAreaLightWidget : public QWidget +{ + Q_OBJECT + +public: + QAreaLightWidget(QWidget* pParent = NULL, RenderSettings* rs = nullptr, AreaLightObject* arealightObject = nullptr); + + virtual QSize sizeHint() const; + +private: + QFormLayout m_MainLayout; + RenderSettings* m_renderSettings; + AreaLightObject* m_arealightObject; +}; diff --git a/agave_app/CMakeLists.txt b/agave_app/CMakeLists.txt index 618035c7..5ca90c0e 100644 --- a/agave_app/CMakeLists.txt +++ b/agave_app/CMakeLists.txt @@ -23,6 +23,10 @@ target_sources(agaveapp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/AppearanceWidget.h" "${CMAKE_CURRENT_SOURCE_DIR}/AppearanceSettingsWidget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/AppearanceSettingsWidget.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ArealightDockWidget.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ArealightDockWidget.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ArealightWidget.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ArealightWidget.h" "${CMAKE_CURRENT_SOURCE_DIR}/CameraDockWidget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/CameraDockWidget.h" "${CMAKE_CURRENT_SOURCE_DIR}/CameraWidget.cpp" @@ -33,6 +37,10 @@ target_sources(agaveapp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/cgiparser.h" "${CMAKE_CURRENT_SOURCE_DIR}/commandBuffer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/commandBuffer.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Film.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Film.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Focus.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Focus.h" "${CMAKE_CURRENT_SOURCE_DIR}/GLView3D.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GLView3D.h" "${CMAKE_CURRENT_SOURCE_DIR}/loadDialog.cpp" @@ -57,6 +65,10 @@ target_sources(agaveapp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/StatisticsWidget.h" "${CMAKE_CURRENT_SOURCE_DIR}/StatisticsDockWidget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/StatisticsDockWidget.h" + "${CMAKE_CURRENT_SOURCE_DIR}/SkylightDockWidget.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/SkylightDockWidget.h" + "${CMAKE_CURRENT_SOURCE_DIR}/SkylightWidget.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/SkylightWidget.h" "${CMAKE_CURRENT_SOURCE_DIR}/streamserver.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/streamserver.h" "${CMAKE_CURRENT_SOURCE_DIR}/streamtestclient.cpp" diff --git a/agave_app/CameraWidget.h b/agave_app/CameraWidget.h index 2bb56e31..35ed6fdb 100644 --- a/agave_app/CameraWidget.h +++ b/agave_app/CameraWidget.h @@ -1,5 +1,6 @@ #pragma once +#include "Camera.h" #include "qtControls/Controls.h" // #include "renderlib/core/prty/prtyProperty.h" diff --git a/agave_app/GLView3D.cpp b/agave_app/GLView3D.cpp index 62274adc..8cf085ba 100644 --- a/agave_app/GLView3D.cpp +++ b/agave_app/GLView3D.cpp @@ -140,6 +140,8 @@ GLView3D::onNewImage(Scene* scene) GLView3D::~GLView3D() { + delete m_appearanceDataObject; + makeCurrent(); check_gl("view dtor makecurrent"); // doneCurrent(); @@ -477,42 +479,21 @@ GLView3D::fromViewerState(const Serialize::ViewerState& s) // syntactic sugar std::shared_ptr& camera = m_viewerWindow->m_CCamera; - /////////////////// - // TODO do all of this through the camera object's properties!!!!!!!!! - /////////////////// - m_cameraObject->getCameraDataObject().Position.SetValue(glm::vec3(s.camera.eye[0], s.camera.eye[1], s.camera.eye[2])); - // camera->m_From = glm::vec3(s.camera.eye[0], s.camera.eye[1], s.camera.eye[2]); - - m_cameraObject->getCameraDataObject().Target.SetValue( - glm::vec3(s.camera.target[0], s.camera.target[1], s.camera.target[2])); - // camera->m_Target = glm::vec3(s.camera.target[0], s.camera.target[1], s.camera.target[2]); - - // m_cameraObject->getCameraDataObject().Up.SetValue(glm::vec3(s.camera.up[0], s.camera.up[1], s.camera.up[2])); + camera->m_From = glm::vec3(s.camera.eye[0], s.camera.eye[1], s.camera.eye[2]); + camera->m_Target = glm::vec3(s.camera.target[0], s.camera.target[1], s.camera.target[2]); camera->m_Up = glm::vec3(s.camera.up[0], s.camera.up[1], s.camera.up[2]); + camera->m_FovV = s.camera.fovY; + camera->SetProjectionMode(s.camera.projection == Serialize::Projection_PID::PERSPECTIVE ? PERSPECTIVE : ORTHOGRAPHIC); + camera->m_OrthoScale = s.camera.orthoScale; - m_cameraObject->getCameraDataObject().FieldOfView.SetValue(s.camera.fovY); - // camera->m_FovV = s.camera.fovY; - - m_cameraObject->getCameraDataObject().ProjectionMode.SetValue( - (s.camera.projection == Serialize::Projection_PID::PERSPECTIVE) ? PERSPECTIVE : ORTHOGRAPHIC); - // camera->SetProjectionMode(s.camera.projection == Serialize::Projection_PID::PERSPECTIVE ? PERSPECTIVE : - // ORTHOGRAPHIC); - - m_cameraObject->getCameraDataObject().OrthoScale.SetValue(s.camera.orthoScale); - // camera->m_OrthoScale = s.camera.orthoScale; - - m_cameraObject->getCameraDataObject().Exposure.SetValue(s.camera.exposure); - // camera->m_Film.m_Exposure = s.camera.exposure; - - m_cameraObject->getCameraDataObject().ApertureSize.SetValue(s.camera.aperture); - // camera->m_Aperture.m_Size = s.camera.aperture; - - m_cameraObject->getCameraDataObject().FocalDistance.SetValue(s.camera.focalDistance); - // camera->m_Focus.m_FocalDistance = s.camera.focalDistance; + camera->m_Film.m_Exposure = s.camera.exposure; + camera->m_Aperture.m_Size = s.camera.aperture; + camera->m_Focus.m_FocalDistance = s.camera.focalDistance; // ASSUMES THIS IS ATTACHED TO m_viewerWindow->m_CCamera !!! - // TODO FIXME if we set EVERYTHING through props, then this is not needed. m_cameraObject->updatePropsFromObject(); + + m_appearanceDataObject->updatePropsFromObject(); } QPixmap diff --git a/agave_app/GLView3D.h b/agave_app/GLView3D.h index 91b7b0c3..c8018c33 100644 --- a/agave_app/GLView3D.h +++ b/agave_app/GLView3D.h @@ -12,8 +12,8 @@ #include #include -class AppearanceObject; -class CameraObject; +class AppearanceDataObject; +class CameraDataObject; class CStatus; class ImageXYZC; class IRenderWindow; @@ -70,6 +70,7 @@ class GLView3D : public QOpenGLWidget // tied to the above camera. CCamera must outlive this: // CameraObject* getCameraDataObject() { return m_cameraObject; } void setCameraObject(CameraObject* cameraObject); + AppearanceObject* getAppearanceDataObject() { return m_appearanceDataObject; } void fromViewerState(const Serialize::ViewerState& s); @@ -113,6 +114,7 @@ public slots: private: CameraObject* m_cameraObject; + AppearanceObject* m_appearanceDataObject; QRenderSettings* m_qrendersettings; /// Rendering timer. diff --git a/agave_app/SkylightDockWidget.cpp b/agave_app/SkylightDockWidget.cpp new file mode 100644 index 00000000..8c105363 --- /dev/null +++ b/agave_app/SkylightDockWidget.cpp @@ -0,0 +1,16 @@ +#include "SkylightDockWidget.h" + +QSkyLightDockWidget::QSkyLightDockWidget(QWidget* pParent, RenderSettings* rs, SkyLightObject* skylightObject) + : QDockWidget(pParent) + , m_SkylightWidget(nullptr, rs, skylightObject) +{ + setWindowTitle("Skylight"); + + setWidget(&m_SkylightWidget); + + QSizePolicy SizePolicy; + + SizePolicy.setVerticalPolicy(QSizePolicy::Maximum); + + setSizePolicy(SizePolicy); +} diff --git a/agave_app/SkylightDockWidget.h b/agave_app/SkylightDockWidget.h new file mode 100644 index 00000000..8bbb105e --- /dev/null +++ b/agave_app/SkylightDockWidget.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "SkylightWidget.h" + +class QSkyLightDockWidget : public QDockWidget +{ + Q_OBJECT + +public: + QSkyLightDockWidget(QWidget* pParent = NULL, RenderSettings* rs = NULL, SkyLightObject* skylightObject = NULL); + +private: + QSkyLightWidget m_SkylightWidget; +}; diff --git a/agave_app/SkylightWidget.cpp b/agave_app/SkylightWidget.cpp new file mode 100644 index 00000000..8a28f417 --- /dev/null +++ b/agave_app/SkylightWidget.cpp @@ -0,0 +1,30 @@ +#include "SkylightWidget.h" +#include "RenderSettings.h" + +#include "qtControls/controlFactory.h" + +#include "renderlib/uiInfo.hpp" +#include "renderlib/SkyLightObject.hpp" +#include "renderlib/ViewerWindow.h" + +#include + +QSkyLightWidget::QSkyLightWidget(QWidget* pParent, RenderSettings* rs, SkyLightObject* skylightObject) + : QWidget(pParent) + , m_MainLayout() + , m_renderSettings(rs) + , m_skylightObject(skylightObject) +{ + Controls::initFormLayout(m_MainLayout); + setLayout(&m_MainLayout); + + if (m_skylightObject) { + createFlatList(&m_MainLayout, m_skylightObject); + } +} + +QSize +QSkyLightWidget::sizeHint() const +{ + return QSize(20, 20); +} diff --git a/agave_app/SkylightWidget.h b/agave_app/SkylightWidget.h new file mode 100644 index 00000000..15b6eb9c --- /dev/null +++ b/agave_app/SkylightWidget.h @@ -0,0 +1,27 @@ +#pragma once + +#include "qtControls/Controls.h" + +#include "renderlib/SkyLightObject.hpp" +#include "renderlib/Logging.h" + +#include +#include + +class RenderSettings; +class ViewerWindow; + +class QSkyLightWidget : public QWidget +{ + Q_OBJECT + +public: + QSkyLightWidget(QWidget* pParent = NULL, RenderSettings* rs = nullptr, SkyLightObject* skylightObject = nullptr); + + virtual QSize sizeHint() const; + +private: + QFormLayout m_MainLayout; + RenderSettings* m_renderSettings; + SkyLightObject* m_skylightObject; +}; diff --git a/agave_app/agaveGui.cpp b/agave_app/agaveGui.cpp index c267a285..3ee18c4e 100644 --- a/agave_app/agaveGui.cpp +++ b/agave_app/agaveGui.cpp @@ -17,7 +17,9 @@ #include "AppearanceDockWidget.h" #include "AppearanceDockWidget2.h" +#include "ArealightDockWidget.h" #include "CameraDockWidget.h" +#include "SkylightDockWidget.h" #include "Serialize.h" #include "StatisticsDockWidget.h" #include "TimelineDockWidget.h" @@ -84,9 +86,19 @@ QMenu#quickViewsMenu {border-radius: 2px;} agaveGui::agaveGui(QWidget* parent) : QMainWindow(parent) { - // create our two document objects - m_cameraObject = std::make_unique(); + // create our document objects + // render settings m_appearanceObject = std::make_unique(); + // scene objects + m_cameraObject = std::make_unique(); + m_areaLightObject = std::make_unique(); + m_areaLightObject->getSceneLight()->m_light = Scene::defaultAreaLight(); + m_areaLightObject->setDirtyCallback( + [this]() { m_appearanceObject->getRenderSettings()->m_DirtyFlags.SetFlag(LightsDirty); }); + m_skyLightObject = std::make_unique(); + m_skyLightObject->getSceneLight()->m_light = Scene::defaultSkyLight(); + m_skyLightObject->setDirtyCallback( + [this]() { m_appearanceObject->getRenderSettings()->m_DirtyFlags.SetFlag(LightsDirty); }); m_ui.setupUi(this); @@ -128,9 +140,11 @@ agaveGui::agaveGui(QWidget* parent) // create camera ui window now that there is an actual camera. setupCameraDock(m_cameraObject.get()); + // setupAreaLightDock(m_areaLightObject.get()); + // setupSkyLightDock(m_skyLightObject.get()); setupTimelineDock(); setupStatisticsDock(); - setupAppearanceDock(m_appearanceObject.get()); + setupAppearanceDock(m_glView->getAppearanceDataObject()); addDockItemsToViewMenu(); @@ -161,7 +175,7 @@ agaveGui::agaveGui(QWidget* parent) QApplication::instance()->applicationName() + " " + QApplication::instance()->applicationVersion(); setWindowTitle(windowTitle); - m_appScene.initLights(); + m_appScene.initLights(m_skyLightObject->getSceneLight(), m_areaLightObject->getSceneLight()); // find a nice size to init agave QScreen* screen = QApplication::primaryScreen(); @@ -358,6 +372,22 @@ agaveGui::createToolbars() helpButton->setMenu(m_helpMenu); m_ui.mainToolBar->addWidget(helpButton); } +void +agaveGui::setupAreaLightDock(AreaLightObject* cdo) +{ + // TODO enable changing/resetting the area light data object shown in this dock? + m_areaLightDock = new QAreaLightDockWidget(this, m_appearanceObject->getRenderSettings().get(), cdo); + m_areaLightDock->setAllowedAreas(Qt::AllDockWidgetAreas); + addDockWidget(Qt::RightDockWidgetArea, m_areaLightDock); +} +void +agaveGui::setupSkyLightDock(SkyLightObject* cdo) +{ + // TODO enable changing/resetting the skylight data object shown in this dock? + m_skylightDock = new QSkyLightDockWidget(this, m_appearanceObject->getRenderSettings().get(), cdo); + m_skylightDock->setAllowedAreas(Qt::AllDockWidgetAreas); + addDockWidget(Qt::RightDockWidgetArea, m_skylightDock); +} void agaveGui::setupCameraDock(CameraObject* cdo) @@ -368,10 +398,6 @@ agaveGui::setupCameraDock(CameraObject* cdo) addDockWidget(Qt::RightDockWidgetArea, m_cameradock); } - m_viewMenu->addSeparator(); - m_viewMenu->addAction(m_cameradock->toggleViewAction()); -} - void agaveGui::setupAppearanceDock(AppearanceObject* ado) { @@ -386,6 +412,8 @@ agaveGui::setupAppearanceDock(AppearanceObject* ado) m_appearanceDockWidget = new QAppearanceDockWidget(this, &m_qrendersettings, m_appearanceObject->getRenderSettings().get(), + m_areaLightObject.get(), + m_skyLightObject.get(), m_toggleRotateControlsAction, m_toggleTranslateControlsAction); m_appearanceDockWidget->setAllowedAreas(Qt::AllDockWidgetAreas); @@ -393,8 +421,9 @@ agaveGui::setupAppearanceDock(AppearanceObject* ado) } void -agaveGui::setupTimelineDock() +agaveGui::createDockWindows() { + m_timelinedock = new QTimelineDockWidget(this, &m_qrendersettings); m_timelinedock->setAllowedAreas(Qt::AllDockWidgetAreas); addDockWidget(Qt::RightDockWidgetArea, m_timelinedock); @@ -411,9 +440,6 @@ agaveGui::setupStatisticsDock() addDockWidget(Qt::RightDockWidgetArea, m_statisticsDockWidget); } -void -agaveGui::addDockItemsToViewMenu() -{ m_viewMenu->addSeparator(); m_viewMenu->addAction(m_timelinedock->toggleViewAction()); m_viewMenu->addSeparator(); @@ -1225,11 +1251,11 @@ agaveGui::viewerStateToApp(const Serialize::ViewerState& v) // m_appScene.m_showScaleBar = v.showScaleBar; /////////////// TODO set these through props in the AppearanceObject - auto rs = m_appearanceObject->appearanceDataObject(); - rs.DensityScale.SetValue(v.density); - rs.StepSizePrimaryRay.SetValue(v.pathTracer.primaryStepSize); - rs.StepSizeSecondaryRay.SetValue(v.pathTracer.secondaryStepSize); - rs.Interpolate.SetValue(v.interpolate); + auto rs = m_appearanceObject->getRenderSettings(); + rs->m_RenderSettings.m_DensityScale = v.density; + rs->m_RenderSettings.m_StepSizeFactor = v.pathTracer.primaryStepSize; + rs->m_RenderSettings.m_StepSizeFactorShadow = v.pathTracer.secondaryStepSize; + rs->m_RenderSettings.m_InterpolatedVolumeSampling = v.interpolate; // channels for (uint32_t i = 0; i < m_appScene.m_volume->sizeC(); ++i) { @@ -1257,10 +1283,14 @@ agaveGui::viewerStateToApp(const Serialize::ViewerState& v) } // lights + // TODO FIXME initialize the light property objects + // create new SceneLights here? or rewrite into pre-existing? Light l0 = stateToLight(v, 0); - m_appScene.m_lighting.SetLight(m_appScene.SphereLightIndex, l0); + m_skyLightObject->getSceneLight()->m_light = l0; + // m_appScene.m_lighting.SetLight(m_appScene.SphereLightIndex, l0); Light l1 = stateToLight(v, 1); - m_appScene.m_lighting.SetLight(m_appScene.AreaLightIndex, l1); + m_areaLightObject->getSceneLight()->m_light = l1; + // m_appScene.m_lighting.SetLight(m_appScene.AreaLightIndex, l1); // capture settings m_captureSettings.width = v.capture.width; @@ -1274,11 +1304,10 @@ agaveGui::viewerStateToApp(const Serialize::ViewerState& v) m_captureSettings.outputDir = v.capture.outputDirectory; m_captureSettings.filenamePrefix = v.capture.filenamePrefix; - auto renderSettings = m_appearanceObject->getRenderSettings(); - renderSettings->m_DirtyFlags.SetFlag(CameraDirty); - renderSettings->m_DirtyFlags.SetFlag(LightsDirty); - renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty); - renderSettings->m_DirtyFlags.SetFlag(TransferFunctionDirty); + rs->m_DirtyFlags.SetFlag(CameraDirty); + rs->m_DirtyFlags.SetFlag(LightsDirty); + rs->m_DirtyFlags.SetFlag(RenderParamsDirty); + rs->m_DirtyFlags.SetFlag(TransferFunctionDirty); } Serialize::ViewerState @@ -1353,20 +1382,20 @@ agaveGui::appToViewerState() v.camera.projection = m_glView->getCamera().m_Projection == PERSPECTIVE ? Serialize::Projection_PID::PERSPECTIVE : Serialize::Projection_PID::ORTHOGRAPHIC; v.camera.orthoScale = m_glView->getCamera().m_OrthoScale; - // CameraObject* cdo = m_cameraObject.get(); - const CameraDataObject& cameraData = m_cameraObject->getCameraDataObject(); - v.camera.fovY = cameraData.FieldOfView.GetValue(); - v.camera.exposure = cameraData.Exposure.GetValue(); - v.camera.aperture = cameraData.ApertureSize.GetValue(); - v.camera.focalDistance = cameraData.FocalDistance.GetValue(); + CameraObject* cdo = m_cameraObject.get(); + v.camera.fovY = cdo->getCameraDataObject().FieldOfView.GetValue(); + v.camera.exposure = cdo->getCameraDataObject().Exposure.GetValue(); + v.camera.aperture = cdo->getCameraDataObject().ApertureSize.GetValue(); + v.camera.focalDistance = cdo->getCameraDataObject().FocalDistance.GetValue(); + auto rs = m_appearanceObject->getRenderSettings(); + v.density = rs->m_RenderSettings.m_DensityScale; + v.interpolate = rs->m_RenderSettings.m_InterpolatedVolumeSampling; v.density = appearanceData.DensityScale.GetValue(); v.interpolate = appearanceData.Interpolate.GetValue(); - v.rendererType = appearanceData.RendererType.GetValue() == 0 ? Serialize::RendererType_PID::RAYMARCH - : Serialize::RendererType_PID::PATHTRACE; - v.pathTracer.primaryStepSize = appearanceData.StepSizePrimaryRay.GetValue(); - v.pathTracer.secondaryStepSize = appearanceData.StepSizeSecondaryRay.GetValue(); + v.pathTracer.primaryStepSize = rs->m_RenderSettings.m_StepSizeFactor; + v.pathTracer.secondaryStepSize = rs->m_RenderSettings.m_StepSizeFactorShadow; if (m_appScene.m_volume) { for (uint32_t i = 0; i < m_appScene.m_volume->sizeC(); ++i) { diff --git a/agave_app/agaveGui.h b/agave_app/agaveGui.h index 2474ddc3..10e4b67f 100644 --- a/agave_app/agaveGui.h +++ b/agave_app/agaveGui.h @@ -15,10 +15,15 @@ class QAppearanceDockWidget; class QAppearanceDockWidget2; +class QAreaLightDockWidget; class QCameraDockWidget; +class QSkyLightDockWidget; class QStatisticsDockWidget; class QTimelineDockWidget; +class AreaLightObject; +class CameraObject; +class SkyLightObject; class IFileReader; class ViewToolbar; struct VolumeDimensions; @@ -98,6 +103,8 @@ private slots: void createMenus(); void createToolbars(); void addDockItemsToViewMenu(); + void setupAreaLightDock(AreaLightObject* light); + void setupSkyLightDock(SkyLightObject* light); void setupCameraDock(CameraObject* cdo); void setupTimelineDock(); void setupAppearanceDock(AppearanceObject* ado); @@ -148,6 +155,10 @@ private slots: QCameraDockWidget* m_cameradock; // Timeline UI QTimelineDockWidget* m_timelinedock; + // Sky light UI + QSkyLightDockWidget* m_skylightDock; + // Area Light UI + QAreaLightDockWidget* m_areaLightDock; QRenderSettings m_qrendersettings; @@ -185,6 +196,8 @@ private slots: Scene m_appScene; int m_currentScene = 0; std::unique_ptr m_cameraObject; + std::unique_ptr m_areaLightObject; + std::unique_ptr m_skyLightObject; std::string m_currentFilePath; // TODO remove the above m_currentFilePath and use this instead diff --git a/agave_app/python/pyrenderer.cpp b/agave_app/python/pyrenderer.cpp index 036fca57..e3eb5ae6 100644 --- a/agave_app/python/pyrenderer.cpp +++ b/agave_app/python/pyrenderer.cpp @@ -45,7 +45,8 @@ OffscreenRenderer::myVolumeInit() m_myVolumeData.m_camera->m_Film.m_Resolution.SetResY(m_height); m_myVolumeData.m_scene = new Scene(); - m_myVolumeData.m_scene->initLights(); + m_myVolumeData.m_scene->initLights(std::make_shared(Scene::defaultSkyLight()), + std::make_shared(Scene::defaultAreaLight())); // TODO allow for all renderer types (e.g. RendererGL also) m_myVolumeData.m_renderer = new RenderGLPT(m_myVolumeData.m_renderSettings); diff --git a/agave_app/qtControls/CMakeLists.txt b/agave_app/qtControls/CMakeLists.txt index 8e8f55a0..506089fd 100644 --- a/agave_app/qtControls/CMakeLists.txt +++ b/agave_app/qtControls/CMakeLists.txt @@ -3,8 +3,6 @@ target_include_directories(agaveapp PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" ) target_sources(agaveapp PRIVATE -"${CMAKE_CURRENT_SOURCE_DIR}/controlFactory.cpp" -"${CMAKE_CURRENT_SOURCE_DIR}/controlFactory.h" "${CMAKE_CURRENT_SOURCE_DIR}/Controls.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Controls.h" "${CMAKE_CURRENT_SOURCE_DIR}/RangeWidget.cpp" diff --git a/agave_app/qtControls/Controls.cpp b/agave_app/qtControls/Controls.cpp index 700003de..6c272e29 100644 --- a/agave_app/qtControls/Controls.cpp +++ b/agave_app/qtControls/Controls.cpp @@ -586,3 +586,52 @@ Controls::createAgaveFormLayout(QWidget* parent) layout->setColumnStretch(1, 100); return layout; } + +QColorWithIntensity::QColorWithIntensity(QColor color, float intensity, QWidget* parent) + : QWidget(parent) +{ + auto* layout = new QHBoxLayout(); + m_intensitySlider = new QNumericSlider(); + m_intensitySlider->setStatusTip(tr("Set intensity")); + m_intensitySlider->setToolTip(tr("Set intensity")); + m_intensitySlider->setRange(0.0, 1000.0); + m_intensitySlider->setSingleStep(10.0); + m_intensitySlider->setValue(intensity); + m_intensitySlider->setDecimals(1); + layout->addWidget(m_intensitySlider, 1); + m_colorButton = new QColorPushButton(); + m_colorButton->setStatusTip(tr("Set color")); + m_colorButton->setToolTip(tr("Set color")); + m_colorButton->SetColor(color); + layout->addWidget(m_colorButton, 0); + layout->setContentsMargins(0, 0, 0, 0); + setLayout(layout); + + // connect intensity slider to emit intensityChanged + connect(m_intensitySlider, &QNumericSlider::valueChanged, this, &QColorWithIntensity::intensityChanged); + connect(m_colorButton, &QColorPushButton::currentColorChanged, this, &QColorWithIntensity::colorChanged); +} + +void +QColorWithIntensity::setIntensity(float intensity) +{ + m_intensitySlider->setValue(intensity); +} + +void +QColorWithIntensity::setColor(const QColor& color) +{ + m_colorButton->SetColor(color); +} + +QColor +QColorWithIntensity::getColor() +{ + return m_colorButton->GetColor(); +} + +float +QColorWithIntensity::getIntensity() +{ + return m_intensitySlider->value(); +} diff --git a/agave_app/qtControls/Controls.h b/agave_app/qtControls/Controls.h index 4bce3125..aa280bc4 100644 --- a/agave_app/qtControls/Controls.h +++ b/agave_app/qtControls/Controls.h @@ -245,6 +245,32 @@ private slots: QSlider m_slider; }; +class QColorWithIntensity : public QWidget +{ + Q_OBJECT +public: + QColorWithIntensity(QColor color, float intensity = 1.0f, QWidget* parent = nullptr); + + void setIntensity(float intensity); + void setColor(const QColor& color); + QColor getColor(); + float getIntensity(); + + void setRange(double min, double max) { m_intensitySlider->setRange(min, max); } + void setDecimals(int decimals) { m_intensitySlider->setDecimals(decimals); } + void setSingleStep(double step) { m_intensitySlider->setSingleStep(step); } + void setNumTickMarks(int num) { m_intensitySlider->setNumTickMarks(num); } + void setSuffix(const QString& suffix) { m_intensitySlider->setSuffix(suffix); } + +signals: + void intensityChanged(float intensity); + void colorChanged(const QColor& color); + +private: + QNumericSlider* m_intensitySlider; + QColorPushButton* m_colorButton; +}; + class AgaveFormLayout : public QGridLayout { Q_OBJECT diff --git a/agave_app/qtControls/controlFactory.cpp b/agave_app/qtControls/controlFactory.cpp index 0883589f..7e4821e1 100644 --- a/agave_app/qtControls/controlFactory.cpp +++ b/agave_app/qtControls/controlFactory.cpp @@ -4,10 +4,76 @@ #include "Section.h" #include "renderlib/core/prty/prtyObject.hpp" -#include "renderlib/core/prty/prtyEnum.hpp" #include +QNumericSlider* +addRow(const FloatSliderSpinnerUiInfo& info) +{ + QNumericSlider* slider = new QNumericSlider(); + slider->setStatusTip(QString::fromStdString(info->GetStatusTip())); + slider->setToolTip(QString::fromStdString(info->GetToolTip())); + slider->setRange(info->min, info->max); + slider->setDecimals(info->decimals); + slider->setSingleStep(info->singleStep); + slider->setNumTickMarks(info->numTickMarks); + slider->setSuffix(QString::fromStdString(info->suffix)); + + slider->setValue(prop->GetValue(), true); + QObject::connect( + slider, &QNumericSlider::valueChanged, [slider, prop](double value) { prop->SetValue(value, true); }); + // TODO how would this capture the "previous" value, for undo? + // QObject::connect(slider, &QNumericSlider::valueChangeCommit, [slider, prop]() { prop->NotifyAll(true); }); + + return slider; +} +QNumericSlider* +create(const IntSliderSpinnerUiInfo* info, std::shared_ptr prop) +{ + QNumericSlider* slider = new QNumericSlider(); + slider->setStatusTip(QString::fromStdString(info->GetStatusTip())); + slider->setToolTip(QString::fromStdString(info->GetToolTip())); + slider->setRange(info->min, info->max); + slider->setSingleStep(info->singleStep); + slider->setNumTickMarks(info->numTickMarks); + slider->setSuffix(QString::fromStdString(info->suffix)); + + slider->setValue(prop->GetValue(), true); + QObject::connect( + slider, &QNumericSlider::valueChanged, [slider, prop](double value) { prop->SetValue(value, true); }); + // TODO how would this capture the "previous" value, for undo? + // QObject::connect(slider, &QNumericSlider::valueChangeCommit, [slider, prop]() { prop->NotifyAll(true); }); + + return slider; +} +QCheckBox* +create(const CheckBoxUiInfo* info, std::shared_ptr prop) +{ + QCheckBox* checkBox = new QCheckBox(); + checkBox->setStatusTip(QString::fromStdString(info->GetStatusTip())); + checkBox->setToolTip(QString::fromStdString(info->GetToolTip())); + // checkBox->setText(QString::fromStdString(info->formLabel)); + checkBox->setCheckState(prop->GetValue() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + QObject::connect(checkBox, &QCheckBox::stateChanged, [checkBox, prop](int state) { + prop->SetValue(state == Qt::CheckState::Checked, true); + }); + return checkBox; +} +QComboBox* +create(const ComboBoxUiInfo* info, std::shared_ptr prop) +{ + QComboBox* comboBox = new QComboBox(); + comboBox->setStatusTip(QString::fromStdString(info->GetStatusTip())); + comboBox->setToolTip(QString::fromStdString(info->GetToolTip())); + for (const auto& item : info->items) { + comboBox->addItem(QString::fromStdString(item)); + } + comboBox->setCurrentIndex(prop->GetValue()); + QObject::connect( + comboBox, &QComboBox::currentIndexChanged, [comboBox, prop](int index) { prop->SetValue(index, true); }); + return comboBox; +} + QNumericSlider* addRow(const FloatSliderSpinnerUiInfo& info) { @@ -56,6 +122,94 @@ addRow(const FloatSliderSpinnerUiInfo& info) return slider; } +QColorWithIntensity* +addRow(const ColorWithIntensityUiInfo& info) +{ + auto* propColor = static_cast(info.GetProperty(0)); + glm::vec4 c = propColor->GetValue(); + QColor qc; + qc.setRgbF(c.r, c.g, c.b); + + QColorWithIntensity* colorPicker = new QColorWithIntensity(qc); + colorPicker->setStatusTip(QString::fromStdString(info.GetStatusTip())); + colorPicker->setToolTip(QString::fromStdString(info.GetToolTip())); + // colorPicker->setRange(info.min, info.max); + // colorPicker->setDecimals(info.decimals); + // colorPicker->setSingleStep(info.singleStep); + // colorPicker->setNumTickMarks(info.numTickMarks); + // colorPicker->setSuffix(QString::fromStdString(info.suffix)); + + auto* prop = static_cast(info.GetProperty(1)); + colorPicker->setIntensity(prop->GetValue()); + auto conn = QObject::connect(colorPicker, &QColorWithIntensity::intensityChanged, [colorPicker, prop](double value) { + prop->SetValue(value, true); + }); + + colorPicker->setColor(qc); + auto connColor = + QObject::connect(colorPicker, &QColorWithIntensity::colorChanged, [colorPicker, propColor](const QColor& value) { + glm::vec4 c; + c.r = value.redF(); + c.g = value.greenF(); + c.b = value.blueF(); + propColor->SetValue(c, true); + }); + + // now add a callback to the property to update the control when the property changes + + // Note: right now, this will not create a circular update because + // of the m_bLocalChangeNoUpdate flag. This IS NOT true the other way + // around. If a control calls its "ValueChanged" then the property will + // call all of its callback controls and one of them could have been the one + // that originally updated the property value(s). By checking the diff of + // the values we can avoid a repetitive setting of the control's values. + prop->AddCallback(new prtyCallbackLambda([colorPicker](prtyProperty* i_pProperty, bool i_bDirty) { + // this is equivalent to QWidget::blockSignals(true); + // if (m_bLocalChangeNoUpdate) + // return; + const float newvalue = (static_cast(i_pProperty))->GetValue(); + // m_bLocalChangeNoUpdate = true; + colorPicker->blockSignals(true); + if ((float)colorPicker->getIntensity() != newvalue) { + // Prevent recursive updates + // slider->setLocalChangeNoUpdate(true); + colorPicker->setIntensity(newvalue); + // slider->setLocalChangeNoUpdate(false); + } + // m_bLocalChangeNoUpdate = false; + colorPicker->blockSignals(false); + })); + propColor->AddCallback(new prtyCallbackLambda([colorPicker](prtyProperty* i_pProperty, bool i_bDirty) { + // this is equivalent to QWidget::blockSignals(true); + // if (m_bLocalChangeNoUpdate) + // return; + const glm::vec4 newvalue = (static_cast(i_pProperty))->GetValue(); + // m_bLocalChangeNoUpdate = true; + colorPicker->blockSignals(true); + QColor qc = colorPicker->getColor(); + glm::vec4 c; + c.r = qc.redF(); + c.g = qc.greenF(); + c.b = qc.blueF(); + if (c != newvalue) { + // Prevent recursive updates + // slider->setLocalChangeNoUpdate(true); + qc.setRgbF(c.r, c.g, c.b); + colorPicker->setColor(qc); + // slider->setLocalChangeNoUpdate(false); + } + // m_bLocalChangeNoUpdate = false; + colorPicker->blockSignals(false); + })); + + QObject::connect(colorPicker, &QColorWithIntensity::destroyed, [conn, connColor]() { + // Disconnect the signal when the color picker is destroyed + QObject::disconnect(conn); + QObject::disconnect(connColor); + }); + return colorPicker; +} + QNumericSlider* addRow(const IntSliderSpinnerUiInfo& info) { @@ -84,9 +238,8 @@ addRow(const ComboBoxUiInfo& info) QComboBox* comboBox = new QComboBox(); comboBox->setStatusTip(QString::fromStdString(info.GetStatusTip())); comboBox->setToolTip(QString::fromStdString(info.GetToolTip())); - auto* prop = static_cast(info.GetProperty(0)); - for (int i = 0; i < prop->GetNumTags(); ++i) { - comboBox->addItem(QString::fromStdString(prop->GetEnumTag(i))); + for (const auto& item : info.items) { + comboBox->addItem(QString::fromStdString(item)); } comboBox->setCurrentIndex(prop->GetValue()); auto conn = QObject::connect( @@ -104,6 +257,7 @@ addRow(const CheckBoxUiInfo& info) QCheckBox* checkBox = new QCheckBox(); checkBox->setStatusTip(QString::fromStdString(info.GetStatusTip())); checkBox->setToolTip(QString::fromStdString(info.GetToolTip())); + // checkBox->setText(QString::fromStdString(info.formLabel)); auto* prop = static_cast(info.GetProperty(0)); checkBox->setCheckState(prop->GetValue() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); auto conn = QObject::connect(checkBox, &QCheckBox::stateChanged, [checkBox, prop](int state) { @@ -154,11 +308,25 @@ addGenericRow(const prtyPropertyUIInfo& info) return addRow(*checkBoxInfo); } else if (const auto* colorPickerInfo = dynamic_cast(&info)) { return addRow(*colorPickerInfo); + } else if (const auto* colorWithIntensityInfo = dynamic_cast(&info)) { + return addRow(*colorWithIntensityInfo); } - return nullptr; // or throw an exception } +template +QWidget* +addPrtyRow(LayoutType* layout, std::shared_ptr propertyInfo) +{ + QWidget* control = addGenericRow(*propertyInfo); + if (control) { + QString label = QString::fromStdString(propertyInfo->GetDescription()); + layout->addRow(label, control); + return control; + } + return nullptr; +} + void createCategorizedSections(QFormLayout* mainLayout, prtyObject* object) { @@ -185,11 +353,7 @@ createCategorizedSections(QFormLayout* mainLayout, prtyObject* object) // Add controls for each property in this category for (const auto& propertyInfo : properties) { - QWidget* control = addGenericRow(*propertyInfo); - if (control) { - QString label = QString::fromStdString(propertyInfo->GetDescription()); - sectionLayout->addRow(label, control); - } + addPrtyRow(sectionLayout, propertyInfo); } // Set the section's content layout @@ -201,18 +365,20 @@ createCategorizedSections(QFormLayout* mainLayout, prtyObject* object) } } +template void -createFlatList(QFormLayout* mainLayout, prtyObject* object) +createFlatList(LayoutType* mainLayout, prtyObject* object) { // Simple flat list of all properties const auto& propertyList = object->GetList(); for (const auto& propertyInfo : propertyList) { if (propertyInfo) { - QWidget* control = addGenericRow(*propertyInfo); - if (control) { - QString label = QString::fromStdString(propertyInfo->GetDescription()); - mainLayout->addRow(label, control); - } + addPrtyRow(mainLayout, propertyInfo); } } } + +template void +createFlatList(QFormLayout* mainLayout, prtyObject* object); +template void +createFlatList(AgaveFormLayout* mainLayout, prtyObject* object); diff --git a/agave_app/qtControls/controlFactory.h b/agave_app/qtControls/controlFactory.h index 5d8b8ea3..4947b258 100644 --- a/agave_app/qtControls/controlFactory.h +++ b/agave_app/qtControls/controlFactory.h @@ -24,6 +24,15 @@ addRow(const FloatSliderSpinnerUiInfo& info); QNumericSlider* addRow(const IntSliderSpinnerUiInfo& info); +QComboBox* +create(const ComboBoxUiInfo* info, std::shared_ptr prop); + +QNumericSlider* +addRow(const FloatSliderSpinnerUiInfo& info); + +QNumericSlider* +addRow(const IntSliderSpinnerUiInfo& info); + QComboBox* addRow(const ComboBoxUiInfo& info); @@ -36,8 +45,9 @@ addRow(const ColorPickerUiInfo& info); QWidget* addGenericRow(const prtyPropertyUIInfo& info); +template void -createFlatList(QFormLayout* mainLayout, prtyObject* object); +createFlatList(LayoutType* mainLayout, prtyObject* object); void -createCategorizedSections(QFormLayout* mainLayout, prtyObject* object); \ No newline at end of file +createCategorizedSections(QFormLayout* mainLayout, prtyObject* object); diff --git a/agave_app/streamserver.cpp b/agave_app/streamserver.cpp index 482fc784..5b4b42fe 100644 --- a/agave_app/streamserver.cpp +++ b/agave_app/streamserver.cpp @@ -49,7 +49,8 @@ StreamServer::createNewRenderer(QWebSocket* client) camera->m_Film.m_Resolution.SetResX(1024); camera->m_Film.m_Resolution.SetResY(1024); Scene* scene = new Scene(); - scene->initLights(); + scene->initLights(std::make_shared(Scene::defaultSkyLight()), + std::make_shared(Scene::defaultAreaLight())); r->configure(nullptr, rs, *scene, *camera, LoadSpec(), renderMode); diff --git a/renderlib/AppScene.cpp b/renderlib/AppScene.cpp index b8200031..d528e12e 100644 --- a/renderlib/AppScene.cpp +++ b/renderlib/AppScene.cpp @@ -77,19 +77,69 @@ Lighting::Lighting(const Lighting& other) { m_NoLights = other.m_NoLights; for (int i = 0; i < MAX_NO_LIGHTS; ++i) { - if (other.m_Lights[i]) { - m_Lights[i] = new Light(*other.m_Lights[i]); - m_sceneLights[i] = new SceneLight(m_Lights[i]); + if (other.m_sceneLights[i]) { + m_sceneLights[i] = other.m_sceneLights[i]; } else { - m_Lights[i] = nullptr; m_sceneLights[i] = nullptr; } } } +Light +Scene::defaultSkyLight() +{ + Light BackgroundLight; + + BackgroundLight.m_T = 1; + float inten = 1.0f; + + float topr = 0.5f; + float topg = 0.5f; + float topb = 0.5f; + float midr = 0.5f; + float midg = 0.5f; + float midb = 0.5f; + float botr = 0.5f; + float botg = 0.5f; + float botb = 0.5f; + + BackgroundLight.m_ColorTop = inten * glm::vec3(topr, topg, topb); + BackgroundLight.m_ColorMiddle = inten * glm::vec3(midr, midg, midb); + BackgroundLight.m_ColorBottom = inten * glm::vec3(botr, botg, botb); + + return BackgroundLight; +} + +Light +Scene::defaultAreaLight() +{ + Light AreaLight; + + AreaLight.m_T = 0; + AreaLight.m_Theta = 0.0f; + AreaLight.m_Phi = HALF_PI_F; + AreaLight.m_Width = 0.15f; + AreaLight.m_Height = 0.15f; + AreaLight.m_Distance = 1.5f; + AreaLight.m_Color = 10.0f * glm::vec3(1.0f, 1.0f, 1.0f); + + return AreaLight; +} + void -Scene::initLights() +Scene::initLights(std::shared_ptr skyLight, std::shared_ptr areaLight) { + // Clear existing lights + for (int i = 0; i < m_lighting.m_NoLights; ++i) { + m_lighting.m_sceneLights[i].reset(); + } + + m_lighting.SetLight(SphereLightIndex, skyLight); + m_lighting.SetLight(AreaLightIndex, areaLight); + m_lighting.m_NoLights = 2; + +// TODO FIXME use this code to initialize the lights way up at the app level. +#if 0 Light BackgroundLight; BackgroundLight.m_T = 1; @@ -122,6 +172,7 @@ Scene::initLights() AreaLight.m_Color = 10.0f * glm::vec3(1.0f, 1.0f, 1.0f); m_lighting.AddLight(AreaLight); +#endif } // set up a couple of lights relative to the img's bounding box @@ -173,14 +224,14 @@ Scene::initBounds(const CBoundingBox& bb) // point lights toward scene's bounding box for (int i = 0; i < m_lighting.m_NoLights; ++i) { // TODO maybe this should be passed through the SceneLight first. - m_lighting.m_Lights[i]->Update(m_boundingBox); + m_lighting.m_sceneLights[i]->m_light.Update(m_boundingBox); // The transform center for the scene light is its target. // This is used so that rotations are centered at the target which is the center of the volume. // Note this is not the same as the light source's position. // This is a very specific UX choice to make it easier to rotate the light around the volume, // but is constraining for other operations e.g. translation. - m_lighting.m_sceneLights[i]->m_transform.m_center = m_lighting.m_Lights[i]->m_Target; + m_lighting.m_sceneLights[i]->m_transform.m_center = m_lighting.m_sceneLights[i]->m_light.m_Target; } } diff --git a/renderlib/AppScene.h b/renderlib/AppScene.h index 8ee9792d..d35f7c1d 100644 --- a/renderlib/AppScene.h +++ b/renderlib/AppScene.h @@ -49,47 +49,36 @@ class Lighting public: Lighting(void) : m_NoLights(0) - , m_Lights{ nullptr, nullptr, nullptr, nullptr } , m_sceneLights{ nullptr, nullptr, nullptr, nullptr } { } ~Lighting() { - for (int i = 0; i < MAX_NO_LIGHTS; ++i) { - delete m_sceneLights[i]; - delete m_Lights[i]; - } + // lights are not owned here. } Lighting(const Lighting& other); - Light& LightRef(int i) const { return *m_Lights[i]; } - - void AddLight(Light& light) + void AddLight(std::shared_ptr sceneLight) { if (m_NoLights >= MAX_NO_LIGHTS) return; - m_Lights[m_NoLights] = new Light(light); - m_sceneLights[m_NoLights] = new SceneLight(m_Lights[m_NoLights]); - + m_sceneLights[m_NoLights] = sceneLight; m_NoLights = m_NoLights + 1; } - void SetLight(int i, Light& light) + + void SetLight(int i, std::shared_ptr sceneLight) { - if (i >= MAX_NO_LIGHTS) + if (m_NoLights >= MAX_NO_LIGHTS) return; - delete m_sceneLights[i]; - delete m_Lights[i]; - - m_Lights[i] = new Light(light); - m_sceneLights[i] = new SceneLight(m_Lights[i]); + m_sceneLights[i] = sceneLight; + m_NoLights = m_NoLights + 1; } - Light* m_Lights[MAX_NO_LIGHTS]; int m_NoLights; - SceneLight* m_sceneLights[MAX_NO_LIGHTS]; + std::shared_ptr m_sceneLights[MAX_NO_LIGHTS]; }; class Scene @@ -110,11 +99,11 @@ class Scene // convenience functions // For now, this must match the order in which the lights were added, in initLights static constexpr int SphereLightIndex = 0; - Light& SphereLight() const { return *m_lighting.m_Lights[SphereLightIndex]; } - SceneLight* SceneSphereLight() const { return m_lighting.m_sceneLights[SphereLightIndex]; } + Light& SphereLight() const { return m_lighting.m_sceneLights[SphereLightIndex]->m_light; } + SceneLight* SceneSphereLight() const { return m_lighting.m_sceneLights[SphereLightIndex].get(); } static constexpr int AreaLightIndex = 1; - Light& AreaLight() const { return *m_lighting.m_Lights[AreaLightIndex]; } - SceneLight* SceneAreaLight() const { return m_lighting.m_sceneLights[AreaLightIndex]; } + Light& AreaLight() const { return m_lighting.m_sceneLights[AreaLightIndex]->m_light; } + SceneLight* SceneAreaLight() const { return m_lighting.m_sceneLights[AreaLightIndex].get(); } // weak ptr! must not outlive the objects it points to. SceneObject* m_selection = nullptr; @@ -123,9 +112,12 @@ class Scene bool m_showScaleBar = false; bool m_showAxisHelper = false; - void initLights(); + void initLights(std::shared_ptr skyLight, std::shared_ptr areaLight); void initSceneFromImg(std::shared_ptr img); void initBounds(const CBoundingBox& bb); void initBoundsFromImg(std::shared_ptr img); void getFirst4EnabledChannels(uint32_t& c0, uint32_t& c1, uint32_t& c2, uint32_t& c3) const; + + static Light defaultSkyLight(); + static Light defaultAreaLight(); }; diff --git a/renderlib/AppearanceDataObject.cpp b/renderlib/AppearanceDataObject.cpp index 886966ff..82055d9a 100644 --- a/renderlib/AppearanceDataObject.cpp +++ b/renderlib/AppearanceDataObject.cpp @@ -3,12 +3,4 @@ #include "Enumerations.h" #include "Logging.h" -AppearanceDataObject::AppearanceDataObject() -{ - RendererType.SetEnumTag(0, "Ray march blending"); - RendererType.SetEnumTag(1, "Path Traced"); - - ShadingType.SetEnumTag(0, "BRDF Only"); - ShadingType.SetEnumTag(1, "Phase Function Only"); - ShadingType.SetEnumTag(2, "Mixed"); -} +AppearanceDataObject::AppearanceDataObject() {} diff --git a/renderlib/AppearanceDataObject.hpp b/renderlib/AppearanceDataObject.hpp index 82904e57..02df6f82 100644 --- a/renderlib/AppearanceDataObject.hpp +++ b/renderlib/AppearanceDataObject.hpp @@ -1,26 +1,26 @@ #pragma once -#include "core/prty/prtyEnum.hpp" +#include "core/prty/prtyInt8.hpp" #include "core/prty/prtyFloat.hpp" #include "core/prty/prtyBoolean.hpp" #include "core/prty/prtyVector3d.hpp" #include "core/prty/prtyColor.hpp" #include "glm.h" -class AppearanceDataObject +class AppearanceDataOject { public: AppearanceDataObject(); - prtyEnum RendererType{ "RendererType", 1 }; - prtyEnum ShadingType{ "ShadingType", 0 }; + prtyInt8 RendererType{ "RendererType", 0 }; + prtyInt8 ShadingType{ "ShadingType", 0 }; prtyFloat DensityScale{ "DensityScale", 1.0f }; prtyFloat GradientFactor{ "GradientFactor", 0.5f }; - prtyFloat StepSizePrimaryRay{ "StepSizePrimaryRay", 4.0f }; - prtyFloat StepSizeSecondaryRay{ "StepSizeSecondaryRay", 4.0f }; - prtyBoolean Interpolate{ "Interpolate", true }; + prtyFloat StepSizePrimaryRay{ "StepSizePrimaryRay", 1.0f }; + prtyFloat StepSizeSecondaryRay{ "StepSizeSecondaryRay", 1.0f }; + prtyBoolean Interpolate{ "Interpolate", false }; prtyColor BackgroundColor{ "BackgroundColor", glm::vec4(0.0f, 0.0f, 0.0f, 1.0f) }; - prtyBoolean ShowBoundingBox{ "ShowBoundingBox", true }; + prtyBoolean ShowBoundingBox{ "ShowBoundingBox", false }; prtyColor BoundingBoxColor{ "BoundingBoxColor", glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; prtyBoolean ShowScaleBar{ "ShowScaleBar", false }; }; diff --git a/renderlib/AppearanceObject.cpp b/renderlib/AppearanceObject.cpp index a641cb32..ed1fc23e 100644 --- a/renderlib/AppearanceObject.cpp +++ b/renderlib/AppearanceObject.cpp @@ -1,6 +1,5 @@ -#include "AppearanceObject.hpp" +#include "AppearanceUiDescription.hpp" -#include "Logging.h" // ComboBoxUiInfo AppearanceUiDescription::m_rendererType("Renderer Type", // "Select volume rendering type", // "Select volume rendering type", @@ -56,101 +55,22 @@ AppearanceObject::AppearanceObject() : prtyObject() { - std::string category("Rendering"); - m_renderSettings = std::make_shared(); - m_rendererType = new ComboBoxUiInfo(&m_appearanceDataObject.RendererType, category, "Renderer Type"); - m_rendererType->SetToolTip("Select volume rendering type"); - m_rendererType->SetStatusTip("Select volume rendering type"); - AddProperty(m_rendererType); - m_shadingType = new ComboBoxUiInfo(&m_appearanceDataObject.ShadingType, category, "Shading Type"); - m_shadingType->SetToolTip("Select volume shading style"); - m_shadingType->SetStatusTip("Select volume shading style"); - AddProperty(m_shadingType); - m_densityScale = new FloatSliderSpinnerUiInfo(&m_appearanceDataObject.DensityScale, category, "Density Scale"); - m_densityScale->SetToolTip("Set scattering density for volume"); - m_densityScale->SetStatusTip("Set scattering density for volume"); - m_densityScale->min = 0.001f; - m_densityScale->max = 100.0f; - m_densityScale->decimals = 3; // decimals - m_densityScale->singleStep = 0.01f; // singleStep - m_densityScale->numTickMarks = 10; // numTickMarks - m_densityScale->suffix = ""; // suffix - AddProperty(m_densityScale); - m_gradientFactor = new FloatSliderSpinnerUiInfo(&m_appearanceDataObject.GradientFactor, category, "Gradient Factor"); - m_gradientFactor->SetToolTip("Mix between BRDF and Phase shading"); - m_gradientFactor->SetStatusTip("Mix between BRDF and Phase shading"); - m_gradientFactor->min = 0.0f; - m_gradientFactor->max = 1.0f; - m_gradientFactor->decimals = 3; // decimals - m_gradientFactor->singleStep = 0.01f; // singleStep - m_gradientFactor->numTickMarks = 10; // numTickMarks - m_gradientFactor->suffix = ""; // suffix - AddProperty(m_gradientFactor); + m_RenderSettings = std::make_shared(); + m_rendererType = new ComboBoxUiInfo(&m_appearanceDataObject.RendererType, "Appearance", "Renderer Type"); + m_shadingType = new ComboBoxUiInfo(&m_appearanceDataObject.ShadingType, "Appearance", "Shading Type"); + m_densityScale = new FloatSliderSpinnerUiInfo(&m_appearanceDataObject.DensityScale, "Appearance", "Density Scale"); + m_gradientFactor = + new FloatSliderSpinnerUiInfo(&m_appearanceDataObject.GradientFactor, "Appearance", "Gradient Factor"); m_stepSizePrimaryRay = - new FloatSliderSpinnerUiInfo(&m_appearanceDataObject.StepSizePrimaryRay, category, "Step Size Primary Ray"); - m_stepSizePrimaryRay->SetToolTip("Set volume ray march step size for camera rays"); - m_stepSizePrimaryRay->SetStatusTip("Set volume ray march step size for camera rays"); - m_stepSizePrimaryRay->min = 1.0f; - m_stepSizePrimaryRay->max = 100.0f; - m_stepSizePrimaryRay->decimals = 3; // decimals - m_stepSizePrimaryRay->singleStep = 0.01f; // singleStep - m_stepSizePrimaryRay->numTickMarks = 10; // numTickMarks - m_stepSizePrimaryRay->suffix = ""; // suffix - AddProperty(m_stepSizePrimaryRay); + new FloatSliderSpinnerUiInfo(&m_appearanceDataObject.StepSizePrimaryRay, "Appearance", "Step Size Primary Ray"); m_stepSizeSecondaryRay = - new FloatSliderSpinnerUiInfo(&m_appearanceDataObject.StepSizeSecondaryRay, category, "Step Size Secondary Ray"); - m_stepSizeSecondaryRay->SetToolTip("Set volume ray march step size for scattered rays"); - m_stepSizeSecondaryRay->SetStatusTip("Set volume ray march step size for scattered rays"); - m_stepSizeSecondaryRay->min = 1.0f; - m_stepSizeSecondaryRay->max = 100.0f; - m_stepSizeSecondaryRay->decimals = 3; // decimals - m_stepSizeSecondaryRay->singleStep = 0.01f; // singleStep - m_stepSizeSecondaryRay->numTickMarks = 10; // numTickMarks - m_stepSizeSecondaryRay->suffix = ""; // suffix - AddProperty(m_stepSizeSecondaryRay); - m_interpolate = new CheckBoxUiInfo(&m_appearanceDataObject.Interpolate, category, "Interpolate"); - m_interpolate->SetToolTip("Interpolated volume sampling"); - m_interpolate->SetStatusTip("Interpolated volume sampling"); - AddProperty(m_interpolate); - m_backgroundColor = new ColorPickerUiInfo(&m_appearanceDataObject.BackgroundColor, category, "Background Color"); - m_backgroundColor->SetToolTip("Set background color"); - m_backgroundColor->SetStatusTip("Set background color"); - AddProperty(m_backgroundColor); - m_showBoundingBox = new CheckBoxUiInfo(&m_appearanceDataObject.ShowBoundingBox, category, "Show Bounding Box"); - m_showBoundingBox->SetToolTip("Show/hide bounding box"); - m_showBoundingBox->SetStatusTip("Show/hide bounding box"); - AddProperty(m_showBoundingBox); - m_boundingBoxColor = new ColorPickerUiInfo(&m_appearanceDataObject.BoundingBoxColor, category, "Bounding Box Color"); - m_boundingBoxColor->SetToolTip("Set bounding box color"); - m_boundingBoxColor->SetStatusTip("Set bounding box color"); - AddProperty(m_boundingBoxColor); - m_showScaleBar = new CheckBoxUiInfo(&m_appearanceDataObject.ShowScaleBar, category, "Show Scale Bar"); - m_showScaleBar->SetToolTip("Show/hide scale bar"); - m_showScaleBar->SetStatusTip("Show/hide scale bar"); - AddProperty(m_showScaleBar); - - m_appearanceDataObject.RendererType.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::RendererTypeChanged)); - m_appearanceDataObject.ShadingType.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::ShadingTypeChanged)); - m_appearanceDataObject.DensityScale.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::DensityScaleChanged)); - m_appearanceDataObject.GradientFactor.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::GradientFactorChanged)); - m_appearanceDataObject.StepSizePrimaryRay.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::StepSizePrimaryRayChanged)); - m_appearanceDataObject.StepSizeSecondaryRay.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::StepSizeSecondaryRayChanged)); - m_appearanceDataObject.Interpolate.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::InterpolateChanged)); - m_appearanceDataObject.BackgroundColor.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::BackgroundColorChanged)); - m_appearanceDataObject.ShowBoundingBox.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::ShowBoundingBoxChanged)); - m_appearanceDataObject.BoundingBoxColor.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::BoundingBoxColorChanged)); - m_appearanceDataObject.ShowScaleBar.AddCallback( - new prtyCallbackWrapper(this, &AppearanceObject::ShowScaleBarChanged)); + new FloatSliderSpinnerUiInfo(&m_appearanceDataObject.StepSizeSecondaryRay, "Appearance", "Step Size Secondary Ray"); + m_interpolate = new CheckBoxUiInfo(&m_appearanceDataObject.Interpolate, "Appearance", "Interpolate"); + m_backgroundColor = new ColorPickerUiInfo(&m_appearanceDataObject.BackgroundColor, "Appearance", "Background Color"); + m_showBoundingBox = new CheckBoxUiInfo(&m_appearanceDataObject.ShowBoundingBox, "Appearance", "Show Bounding Box"); + m_boundingBoxColor = + new ColorPickerUiInfo(&m_appearanceDataObject.BoundingBoxColor, "Appearance", "Bounding Box Color"); + m_showScaleBar = new CheckBoxUiInfo(&m_appearanceDataObject.ShowScaleBar, "Appearance", "Show Scale Bar"); } void @@ -165,17 +85,17 @@ AppearanceObject::updatePropsFromObject() m_appearanceDataObject.StepSizeSecondaryRay.SetValue(m_renderSettings->m_RenderSettings.m_StepSizeFactorShadow); m_appearanceDataObject.Interpolate.SetValue(m_renderSettings->m_RenderSettings.m_InterpolatedVolumeSampling); } - if (auto scene = m_scene.lock()) { - m_appearanceDataObject.BackgroundColor.SetValue(glm::vec4(scene->m_material.m_backgroundColor[0], - scene->m_material.m_backgroundColor[1], - scene->m_material.m_backgroundColor[2], - 1.0f)); - m_appearanceDataObject.ShowBoundingBox.SetValue(scene->m_material.m_showBoundingBox); - m_appearanceDataObject.BoundingBoxColor.SetValue(glm::vec4(scene->m_material.m_boundingBoxColor[0], - scene->m_material.m_boundingBoxColor[1], - scene->m_material.m_boundingBoxColor[2], - 1.0f)); - m_appearanceDataObject.ShowScaleBar.SetValue(scene->m_showScaleBar); + if (m_scene) { + BackgroundColor.SetValue(glm::vec4(m_scene->m_material.m_backgroundColor[0], + m_scene->m_material.m_backgroundColor[1], + m_scene->m_material.m_backgroundColor[2], + 1.0f)); + ShowBoundingBox.SetValue(m_scene->m_material.m_showBoundingBox); + BoundingBoxColor.SetValue(glm::vec4(m_scene->m_material.m_boundingBoxColor[0], + m_scene->m_material.m_boundingBoxColor[1], + m_scene->m_material.m_boundingBoxColor[2], + 1.0f)); + ShowScaleBar.SetValue(m_scene->m_showScaleBar); } } @@ -191,96 +111,17 @@ AppearanceObject::updateObjectFromProps() m_renderSettings->m_RenderSettings.m_StepSizeFactor = m_appearanceDataObject.StepSizePrimaryRay.GetValue(); m_renderSettings->m_RenderSettings.m_StepSizeFactorShadow = m_appearanceDataObject.StepSizeSecondaryRay.GetValue(); m_renderSettings->m_RenderSettings.m_InterpolatedVolumeSampling = m_appearanceDataObject.Interpolate.GetValue(); - if (auto scene = m_scene.lock()) { - scene->m_material.m_backgroundColor[0] = m_appearanceDataObject.BackgroundColor.GetValue().x; - scene->m_material.m_backgroundColor[1] = m_appearanceDataObject.BackgroundColor.GetValue().y; - scene->m_material.m_backgroundColor[2] = m_appearanceDataObject.BackgroundColor.GetValue().z; - scene->m_material.m_showBoundingBox = m_appearanceDataObject.ShowBoundingBox.GetValue(); - scene->m_material.m_boundingBoxColor[0] = m_appearanceDataObject.BoundingBoxColor.GetValue().x; - scene->m_material.m_boundingBoxColor[1] = m_appearanceDataObject.BoundingBoxColor.GetValue().y; - scene->m_material.m_boundingBoxColor[2] = m_appearanceDataObject.BoundingBoxColor.GetValue().z; - scene->m_showScaleBar = m_appearanceDataObject.ShowScaleBar.GetValue(); - } + m_scene->m_material.m_backgroundColor[0] = m_appearanceDataObject.BackgroundColor.GetValue().x; + m_scene->m_material.m_backgroundColor[1] = m_appearanceDataObject.BackgroundColor.GetValue().y; + m_scene->m_material.m_backgroundColor[2] = m_appearanceDataObject.BackgroundColor.GetValue().z; + m_scene->m_material.m_showBoundingBox = m_appearanceDataObject.ShowBoundingBox.GetValue(); + m_scene->m_material.m_boundingBoxColor[0] = m_appearanceDataObject.BoundingBoxColor.GetValue().x; + m_scene->m_material.m_boundingBoxColor[1] = m_appearanceDataObject.BoundingBoxColor.GetValue().y; + m_scene->m_material.m_boundingBoxColor[2] = m_appearanceDataObject.BoundingBoxColor.GetValue().z; + m_scene->m_showScaleBar = m_appearanceDataObject.ShowScaleBar.GetValue(); + m_renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty); m_renderSettings->m_DirtyFlags.SetFlag(TransferFunctionDirty); m_renderSettings->m_DirtyFlags.SetFlag(LightsDirty); } -} - -void -AppearanceObject::RendererTypeChanged(prtyProperty* i_Property, bool i_bDirty) -{ - LOG_ERROR << "Renderer type changed, but not implemented yet!"; -} -void -AppearanceObject::ShadingTypeChanged(prtyProperty* i_Property, bool i_bDirty) -{ - m_renderSettings->m_RenderSettings.m_ShadingType = m_appearanceDataObject.ShadingType.GetValue(); - m_renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty); -} -void -AppearanceObject::DensityScaleChanged(prtyProperty* i_Property, bool i_bDirty) -{ - m_renderSettings->m_RenderSettings.m_DensityScale = m_appearanceDataObject.DensityScale.GetValue(); - m_renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty); -} -void -AppearanceObject::GradientFactorChanged(prtyProperty* i_Property, bool i_bDirty) -{ - m_renderSettings->m_RenderSettings.m_GradientFactor = m_appearanceDataObject.GradientFactor.GetValue(); - m_renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty); -} -void -AppearanceObject::StepSizePrimaryRayChanged(prtyProperty* i_Property, bool i_bDirty) -{ - m_renderSettings->m_RenderSettings.m_StepSizeFactor = m_appearanceDataObject.StepSizePrimaryRay.GetValue(); - m_renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty); -} -void -AppearanceObject::StepSizeSecondaryRayChanged(prtyProperty* i_Property, bool i_bDirty) -{ - m_renderSettings->m_RenderSettings.m_StepSizeFactorShadow = m_appearanceDataObject.StepSizeSecondaryRay.GetValue(); - m_renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty); -} -void -AppearanceObject::InterpolateChanged(prtyProperty* i_Property, bool i_bDirty) -{ - m_renderSettings->m_RenderSettings.m_InterpolatedVolumeSampling = m_appearanceDataObject.Interpolate.GetValue(); - m_renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty); -} -void -AppearanceObject::BackgroundColorChanged(prtyProperty* i_Property, bool i_bDirty) -{ - if (auto scene = m_scene.lock()) { - scene->m_material.m_backgroundColor[0] = m_appearanceDataObject.BackgroundColor.GetValue().x; - scene->m_material.m_backgroundColor[1] = m_appearanceDataObject.BackgroundColor.GetValue().y; - scene->m_material.m_backgroundColor[2] = m_appearanceDataObject.BackgroundColor.GetValue().z; - m_renderSettings->m_DirtyFlags.SetFlag(EnvironmentDirty); - } -} -void -AppearanceObject::ShowBoundingBoxChanged(prtyProperty* i_Property, bool i_bDirty) -{ - if (auto scene = m_scene.lock()) { - scene->m_material.m_showBoundingBox = m_appearanceDataObject.ShowBoundingBox.GetValue(); - m_renderSettings->m_DirtyFlags.SetFlag(EnvironmentDirty); - } -} -void -AppearanceObject::BoundingBoxColorChanged(prtyProperty* i_Property, bool i_bDirty) -{ - if (auto scene = m_scene.lock()) { - scene->m_material.m_boundingBoxColor[0] = m_appearanceDataObject.BoundingBoxColor.GetValue().x; - scene->m_material.m_boundingBoxColor[1] = m_appearanceDataObject.BoundingBoxColor.GetValue().y; - scene->m_material.m_boundingBoxColor[2] = m_appearanceDataObject.BoundingBoxColor.GetValue().z; - m_renderSettings->m_DirtyFlags.SetFlag(EnvironmentDirty); - } -} -void -AppearanceObject::ShowScaleBarChanged(prtyProperty* i_Property, bool i_bDirty) -{ - if (auto scene = m_scene.lock()) { - scene->m_showScaleBar = m_appearanceDataObject.ShowScaleBar.GetValue(); - m_renderSettings->m_DirtyFlags.SetFlag(EnvironmentDirty); - } -} +} \ No newline at end of file diff --git a/renderlib/AppearanceObject.hpp b/renderlib/AppearanceObject.hpp index 36774846..49e1321c 100644 --- a/renderlib/AppearanceObject.hpp +++ b/renderlib/AppearanceObject.hpp @@ -3,7 +3,6 @@ #include "AppearanceDataObject.hpp" #include "core/prty/prtyObject.hpp" #include "RenderSettings.h" -#include "AppScene.h" #include "uiInfo.hpp" struct AppearanceUiDescription @@ -30,7 +29,7 @@ class AppearanceObject : public prtyObject void updateObjectFromProps(); // Getter for appearance data object - AppearanceDataObject& appearanceDataObject() { return m_appearanceDataObject; } + // AppearanceDataObject& getAppearanceDataObject() { return m_appearanceDataObject; } const AppearanceDataObject& getAppearanceDataObject() const { return m_appearanceDataObject; } // Getters for UI info objects @@ -53,9 +52,8 @@ class AppearanceObject : public prtyObject // the properties AppearanceDataObject m_appearanceDataObject; - // the actual settings + // the actual camera std::shared_ptr m_renderSettings; - std::weak_ptr m_scene; // the ui info ComboBoxUiInfo* m_rendererType; @@ -69,16 +67,4 @@ class AppearanceObject : public prtyObject CheckBoxUiInfo* m_showBoundingBox; ColorPickerUiInfo* m_boundingBoxColor; CheckBoxUiInfo* m_showScaleBar; - - void RendererTypeChanged(prtyProperty* i_Property, bool i_bDirty); - void ShadingTypeChanged(prtyProperty* i_Property, bool i_bDirty); - void DensityScaleChanged(prtyProperty* i_Property, bool i_bDirty); - void GradientFactorChanged(prtyProperty* i_Property, bool i_bDirty); - void StepSizePrimaryRayChanged(prtyProperty* i_Property, bool i_bDirty); - void StepSizeSecondaryRayChanged(prtyProperty* i_Property, bool i_bDirty); - void InterpolateChanged(prtyProperty* i_Property, bool i_bDirty); - void BackgroundColorChanged(prtyProperty* i_Property, bool i_bDirty); - void ShowBoundingBoxChanged(prtyProperty* i_Property, bool i_bDirty); - void BoundingBoxColorChanged(prtyProperty* i_Property, bool i_bDirty); - void ShowScaleBarChanged(prtyProperty* i_Property, bool i_bDirty); }; diff --git a/renderlib/AreaLightObject.cpp b/renderlib/AreaLightObject.cpp new file mode 100644 index 00000000..434037b5 --- /dev/null +++ b/renderlib/AreaLightObject.cpp @@ -0,0 +1,158 @@ +#include "AreaLightObject.hpp" + +#include "SceneLight.h" +#include "MathUtil.h" +#include "Logging.h" + +AreaLightObject::AreaLightObject() + : prtyObject() +{ + m_sceneLight = std::make_shared(); + + m_thetaUIInfo = new FloatSliderSpinnerUiInfo(&m_arealightDataObject.Theta, "Position", "Theta"); + m_thetaUIInfo->SetToolTip("Set Theta angle"); + m_thetaUIInfo->SetStatusTip("Set area light theta angle in degrees"); + m_thetaUIInfo->min = 0.0f; + m_thetaUIInfo->max = 360.0f; + m_thetaUIInfo->decimals = 1; + m_thetaUIInfo->singleStep = 1.0f; + m_thetaUIInfo->suffix = "°"; + AddProperty(m_thetaUIInfo); + + m_phiUIInfo = new FloatSliderSpinnerUiInfo(&m_arealightDataObject.Phi, "Position", "Phi"); + m_phiUIInfo->SetToolTip("Set Phi angle"); + m_phiUIInfo->SetStatusTip("Set area light phi angle in degrees"); + m_phiUIInfo->min = 0.0f; + m_phiUIInfo->max = 180.0f; + m_phiUIInfo->decimals = 1; + m_phiUIInfo->singleStep = 1.0f; + m_phiUIInfo->suffix = "°"; + AddProperty(m_phiUIInfo); + + m_sizeUIInfo = new FloatSliderSpinnerUiInfo(&m_arealightDataObject.Size, "Dimensions", "Size"); + m_sizeUIInfo->SetToolTip("Set Size"); + m_sizeUIInfo->SetStatusTip("Set area light size"); + m_sizeUIInfo->min = 0.1f; + m_sizeUIInfo->max = 100.0f; + m_sizeUIInfo->decimals = 2; + m_sizeUIInfo->singleStep = 0.1f; + AddProperty(m_sizeUIInfo); + + m_distanceUIInfo = new FloatSliderSpinnerUiInfo(&m_arealightDataObject.Distance, "Position", "Distance"); + m_distanceUIInfo->SetToolTip("Set Distance"); + m_distanceUIInfo->SetStatusTip("Set area light distance"); + m_distanceUIInfo->min = 0.1f; + m_distanceUIInfo->max = 1000.0f; + m_distanceUIInfo->decimals = 1; + m_distanceUIInfo->singleStep = 1.0f; + AddProperty(m_distanceUIInfo); + + m_intensityUIInfo = + new ColorWithIntensityUiInfo(&m_arealightDataObject.Color, &m_arealightDataObject.Intensity, "Light", "Intensity"); + m_intensityUIInfo->SetToolTip("Set Intensity"); + m_intensityUIInfo->SetStatusTip("Set area light intensity"); + m_intensityUIInfo->min = 0.0f; + m_intensityUIInfo->max = 1000.0f; + m_intensityUIInfo->decimals = 1; + m_intensityUIInfo->singleStep = 1.0f; + AddProperty(m_intensityUIInfo); + + // m_colorUIInfo = new ColorPickerUiInfo(&m_arealightDataObject.Color, "Light", "Color"); + // m_colorUIInfo->SetToolTip("Set Color"); + // m_colorUIInfo->SetStatusTip("Set area light color"); + // AddProperty(m_colorUIInfo); + + // Add callbacks for property changes + m_arealightDataObject.Theta.AddCallback( + new prtyCallbackWrapper(this, &AreaLightObject::ThetaChanged)); + m_arealightDataObject.Phi.AddCallback(new prtyCallbackWrapper(this, &AreaLightObject::PhiChanged)); + m_arealightDataObject.Size.AddCallback(new prtyCallbackWrapper(this, &AreaLightObject::SizeChanged)); + m_arealightDataObject.Distance.AddCallback( + new prtyCallbackWrapper(this, &AreaLightObject::DistanceChanged)); + m_arealightDataObject.Intensity.AddCallback( + new prtyCallbackWrapper(this, &AreaLightObject::IntensityChanged)); + m_arealightDataObject.Color.AddCallback( + new prtyCallbackWrapper(this, &AreaLightObject::ColorChanged)); +} + +void +AreaLightObject::updatePropsFromSceneLight() +{ + if (!m_sceneLight) + return; + + const Light& light = m_sceneLight->m_light; + + // Convert from radians to degrees and update properties + m_arealightDataObject.Theta.SetValue(light.m_Theta * (180.0f / PI_F)); + m_arealightDataObject.Phi.SetValue(light.m_Phi * (180.0f / PI_F)); + m_arealightDataObject.Size.SetValue(light.m_Width); + m_arealightDataObject.Distance.SetValue(light.m_Distance); + m_arealightDataObject.Intensity.SetValue(light.m_ColorIntensity); + m_arealightDataObject.Color.SetValue(glm::vec4(light.m_Color, 1.0f)); +} + +void +AreaLightObject::updateSceneLightFromProps() +{ + if (!m_sceneLight) + return; + + Light& light = m_sceneLight->m_light; + + // Convert from degrees to radians and update light + light.m_Theta = m_arealightDataObject.Theta.GetValue() * (PI_F / 180.0f); + light.m_Phi = m_arealightDataObject.Phi.GetValue() * (PI_F / 180.0f); + light.m_Width = m_arealightDataObject.Size.GetValue(); + light.m_Distance = m_arealightDataObject.Distance.GetValue(); + light.m_ColorIntensity = m_arealightDataObject.Intensity.GetValue(); + + glm::vec4 color = m_arealightDataObject.Color.GetValue(); + light.m_Color = glm::vec3(color.x, color.y, color.z); + + // Notify observers + for (auto& observer : m_sceneLight->m_observers) { + observer(light); + } + + // Call dirty callback if set + if (m_dirtyCallback) { + m_dirtyCallback(); + } +} + +void +AreaLightObject::ThetaChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +AreaLightObject::PhiChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +AreaLightObject::SizeChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +AreaLightObject::DistanceChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +AreaLightObject::IntensityChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +AreaLightObject::ColorChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} diff --git a/renderlib/AreaLightObject.hpp b/renderlib/AreaLightObject.hpp new file mode 100644 index 00000000..036f1025 --- /dev/null +++ b/renderlib/AreaLightObject.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "core/prty/prtyObject.hpp" +#include "core/prty/prtyColor.hpp" +#include "core/prty/prtyFloat.hpp" +#include "uiInfo.hpp" + +#include +#include + +class SceneLight; + +// Data object for arealight properties +class ArealightDataObject +{ +public: + ArealightDataObject() = default; + + prtyFloat Theta{ "Theta", 0.0f }; + prtyFloat Phi{ "Phi", 1.5708f }; // PI/2 + prtyFloat Size{ "Size", 1.0f }; + prtyFloat Distance{ "Distance", 10.0f }; + prtyFloat Intensity{ "Intensity", 100.0f }; + prtyColor Color{ "Color", glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; +}; + +class AreaLightObject : public prtyObject +{ +public: + AreaLightObject(); + + std::shared_ptr getSceneLight() const { return m_sceneLight; } + + // Update properties from scene light instance + void updatePropsFromSceneLight(); + + // Update scene light instance from properties (called automatically via callbacks) + void updateSceneLightFromProps(); + + // Property change callbacks + void ThetaChanged(prtyProperty* i_Property, bool i_bDirty); + void PhiChanged(prtyProperty* i_Property, bool i_bDirty); + void SizeChanged(prtyProperty* i_Property, bool i_bDirty); + void DistanceChanged(prtyProperty* i_Property, bool i_bDirty); + void IntensityChanged(prtyProperty* i_Property, bool i_bDirty); + void ColorChanged(prtyProperty* i_Property, bool i_bDirty); + + void setDirtyCallback(std::function callback) { m_dirtyCallback = callback; } + +private: + ArealightDataObject m_arealightDataObject; + + // the actual object + std::shared_ptr m_sceneLight; + + std::function m_dirtyCallback; + + // UI Info objects + FloatSliderSpinnerUiInfo* m_thetaUIInfo = nullptr; + FloatSliderSpinnerUiInfo* m_phiUIInfo = nullptr; + FloatSliderSpinnerUiInfo* m_sizeUIInfo = nullptr; + FloatSliderSpinnerUiInfo* m_distanceUIInfo = nullptr; + ColorWithIntensityUiInfo* m_intensityUIInfo = nullptr; + // ColorPickerUiInfo* m_colorUIInfo = nullptr; +}; diff --git a/renderlib/CMakeLists.txt b/renderlib/CMakeLists.txt index 38180589..668adafb 100644 --- a/renderlib/CMakeLists.txt +++ b/renderlib/CMakeLists.txt @@ -20,6 +20,8 @@ target_sources(renderlib PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/AppearanceObject.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/AppScene.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/AppScene.h" + "${CMAKE_CURRENT_SOURCE_DIR}/AreaLightObject.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/AreaLightObject.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/AreaLightTool.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/AreaLightTool.h" "${CMAKE_CURRENT_SOURCE_DIR}/AxisHelperTool.cpp" @@ -79,6 +81,8 @@ target_sources(renderlib PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/ScenePlane.h" "${CMAKE_CURRENT_SOURCE_DIR}/SceneView.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/SceneView.h" + "${CMAKE_CURRENT_SOURCE_DIR}/SkyLightObject.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/SkyLightObject.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/Status.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Status.h" "${CMAKE_CURRENT_SOURCE_DIR}/StringUtil.h" diff --git a/renderlib/CameraDataObject.hpp b/renderlib/CameraDataObject.hpp index 1e4eb095..a26c862c 100644 --- a/renderlib/CameraDataObject.hpp +++ b/renderlib/CameraDataObject.hpp @@ -1,37 +1,18 @@ #pragma once #include "core/prty/prtyFloat.hpp" -#include "core/prty/prtyEnum.hpp" +#include "core/prty/prtyInt8.hpp" #include "core/prty/prtyBoolean.hpp" -#include "core/prty/prtyVector3d.hpp" class CameraDataObject { public: - CameraDataObject() - { - ExposureIterations.SetEnumTag(0, "1"); - ExposureIterations.SetEnumTag(1, "2"); - ExposureIterations.SetEnumTag(2, "4"); - ExposureIterations.SetEnumTag(3, "8"); - - ProjectionMode.SetEnumTag(0, "Perspective"); - ProjectionMode.SetEnumTag(1, "Orthographic"); - } + CameraDataObject() {} prtyFloat Exposure{ "Exposure", 0.75f }; - prtyEnum ExposureIterations{ "ExposureIterations", 0 }; + prtyInt8 ExposureIterations{ "ExposureIterations", 1 }; prtyBoolean NoiseReduction{ "NoiseReduction", false }; prtyFloat ApertureSize{ "ApertureSize", 0.0f }; - prtyFloat FieldOfView{ "FieldOfView", 30.0f }; // degrees + prtyFloat FieldOfView{ "FieldOfView", 30.0f }; prtyFloat FocalDistance{ "FocalDistance", 0.0f }; - - prtyVector3d Position{ "Position", glm::vec3(0.0f, 0.0f, 0.0f) }; - prtyVector3d Target{ "Target", glm::vec3(0.0f, 0.0f, -1.0f) }; - prtyFloat NearPlane{ "NearPlane", 0.1f }; - prtyFloat FarPlane{ "FarPlane", 1000.0f }; - prtyFloat Roll{ "Roll", 0.0f }; // tilt angle in degrees - - prtyFloat OrthoScale{ "OrthoScale", 1.0f }; // orthographic scale for orthographic projection - prtyEnum ProjectionMode{ "ProjectionMode", 0 }; // 0 = perspective, 1 = orthographic }; diff --git a/renderlib/CameraObject.cpp b/renderlib/CameraObject.cpp index 1d3614cc..d45b5def 100644 --- a/renderlib/CameraObject.cpp +++ b/renderlib/CameraObject.cpp @@ -1,7 +1,4 @@ -#include "CameraObject.hpp" - -#include "Logging.h" -#include "glm.h" +#include "CameraUiDescription.hpp" // FloatSliderSpinnerUiInfo CameraUiDescription::m_exposure("Exposure", // "Set Exposure", @@ -52,102 +49,20 @@ CameraObject::CameraObject() { m_camera = std::make_shared(); m_ExposureUIInfo = new FloatSliderSpinnerUiInfo(&m_cameraDataObject.Exposure, "Camera", "Exposure"); - m_ExposureUIInfo->SetToolTip("Set Exposure"); - m_ExposureUIInfo->SetStatusTip("Set camera exposure"); - m_ExposureUIInfo->min = 0.0f; - m_ExposureUIInfo->max = 1.0f; - m_ExposureUIInfo->decimals = 2; // decimals - m_ExposureUIInfo->singleStep = 0.01f; // singleStep - m_ExposureUIInfo->numTickMarks = 0; // numTickMarks - AddProperty(m_ExposureUIInfo); m_ExposureIterationsUIInfo = new ComboBoxUiInfo(&m_cameraDataObject.ExposureIterations, "Camera", "Exposure Iterations"); - m_ExposureIterationsUIInfo->SetToolTip("Set Exposure Iterations"); - m_ExposureIterationsUIInfo->SetStatusTip("Set number of samples to accumulate per viewport update"); - AddProperty(m_ExposureIterationsUIInfo); m_NoiseReductionUIInfo = new CheckBoxUiInfo(&m_cameraDataObject.NoiseReduction, "Camera", "Noise Reduction"); - m_NoiseReductionUIInfo->SetToolTip("Enable Noise Reduction"); - m_NoiseReductionUIInfo->SetStatusTip("Enable denoising pass"); - AddProperty(m_NoiseReductionUIInfo); m_ApertureSizeUIInfo = new FloatSliderSpinnerUiInfo(&m_cameraDataObject.ApertureSize, "Camera", "Aperture Size"); - m_ApertureSizeUIInfo->SetToolTip("Set Aperture Size"); - m_ApertureSizeUIInfo->SetStatusTip("Set camera aperture size"); - m_ApertureSizeUIInfo->min = 0.0f; - m_ApertureSizeUIInfo->max = 0.1f; - m_ApertureSizeUIInfo->decimals = 2; // decimals - m_ApertureSizeUIInfo->singleStep = 0.01f; // - m_ApertureSizeUIInfo->numTickMarks = 0; // numTickMarks - m_ApertureSizeUIInfo->suffix = " mm"; // suffix - AddProperty(m_ApertureSizeUIInfo); m_FieldOfViewUIInfo = new FloatSliderSpinnerUiInfo(&m_cameraDataObject.FieldOfView, "Camera", "Field of View"); - m_FieldOfViewUIInfo->SetToolTip("Set Field of View"); - m_FieldOfViewUIInfo->SetStatusTip("Set camera field of view angle"); - m_FieldOfViewUIInfo->min = 10.0f; - m_FieldOfViewUIInfo->max = 150.0f; - m_FieldOfViewUIInfo->decimals = 2; // decimals - m_FieldOfViewUIInfo->singleStep = 0.01f; // single - m_FieldOfViewUIInfo->numTickMarks = 0; // numTickMarks - m_FieldOfViewUIInfo->suffix = " deg"; // suffix - AddProperty(m_FieldOfViewUIInfo); m_FocalDistanceUIInfo = new FloatSliderSpinnerUiInfo(&m_cameraDataObject.FocalDistance, "Camera", "Focal Distance"); - m_FocalDistanceUIInfo->SetToolTip("Set Focal Distance"); - m_FocalDistanceUIInfo->SetStatusTip("Set focal distance"); - m_FocalDistanceUIInfo->min = 0.0f; - m_FocalDistanceUIInfo->max = 15.0f; - m_FocalDistanceUIInfo->decimals = 2; // decimals - m_FocalDistanceUIInfo->singleStep = 0.01f; // single - m_FocalDistanceUIInfo->numTickMarks = 0; // numTickMarks - m_FocalDistanceUIInfo->suffix = " m"; // suffix - AddProperty(m_FocalDistanceUIInfo); - - m_cameraDataObject.Exposure.AddCallback(new prtyCallbackWrapper(this, &CameraObject::ExposureChanged)); - m_cameraDataObject.ExposureIterations.AddCallback( - new prtyCallbackWrapper(this, &CameraObject::ExposureIterationsChanged)); - m_cameraDataObject.NoiseReduction.AddCallback( - new prtyCallbackWrapper(this, &CameraObject::NoiseReductionChanged)); - m_cameraDataObject.ApertureSize.AddCallback( - new prtyCallbackWrapper(this, &CameraObject::ApertureSizeChanged)); - m_cameraDataObject.FieldOfView.AddCallback( - new prtyCallbackWrapper(this, &CameraObject::FieldOfViewChanged)); - m_cameraDataObject.FocalDistance.AddCallback( - new prtyCallbackWrapper(this, &CameraObject::FocalDistanceChanged)); - - m_cameraDataObject.Position.AddCallback( - new prtyCallbackWrapper(this, &CameraObject::TransformationChanged)); - m_cameraDataObject.Target.AddCallback( - new prtyCallbackWrapper(this, &CameraObject::TransformationChanged)); - m_cameraDataObject.Roll.AddCallback( - new prtyCallbackWrapper(this, &CameraObject::TransformationChanged)); } void CameraObject::updatePropsFromObject() { - // TODO FIXME if we set everything through props, then this is not needed. if (m_camera) { m_cameraDataObject.Exposure.SetValue(1.0f - m_camera->m_Film.m_Exposure); - - uint8_t exposureIterationsValue = m_camera->m_Film.m_ExposureIterations; - // convert m_camera->m_Film.m_ExposureIterations to string - // and then find the corresponding index in the enum - switch (m_camera->m_Film.m_ExposureIterations) { - case 1: - exposureIterationsValue = 0; - break; - case 2: - exposureIterationsValue = 1; - break; - case 4: - exposureIterationsValue = 2; - break; - case 8: - exposureIterationsValue = 3; - break; - default: - LOG_ERROR << "Invalid Exposure Iterations: " << m_camera->m_Film.m_ExposureIterations; - exposureIterationsValue = 0; // default to 1 - } - m_cameraDataObject.ExposureIterations.SetValue(exposureIterationsValue); + m_cameraDataObject.ExposureIterations.SetValue(m_camera->m_Film.m_ExposureIterations); // TODO this is not hooked up to the camera properly // m_cameraDataObject.NoiseReduction.SetValue(m_camera->m_Film.m_NoiseReduction); m_cameraDataObject.ApertureSize.SetValue(m_camera->m_Aperture.m_Size); @@ -155,33 +70,13 @@ CameraObject::updatePropsFromObject() m_cameraDataObject.FocalDistance.SetValue(m_camera->m_Focus.m_FocalDistance); } } -uint8_t -CameraObject::GetExposureIterationsValue(int i_ComboBoxIndex) -{ - // Convert the combo box index to the corresponding exposure iterations value - switch (i_ComboBoxIndex) { - case 0: - return 1; // 1 iteration - case 1: - return 2; // 2 iterations - case 2: - return 4; // 4 iterations - case 3: - return 8; // 8 iterations - default: - LOG_ERROR << "Invalid Exposure Iterations index: " << i_ComboBoxIndex; - return 1; // default to 1 iteration - } -} - void CameraObject::updateObjectFromProps() { // update low-level camera object from properties if (m_camera) { m_camera->m_Film.m_Exposure = 1.0f - m_cameraDataObject.Exposure.GetValue(); - uint8_t exposureIterationsValue = GetExposureIterationsValue(m_cameraDataObject.ExposureIterations.GetValue()); - m_camera->m_Film.m_ExposureIterations = exposureIterationsValue; + m_camera->m_Film.m_ExposureIterations = m_cameraDataObject.ExposureIterations.GetValue(); // Aperture m_camera->m_Aperture.m_Size = m_cameraDataObject.ApertureSize.GetValue(); @@ -211,7 +106,7 @@ CameraObject::ExposureChanged(prtyProperty* i_Property, bool i_bDirty) void CameraObject::ExposureIterationsChanged(prtyProperty* i_Property, bool i_bDirty) { - m_camera->m_Film.m_ExposureIterations = GetExposureIterationsValue(m_cameraDataObject.ExposureIterations.GetValue()); + m_camera->m_Film.m_ExposureIterations = m_cameraDataObject.ExposureIterations.GetValue(); m_camera->m_Dirty = true; } void @@ -237,25 +132,3 @@ CameraObject::FocalDistanceChanged(prtyProperty* i_Property, bool i_bDirty) m_camera->m_Focus.m_FocalDistance = m_cameraDataObject.FocalDistance.GetValue(); m_camera->m_Dirty = true; } - -//-------------------------------------------------------------------- -// common code when a property related to position of light is changed -//-------------------------------------------------------------------- -void -CameraObject::TransformationChanged(prtyProperty* i_Property, bool i_bDirty) -{ - // Rotate up vector through tilt angle - glm::vec3 pos, target; - // assumes world space. - pos = m_cameraDataObject.Position.GetValue(); - target = m_cameraDataObject.Target.GetValue(); - glm::vec3 up = glm::vec3(0, 1, 0); // default up vector - // Rotate the up vector around the vector from position to target - // using the roll angle (tilt angle) - up = glm::rotate(up, DEG_TO_RAD * m_cameraDataObject.Roll.GetValue(), target - pos); - - m_camera->m_From = pos; - m_camera->m_Target = target; - m_camera->m_Up = up; - m_camera->m_Dirty = true; -} diff --git a/renderlib/CameraObject.hpp b/renderlib/CameraObject.hpp index bc35a688..b51a7e03 100644 --- a/renderlib/CameraObject.hpp +++ b/renderlib/CameraObject.hpp @@ -24,7 +24,7 @@ class CameraObject : public prtyObject void updateObjectFromProps(); // Getter for camera data object - CameraDataObject& getCameraDataObject() { return m_cameraDataObject; } + // CameraDataObject& getCameraDataObject() { return m_cameraDataObject; } const CameraDataObject& getCameraDataObject() const { return m_cameraDataObject; } // Getters for UI info objects @@ -38,9 +38,6 @@ class CameraObject : public prtyObject // Getter for the camera std::shared_ptr getCamera() const { return m_camera; } - // Convert UI specific combo box index to a known enum type - static uint8_t GetExposureIterationsValue(int i_ComboBoxIndex); - private: // the properties CameraDataObject m_cameraDataObject; @@ -55,12 +52,4 @@ class CameraObject : public prtyObject FloatSliderSpinnerUiInfo* m_ApertureSizeUIInfo; FloatSliderSpinnerUiInfo* m_FieldOfViewUIInfo; FloatSliderSpinnerUiInfo* m_FocalDistanceUIInfo; - - void ExposureChanged(prtyProperty* i_Property, bool i_bDirty); - void ExposureIterationsChanged(prtyProperty* i_Property, bool i_bDirty); - void NoiseReductionChanged(prtyProperty* i_Property, bool i_bDirty); - void ApertureSizeChanged(prtyProperty* i_Property, bool i_bDirty); - void FieldOfViewChanged(prtyProperty* i_Property, bool i_bDirty); - void FocalDistanceChanged(prtyProperty* i_Property, bool i_bDirty); - void TransformationChanged(prtyProperty* i_Property, bool i_bDirty); }; diff --git a/renderlib/SceneLight.cpp b/renderlib/SceneLight.cpp index f4525d45..868a33b9 100644 --- a/renderlib/SceneLight.cpp +++ b/renderlib/SceneLight.cpp @@ -12,16 +12,16 @@ SceneLight::updateTransform() // because they will be used in future light updates float phi, theta; Light::cartesianToSpherical(normdir, phi, theta); - m_light->m_Phi = phi; - m_light->m_Theta = theta; + m_light.m_Phi = phi; + m_light.m_Theta = theta; // get m_P in world space: - m_light->m_P = m_light->m_Distance * normdir + m_light->m_Target; + m_light.m_P = m_light.m_Distance * normdir + m_light.m_Target; - m_light->updateBasisFrame(); + m_light.updateBasisFrame(); // this lets the GUI have a chance to update in an abstract way for (auto it = m_observers.begin(); it != m_observers.end(); ++it) { - (*it)(*m_light); + (*it)(m_light); } } diff --git a/renderlib/SceneLight.h b/renderlib/SceneLight.h index 9a43d320..e1f5bf56 100644 --- a/renderlib/SceneLight.h +++ b/renderlib/SceneLight.h @@ -8,20 +8,25 @@ #include #include -// MUST NOT OUTLIVE ITS LIGHT class SceneLight : public SceneObject { public: - SceneLight(Light* light) + SceneLight() + { + // we want the rotate manipulator to be centered at the target of the light, by default + m_transform.m_center = m_light.m_Target; + m_tool = std::make_unique(&m_light); + } + SceneLight(const Light& light) : m_light(light) { // we want the rotate manipulator to be centered at the target of the light, by default - m_transform.m_center = light->m_Target; - m_tool = std::make_unique(light); + m_transform.m_center = m_light.m_Target; + m_tool = std::make_unique(&m_light); } void updateTransform(); - Light* m_light; + Light m_light; std::vector> m_observers; std::unique_ptr m_tool; diff --git a/renderlib/SkyLightObject.cpp b/renderlib/SkyLightObject.cpp new file mode 100644 index 00000000..9f169a1e --- /dev/null +++ b/renderlib/SkyLightObject.cpp @@ -0,0 +1,155 @@ +#include "SkyLightObject.hpp" + +#include "SceneLight.h" +#include "Logging.h" + +SkyLightObject::SkyLightObject() + : prtyObject() +{ + m_sceneLight = std::make_shared(); + + m_topIntensityUIInfo = new ColorWithIntensityUiInfo( + &m_skylightDataObject.TopColor, &m_skylightDataObject.TopIntensity, "Intensity", "Top"); + // m_topIntensityUIInfo = new FloatSliderSpinnerUiInfo(&m_skylightDataObject.TopIntensity, "Intensity", "Top + // Intensity"); + m_topIntensityUIInfo->SetToolTip("Set Top Intensity"); + m_topIntensityUIInfo->SetStatusTip("Set skylight top intensity"); + m_topIntensityUIInfo->min = 0.0f; + m_topIntensityUIInfo->max = 10.0f; + m_topIntensityUIInfo->decimals = 2; + m_topIntensityUIInfo->singleStep = 0.1f; + AddProperty(m_topIntensityUIInfo); + + // m_topColorUIInfo = new ColorPickerUiInfo(&m_skylightDataObject.TopColor, "Color", "Top Color"); + // m_topColorUIInfo->SetToolTip("Set Top Color"); + // m_topColorUIInfo->SetStatusTip("Set skylight top color"); + // AddProperty(m_topColorUIInfo); + + m_middleIntensityUIInfo = new ColorWithIntensityUiInfo( + &m_skylightDataObject.MiddleColor, &m_skylightDataObject.MiddleIntensity, "Intensity", "Mid"); + // m_middleIntensityUIInfo = + // new FloatSliderSpinnerUiInfo(&m_skylightDataObject.MiddleIntensity, "Intensity", "Middle Intensity"); + m_middleIntensityUIInfo->SetToolTip("Set Middle Intensity"); + m_middleIntensityUIInfo->SetStatusTip("Set skylight middle intensity"); + m_middleIntensityUIInfo->min = 0.0f; + m_middleIntensityUIInfo->max = 10.0f; + m_middleIntensityUIInfo->decimals = 2; + m_middleIntensityUIInfo->singleStep = 0.1f; + AddProperty(m_middleIntensityUIInfo); + + // m_middleColorUIInfo = new ColorPickerUiInfo(&m_skylightDataObject.MiddleColor, "Color", "Middle Color"); + // m_middleColorUIInfo->SetToolTip("Set Middle Color"); + // m_middleColorUIInfo->SetStatusTip("Set skylight middle color"); + // AddProperty(m_middleColorUIInfo); + + m_bottomIntensityUIInfo = new ColorWithIntensityUiInfo( + &m_skylightDataObject.BottomColor, &m_skylightDataObject.BottomIntensity, "Intensity", "Bot"); + // m_bottomIntensityUIInfo = + // new FloatSliderSpinnerUiInfo(&m_skylightDataObject.BottomIntensity, "Intensity", "Bottom Intensity"); + m_bottomIntensityUIInfo->SetToolTip("Set Bottom Intensity"); + m_bottomIntensityUIInfo->SetStatusTip("Set skylight bottom intensity"); + m_bottomIntensityUIInfo->min = 0.0f; + m_bottomIntensityUIInfo->max = 10.0f; + m_bottomIntensityUIInfo->decimals = 2; + m_bottomIntensityUIInfo->singleStep = 0.1f; + AddProperty(m_bottomIntensityUIInfo); + + // m_bottomColorUIInfo = new ColorPickerUiInfo(&m_skylightDataObject.BottomColor, "Color", "Bottom Color"); + // m_bottomColorUIInfo->SetToolTip("Set Bottom Color"); + // m_bottomColorUIInfo->SetStatusTip("Set skylight bottom color"); + // AddProperty(m_bottomColorUIInfo); + + m_skylightDataObject.TopIntensity.AddCallback( + new prtyCallbackWrapper(this, &SkyLightObject::TopIntensityChanged)); + m_skylightDataObject.TopColor.AddCallback( + new prtyCallbackWrapper(this, &SkyLightObject::TopColorChanged)); + m_skylightDataObject.MiddleIntensity.AddCallback( + new prtyCallbackWrapper(this, &SkyLightObject::MiddleIntensityChanged)); + m_skylightDataObject.MiddleColor.AddCallback( + new prtyCallbackWrapper(this, &SkyLightObject::MiddleColorChanged)); + m_skylightDataObject.BottomIntensity.AddCallback( + new prtyCallbackWrapper(this, &SkyLightObject::BottomIntensityChanged)); + m_skylightDataObject.BottomColor.AddCallback( + new prtyCallbackWrapper(this, &SkyLightObject::BottomColorChanged)); +} + +void +SkyLightObject::updatePropsFromSceneLight() +{ + if (!m_sceneLight) + return; + + const Light& light = m_sceneLight->m_light; + + m_skylightDataObject.TopIntensity.SetValue(light.m_ColorTopIntensity); + m_skylightDataObject.TopColor.SetValue(glm::vec4(light.m_ColorTop, 1.0f)); + m_skylightDataObject.MiddleIntensity.SetValue(light.m_ColorMiddleIntensity); + m_skylightDataObject.MiddleColor.SetValue(glm::vec4(light.m_ColorMiddle, 1.0f)); + m_skylightDataObject.BottomIntensity.SetValue(light.m_ColorBottomIntensity); + m_skylightDataObject.BottomColor.SetValue(glm::vec4(light.m_ColorBottom, 1.0f)); +} + +void +SkyLightObject::updateSceneLightFromProps() +{ + if (!m_sceneLight) + return; + + Light& light = m_sceneLight->m_light; + + light.m_ColorTopIntensity = m_skylightDataObject.TopIntensity.GetValue(); + glm::vec4 topColor = m_skylightDataObject.TopColor.GetValue(); + light.m_ColorTop = glm::vec3(topColor.x, topColor.y, topColor.z); + + light.m_ColorMiddleIntensity = m_skylightDataObject.MiddleIntensity.GetValue(); + glm::vec4 middleColor = m_skylightDataObject.MiddleColor.GetValue(); + light.m_ColorMiddle = glm::vec3(middleColor.x, middleColor.y, middleColor.z); + + light.m_ColorBottomIntensity = m_skylightDataObject.BottomIntensity.GetValue(); + glm::vec4 bottomColor = m_skylightDataObject.BottomColor.GetValue(); + light.m_ColorBottom = glm::vec3(bottomColor.x, bottomColor.y, bottomColor.z); + + for (auto& observer : m_sceneLight->m_observers) { + observer(light); + } + + if (m_dirtyCallback) { + m_dirtyCallback(); + } +} + +void +SkyLightObject::TopIntensityChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +SkyLightObject::TopColorChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +SkyLightObject::MiddleIntensityChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +SkyLightObject::MiddleColorChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +SkyLightObject::BottomIntensityChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} + +void +SkyLightObject::BottomColorChanged(prtyProperty* i_Property, bool i_bDirty) +{ + updateSceneLightFromProps(); +} diff --git a/renderlib/SkyLightObject.hpp b/renderlib/SkyLightObject.hpp new file mode 100644 index 00000000..bce75a84 --- /dev/null +++ b/renderlib/SkyLightObject.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "core/prty/prtyObject.hpp" +#include "core/prty/prtyColor.hpp" +#include "core/prty/prtyFloat.hpp" +#include "uiInfo.hpp" + +#include +#include + +class SceneLight; + +// Data object for skylight properties +class SkylightDataObject +{ +public: + SkylightDataObject() = default; + + prtyFloat TopIntensity{ "TopIntensity", 1.0f }; + prtyColor TopColor{ "TopColor", glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; + prtyFloat MiddleIntensity{ "MiddleIntensity", 1.0f }; + prtyColor MiddleColor{ "MiddleColor", glm::vec4(0.5f, 0.5f, 0.5f, 1.0f) }; + prtyFloat BottomIntensity{ "BottomIntensity", 1.0f }; + prtyColor BottomColor{ "BottomColor", glm::vec4(0.2f, 0.2f, 0.2f, 1.0f) }; +}; + +class SkyLightObject : public prtyObject +{ +public: + SkyLightObject(); + + std::shared_ptr getSceneLight() const { return m_sceneLight; } + + // Update properties from scene light instance + void updatePropsFromSceneLight(); + + // Update scene light instance from properties (called automatically via callbacks) + void updateSceneLightFromProps(); + + // Property change callbacks + void TopIntensityChanged(prtyProperty* i_Property, bool i_bDirty); + void TopColorChanged(prtyProperty* i_Property, bool i_bDirty); + void MiddleIntensityChanged(prtyProperty* i_Property, bool i_bDirty); + void MiddleColorChanged(prtyProperty* i_Property, bool i_bDirty); + void BottomIntensityChanged(prtyProperty* i_Property, bool i_bDirty); + void BottomColorChanged(prtyProperty* i_Property, bool i_bDirty); + + void setDirtyCallback(std::function callback) { m_dirtyCallback = callback; } + +private: + SkylightDataObject m_skylightDataObject; + + // the actual object + std::shared_ptr m_sceneLight; + + std::function m_dirtyCallback; + + // UI Info objects + ColorWithIntensityUiInfo* m_topIntensityUIInfo = nullptr; + // ColorPickerUiInfo* m_topColorUIInfo = nullptr; + ColorWithIntensityUiInfo* m_middleIntensityUIInfo = nullptr; + // ColorPickerUiInfo* m_middleColorUIInfo = nullptr; + ColorWithIntensityUiInfo* m_bottomIntensityUIInfo = nullptr; + // ColorPickerUiInfo* m_bottomColorUIInfo = nullptr; +}; diff --git a/renderlib/core/prty/prtyProperty.hpp b/renderlib/core/prty/prtyProperty.hpp index ef78dce4..0d6c29b8 100644 --- a/renderlib/core/prty/prtyProperty.hpp +++ b/renderlib/core/prty/prtyProperty.hpp @@ -71,6 +71,7 @@ typedef std::vector property_list; ** prtyControlMgr::DeInitialize(); ** prtyCallbackMgr::DeInitialize(); ** +** Refer to test/prty application for an example. ** ** ** diff --git a/renderlib/core/prty/prtyPropertyCallback.hpp b/renderlib/core/prty/prtyPropertyCallback.hpp index 7e55f73a..f5911f46 100644 --- a/renderlib/core/prty/prtyPropertyCallback.hpp +++ b/renderlib/core/prty/prtyPropertyCallback.hpp @@ -2,6 +2,8 @@ #include +#include + //============================================================================ // forward references //============================================================================ diff --git a/renderlib/core/prty/prtyPropertyUIInfo.hpp b/renderlib/core/prty/prtyPropertyUIInfo.hpp index 765ea554..ae3cab43 100644 --- a/renderlib/core/prty/prtyPropertyUIInfo.hpp +++ b/renderlib/core/prty/prtyPropertyUIInfo.hpp @@ -1,3 +1,11 @@ +/****************************************************************************\ +** prtyPropertyUIInfo.hpp +** +** Property UI info +** +** +** +\****************************************************************************/ #pragma once #include diff --git a/renderlib/graphics/RenderGLPT.cpp b/renderlib/graphics/RenderGLPT.cpp index 6a7564f0..0c00564d 100644 --- a/renderlib/graphics/RenderGLPT.cpp +++ b/renderlib/graphics/RenderGLPT.cpp @@ -194,7 +194,7 @@ RenderGLPT::doRender(const CCamera& camera) } if (m_renderSettings->m_DirtyFlags.HasFlag(LightsDirty)) { for (int i = 0; i < m_scene->m_lighting.m_NoLights; ++i) { - m_scene->m_lighting.m_Lights[i]->Update(m_scene->m_boundingBox); + m_scene->m_lighting.m_sceneLights[i]->m_light.Update(m_scene->m_boundingBox); } // Reset no. iterations diff --git a/renderlib/uiInfo.hpp b/renderlib/uiInfo.hpp index c3b95c2e..5a3ac8c7 100644 --- a/renderlib/uiInfo.hpp +++ b/renderlib/uiInfo.hpp @@ -1,61 +1,77 @@ #pragma once -#include "core/prty/prtyPropertyUIInfo.hpp" - #include #include -class CheckBoxUiInfo : public prtyPropertyUIInfo +struct GenericUIInfo { -public: - static constexpr const char* TYPE = "CheckBox"; - CheckBoxUiInfo(prtyProperty* i_pProperty) - : prtyPropertyUIInfo(i_pProperty) - { - SetControlName(TYPE); - } - CheckBoxUiInfo(prtyProperty* i_pProperty, const std::string& i_Category, const std::string& i_Description) - : prtyPropertyUIInfo(i_pProperty, i_Category, i_Description) + std::string type; + std::string formLabel; + std::string statusTip; + std::string toolTip; + + GenericUIInfo() = default; + GenericUIInfo(std::string type, std::string formLabel, std::string statusTip, std::string toolTip) + : type(type) + , formLabel(formLabel) + , statusTip(statusTip) + , toolTip(toolTip) { - SetControlName(TYPE); } }; - -class ColorPickerUiInfo : public prtyPropertyUIInfo +struct CheckBoxUiInfo : public GenericUIInfo { -public: - static constexpr const char* TYPE = "ColorPicker"; - ColorPickerUiInfo(prtyProperty* i_pProperty) - : prtyPropertyUIInfo(i_pProperty) + static constexpr const char* TYPE = "CheckBox"; + + CheckBoxUiInfo() { type = CheckBoxUiInfo::TYPE; } + CheckBoxUiInfo(std::string formLabel, std::string statusTip, std::string toolTip) + : GenericUIInfo(CheckBoxUiInfo::TYPE, formLabel, statusTip, toolTip) { - SetControlName(TYPE); } - ColorPickerUiInfo(prtyProperty* i_pProperty, const std::string& i_Category, const std::string& i_Description) - : prtyPropertyUIInfo(i_pProperty, i_Category, i_Description) +}; +struct ComboBoxUiInfo : public GenericUIInfo +{ + static constexpr const char* TYPE = "ComboBox"; + std::vector items; + + ComboBoxUiInfo() { type = ComboBoxUiInfo::TYPE; } + ComboBoxUiInfo(std::string formLabel, std::string statusTip, std::string toolTip, std::vector items) + : GenericUIInfo(ComboBoxUiInfo::TYPE, formLabel, statusTip, toolTip) + , items(items) { - SetControlName(TYPE); } }; -class ComboBoxUiInfo : public prtyPropertyUIInfo +class ColorWithIntensityUiInfo : public prtyPropertyUIInfo { public: - static constexpr const char* TYPE = "ComboBox"; + static constexpr const char* TYPE = "ColorWithIntensity"; + float min = 0.0f; + float max = 0.0f; + int decimals = 0; + float singleStep = 0.0f; + int numTickMarks = 0; + std::string suffix; - ComboBoxUiInfo(prtyProperty* i_pProperty) - : prtyPropertyUIInfo(i_pProperty) + ColorWithIntensityUiInfo(prtyProperty* i_pColorProperty, prtyProperty* i_pIntensityProperty) + : prtyPropertyUIInfo(i_pColorProperty) { + AddProperty(i_pIntensityProperty); SetControlName(TYPE); } - ComboBoxUiInfo(prtyProperty* i_pProperty, const std::string& i_Category, const std::string& i_Description) - : prtyPropertyUIInfo(i_pProperty, i_Category, i_Description) + ColorWithIntensityUiInfo(prtyProperty* i_pColorProperty, + prtyProperty* i_pIntensityProperty, + const std::string& i_Category, + const std::string& i_Description) + : prtyPropertyUIInfo(i_pColorProperty, i_Category, i_Description) { + AddProperty(i_pIntensityProperty); SetControlName(TYPE); } }; + class FloatSliderSpinnerUiInfo : public prtyPropertyUIInfo { -public: static constexpr const char* TYPE = "FloatSliderSpinner"; float min = 0.0f; float max = 0.0f; @@ -64,39 +80,28 @@ class FloatSliderSpinnerUiInfo : public prtyPropertyUIInfo int numTickMarks = 0; std::string suffix; - FloatSliderSpinnerUiInfo(prtyProperty* i_pProperty) - : prtyPropertyUIInfo(i_pProperty) + FloatSliderSpinnerUiInfo() { type = FloatSliderSpinnerUiInfo::TYPE; } + FloatSliderSpinnerUiInfo(std::string formLabel, + std::string statusTip, + std::string toolTip, + float min, + float max, + int decimals, + float singleStep, + int numTickMarks = 0, + std::string suffix = "") + : GenericUIInfo(FloatSliderSpinnerUiInfo::TYPE, formLabel, statusTip, toolTip) + , min(min) + , max(max) + , decimals(decimals) + , singleStep(singleStep) + , numTickMarks(numTickMarks) + , suffix(suffix) { - SetControlName(TYPE); - } - FloatSliderSpinnerUiInfo(prtyProperty* i_pProperty, const std::string& i_Category, const std::string& i_Description) - : prtyPropertyUIInfo(i_pProperty, i_Category, i_Description) - { - SetControlName(TYPE); } }; -// std::string statusTip, -// std::string toolTip, -// float min, -// float max, -// int decimals, -// float singleStep, -// int numTickMarks = 0, -// std::string suffix = "") -// : GenericUIInfo(FloatSliderSpinnerUiInfo::TYPE, formLabel, statusTip, toolTip) -// , min(min) -// , max(max) -// , decimals(decimals) -// , singleStep(singleStep) -// , numTickMarks(numTickMarks) -// , suffix(suffix) -// { -// } -// }; - -class IntSliderSpinnerUiInfo : public prtyPropertyUIInfo +struct IntSliderSpinnerUiInfo : public GenericUIInfo { -public: static constexpr const char* TYPE = "IntSliderSpinner"; int min; int max; @@ -104,15 +109,16 @@ class IntSliderSpinnerUiInfo : public prtyPropertyUIInfo int numTickMarks; std::string suffix; - IntSliderSpinnerUiInfo(prtyProperty* i_pProperty) - : prtyPropertyUIInfo(i_pProperty) - { - SetControlName(TYPE); - } + IntSliderSpinnerUiInfo() { type = IntSliderSpinnerUiInfo::TYPE; } +}; - IntSliderSpinnerUiInfo(prtyProperty* i_pProperty, const std::string& i_Category, const std::string& i_Description) - : prtyPropertyUIInfo(i_pProperty, i_Category, i_Description) +struct ColorPickerUiInfo : public GenericUIInfo +{ + static constexpr const char* TYPE = "ColorPicker"; + + ColorPickerUiInfo() { type = ColorPickerUiInfo::TYPE; } + ColorPickerUiInfo(std::string formLabel, std::string statusTip, std::string toolTip) + : GenericUIInfo(ColorPickerUiInfo::TYPE, formLabel, statusTip, toolTip) { - SetControlName(TYPE); } };