summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/first_app.cpp125
-rwxr-xr-xsrc/first_app.hpp36
-rw-r--r--src/keyboard_movement_controller.cpp42
-rw-r--r--src/keyboard_movement_controller.hpp31
-rwxr-xr-xsrc/main.cpp18
-rw-r--r--src/simple_render_system.cpp94
-rw-r--r--src/simple_render_system.hpp37
7 files changed, 383 insertions, 0 deletions
diff --git a/src/first_app.cpp b/src/first_app.cpp
new file mode 100755
index 0000000..6a5bfa9
--- /dev/null
+++ b/src/first_app.cpp
@@ -0,0 +1,125 @@
+#include "first_app.hpp"
+
+#include "xe_camera.hpp"
+#include "xe_game_object.hpp"
+#include "xe_model.hpp"
+#include "simple_render_system.hpp"
+#include "keyboard_movement_controller.hpp"
+
+
+#define GLM_FORCE_RADIANS
+#define GLM_FORCE_DEPTH_ZERO_TO_ONE
+#include <glm/glm.hpp>
+#include <glm/gtc/constants.hpp>
+
+#include <array>
+#include <chrono>
+#include <cassert>
+#include <stdexcept>
+
+namespace xe {
+
+struct GlobalUbo {
+ glm::mat4 projectionView{1.f};
+ glm::vec3 lightDirection = glm::normalize(glm::vec3{-1.f, 3.f, 1.f});
+};
+
+FirstApp::FirstApp() {
+ globalPool = XeDescriptorPool::Builder(xeDevice)
+ .setMaxSets(XeSwapChain::MAX_FRAMES_IN_FLIGHT)
+ .addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
+ .addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
+ .build();
+ loadGameObjects();
+}
+
+FirstApp::~FirstApp() {}
+
+void FirstApp::run() {
+
+ std::vector<std::unique_ptr<XeBuffer>> uboBuffers(XeSwapChain::MAX_FRAMES_IN_FLIGHT);
+ for (int i = 0; i < uboBuffers.size(); i++) {
+ uboBuffers[i] = std::make_unique<XeBuffer>(
+ xeDevice,
+ sizeof(GlobalUbo),
+ XeSwapChain::MAX_FRAMES_IN_FLIGHT,
+ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+ uboBuffers[i]->map();
+ }
+
+ auto globalSetLayout = XeDescriptorSetLayout::Builder(xeDevice)
+ .addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT)
+ .build();
+
+ std::vector<VkDescriptorSet> globalDescriptorSets(XeSwapChain::MAX_FRAMES_IN_FLIGHT);
+ for (int i = 0; i < globalDescriptorSets.size(); i++) {
+ auto bufferInfo = uboBuffers[i]->descriptorInfo();
+ XeDescriptorWriter(*globalSetLayout, *globalPool)
+ .writeBuffer(0, &bufferInfo)
+ .build(globalDescriptorSets[i]);
+ }
+
+ SimpleRenderSystem simpleRenderSystem{xeDevice, xeRenderer.getSwapChainRenderPass(), globalSetLayout->getDescriptorSetLayout()};
+ XeCamera camera{};
+ camera.setViewTarget(glm::vec3(-1.f, -2.f, 20.f), glm::vec3(0.f, 0.f, 2.5f));
+
+ auto viewerObject = XeGameObject::createGameObject();
+ KeyboardMovementController cameraController{};
+
+ auto currentTime = std::chrono::high_resolution_clock::now();
+
+ while (!xeWindow.shouldClose()) {
+ glfwPollEvents();
+
+ auto newTime = std::chrono::high_resolution_clock::now();
+ float frameTime = std::chrono::duration<float, std::chrono::seconds::period>(newTime - currentTime).count();
+ currentTime = newTime;
+
+ cameraController.moveInPlaneXZ(xeWindow.getGLFWwindow(), frameTime, viewerObject);
+ camera.setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);
+
+ float aspect = xeRenderer.getAspectRatio();
+ camera.setPerspectiveProjection(glm::radians(50.f), aspect, 0.1f, 100.f);
+
+ if(auto commandBuffer = xeRenderer.beginFrame()) {
+
+ int frameIndex = xeRenderer.getFrameIndex();
+ XeFrameInfo frameInfo{
+ frameIndex,
+ frameTime,
+ commandBuffer,
+ camera,
+ globalDescriptorSets[frameIndex]
+ };
+
+ // update
+ GlobalUbo ubo{};
+ ubo.projectionView = camera.getProjection() * camera.getView();
+ uboBuffers[frameIndex]->writeToBuffer(&ubo);
+ uboBuffers[frameIndex]->flush();
+
+ // render
+ xeRenderer.beginSwapChainRenderPass(commandBuffer);
+ simpleRenderSystem.renderGameObjects(frameInfo, gameObjects);
+ xeRenderer.endSwapChainRenderPass(commandBuffer);
+ xeRenderer.endFrame();
+ }
+
+ }
+
+ vkDeviceWaitIdle(xeDevice.device());
+
+}
+
+void FirstApp::loadGameObjects() {
+ std::shared_ptr<XeModel> xeModel = XeModel::createModelFromFile(xeDevice, "res/models/stanford-dragon.obj");
+
+ auto cube = XeGameObject::createGameObject();
+ cube.model = xeModel;
+ cube.transform.translation = {.0f, .0f, 2.5f};
+ cube.transform.scale = {.5f, .5f, .5f};
+ gameObjects.push_back(std::move(cube));
+}
+
+} \ No newline at end of file
diff --git a/src/first_app.hpp b/src/first_app.hpp
new file mode 100755
index 0000000..bcdf33e
--- /dev/null
+++ b/src/first_app.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "xe_renderer.hpp"
+#include "xe_window.hpp"
+#include "xe_device.hpp"
+#include "xe_game_object.hpp"
+#include "xe_descriptors.hpp"
+
+#include <memory>
+#include <vector>
+
+namespace xe {
+class FirstApp {
+ public:
+ static constexpr int WIDTH = 800;
+ static constexpr int HEIGHT = 600;
+
+ FirstApp();
+ ~FirstApp();
+
+ FirstApp(const FirstApp &) = delete;
+ FirstApp operator=(const FirstApp &) = delete;
+
+ void run();
+
+ private:
+ void loadGameObjects();
+
+ XeWindow xeWindow{WIDTH, HEIGHT, "Hello Vulkan!"};
+ XeDevice xeDevice{xeWindow};
+ XeRenderer xeRenderer{xeWindow, xeDevice};
+
+ std::unique_ptr<XeDescriptorPool> globalPool{};
+ std::vector<XeGameObject> gameObjects;
+};
+} \ No newline at end of file
diff --git a/src/keyboard_movement_controller.cpp b/src/keyboard_movement_controller.cpp
new file mode 100644
index 0000000..6782709
--- /dev/null
+++ b/src/keyboard_movement_controller.cpp
@@ -0,0 +1,42 @@
+#include "keyboard_movement_controller.hpp"
+#include <glm/common.hpp>
+#include <glm/fwd.hpp>
+#include <glm/geometric.hpp>
+#include <limits>
+
+namespace xe {
+
+void KeyboardMovementController::moveInPlaneXZ(GLFWwindow* window, float dt, XeGameObject& gameObject) {
+ glm::vec3 rotate{0};
+ if(glfwGetKey(window, keys.lookRight) == GLFW_PRESS) rotate.y += 1.f;
+ if(glfwGetKey(window, keys.lookLeft) == GLFW_PRESS) rotate.y -= 1.f;
+ if(glfwGetKey(window, keys.lookUp) == GLFW_PRESS) rotate.x -= 1.f;
+ if(glfwGetKey(window, keys.lookDown) == GLFW_PRESS) rotate.x += 1.f;
+
+ if (glm::dot(rotate, rotate) > std::numeric_limits<float>::epsilon()) {
+ gameObject.transform.rotation += lookSpeed * dt * glm::normalize(rotate);
+ }
+
+ gameObject.transform.rotation.x = glm::clamp(gameObject.transform.rotation.x, -1.5f, 1.5f);
+ gameObject.transform.rotation.y = glm::mod(gameObject.transform.rotation.y, glm::two_pi<float>());
+
+ float yaw = gameObject.transform.rotation.y;
+ const glm::vec3 forwardDir{sin(yaw), 0.f, cos(yaw)};
+ const glm::vec3 rightDir{forwardDir.z, 0.f, -forwardDir.x};
+ const glm::vec3 upDir{0.f, 01.f, 0.f};
+
+ glm::vec3 moveDir{0};
+ if(glfwGetKey(window, keys.moveForward) == GLFW_PRESS) moveDir += forwardDir;
+ if(glfwGetKey(window, keys.moveBackward) == GLFW_PRESS) moveDir -= forwardDir;
+ if(glfwGetKey(window, keys.moveRight) == GLFW_PRESS) moveDir += rightDir;
+ if(glfwGetKey(window, keys.moveLeft) == GLFW_PRESS) moveDir -= rightDir;
+ if(glfwGetKey(window, keys.moveUp) == GLFW_PRESS) moveDir += upDir;
+ if(glfwGetKey(window, keys.moveDown) == GLFW_PRESS) moveDir -= upDir;
+
+ if (glm::dot(moveDir, moveDir) > std::numeric_limits<float>::epsilon()) {
+ gameObject.transform.translation += moveSpeed * dt * glm::normalize(moveDir);
+ }
+
+}
+
+} \ No newline at end of file
diff --git a/src/keyboard_movement_controller.hpp b/src/keyboard_movement_controller.hpp
new file mode 100644
index 0000000..b90d361
--- /dev/null
+++ b/src/keyboard_movement_controller.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "xe_game_object.hpp"
+#include "xe_window.hpp"
+#include <GLFW/glfw3.h>
+
+namespace xe {
+ class KeyboardMovementController {
+
+ public:
+ struct KeyMappings {
+ int moveLeft = GLFW_KEY_A;
+ int moveRight = GLFW_KEY_D;
+ int moveForward = GLFW_KEY_W;
+ int moveBackward = GLFW_KEY_S;
+ int moveUp = GLFW_KEY_E;
+ int moveDown = GLFW_KEY_Q;
+ int lookLeft = GLFW_KEY_LEFT;
+ int lookRight = GLFW_KEY_RIGHT;
+ int lookUp = GLFW_KEY_UP;
+ int lookDown = GLFW_KEY_DOWN;
+ };
+
+ void moveInPlaneXZ(GLFWwindow* window, float dt, XeGameObject& gameObject);
+
+ KeyMappings keys{};
+ float moveSpeed{3.f};
+ float lookSpeed{1.5f};
+
+ };
+} \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100755
index 0000000..30b64d9
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,18 @@
+#include "first_app.hpp"
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+int main() {
+ xe::FirstApp app{};
+
+ try {
+ app.run();
+ } catch (const std::exception &e) {
+ std::cerr << e.what() << '\n';
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/src/simple_render_system.cpp b/src/simple_render_system.cpp
new file mode 100644
index 0000000..6e4ab30
--- /dev/null
+++ b/src/simple_render_system.cpp
@@ -0,0 +1,94 @@
+#include "simple_render_system.hpp"
+#include "xe_device.hpp"
+#include <vector>
+#include <vulkan/vulkan_core.h>
+
+#define GLM_FORCE_RADIANS
+#define GLM_FORCE_DEPTH_ZERO_TO_ONE
+#include <glm/glm.hpp>
+#include <glm/gtc/constants.hpp>
+
+#include <array>
+#include <cassert>
+#include <stdexcept>
+
+namespace xe {
+
+struct SimplePushConstantData {
+ glm::mat4 modelMatrix{1.f};
+ glm::mat4 normalMatrix{1.f};
+};
+
+SimpleRenderSystem::SimpleRenderSystem(XeDevice& device, VkRenderPass renderPass, VkDescriptorSetLayout globalSetLayout) : xeDevice{device} {
+ createPipelineLayout(globalSetLayout);
+ createPipeline(renderPass);
+}
+
+SimpleRenderSystem::~SimpleRenderSystem() { vkDestroyPipelineLayout(xeDevice.device(), pipelineLayout, nullptr); }
+
+void SimpleRenderSystem::createPipelineLayout(VkDescriptorSetLayout globalSetLayout) {
+
+ VkPushConstantRange pushConstantRange;
+ pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
+ pushConstantRange.offset = 0;
+ pushConstantRange.size = sizeof(SimplePushConstantData);
+
+ std::vector<VkDescriptorSetLayout> descriptorSetLayouts{globalSetLayout};
+
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(descriptorSetLayouts.size());
+ pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
+ pipelineLayoutInfo.pushConstantRangeCount = 1;
+ pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
+ if(vkCreatePipelineLayout(xeDevice.device(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
+ std::runtime_error("failed to create pipeline layout!");
+ }
+}
+
+void SimpleRenderSystem::createPipeline(VkRenderPass renderPass) {
+ assert(pipelineLayout != nullptr && "Canor create pipeline before pipeline layout");
+
+ PipelineConfigInfo pipelineConfig{};
+ XePipeline::defaultPipelineConfigInfo(pipelineConfig);
+ pipelineConfig.renderPass = renderPass;
+ pipelineConfig.pipelineLayout = pipelineLayout;
+ xePipeline = std::make_unique<XePipeline>(
+ xeDevice,
+ "res/shaders/simple_shader.vert.spv",
+ "res/shaders/simple_shader.frag.spv",
+ pipelineConfig
+ );
+}
+
+void SimpleRenderSystem::renderGameObjects(XeFrameInfo &frameInfo, std::vector<XeGameObject> &gameObjects) {
+ xePipeline->bind(frameInfo.commandBuffer);
+
+ vkCmdBindDescriptorSets(
+ frameInfo.commandBuffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ pipelineLayout,
+ 0,
+ 1,
+ &frameInfo.globalDescriptorSet,
+ 0,
+ nullptr);
+
+ for (auto& obj: gameObjects) {
+ SimplePushConstantData push{};
+ push.modelMatrix = obj.transform.mat4();
+ push.normalMatrix = obj.transform.normalMatrix();
+
+ vkCmdPushConstants(
+ frameInfo.commandBuffer,
+ pipelineLayout,
+ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+ 0,
+ sizeof(SimplePushConstantData),
+ &push);
+ obj.model->bind(frameInfo.commandBuffer);
+ obj.model->draw(frameInfo.commandBuffer);
+ }
+}
+
+} \ No newline at end of file
diff --git a/src/simple_render_system.hpp b/src/simple_render_system.hpp
new file mode 100644
index 0000000..b0d4a39
--- /dev/null
+++ b/src/simple_render_system.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "xe_camera.hpp"
+#include "xe_pipeline.hpp"
+#include "xe_device.hpp"
+#include "xe_game_object.hpp"
+#include "xe_frame_info.hpp"
+
+#include <memory>
+#include <vector>
+#include <vulkan/vulkan_core.h>
+
+namespace xe {
+class SimpleRenderSystem {
+ public:
+
+ SimpleRenderSystem(XeDevice& device, VkRenderPass renderPass, VkDescriptorSetLayout globalSetLayout);
+ ~SimpleRenderSystem();
+
+ SimpleRenderSystem(const SimpleRenderSystem &) = delete;
+ SimpleRenderSystem operator=(const SimpleRenderSystem &) = delete;
+
+ void renderGameObjects(
+ XeFrameInfo &frameInfo,
+ std::vector<XeGameObject> &gameObjects
+ );
+
+ private:
+ void createPipelineLayout(VkDescriptorSetLayout globalSetLayout);
+ void createPipeline(VkRenderPass renderPass);
+
+ XeDevice& xeDevice;
+
+ std::unique_ptr<XePipeline> xePipeline;
+ VkPipelineLayout pipelineLayout;
+};
+} \ No newline at end of file