diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/first_app.cpp | 125 | ||||
-rwxr-xr-x | src/first_app.hpp | 36 | ||||
-rw-r--r-- | src/keyboard_movement_controller.cpp | 42 | ||||
-rw-r--r-- | src/keyboard_movement_controller.hpp | 31 | ||||
-rwxr-xr-x | src/main.cpp | 18 | ||||
-rw-r--r-- | src/simple_render_system.cpp | 94 | ||||
-rw-r--r-- | src/simple_render_system.hpp | 37 |
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 |