#include "sceneviewer.h" #include #include #include #include #include "illuminer.h" SceneViewer::SceneViewer(QWidget* parent) : QOpenGLWidget(parent) { // OpenGL initialize QSurfaceFormat format; format.setProfile(QSurfaceFormat::CoreProfile); format.setVersion(4, 3); setFormat(format); // Create temp folder QDir dir; if (!dir.exists("./temp")) { dir.mkdir("./temp"); } if (!dir.exists("./temp/shaders")) { dir.mkdir("./temp/shaders"); } // Copy the shaders to the temp folder extractShaderResorce("vertexshader.glsl"); extractShaderResorce("fragmentshader.glsl"); extractShaderResorce("skyboxvertexshader.glsl"); extractShaderResorce("skyboxfragmentshader.glsl"); } SceneViewer::~SceneViewer() { if (_dirLight) { delete _dirLight; } for (auto obj : _objects) { delete obj; } } void SceneViewer::extractShaderResorce(const QString& shaderName) { QString shaderResourcePath = ":/shaders/" + shaderName; QString shaderTempPath = "./temp/shaders/" + shaderName; if (QFile::exists(shaderTempPath)) { QFile::remove(shaderTempPath); } QFile::copy(shaderResourcePath, shaderTempPath); QFile::setPermissions(shaderTempPath, QFile::ReadOwner | QFile::WriteOwner); } void SceneViewer::initializeGL() { initializeOpenGLFunctions(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glEnable(GL_FRAMEBUFFER_SRGB); Logger::info("Currently running on OpenGL version: " + std::string((const char*)glGetString(GL_VERSION))); _shaderProgram.ensureInitialized(); Logger::info("Shader Program initialized"); VertexShader vertexShader("./temp/shaders/vertexshader.glsl"); FragmentShader fragmentShader("./temp/shaders/fragmentshader.glsl"); _shaderProgram.attachShader(vertexShader); _shaderProgram.attachShader(fragmentShader); vertexShader.dispose(); fragmentShader.dispose(); _skyShader.ensureInitialized(); Logger::info("Sky Shader initialized"); VertexShader skyVertexShader("./temp/shaders/skyboxvertexshader.glsl"); FragmentShader skyFragmentShader("./temp/shaders/skyboxfragmentshader.glsl"); _skyShader.attachShader(skyVertexShader); _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); _objects.push_back(backpack); Renderable* backpack2 = new Renderable(model); backpack2->move(glm::vec3(-5.0f, -2.0f, -2.0f)); backpack2->makeLight(); backpack2->originalLight()->setIdealDistance(500); _objects.push_back(backpack2); // Test Code End _camera.setPosition(glm::vec3(0.0f, 0.0f, 10.0f)); } void SceneViewer::resizeGL(int w, int h) { glViewport(0, 0, w, h); } void SceneViewer::paintGL() { Logger::debug("Repainting"); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _shaderProgram.bind(); // Set view and projection matrices glm::mat4 view = _camera.viewMatrix(); glm::mat4 projection = _camera.projectionMatrix((float)width() / (float)height()); _shaderProgram.setUniform("view", view); _shaderProgram.setUniform("projection", projection); _shaderProgram.setUniform("viewPos", _camera.position()); int pointLights = 0; int spotLights = 0; for (auto object : _objects) { if (object->hasLight()) { ScopedLight light = object->transformedLight(); if (light.isPointLight()) { light.updateShader(_shaderProgram, pointLights++); } else { light.updateShader(_shaderProgram, spotLights++); } } } _shaderProgram.setUniform("pointlightnr", pointLights); _shaderProgram.setUniform("spotlightnr", spotLights); if (_dirLight != nullptr) { _dirLight->updateShader(_shaderProgram, 0); } _shaderProgram.setUniform("dirlightnr", _dirLight != nullptr ? 1 : 0); for (auto object : _objects) { object->render(_shaderProgram); } _shaderProgram.unbind(); _skyShader.bind(); _skyShader.setUniform("view", glm::mat4(glm::mat3(view))); _skyShader.setUniform("projection", projection); _sky->render(); _skyShader.unbind(); } void SceneViewer::mousePressEvent(QMouseEvent* event) { Logger::debug("Mouse pressed at: " + std::to_string(event->x()) + ", " + std::to_string(event->y())); if (event->button() == Qt::LeftButton) { // TODO: Hit test on objects } else { _lastMousePosition = event->pos(); } } void SceneViewer::mouseMoveEvent(QMouseEvent* event) { if (event->buttons() != Qt::NoButton) { Logger::debug("Mouse moved with offset: " + std::to_string(event->x() - _lastMousePosition.x()) + ", " + std::to_string(event->y() - _lastMousePosition.y())); } // Check the type of button pressed switch (event->buttons()) { case Qt::LeftButton: { // Move the selected object if (_selectedObject != nullptr) { // TODO: move the selected object } break; } case Qt::RightButton: { // Move the camera float xoffset = event->x() - _lastMousePosition.x(); float yoffset = _lastMousePosition.y() - event->y(); // reversed since y-coordinates go from bottom to top float xmovement = xoffset * _cameraMovementSpeed; float ymovement = yoffset * _cameraMovementSpeed; glm::vec3 cameraPrevPos = _camera.position(); _camera.move({ -xmovement, -ymovement }); glm::vec3 cameraNewPos = _camera.position(); _rotateCenter += cameraNewPos - cameraPrevPos; Logger::debug("Camera moved to: " + std::to_string(_camera.position().x) + ", " + std::to_string(_camera.position().y) + ", " + std::to_string(_camera.position().z)); Logger::debug("New center: " + std::to_string(_rotateCenter.x) + ", " + std::to_string(_rotateCenter.y) + ", " + std::to_string(_rotateCenter.z)); break; } case Qt::MiddleButton: { // Rotate the camera float xoffset = event->x() - _lastMousePosition.x(); float yoffset = _lastMousePosition.y() - event->y(); // reversed since y-coordinates go from bottom to top // Calculate pitch angle float pitch = yoffset * _cameraRotationSpeed; // Calculate yaw angle float yaw = xoffset * _cameraRotationSpeed; _camera.rotate(_rotateCenter, pitch, -yaw); Logger::debug("Camera rotated to: " + std::to_string(_camera.position().x) + ", " + std::to_string(_camera.position().y) + ", " + std::to_string(_camera.position().z)); Logger::debug("Center at: " + std::to_string(_rotateCenter.x) + ", " + std::to_string(_rotateCenter.y) + ", " + std::to_string(_rotateCenter.z)); break; } default: { Logger::warning("Unknown mouse button input"); Logger::warning("Mouse button: " + std::to_string(event->buttons())); break; } } // Update the last mouse position _lastMousePosition = event->pos(); // Update the view parentWidget()->update(); } void SceneViewer::wheelEvent(QWheelEvent* event) { // Zoom in or out float wheelOffset = event->angleDelta().y(); Logger::debug("Wheel offset: " + std::to_string(wheelOffset)); _camera.push(wheelOffset * _cameraPushSpeed); glm::vec3 cameraFront = _camera.front(); _rotateCenter += wheelOffset * _cameraPushSpeed * cameraFront; Logger::debug("New camera position: " + std::to_string(_camera.position().x) + ", " + std::to_string(_camera.position().y) + ", " + std::to_string(_camera.position().z)); Logger::debug("New center position: " + std::to_string(_rotateCenter.x) + ", " + std::to_string(_rotateCenter.y) + ", " + std::to_string(_rotateCenter.z)); // Update the view parentWidget()->update(); } void SceneViewer::showEvent(QShowEvent* event) { // Call show event of super class QOpenGLWidget::showEvent(event); if (_initialized) { return; } //// Create mask for rounded corner //QPainterPath mask; //mask.addRoundedRect(rect(), _cornerRadius, _cornerRadius); //setMask(mask.toFillPolygon().toPolygon()); _initialized = true; } void SceneViewer::resizeEvent(QResizeEvent* event) { // Call resize event of super class QOpenGLWidget::resizeEvent(event); //// Create mask for rounded corner //QPainterPath mask; //mask.addRoundedRect(rect(), _cornerRadius, _cornerRadius); //setMask(mask.toFillPolygon().toPolygon()); }