diff --git a/.gitignore b/.gitignore index 96d3490..d4ebd0d 100644 --- a/.gitignore +++ b/.gitignore @@ -364,4 +364,5 @@ FodyWeavers.xsd /FinalProject/temp/shaders /Models /Terrains + /terrain diff --git a/FinalProject/FinalProject.vcxproj b/FinalProject/FinalProject.vcxproj index 85ae864..20884cb 100644 --- a/FinalProject/FinalProject.vcxproj +++ b/FinalProject/FinalProject.vcxproj @@ -125,6 +125,12 @@ + + input + %(Filename).moc + input + %(Filename).moc + @@ -162,6 +168,7 @@ + diff --git a/FinalProject/FinalProject.vcxproj.filters b/FinalProject/FinalProject.vcxproj.filters index 2b3fe40..f804ae4 100644 --- a/FinalProject/FinalProject.vcxproj.filters +++ b/FinalProject/FinalProject.vcxproj.filters @@ -77,6 +77,12 @@ {6c5ac0df-26ad-40ad-860c-3d0372b81094} + + {cb50686f-5bfb-4087-a103-04188e392f6d} + + + {9bdb6f33-7b69-4419-878a-e4891d73f84f} + @@ -180,8 +186,8 @@ Source Files\Qt Widgets\Pages\Scene Editor\Object Setter - - Source Files\OpenGL Abstractions + + Source Files\Qt Widgets\Pages\Setting Page @@ -292,6 +298,9 @@ Header Files\Qt Widgets\Pages\Scene Editor\Object Setter + + Header Files\Qt Widgets\Pages\Setting Page + diff --git a/FinalProject/aboutpage.cpp b/FinalProject/aboutpage.cpp index 62b2631..cab2ed6 100644 --- a/FinalProject/aboutpage.cpp +++ b/FinalProject/aboutpage.cpp @@ -26,7 +26,7 @@ AboutPage::AboutPage(QWidget* parent) : _mainWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); _mainWidget->setStyleSheet("QWidget#mainWidget { background-color: #efefef; border-radius: 8px; }"); _mainLayout = new QVBoxLayout(_mainWidget); - _mainLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft); + _mainLayout->setAlignment(Qt::AlignTop); _mainLayout->setContentsMargins(0, 8, 0, 8); _mainLayout->setSpacing(8); _mainWidget->setLayout(_mainLayout); diff --git a/FinalProject/editorpage.cpp b/FinalProject/editorpage.cpp index 6dfdd98..9be39ee 100644 --- a/FinalProject/editorpage.cpp +++ b/FinalProject/editorpage.cpp @@ -78,6 +78,12 @@ EditorPage::EditorPage(QWidget* parent) : EditorPage::~EditorPage() {} +void EditorPage::updateSetting(QPair setting) { + if (_sceneViewer != nullptr) { + _sceneViewer->updateSetting(setting); + } +} + PushButton* EditorPage::getPageIconButton(QWidget* context) { // Check for existed button if (_iconButton != nullptr) { diff --git a/FinalProject/editorpage.h b/FinalProject/editorpage.h index 3b28202..7d0be52 100644 --- a/FinalProject/editorpage.h +++ b/FinalProject/editorpage.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "pagewidget.h" #include "sceneviewer.h" @@ -44,6 +45,9 @@ private: ModelSetter* _modelSetter = nullptr; +public: + void updateSetting(QPair setting); + public: virtual PushButton* getPageIconButton(QWidget* context) override; virtual PushButton* getPageTextButton(QWidget* context) override; diff --git a/FinalProject/illuminer.h b/FinalProject/illuminer.h index d0226d8..9e08a48 100644 --- a/FinalProject/illuminer.h +++ b/FinalProject/illuminer.h @@ -30,19 +30,21 @@ public: class DirLight : public Illuminer{ protected: glm::vec3 _direction; // The outgoing direction of the light source + float _intensity = 50; public: DirLight(glm::vec3 direction = glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3 color = glm::vec3(1.0f)); ~DirLight(); protected: - virtual glm::vec3 ambientLightColor() const override { return glm::vec3(0.2f) * _lightColor; } - virtual glm::vec3 diffuseLightColor() const override { return glm::vec3(0.6f) * _lightColor; } + virtual glm::vec3 ambientLightColor() const override { return glm::vec3(_intensity / 200.0f) * _lightColor; } + virtual glm::vec3 diffuseLightColor() const override { return glm::vec3(_intensity / 100.0f) * _lightColor; } virtual glm::vec3 specularLightColor() const override { return glm::vec3(1.0f) * _lightColor; } public: glm::vec3 lightDirection() const { return _direction; } // The same direction as the outgoing direction void setLightDirection(glm::vec3 direction) { _direction = direction; } + void setIntensity(float intensity) { _intensity = intensity; } // Render util function virtual void updateShader(ShaderProgram shader, int index) const override; diff --git a/FinalProject/mainwindow.cpp b/FinalProject/mainwindow.cpp index dee9516..70bab45 100644 --- a/FinalProject/mainwindow.cpp +++ b/FinalProject/mainwindow.cpp @@ -45,10 +45,17 @@ MainWindow::MainWindow(QWidget *parent) _editorPage->setMouseTracking(true); _sideBar->addPage(_editorPage); + // Create setting page and connect to side bar + _settingPage = new SettingPage(_placeHolderWidget); + _settingPage->setMouseTracking(true); + _sideBar->addPage(_settingPage); + // Create about page and connect to side bar _aboutPage = new AboutPage(_placeHolderWidget); _aboutPage->setMouseTracking(true); _sideBar->addPage(_aboutPage); + + connect(_settingPage, &SettingPage::onSettingsChanged, _editorPage, &EditorPage::updateSetting); } MainWindow::~MainWindow() { @@ -65,6 +72,7 @@ void MainWindow::resizePages(QResizeEvent* event) { // Resize the editor page _editorPage->resize(size); + _settingPage->resize(size); _aboutPage->resize(size); } @@ -74,6 +82,7 @@ void MainWindow::showEvent(QShowEvent* event) { // Resize all the pages based on the placeholder widget _editorPage->resize(_placeHolderWidget->size()); + _settingPage->resize(_placeHolderWidget->size()); _aboutPage->resize(_placeHolderWidget->size()); } diff --git a/FinalProject/mainwindow.h b/FinalProject/mainwindow.h index d6f63c0..2dead03 100644 --- a/FinalProject/mainwindow.h +++ b/FinalProject/mainwindow.h @@ -6,6 +6,7 @@ #include "sidebar.h" #include "editorpage.h" #include "aboutpage.h" +#include "settingpage.h" class MainWindow : public FramelessWindow { @@ -23,6 +24,7 @@ private: SideBar* _sideBar = nullptr; EditorPage* _editorPage = nullptr; AboutPage* _aboutPage = nullptr; + SettingPage* _settingPage = nullptr; // Place holder widget for resizing pages QWidget* _placeHolderWidget = nullptr; diff --git a/FinalProject/sceneviewer.cpp b/FinalProject/sceneviewer.cpp index ab24aa9..4e78ac6 100644 --- a/FinalProject/sceneviewer.cpp +++ b/FinalProject/sceneviewer.cpp @@ -146,7 +146,7 @@ void SceneViewer::initializeGL() { _skyShader.attachShader(skyFragmentShader); skyVertexShader.dispose(); skyFragmentShader.dispose(); - + _terrainShader.ensureInitialized(); Logger::info("Terrain Shader initialized"); @@ -156,24 +156,8 @@ void SceneViewer::initializeGL() { _terrainShader.attachShader(terrainFragmentShader); terrainVertexShader.dispose(); terrainFragmentShader.dispose(); - - // Test Code Start - _sky = new SkyBox("D:\\ProgrammingFile\\SceneEditor\\SkyBoxes"); - _terrain = new Terrain("D:\\ProgrammingFile\\SceneEditor\\Terrains"); _dirLight = new DirLight(); - - //Model* model = new Model("E:\\Repositories\\CollegeProjects\\CGAssignments\\FinalProject\\Models\\backpack\\backpack.obj"); - //Renderable* backpack = new Renderable(model); - //backpack->move(glm::vec3(-5.0f, -2.0f, -2.0f)); - //backpack->updateBoundary(); - //_objects.push_back(backpack); - // - //Renderable* backpack2 = new Renderable(model); - //backpack2->makeLight(); - //backpack2->originalLight()->setIdealDistance(500); - //_objects.push_back(backpack2); - // Test Code End _camera.setPosition(glm::vec3(0.0f, 0.0f, 10.0f)); } @@ -239,7 +223,7 @@ void SceneViewer::paintGL() { _shaderProgram.setUniform("pointlightnr", pointLights); _shaderProgram.setUniform("spotlightnr", spotLights); - if (_dirLight != nullptr) { + if (_dirLight != nullptr && _dirLightOn) { _dirLight->updateShader(_shaderProgram, 0); } @@ -569,3 +553,62 @@ void SceneViewer::deleteObject() { emit onSelect(nullptr); parentWidget()->update(); } + +void SceneViewer::updateSetting(QPair setting) { + makeCurrent(); + if (setting.first == "stickSurface") { + _stickToSurface = true; + } + else if (setting.first == "skybox") { + if (_sky != nullptr) { + delete _sky; + _sky = nullptr; + } + if (!setting.second.isEmpty()) { + _sky = new SkyBox(setting.second.toStdString()); + } + } + else if (setting.first == "terrain") { + if (_terrain != nullptr) { + delete _terrain; + _terrain = nullptr; + } + if (!setting.second.isEmpty()) { + _terrain = new Terrain(setting.second.toStdString()); + } + } + else if (setting.first == "dirLight") { + if (setting.second == "true") { + _dirLightOn = true; + } + else { + _dirLightOn = false; + } + } + else if (setting.first == "dirLightColorR") { + _dirLight->setLightColor(glm::vec3(setting.second.toFloat(), _dirLight->lightColor().y, _dirLight->lightColor().z)); + } + else if (setting.first == "dirLightColorG") { + _dirLight->setLightColor(glm::vec3(_dirLight->lightColor().x, setting.second.toFloat(), _dirLight->lightColor().z)); + } + else if (setting.first == "dirLightColorB") { + _dirLight->setLightColor(glm::vec3(_dirLight->lightColor().x, _dirLight->lightColor().y, setting.second.toFloat())); + } + else if (setting.first == "dirLightIntensity") { + _dirLight->setIntensity(setting.second.toFloat()); + } + else if (setting.first == "dirLightDir") { + // parse "x,y,z" + QStringList list = setting.second.split(","); + if (list.size() == 3) { + _dirLight->setLightDirection(glm::vec3(list[0].toFloat(), list[1].toFloat(), list[2].toFloat())); + } + else { + Logger::error("Invalid direction light direction setting"); + } + } + else { + Logger::warning("Unknown setting input"); + } + doneCurrent(); +} diff --git a/FinalProject/sceneviewer.h b/FinalProject/sceneviewer.h index 225c696..24532b4 100644 --- a/FinalProject/sceneviewer.h +++ b/FinalProject/sceneviewer.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -24,10 +25,11 @@ private: // OpenGL section------------------------------------- // List of objects currently in the scene std::vector _objects; + // Sky Box + SkyBox* _sky = nullptr; // Dir light + bool _dirLightOn = false; DirLight* _dirLight = nullptr; - // Sky Box - SkyBox* _sky; // Terrain Terrain* _terrain; // Shader program for objects @@ -103,6 +105,7 @@ public: parentWidget()->update(); } void deleteObject(); + void updateSetting(QPair setting); signals: void onHover(Renderable* object); diff --git a/FinalProject/settingpage.cpp b/FinalProject/settingpage.cpp new file mode 100644 index 0000000..9f584fc --- /dev/null +++ b/FinalProject/settingpage.cpp @@ -0,0 +1,313 @@ +#include +#include +#include + +#include "settingpage.h" +#include "logger.h" + +SettingPage::SettingPage(QWidget* parent) : + PageWidget(parent) +{ + _contentWidget->setMouseTracking(true); + + // Construct title layout + _titleLayout = new QVBoxLayout(_contentWidget); + _titleLayout->setContentsMargins(28, 46, 28, 28); + _titleLayout->setSpacing(18); + _titleLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft); + _contentWidget->setLayout(_titleLayout); + + // Construct title + _titleLabel = new QLabel("SETTINGS", _contentWidget); + _titleLabel->setFont(_titleFont); + _titleLayout->addWidget(_titleLabel); + _titleLabel->show(); + + // Construct main layout + _mainWidget = new QWidget(_contentWidget); + _mainWidget->setObjectName("mainWidget"); + _mainWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + _mainWidget->setStyleSheet("QWidget#mainWidget { background-color: #f5f5f5; border-radius: 8px; }"); + _mainLayout = new QVBoxLayout(_mainWidget); + _mainLayout->setAlignment(Qt::AlignTop); + _mainLayout->setContentsMargins(12, 12, 12, 12); + _mainLayout->setSpacing(8); + _mainWidget->setLayout(_mainLayout); + _titleLayout->addWidget(_mainWidget); + _mainWidget->show(); + + // Create stick surface button + _stickSurfaceBtn = new PushButton(nullptr, _mainWidget); + _stickSurfaceBtn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _stickSurfaceBtn->setMaximumHeight(48); + _stickSurfaceBtn->setBackgroundColor(QColor(220, 220, 220)); + _stickSurfaceBtnLabel = new QLabel("Stick to Surface", _stickSurfaceBtn); + _stickSurfaceBtnLabel->setAlignment(Qt::AlignCenter); + _stickSurfaceBtnLabel->show(); + _stickSurfaceBtn->setChildWidget(_stickSurfaceBtnLabel); + _mainLayout->addWidget(_stickSurfaceBtn); + _stickSurfaceBtn->show(); + connect(_stickSurfaceBtn, &PushButton::onClick, this, [=]() { + if (_stickSurfaceBtn->isSelected()) { + _stickSurfaceBtn->deselect(); + emit onSettingsChanged(QPair("stickSurface", "false")); + } + else { + _stickSurfaceBtn->select(); + emit onSettingsChanged(QPair("stickSurface", "true")); + } + }); + + // Create skybox selector + _skyTerSelContainer = new QWidget(_mainWidget); + _skyTerSelContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _skyTerSelContainer->setMaximumHeight(48); + _skyTerSelLayout = new QHBoxLayout(_skyTerSelContainer); + _skyTerSelLayout->setContentsMargins(0, 0, 0, 0); + _skyTerSelLayout->setSpacing(6); + _skyTerSelContainer->setLayout(_skyTerSelLayout); + _mainLayout->addWidget(_skyTerSelContainer); + _skyTerSelContainer->show(); + + _skySelector = new PushButton(nullptr, _skyTerSelContainer); + _skySelector->setBackgroundColor(QColor(220, 220, 220)); + _skySelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _skySelectorLabel = new QLabel("Import Skybox", _skySelector); + _skySelectorLabel->setAlignment(Qt::AlignCenter); + _skySelectorLabel->show(); + _skySelector->setChildWidget(_skySelectorLabel); + _skyTerSelLayout->addWidget(_skySelector); + _skySelector->show(); + connect(_skySelector, &PushButton::onClick, this, &SettingPage::selectSkyBox); + + _terrainSelector = new PushButton(nullptr, _skyTerSelContainer); + _terrainSelector->setBackgroundColor(QColor(220, 220, 220)); + _terrainSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _terrainSelectorLabel = new QLabel("Import Terrain", _terrainSelector); + _terrainSelectorLabel->setAlignment(Qt::AlignCenter); + _terrainSelectorLabel->show(); + _terrainSelector->setChildWidget(_terrainSelectorLabel); + _skyTerSelLayout->addWidget(_terrainSelector); + _terrainSelector->show(); + connect(_terrainSelector, &PushButton::onClick, this, &SettingPage::selectTerrain); + + // Create direction light setter + _dirLightSwitch = new PushButton(nullptr, _mainWidget); + _dirLightSwitch->setBackgroundColor(QColor(220, 220, 220)); + _dirLightSwitch->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _dirLightSwitch->setMaximumHeight(48); + _dirLightSwitchLabel = new QLabel("Directional Light", _dirLightSwitch); + _dirLightSwitchLabel->setAlignment(Qt::AlignCenter); + _dirLightSwitchLabel->show(); + _dirLightSwitch->setChildWidget(_dirLightSwitchLabel); + _mainLayout->addWidget(_dirLightSwitch); + _dirLightSwitch->show(); + connect(_dirLightSwitch, &PushButton::onClick, this, [=]() { + if (_dirLightSwitch->isSelected()) { + _dirLightSwitch->deselect(); + _dirLightColorR->setEnabled(false); + _dirLightColorG->setEnabled(false); + _dirLightColorB->setEnabled(false); + _dirLightIntensity->setEnabled(false); + _dirLightTheta->setEnabled(false); + _dirLightPhi->setEnabled(false); + emit onSettingsChanged(QPair("dirLight", "false")); + } + else { + _dirLightSwitch->select(); + _dirLightColorR->setEnabled(true); + _dirLightColorG->setEnabled(true); + _dirLightColorB->setEnabled(true); + _dirLightIntensity->setEnabled(true); + _dirLightTheta->setEnabled(true); + _dirLightPhi->setEnabled(true); + emit onSettingsChanged(QPair("dirLight", "true")); + } + }); + + _dirLightColorR = new ModelAttributeSlide("Red", 0, 255, 255, _mainWidget); + _dirLightColorR->setValue(255); + _dirLightColorR->setEnabled(false); + _mainLayout->addWidget(_dirLightColorR); + _dirLightColorR->show(); + connect(_dirLightColorR, &ModelAttributeSlide::onChanged, this, [=](int value) { + emit onSettingsChanged(QPair("dirLightColorR", QString::number(value / 255.0f))); + }); + + _dirLightColorG = new ModelAttributeSlide("Green", 0, 255, 255, _mainWidget); + _dirLightColorG->setValue(255); + _dirLightColorG->setEnabled(false); + _mainLayout->addWidget(_dirLightColorG); + _dirLightColorG->show(); + connect(_dirLightColorG, &ModelAttributeSlide::onChanged, this, [=](int value) { + emit onSettingsChanged(QPair("dirLightColorG", QString::number(value / 255.0f))); + }); + + _dirLightColorB = new ModelAttributeSlide("Blue", 0, 255, 255, _mainWidget); + _dirLightColorB->setValue(255); + _dirLightColorB->setEnabled(false); + _mainLayout->addWidget(_dirLightColorB); + _dirLightColorB->show(); + connect(_dirLightColorB, &ModelAttributeSlide::onChanged, this, [=](int value) { + emit onSettingsChanged(QPair("dirLightColorB", QString::number(value / 255.0f))); + }); + + _dirLightIntensity = new ModelAttributeSlide("Intensity", 0, 100, 100, _mainWidget); + _dirLightIntensity->setValue(50); + _dirLightIntensity->setEnabled(false); + _mainLayout->addWidget(_dirLightIntensity); + _dirLightIntensity->show(); + connect(_dirLightIntensity, &ModelAttributeSlide::onChanged, this, [=](int value) { + emit onSettingsChanged(QPair("dirLightIntensity", QString::number(value))); + }); + + _dirLightTheta = new ModelAttributeSlide("Rotate\u03B8", 0, 360, 3600, _mainWidget); + _dirLightTheta->setValue(0); + _dirLightTheta->setEnabled(false); + _mainLayout->addWidget(_dirLightTheta); + _dirLightTheta->show(); + connect(_dirLightTheta, &ModelAttributeSlide::onChanged, this, [=]() { + // Calculate direction vector by theta and phi + float theta = _dirLightTheta->val(); // theta angle + float phi = _dirLightPhi->val(); // phi angle + float x = sin(theta) * cos(phi); + float y = sin(theta) * sin(phi); + float z = cos(theta); + glm::vec3 dir = glm::vec3(x, y, z); + emit onSettingsChanged(QPair("dirLightDir", QString::number(dir.x) + "," + QString::number(dir.y) + "," + QString::number(dir.z))); + }); + + _dirLightPhi = new ModelAttributeSlide("Rotate\u03C6", 0, 360, 3600, _mainWidget); + _dirLightPhi->setValue(0); + _dirLightPhi->setEnabled(false); + _mainLayout->addWidget(_dirLightPhi); + _dirLightPhi->show(); + connect(_dirLightPhi, &ModelAttributeSlide::onChanged, this, [=]() { + // Calculate direction vector by theta and phi + float theta = _dirLightTheta->val(); // theta angle + float phi = _dirLightPhi->val(); // phi angle + float x = sin(theta) * cos(phi); + float y = sin(theta) * sin(phi); + float z = cos(theta); + glm::vec3 dir = glm::vec3(x, y, z); + emit onSettingsChanged(QPair("dirLightDir", QString::number(dir.x) + "," + QString::number(dir.y) + "," + QString::number(dir.z))); + }); +} + +SettingPage::~SettingPage() {} + +PushButton* SettingPage::getPageIconButton(QWidget* context) { + // Check for existed button + if (_iconButton != nullptr) { + return _iconButton; + } + + // Generate new icon button + _iconButton = new PushButton(nullptr, context); + _iconButton->setMargin(20, 18, 16, 18); + _iconButtonLabel = new QLabel(_iconButton); + _iconButtonLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + QFont iconButtonFont("Font Awesome 6 Free Solid", 12); + iconButtonFont.setStyleStrategy(QFont::PreferAntialias); + _iconButtonLabel->setFont(iconButtonFont); + _iconButtonLabel->setText("\uf013"); + _iconButtonLabel->setAlignment(Qt::AlignLeft); + _iconButton->setChildWidget(_iconButtonLabel); + + // Return newly generated icon + return _iconButton; +} + +PushButton* SettingPage::getPageTextButton(QWidget* context) { + // Check for existed button + if (_textButton != nullptr) { + return _textButton; + } + + // Generate new text button + _textButton = new PushButton(nullptr, context); + _textButton->setMargin(20, 18, 16, 18); + _textButtonWidget = new QWidget(_textButton); + _textButtonLayout = new QHBoxLayout(_textButtonWidget); + _textButtonLayout->setContentsMargins(0, 0, 0, 0); + _textButtonLayout->setSpacing(12); + _textButtonWidget->setLayout(_textButtonLayout); + + // Generate text button contents + _textButtonIcon = new QLabel(_textButtonWidget); + QFont textButtonFont("Font Awesome 6 Free Solid", 12); + textButtonFont.setStyleStrategy(QFont::PreferQuality); + _textButtonIcon->setFont(textButtonFont); + _textButtonIcon->setText("\uf013"); + _textButtonIcon->setAlignment(Qt::AlignLeft); + + _textButtonLabel = new QLabel(_textButtonWidget); + _textButtonLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + _textButtonLabel->setText("Settings"); + _textButtonLabel->setAlignment(Qt::AlignLeft); + + // Add text button contents to layout + _textButtonLayout->addWidget(_textButtonIcon); + _textButtonLayout->addWidget(_textButtonLabel); + _textButtonIcon->show(); + _textButtonLabel->show(); + + // Set text button child widget + _textButton->setChildWidget(_textButtonWidget); + _textButtonWidget->show(); + + // Return newly generated text button + return _textButton; +} + +void SettingPage::selectSkyBox() { + // Select a directory that contains back.jpg, bottom.jpg, front.jpg, left.jpg, right.jpg, top.jpg + QString dir = QFileDialog::getExistingDirectory(this, tr("Select Skybox Directory"), QDir::currentPath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (dir.isEmpty()) { + Logger::warning("Tempt to open invalid skybox folder"); + emit onSettingsChanged(QPair("skybox", "")); + return; + } + + // Check if the directory contains all the required files + QDir skyboxDir(dir); + QStringList skyboxFiles = skyboxDir.entryList(QStringList() << "*.jpg", QDir::Files); + if ( + skyboxFiles.indexOf("back.jpg") == -1 || + skyboxFiles.indexOf("bottom.jpg") == -1 || + skyboxFiles.indexOf("front.jpg") == -1 || + skyboxFiles.indexOf("left.jpg") == -1 || + skyboxFiles.indexOf("right.jpg") == -1 || + skyboxFiles.indexOf("top.jpg") == -1 + ) { + QMessageBox::warning(this, "Error", "The selected directory does not contain all the required files."); + Logger::warning("Tempt to open invalid skybox folder"); + emit onSettingsChanged(QPair("skybox", "")); + return; + } + + emit onSettingsChanged(QPair("skybox", dir)); +} + +void SettingPage::selectTerrain() { + QString dir = QFileDialog::getExistingDirectory(this, tr("Select Terrain Directory"), QDir::currentPath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (dir.isEmpty()) { + Logger::warning("Tempt to open invalid terrain folder"); + emit onSettingsChanged(QPair("terrain", "")); + return; + } + + QDir terrainDir(dir); + QStringList terrainFiles = terrainDir.entryList(QStringList() << "*.jpg", QDir::Files); + if ( + terrainFiles.indexOf("heightmap.png") == -1 || + terrainFiles.indexOf("texture.jpg") == -1 + ) { + QMessageBox::warning(this, "Error", "The selected directory does not contain all the required files."); + Logger::warning("Tempt to open invalid terrain folder"); + emit onSettingsChanged(QPair("terrain", "")); + return; + } + + emit onSettingsChanged(QPair("terrain", dir)); +} diff --git a/FinalProject/settingpage.h b/FinalProject/settingpage.h new file mode 100644 index 0000000..0956258 --- /dev/null +++ b/FinalProject/settingpage.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include +#include + +#include "pagewidget.h" +#include "lineeditwidget.h" +#include "modelattrslide.h" + +class SettingPage : public PageWidget +{ + Q_OBJECT + +public: + SettingPage(QWidget* parent = 0); + ~SettingPage(); + +private: + // Push button icons + QLabel* _iconButtonLabel = nullptr; + QWidget* _textButtonWidget = nullptr; + QHBoxLayout* _textButtonLayout = nullptr; + QLabel* _textButtonIcon = nullptr; + QLabel* _textButtonLabel = nullptr; + + // UI elements + QVBoxLayout* _titleLayout = nullptr; + const QFont _titleFont = QFont("DengXian", 26, QFont::ExtraLight); + QLabel* _titleLabel = nullptr; + + QWidget* _mainWidget = nullptr; + QVBoxLayout* _mainLayout = nullptr; + + // Stick to surface checkbox + PushButton* _stickSurfaceBtn = nullptr; + QLabel* _stickSurfaceBtnLabel = nullptr; + + // Terrain & Skybox selector + QWidget* _skyTerSelContainer = nullptr; + QHBoxLayout* _skyTerSelLayout = nullptr; + PushButton* _skySelector = nullptr; + QLabel* _skySelectorLabel = nullptr; + PushButton* _terrainSelector = nullptr; + QLabel* _terrainSelectorLabel = nullptr; + + // Dir light setter + //QWidget* _dirLightSetter = nullptr; + //QHBoxLayout* _dirLightSetterLayout = nullptr; + PushButton* _dirLightSwitch = nullptr; + QLabel* _dirLightSwitchLabel = nullptr; + //QVBoxLayout* _dirLightColorLayout = nullptr; + ModelAttributeSlide* _dirLightColorR = nullptr; + ModelAttributeSlide* _dirLightColorG = nullptr; + ModelAttributeSlide* _dirLightColorB = nullptr; + //QVBoxLayout* _dirLightAttrLayout; + ModelAttributeSlide* _dirLightIntensity = nullptr; + ModelAttributeSlide* _dirLightTheta = nullptr; + ModelAttributeSlide* _dirLightPhi = nullptr; + +private: + void selectSkyBox(); + void selectTerrain(); + +public: + virtual PushButton* getPageIconButton(QWidget* context) override; + virtual PushButton* getPageTextButton(QWidget* context) override; + +signals: + void onSettingsChanged(QPair settings); +}; \ No newline at end of file