should prob put this on git sometime

This commit is contained in:
2026-01-03 01:48:40 +01:00
commit 1b8cc96164
52 changed files with 12002 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
#ifndef APP_H
#define APP_H
#include <filesystem>
#include <string>
#include "glm/vec2.hpp"
#include <SDL2/SDL.h>
#include <destrum/Graphics/GfxDevice.h>
class App {
public:
struct AppParams {
glm::ivec2 windowSize{};
glm::ivec2 renderSize{};
std::string appName{"Destrum App"};
std::string windowTitle;
std::filesystem::path exeDir;
};
void init(const AppParams& params);
void run();
void cleanup();
protected:
SDL_Window* window{nullptr};
AppParams m_params{};
GfxDevice gfxDevice;
bool isRunning{false};
bool gamePaused{false};
bool frameLimit{true};
float frameTime{0.f};
float avgFPS{0.f};
};
#endif //APP_H

View File

@@ -0,0 +1,32 @@
#ifndef ASSETFS_H
#define ASSETFS_H
#include <filesystem>
#include <string>
#include <vector>
#include <destrum/Singleton.h>
struct FSMount {
std::string scheme; // "engine", "game"
std::filesystem::path root;
};
class AssetFS final: public Singleton<AssetFS> {
public:
void Init(std::filesystem::path exeDir);
void Mount(std::string scheme, std::filesystem::path root);
std::vector<uint8_t> ReadBytes(std::string_view vpath);
[[nodiscard]] std::filesystem::path GetFullPath(std::string_view vpath) const;
private:
static std::vector<uint8_t> ReadFile(const std::filesystem::path& fullPath);
std::vector<FSMount> mounts;
bool initialized{false};
};
#endif //ASSETFS_H

View File

@@ -0,0 +1,94 @@
#ifndef GFXDEVICE_H
#define GFXDEVICE_H
#include <VkBootstrap.h>
#include <vk_mem_alloc.h>
#include <SDL.h>
#include <destrum/Graphics/VImage.h>
#include <destrum/Graphics/Swapchain.h>
#include <vulkan/vulkan.h>
#include <volk.h>
#include <VkBootstrap.h>
#include <vk_mem_alloc.h>
#include "ImmediateExecuter.h"
#include <destrum/Graphics/Swapchain.h>
using ImageId = std::uint32_t;
static const auto NULL_IMAGE_ID = std::numeric_limits<std::uint32_t>::max();
namespace {
using ImmediateExecuteFunction = std::function<void(VkCommandBuffer)>;
}
class GfxDevice {
public:
struct FrameData {
VkCommandPool commandPool;
VkCommandBuffer commandBuffer;
};
GfxDevice();
GfxDevice(const GfxDevice&) = delete;
GfxDevice& operator=(const GfxDevice&) = delete;
void init(SDL_Window* window, const std::string& appName, bool vSync);
void recreateSwapchain(int width, int height);
VkCommandBuffer beginFrame();
bool needsSwapchainRecreate() const { return swapchain.isDirty(); }
struct EndFrameProps {
const VkClearColorValue clearColor{ {0.f, 0.f, 0.f, 1.f} };
glm::ivec4 drawImageBlitRect{}; // where to blit draw image to
};
void endFrame(VkCommandBuffer cmd, const VImage& drawImage, const EndFrameProps& props);
void cleanup();
void waitIdle();
void immediateSubmit(ImmediateExecuteFunction&& f) const;
vkb::Device getDevice() const { return device; }
std::uint32_t getCurrentFrameIndex() const
{
return frameNumber % FRAMES_IN_FLIGHT;
}
FrameData& getCurrentFrame() {
return frames[getCurrentFrameIndex()];
}
VkExtent2D getSwapchainExtent() const { return swapchain.getExtent(); }
private:
vkb::Instance instance;
vkb::PhysicalDevice physicalDevice;
vkb::Device device;
VmaAllocator allocator;
std::uint32_t graphicsQueueFamily;
VkQueue graphicsQueue;
VkSurfaceKHR surface;
VkFormat swapchainFormat;
Swapchain swapchain;
std::array<FrameData, FRAMES_IN_FLIGHT> frames{};
std::uint32_t frameNumber{0};
VulkanImmediateExecutor executor;
ImageId whiteImageId{NULL_IMAGE_ID};
ImageId errorImageId{NULL_IMAGE_ID};
};
#endif //GFXDEVICE_H

