From 3455cbf9e1a6e5e1909846b2fc104dac2fe00527 Mon Sep 17 00:00:00 2001
From: Linloir <3145078758@qq.com>
Date: Mon, 19 Dec 2022 21:31:03 +0800
Subject: [PATCH] [CORE][ADD] Settings page
---
.gitignore | 1 +
FinalProject/FinalProject.vcxproj | 7 +
FinalProject/FinalProject.vcxproj.filters | 12 +
FinalProject/aboutpage.cpp | 2 +-
FinalProject/editorpage.cpp | 6 +
FinalProject/editorpage.h | 4 +
FinalProject/illuminer.h | 6 +-
FinalProject/mainwindow.cpp | 9 +
FinalProject/mainwindow.h | 2 +
FinalProject/sceneviewer.cpp | 88 ++++--
FinalProject/sceneviewer.h | 6 +-
FinalProject/settingpage.cpp | 313 ++++++++++++++++++++++
FinalProject/settingpage.h | 72 +++++
13 files changed, 503 insertions(+), 25 deletions(-)
create mode 100644 FinalProject/settingpage.cpp
create mode 100644 FinalProject/settingpage.h
diff --git a/.gitignore b/.gitignore
index 7081f79..8176532 100644
--- a/.gitignore
+++ b/.gitignore
@@ -363,3 +363,4 @@ MigrationBackup/
FodyWeavers.xsd
/FinalProject/temp/shaders
/Models
+/Terrains
diff --git a/FinalProject/FinalProject.vcxproj b/FinalProject/FinalProject.vcxproj
index fa35487..e5a0ec1 100644
--- a/FinalProject/FinalProject.vcxproj
+++ b/FinalProject/FinalProject.vcxproj
@@ -125,6 +125,12 @@
+
+ input
+ %(Filename).moc
+ input
+ %(Filename).moc
+
@@ -161,6 +167,7 @@
+
diff --git a/FinalProject/FinalProject.vcxproj.filters b/FinalProject/FinalProject.vcxproj.filters
index 9409877..fda6c2d 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,6 +186,9 @@
Source Files\Qt Widgets\Pages\Scene Editor\Object Setter
+
+ Source Files\Qt Widgets\Pages\Setting Page
+
@@ -286,6 +295,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 dc915eb..02b1feb 100644
--- a/FinalProject/sceneviewer.cpp
+++ b/FinalProject/sceneviewer.cpp
@@ -131,23 +131,8 @@ void SceneViewer::initializeGL() {
_skyShader.attachShader(skyFragmentShader);
skyVertexShader.dispose();
skyFragmentShader.dispose();
-
- // Test Code Start
- _sky = new SkyBox("E:\\Repositories\\CollegeProjects\\CGAssignments\\FinalProject\\SkyBoxes");
_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));
}
@@ -188,7 +173,7 @@ void SceneViewer::paintGL() {
_shaderProgram.setUniform("pointlightnr", pointLights);
_shaderProgram.setUniform("spotlightnr", spotLights);
- if (_dirLight != nullptr) {
+ if (_dirLight != nullptr && _dirLightOn) {
_dirLight->updateShader(_shaderProgram, 0);
}
@@ -227,11 +212,13 @@ void SceneViewer::paintGL() {
_boundShader.unbind();
}
- _skyShader.bind();
- _skyShader.setUniform("view", glm::mat4(glm::mat3(view)));
- _skyShader.setUniform("projection", projection);
- _sky->render();
- _skyShader.unbind();
+ if (_sky != nullptr) {
+ _skyShader.bind();
+ _skyShader.setUniform("view", glm::mat4(glm::mat3(view)));
+ _skyShader.setUniform("projection", projection);
+ _sky->render();
+ _skyShader.unbind();
+ }
}
void SceneViewer::mousePressEvent(QMouseEvent* event) {
@@ -520,3 +507,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 71585e1..fac3288 100644
--- a/FinalProject/sceneviewer.h
+++ b/FinalProject/sceneviewer.h
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
@@ -23,13 +24,15 @@ 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;
// Shader program for objects
ShaderProgram _shaderProgram = ShaderProgram::empty();
ShaderProgram _boundShader = ShaderProgram::empty();
ShaderProgram _skyShader = ShaderProgram::empty();
- SkyBox* _sky;
// Main camera
Camera _camera;
float _cameraMovementSpeed = 0.02f;
@@ -98,6 +101,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