View File

@@ -0,0 +1,27 @@
#ifndef IMMEDIATEEXECUTER_H
#define IMMEDIATEEXECUTER_H
#include <cstdint>
#include <functional>
#include <vulkan/vulkan.h>
class VulkanImmediateExecutor {
public:
void init(VkDevice device, std::uint32_t graphicsQueueFamily, VkQueue graphicsQueue);
void cleanup(VkDevice device);
void immediateSubmit(std::function<void(VkCommandBuffer cmd)>&& function) const;
private:
bool initialized{false};
VkDevice device;
VkQueue graphicsQueue;
VkCommandBuffer immCommandBuffer;
VkCommandPool immCommandPool;
VkFence immFence;
};
#endif //IMMEDIATEEXECUTER_H

View File

@@ -0,0 +1,62 @@
#ifndef INIT_H
#define INIT_H
#pragma once
#include <cstdint>
#include <optional>
#include <vulkan/vulkan.h>
struct VImage;
namespace vkinit
{
VkImageSubresourceRange imageSubresourceRange(VkImageAspectFlags aspectMask);
VkSemaphoreSubmitInfo semaphoreSubmitInfo(VkPipelineStageFlags2 stageMask, VkSemaphore semaphore);
VkCommandPoolCreateInfo commandPoolCreateInfo(
VkCommandPoolCreateFlags flags,
std::uint32_t queueFamilyIndex);
VkCommandBufferSubmitInfo commandBufferSubmitInfo(VkCommandBuffer cmd);
VkCommandBufferAllocateInfo commandBufferAllocateInfo(
VkCommandPool commandPool,
std::uint32_t commandBufferCount);
VkSubmitInfo2 submitInfo(
const VkCommandBufferSubmitInfo* cmd,
const VkSemaphoreSubmitInfo* waitSemaphoreInfo,
const VkSemaphoreSubmitInfo* signalSemaphoreInfo);
VkImageCreateInfo imageCreateInfo(
VkFormat format,
VkImageUsageFlags usageFlags,
VkExtent3D extent,
std::uint32_t mipLevels = 1);
VkImageViewCreateInfo imageViewCreateInfo(
VkFormat format,
VkImage image,
VkImageAspectFlags aspectFlags);
VkRenderingAttachmentInfo attachmentInfo(
VkImageView view,
VkImageLayout layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
std::optional<VkClearValue> clearValue = std::nullopt);
VkRenderingAttachmentInfo depthAttachmentInfo(
VkImageView view,
VkImageLayout layout,
std::optional<float> depthClearValue = 0.f);
VkRenderingInfo renderingInfo(
VkExtent2D renderExtent,
const VkRenderingAttachmentInfo* colorAttachment,
const VkRenderingAttachmentInfo* depthAttachment);
VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo(
VkShaderStageFlagBits stage,
VkShaderModule shaderModule);
} // end of namespace vkinit
#endif //INIT_H

View File

@@ -0,0 +1,58 @@
#ifndef VPIPELINE_H
#define VPIPELINE_H
#include <string>
#include <vector>
#include <destrum/Graphics/GfxDevice.h>
struct PipelineConfigInfo {
std::string name;
VkPipelineViewportStateCreateInfo viewportInfo{};
VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo{};
VkPipelineRasterizationStateCreateInfo rasterizationInfo{};
VkPipelineMultisampleStateCreateInfo multisampleInfo{};
VkPipelineColorBlendAttachmentState colorBlendAttachment{};
VkPipelineColorBlendStateCreateInfo colorBlendInfo{};
VkPipelineDepthStencilStateCreateInfo depthStencilInfo{};
std::vector<VkDynamicState> dynamicStateEnables{};
VkPipelineDynamicStateCreateInfo dynamicStateInfo{};
std::vector<VkFormat> colorAttachments{};
VkFormat depthAttachment{VK_FORMAT_UNDEFINED};
std::vector<VkVertexInputBindingDescription> vertexBindingDescriptions{};
std::vector<VkVertexInputAttributeDescription> vertexAttributeDescriptions{};
VkPipelineLayout pipelineLayout = nullptr;
};
class Pipeline {
public:
Pipeline(GfxDevice& device, const std::string& vertPath, const std::string& fragPath, const PipelineConfigInfo& configInfo);
~Pipeline();
Pipeline(const Pipeline& other) = delete;
Pipeline(Pipeline&& other) noexcept = delete;
Pipeline& operator=(const Pipeline& other) = delete;
Pipeline& operator=(Pipeline&& other) noexcept = delete;
void bind(VkCommandBuffer buffer) const;
static void DefaultPipelineConfigInfo(PipelineConfigInfo& configInfo);
private:
static std::vector<char> readFile(const std::string& filename);
void CreateGraphicsPipeline(const std::string& vertPath, const std::string& fragPath, const PipelineConfigInfo& configInfo);
void CreateShaderModule(const std::vector<char>& code, VkShaderModule* shaderModule) const;
GfxDevice& m_device;
VkPipeline m_graphicsPipeline{VK_NULL_HANDLE};
VkShaderModule m_vertShaderModule{VK_NULL_HANDLE};
VkShaderModule m_fragShaderModule{VK_NULL_HANDLE};
};
#endif //VPIPELINE_H

View File

@@ -0,0 +1,24 @@
#ifndef MESHPIPELINE_H
#define MESHPIPELINE_H
#include <vulkan/vulkan.h>
#include <memory>
#include <destrum/Graphics/Pipeline.h>
class MeshPipeline {
public:
MeshPipeline();
~MeshPipeline();
void init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat depthImageFormat);
void draw();
private:
VkPipelineLayout m_pipelineLayout;
std::unique_ptr<Pipeline> m_pipeline;
};
#endif //MESHPIPELINE_H

View File

@@ -0,0 +1,10 @@
#ifndef RENDERER_H
#define RENDERER_H
class GameRenderer {
public:
private:
};
#endif //RENDERER_H

View File

@@ -0,0 +1,15 @@
#ifndef BUFFER_H
#define BUFFER_H
#include <vk_mem_alloc.h>
#include <vulkan/vulkan.h>
struct GPUBuffer {
VkBuffer buffer{VK_NULL_HANDLE};
VmaAllocation allocation;
VmaAllocationInfo info;
VkDeviceAddress address{0};
};
#endif //BUFFER_H

View File

@@ -0,0 +1,53 @@
#ifndef MESH_H
#define MESH_H
#include <cstdint>
#include <string>
#include <vector>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
struct CPUMesh {
std::vector<std::uint32_t> indices;
struct Vertex {
glm::vec3 position;
float uv_x{};
glm::vec3 normal;
float uv_y{};
glm::vec4 tangent;
};
std::vector<Vertex> vertices;
std::string name;
glm::vec3 minPos;
glm::vec3 maxPos;
};
struct GPUMesh {
GPUBuffer vertexBuffer;
GPUBuffer indexBuffer;
std::uint32_t numVertices{0};
std::uint32_t numIndices{0};
// AABB
glm::vec3 minPos;
glm::vec3 maxPos;
math::Sphere boundingSphere;
bool hasSkeleton{false};
// skinned meshes only
GPUBuffer skinningDataBuffer;
};
struct SkinnedMesh {
GPUBuffer skinnedVertexBuffer;
};
#endif //MESH_H

View File

@@ -0,0 +1,54 @@
#ifndef SWAPCHAIN_H
#define SWAPCHAIN_H
#include <array>
#include <cstdint>
#include <vulkan/vulkan.h>
#include "VkBootstrap.h"
class GfxDevice;
static constexpr int FRAMES_IN_FLIGHT = 2;
class Swapchain {
public:
void initSync(VkDevice device);
//Ye ye, passing a pointer is bad bla bla @Kobe
void createSwapchain(GfxDevice* gfxDevice, VkFormat format, std::uint32_t width, std::uint32_t height, bool vSync);
void recreateSwapchain(const GfxDevice& gfxDevice, VkFormat format, std::uint32_t width, std::uint32_t height, bool vSync);
void cleanup();
[[nodiscard]] VkExtent2D getExtent() const { return extent; }
[[nodiscard]] const std::vector<VkImage>& getImages() const { return images; }
[[nodiscard]] std::uint32_t getImageCount() const { return static_cast<std::uint32_t>(images.size()); }
void beginFrame(int index) const;
void resetFences(int index) const;
std::pair<VkImage, int> acquireNextImage(int index);
void submitAndPresent(VkCommandBuffer cmd, VkQueue graphicsQueue, std::uint32_t imageIndex, std::uint32_t frameIndex);
[[nodiscard]] bool isDirty() const { return dirty; }
[[nodiscard]] VkImageView getImageView(int index) const { return imageViews[index]; }
private:
struct FrameData {
VkSemaphore swapchainSemaphore;
VkFence renderFence;
};
std::vector<VkSemaphore> imageRenderSemaphores;
std::array<FrameData, FRAMES_IN_FLIGHT> frames;
vkb::Swapchain m_swapchain; //Euuuh, m_ cuz like cpluhpluh
std::vector<VkImage> images;
std::vector<VkImageView> imageViews;
bool dirty{false};
GfxDevice* m_gfxDevice{nullptr};
VkExtent2D extent{};
};
#endif //SWAPCHAIN_H

View File

@@ -0,0 +1,39 @@
#ifndef UTIL_H
#define UTIL_H
#include <vulkan/vulkan.h>
#define VK_CHECK(call) \
do { \
VkResult result_ = call; \
assert(result_ == VK_SUCCESS); \
} while (0)
namespace vkutil {
void transitionImage(
VkCommandBuffer cmd,
VkImage image,
VkImageLayout currentLayout,
VkImageLayout newLayout);
void copyImageToImage(
VkCommandBuffer cmd,
VkImage source,
VkImage destination,
VkExtent2D srcSize,
VkExtent2D dstSize,
VkFilter filter);
void copyImageToImage(
VkCommandBuffer cmd,
VkImage source,
VkImage destination,
VkExtent2D srcSize,
int destX,
int destY,
int destW,
int destH,
VkFilter filter);
}
#endif //UTIL_H

View File

@@ -0,0 +1,48 @@
#ifndef VIMAGE_H
#define VIMAGE_H
#include <cstdint>
#include <string>
#include <vulkan/vulkan.h>
#include <vk_mem_alloc.h>
#include <glm/glm.hpp>
class VImage {
public:
glm::ivec2 getSize2D() const { return glm::ivec2{extent.width, extent.height}; }
VkExtent2D getExtent2D() const { return VkExtent2D{extent.width, extent.height}; }
std::uint32_t getBindlessId() const
{
assert(id != NULL_BINDLESS_ID && "Image wasn't added to bindless set");
return id;
}
void setBindlessId(const std::uint32_t id)
{
assert(id != NULL_BINDLESS_ID);
this->id = id;
}
bool isInitialized() const { return id != NULL_BINDLESS_ID; }
VkImage getImage() const { return image; }
VkImageView getImageView() const { return imageView; }
VmaAllocation getAllocation() const { return allocation; }
private:
VkImage image;
VkImageView imageView;
VmaAllocation allocation;
VkFormat format;
VkImageUsageFlags usage;
VkExtent3D extent;
std::uint32_t mipLevels{1};
std::uint32_t numLayers{1};
std::string debugName{};
std::uint32_t id{NULL_BINDLESS_ID}; // bindless id - always equals to ImageId
static const auto NULL_BINDLESS_ID = std::numeric_limits<std::uint32_t>::max();
};
#endif //VIMAGE_H

View File

@@ -0,0 +1,22 @@
#ifndef SINGLETON_H
#define SINGLETON_H
template <typename T>
class Singleton {
public:
static T& GetInstance() {
static T instance{};
return instance;
}
virtual ~Singleton() = default;
Singleton(const Singleton& other) = delete;
Singleton(Singleton&& other) = delete;
Singleton& operator=(const Singleton& other) = delete;
Singleton& operator=(Singleton&& other) = delete;
protected:
Singleton() = default;
};
#endif //SINGLETON_H