Re-add model loading and clean up code

This commit is contained in:
Bailey Harrison 2023-01-05 13:21:33 +00:00
parent eac852eb93
commit b2831e2b5d
21 changed files with 701 additions and 259 deletions

View File

@ -12,6 +12,7 @@ set(SRC_FILES
"src/ecs_system.cpp" "src/ecs_system.cpp"
"src/application.cpp" "src/application.cpp"
"src/systems/transform.cpp"
"src/systems/render.cpp" "src/systems/render.cpp"
"src/resources/material.cpp" "src/resources/material.cpp"
@ -21,6 +22,7 @@ set(SRC_FILES
"src/gfx_device_vulkan.cpp" "src/gfx_device_vulkan.cpp"
"src/util/files.cpp" "src/util/files.cpp"
"src/util/model_loader.cpp"
"src/scene_manager.cpp" "src/scene_manager.cpp"
"src/input_manager.cpp" "src/input_manager.cpp"
@ -46,6 +48,7 @@ set(INCLUDE_FILES
"include/engine_api.h" "include/engine_api.h"
"include/util/files.hpp" "include/util/files.hpp"
"include/util/model_loader.hpp"
"include/util.hpp" "include/util.hpp"
"include/logger.hpp" "include/logger.hpp"
@ -81,8 +84,9 @@ set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
if (MSVC) if (MSVC)
target_compile_options(${PROJECT_NAME} PRIVATE /W3) target_compile_options(${PROJECT_NAME} PRIVATE /W3)
target_compile_options(${PROJECT_NAME} PRIVATE /MP) target_compile_options(${PROJECT_NAME} PRIVATE /MP)
target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS) target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS)
else()
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic)
endif() endif()
target_include_directories(${PROJECT_NAME} PUBLIC include) target_include_directories(${PROJECT_NAME} PUBLIC include)
@ -125,7 +129,7 @@ if(ENGINE_BUILD_OPENGL)
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
add_subdirectory(dependencies/glad) add_subdirectory(dependencies/glad)
target_link_libraries(${PROJECT_NAME} PUBLIC glad) target_link_libraries(${PROJECT_NAME} PUBLIC glad)
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glad/include) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/glad/include)
endif() endif()
if(ENGINE_BUILD_VULKAN) if(ENGINE_BUILD_VULKAN)
@ -137,7 +141,7 @@ if(ENGINE_BUILD_VULKAN)
add_subdirectory(dependencies/volk) add_subdirectory(dependencies/volk)
target_link_libraries(${PROJECT_NAME} PRIVATE volk_headers) target_link_libraries(${PROJECT_NAME} PRIVATE volk_headers)
# Vulkan Memory Allocator # Vulkan Memory Allocator
target_include_directories(${PROJECT_NAME} PRIVATE dependencies/VulkanMemoryAllocator/include) target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE dependencies/VulkanMemoryAllocator/include)
# shaderc # shaderc
if (MSVC) if (MSVC)
include(FindVulkan) include(FindVulkan)
@ -151,7 +155,7 @@ endif()
# SDL2: # SDL2:
find_package(SDL2) find_package(SDL2)
if (SDL2_FOUND) if (SDL2_FOUND)
target_include_directories(${PROJECT_NAME} PUBLIC ${SDL2_INCLUDE_DIRS}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS})
else() else()
set(SDL2_DISABLE_INSTALL ON CACHE INTERNAL "" FORCE) set(SDL2_DISABLE_INSTALL ON CACHE INTERNAL "" FORCE)
set(SDL_SHARED ON CACHE INTERNAL "" FORCE) set(SDL_SHARED ON CACHE INTERNAL "" FORCE)
@ -159,7 +163,7 @@ else()
set(SDL_TEST OFF CACHE INTERNAL "" FORCE) set(SDL_TEST OFF CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS ON) set(BUILD_SHARED_LIBS ON)
add_subdirectory(dependencies/SDL) add_subdirectory(dependencies/SDL)
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/SDL/include) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/SDL/include)
endif() endif()
target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2) target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2)
target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2main) target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2main)
@ -167,14 +171,14 @@ target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2main)
# GLM: # GLM:
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
add_subdirectory(dependencies/glm) add_subdirectory(dependencies/glm)
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glm) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/glm)
# spdlog # spdlog
set(SPDLOG_BUILD_SHARED OFF CACHE INTERNAL "" FORCE) set(SPDLOG_BUILD_SHARED OFF CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
add_subdirectory(dependencies/spdlog) add_subdirectory(dependencies/spdlog)
target_link_libraries(${PROJECT_NAME} PUBLIC spdlog) target_link_libraries(${PROJECT_NAME} PUBLIC spdlog)
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/spdlog/include) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/spdlog/include)
# freetype # freetype
#set(FT_DISABLE_ZLIB TRUE CACHE INTERNAL "" FORCE) #set(FT_DISABLE_ZLIB TRUE CACHE INTERNAL "" FORCE)
@ -188,7 +192,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC dependencies/spdlog/include)
#target_include_directories(${PROJECT_NAME} PRIVATE dependencies/freetype/include) #target_include_directories(${PROJECT_NAME} PRIVATE dependencies/freetype/include)
# stb # stb
target_include_directories(${PROJECT_NAME} PRIVATE dependencies/stb) target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE dependencies/stb)
# assimp # assimp
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE) set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE)
@ -197,5 +201,5 @@ set(ASSIMP_BUILD_ZLIB ON CACHE INTERNAL "" FORCE)
set(ASSIMP_NO_EXPORT ON CACHE INTERNAL "" FORCE) set(ASSIMP_NO_EXPORT ON CACHE INTERNAL "" FORCE)
set(ASSIMP_INSTALL OFF CACHE INTERNAL "" FORCE) set(ASSIMP_INSTALL OFF CACHE INTERNAL "" FORCE)
add_subdirectory(dependencies/assimp) add_subdirectory(dependencies/assimp)
target_include_directories(${PROJECT_NAME} PRIVATE dependencies/assimp/include) target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE dependencies/assimp/include)
target_link_libraries(${PROJECT_NAME} PRIVATE assimp) target_link_libraries(${PROJECT_NAME} PRIVATE assimp)

View File

@ -30,7 +30,7 @@ namespace engine {
gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize, bool alphaBlending, bool backfaceCulling); gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize, bool alphaBlending, bool backfaceCulling);
void destroyPipeline(const gfx::Pipeline* pipeline); void destroyPipeline(const gfx::Pipeline* pipeline);
void updateUniformBuffer(const gfx::Pipeline* pipeline, void* data, size_t size, uint32_t offset); void updateUniformBuffer(const gfx::Pipeline* pipeline, const void* data, size_t size, uint32_t offset);
gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data); gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);
void destroyBuffer(const gfx::Buffer* buffer); void destroyBuffer(const gfx::Buffer* buffer);

View File

@ -7,15 +7,15 @@
namespace engine { namespace engine {
class IResourceManager {
public:
virtual ~IResourceManager() = default;
};
template <class T> template <class T>
class ResourceManager { class ResourceManager : public IResourceManager {
public: public:
ResourceManager() {}
~ResourceManager() {}
ResourceManager(const ResourceManager&) = delete;
ResourceManager& operator=(const ResourceManager&) = delete;
std::shared_ptr<T> add(const std::string& name, std::unique_ptr<T>&& resource) std::shared_ptr<T> add(const std::string& name, std::unique_ptr<T>&& resource)
{ {
if (m_resources.contains(name) == false) { if (m_resources.contains(name) == false) {
@ -34,8 +34,12 @@ namespace engine {
std::weak_ptr<T> ptr = m_resources.at(name); std::weak_ptr<T> ptr = m_resources.at(name);
if (ptr.expired() == false) { if (ptr.expired() == false) {
return ptr.lock(); return ptr.lock();
} else {
m_resources.erase(name);
} }
} }
// resource doesn't exist:
throw std::runtime_error("Resource doesn't exist: " + name);
return {}; return {};
} }

View File

@ -29,11 +29,18 @@ public:
m_vb = m_gfx->createBuffer(gfx::BufferType::VERTEX, vertices.size() * sizeof(Vertex), vertices.data()); m_vb = m_gfx->createBuffer(gfx::BufferType::VERTEX, vertices.size() * sizeof(Vertex), vertices.data());
std::vector<uint32_t> indices(m_count); std::vector<uint32_t> indices(m_count);
for (int i = 0; i < m_count; i++) { for (uint32_t i = 0; i < m_count; i++) {
indices[i] = i; indices[i] = i;
} }
m_ib = m_gfx->createBuffer(gfx::BufferType::INDEX, indices.size() * sizeof(uint32_t), indices.data()); m_ib = m_gfx->createBuffer(gfx::BufferType::INDEX, indices.size() * sizeof(uint32_t), indices.data());
} }
Mesh(GFXDevice* gfx, const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices)
: m_gfx(gfx)
{
m_count = vertices.size();
m_vb = m_gfx->createBuffer(gfx::BufferType::VERTEX, vertices.size() * sizeof(Vertex), vertices.data());
m_ib = m_gfx->createBuffer(gfx::BufferType::INDEX, indices.size() * sizeof(uint32_t), indices.data());
}
~Mesh() ~Mesh()
{ {
m_gfx->destroyBuffer(m_ib); m_gfx->destroyBuffer(m_ib);

View File

@ -2,6 +2,7 @@
#include "log.hpp" #include "log.hpp"
#include "resource_manager.hpp"
#include "ecs_system.hpp" #include "ecs_system.hpp"
#include <map> #include <map>
@ -23,6 +24,34 @@ namespace engine {
void update(float ts); void update(float ts);
Application* app() { return m_app; }
/* resource stuff */
template <typename T>
void registerResourceManager()
{
size_t hash = typeid(T).hash_code();
assert(m_resourceManagers.contains(hash) == false && "Registering resource manager type more than once.");
m_resourceManagers.emplace(hash, std::make_unique<ResourceManager<T>>());
}
template <typename T>
std::shared_ptr<T> addResource(const std::string& name, std::unique_ptr<T>&& resource)
{
auto resourceManager = getResourceManager<T>();
return resourceManager->add(name, std::move(resource));
}
template <typename T>
std::shared_ptr<T> getResource(const std::string& name)
{
auto resourceManager = getResourceManager<T>();
return resourceManager->get(name);
}
/* ecs stuff */
uint32_t createEntity(const std::string& tag, uint32_t parent = 0); uint32_t createEntity(const std::string& tag, uint32_t parent = 0);
uint32_t getEntity(const std::string& tag, uint32_t parent = 0); uint32_t getEntity(const std::string& tag, uint32_t parent = 0);
@ -97,12 +126,30 @@ namespace engine {
return castedPtr; return castedPtr;
} }
Application* app() { return m_app; }
private: private:
Application* const m_app; Application* const m_app;
uint32_t m_nextEntityID = 1000; uint32_t m_nextEntityID = 1000;
/* resource stuff */
std::map<size_t, std::unique_ptr<IResourceManager>> m_resourceManagers{};
template <typename T>
ResourceManager<T>* getResourceManager()
{
size_t hash = typeid(T).hash_code();
auto it = m_resourceManagers.find(hash);
if (it == m_resourceManagers.end()) {
throw std::runtime_error("Cannot find resource manager.");
}
auto ptr = it->second.get();
auto castedPtr = dynamic_cast<ResourceManager<T>*>(ptr);
assert(castedPtr != nullptr);
return castedPtr;
}
/* ecs stuff */
size_t m_nextSignaturePosition = 0; size_t m_nextSignaturePosition = 0;
// maps component hashes to signature positions // maps component hashes to signature positions
std::map<size_t, size_t> m_componentSignaturePositions{}; std::map<size_t, size_t> m_componentSignaturePositions{};

View File

@ -12,13 +12,23 @@ namespace engine {
class RenderSystem : public System { class RenderSystem : public System {
public: public:
RenderSystem(Scene* scene) RenderSystem(Scene* scene);
: System(scene, { typeid(TransformComponent).hash_code(), typeid(RenderableComponent).hash_code() })
{
}
void onUpdate(float ts) override; void onUpdate(float ts) override;
void setCameraEntity(uint32_t entity) { m_camera.camEntity = entity; }
private:
struct {
// only uses transform component, which is required for all entities anyway
uint32_t camEntity = 0;
float horizontalFovDegrees = 70.0f;
float clipNear = 0.1f;
float clipFar = 1000.0f;
} m_camera;
float m_viewportAspectRatio = 1.0f;
}; };
} }

View File

@ -1,65 +1,17 @@
#pragma once #pragma once
#include "ecs_system.hpp" #include "ecs_system.hpp"
#include "components/transform.hpp"
#include "scene.hpp"
#include "log.hpp"
#include <glm/vec3.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/mat4x4.hpp>
#include <typeinfo>
#include <string.h>
namespace engine { namespace engine {
class TransformSystem : public System { class TransformSystem : public System {
public: public:
TransformSystem(Scene* scene) TransformSystem(Scene* scene);
: System(scene, { typeid(TransformComponent).hash_code() })
{
}
void onUpdate(float ts) override void onUpdate(float ts) override;
{
for (uint32_t entity : m_entities) {
auto t = m_scene->getComponent<TransformComponent>(entity); uint32_t getChildEntity(uint32_t parent, const std::string& tag);
// TRACE("tag is {}", t->tag);
glm::mat4 transform;
// rotation
transform = glm::mat4_cast(t->rotation);
// position
reinterpret_cast<glm::vec3&>(transform[3]) = t->position;
// scale (effectively applied first)
transform = glm::scale(transform, t->scale);
if (t->parent != 0) {
transform = m_scene->getComponent<TransformComponent>(t->parent)->worldMatrix * transform;
}
t->worldMatrix = transform;
}
}
uint32_t getChildEntity(uint32_t parent, const std::string& tag)
{
for (uint32_t entity : m_entities) {
auto t = m_scene->getComponent<TransformComponent>(entity);
if (t->parent == parent) {
if (t->tag == tag) {
return entity;
}
}
}
return 0;
}
}; };

View File

@ -0,0 +1,13 @@
#pragma once
#include "scene.hpp"
#include "resources/shader.hpp"
#include <string>
namespace engine::util {
uint32_t loadMeshFromFile(Scene* parent, const std::string& path);
}

View File

@ -114,7 +114,7 @@ namespace engine {
// returns the number of frames elapsed since window creation // returns the number of frames elapsed since window creation
uint64_t getFrameCount() const; uint64_t getFrameCount() const;
uint64_t getStartTime() const;; uint64_t getStartTime() const;
float dt() const; // returns delta time in seconds float dt() const; // returns delta time in seconds
uint64_t getFPS() const; uint64_t getFPS() const;
uint64_t getAvgFPS() const; uint64_t getAvgFPS() const;

View File

@ -73,6 +73,8 @@ namespace engine {
auto beginFrame = std::chrono::steady_clock::now(); auto beginFrame = std::chrono::steady_clock::now();
auto endFrame = beginFrame + FRAMETIME_LIMIT; auto endFrame = beginFrame + FRAMETIME_LIMIT;
auto lastTick = m_window->getNanos();
// single-threaded game loop // single-threaded game loop
while (m_window->isRunning()) { while (m_window->isRunning()) {
@ -91,6 +93,12 @@ namespace engine {
m_window->getInputAndEvents(); m_window->getInputAndEvents();
/* fps limiter */ /* fps limiter */
uint64_t now = m_window->getNanos();
if (now - lastTick >= 1000000000LL * 10LL) {
lastTick = now;
m_window->setTitle(std::to_string(m_window->getAvgFPS()));
m_window->resetAvgFPS();
}
if (m_enableFrameLimiter) { if (m_enableFrameLimiter) {
std::this_thread::sleep_until(endFrame); std::this_thread::sleep_until(endFrame);
} }

View File

@ -155,8 +155,9 @@ namespace engine {
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
case gfx::BufferType::INDEX: case gfx::BufferType::INDEX:
return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
default:
throw std::runtime_error("This buffer type does not have usage bits");
} }
throw std::runtime_error("Unknown buffer type");
} }
static VkFilter getTextureFilter(gfx::TextureFilter filter) static VkFilter getTextureFilter(gfx::TextureFilter filter)
@ -222,7 +223,7 @@ namespace engine {
static std::vector<const char*> getRequiredVulkanExtensions(SDL_Window* window) static std::vector<const char*> getRequiredVulkanExtensions(SDL_Window* window)
{ {
SDL_bool res; [[maybe_unused]] SDL_bool res;
unsigned int sdlExtensionCount = 0; unsigned int sdlExtensionCount = 0;
res = SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, nullptr); res = SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, nullptr);
@ -239,7 +240,7 @@ namespace engine {
constexpr const char* VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation"; constexpr const char* VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation";
LayerInfo info; LayerInfo info;
VkResult res; [[maybe_unused]] VkResult res;
uint32_t layerCount; uint32_t layerCount;
res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr); res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
@ -269,6 +270,7 @@ namespace engine {
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData) void* pUserData)
{ {
(void)pUserData;
std::string msgType{}; std::string msgType{};
@ -357,7 +359,7 @@ namespace engine {
{ {
uint32_t bitmask = static_cast<uint32_t>(flags); uint32_t bitmask = static_cast<uint32_t>(flags);
for (int i = 0; i < queues.size(); i++) { for (size_t i = 0; i < queues.size(); i++) {
if (bitmask & static_cast<uint32_t>(QueueFlags::GRAPHICS)) { if (bitmask & static_cast<uint32_t>(QueueFlags::GRAPHICS)) {
if (queues[i].supportsGraphics == false) continue; if (queues[i].supportsGraphics == false) continue;
@ -382,7 +384,7 @@ namespace engine {
{ {
Swapchain::MSTarget target{}; Swapchain::MSTarget target{};
VkResult res; [[maybe_unused]] VkResult res;
VkImageCreateInfo imageInfo{}; VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
@ -408,7 +410,8 @@ namespace engine {
res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &target.colorImage, &target.colorImageAllocation, nullptr); res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &target.colorImage, &target.colorImageAllocation, nullptr);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
VkImageViewCreateInfo imageViewInfo{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; VkImageViewCreateInfo imageViewInfo{};
imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewInfo.image = target.colorImage; imageViewInfo.image = target.colorImage;
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewInfo.format = colorFormat; imageViewInfo.format = colorFormat;
@ -433,7 +436,7 @@ namespace engine {
{ {
DepthBuffer db{}; DepthBuffer db{};
VkResult res; [[maybe_unused]] VkResult res;
VkImageCreateInfo imageInfo{}; VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
@ -459,7 +462,8 @@ namespace engine {
res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &db.image, &db.allocation, nullptr); res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &db.image, &db.allocation, nullptr);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
VkImageViewCreateInfo imageViewInfo{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; VkImageViewCreateInfo imageViewInfo{};
imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewInfo.image = db.image; imageViewInfo.image = db.image;
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewInfo.format = VK_FORMAT_D32_SFLOAT; imageViewInfo.format = VK_FORMAT_D32_SFLOAT;
@ -498,9 +502,9 @@ namespace engine {
} }
// This is called not just on initialisation, but also when the window is resized. // This is called not just on initialisation, but also when the window is resized.
static void createSwapchain(VkDevice device, VkPhysicalDevice physicalDevice, VmaAllocator allocator, std::vector<Queue> queues, SDL_Window* window, VkSurfaceKHR surface, Swapchain* swapchain, bool vsync) static void createSwapchain(VkDevice device, VkPhysicalDevice physicalDevice, VmaAllocator allocator, std::vector<Queue> queues, SDL_Window* window, VkSurfaceKHR surface, bool vsync, Swapchain* swapchain)
{ {
VkResult res; [[maybe_unused]] VkResult res;
// get surface capabilities // get surface capabilities
VkSurfaceCapabilitiesKHR caps; VkSurfaceCapabilitiesKHR caps;
@ -723,7 +727,7 @@ namespace engine {
swapchain->imageViews.resize(swapchain->images.size()); swapchain->imageViews.resize(swapchain->images.size());
swapchain->framebuffers.resize(swapchain->images.size()); swapchain->framebuffers.resize(swapchain->images.size());
for (int i = 0; i < swapchain->images.size(); i++) { for (size_t i = 0; i < swapchain->images.size(); i++) {
VkImageViewCreateInfo createInfo{}; VkImageViewCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
@ -783,7 +787,7 @@ namespace engine {
static void copyBuffer(VkDevice device, VkCommandPool commandPool, VkQueue queue, VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) static void copyBuffer(VkDevice device, VkCommandPool commandPool, VkQueue queue, VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
{ {
VkResult res; [[maybe_unused]] VkResult res;
VkCommandBufferAllocateInfo allocInfo{}; VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@ -828,11 +832,12 @@ namespace engine {
} }
VkCommandBuffer beginOneTimeCommands(VkDevice device, VkCommandPool commandPool, VkQueue queue) VkCommandBuffer beginOneTimeCommands(VkDevice device, VkCommandPool commandPool)
{ {
VkResult res; [[maybe_unused]] VkResult res;
VkCommandBufferAllocateInfo allocInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = commandPool; allocInfo.commandPool = commandPool;
allocInfo.commandBufferCount = 1; allocInfo.commandBufferCount = 1;
@ -841,7 +846,8 @@ namespace engine {
res = vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); res = vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
VkCommandBufferBeginInfo beginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
res = vkBeginCommandBuffer(commandBuffer, &beginInfo); res = vkBeginCommandBuffer(commandBuffer, &beginInfo);
@ -852,11 +858,12 @@ namespace engine {
static void endOneTimeCommands(VkDevice device, VkCommandPool commandPool, VkCommandBuffer commandBuffer, VkQueue queue) static void endOneTimeCommands(VkDevice device, VkCommandPool commandPool, VkCommandBuffer commandBuffer, VkQueue queue)
{ {
VkResult res; [[maybe_unused]] VkResult res;
res = vkEndCommandBuffer(commandBuffer); res = vkEndCommandBuffer(commandBuffer);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
VkSubmitInfo submitInfo{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer; submitInfo.pCommandBuffers = &commandBuffer;
@ -871,7 +878,8 @@ namespace engine {
static void cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels, VkImage image) static void cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels, VkImage image)
{ {
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout; barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout; barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
@ -911,7 +919,8 @@ namespace engine {
static void cmdGenerateMipmaps(VkCommandBuffer commandBuffer, VkImage image, int32_t width, int32_t height, uint32_t mipLevels) static void cmdGenerateMipmaps(VkCommandBuffer commandBuffer, VkImage image, int32_t width, int32_t height, uint32_t mipLevels)
{ {
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = image; barrier.image = image;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
@ -1052,9 +1061,9 @@ namespace engine {
// get the both the engine and application versions // get the both the engine and application versions
int appVersionMajor = 0, appVersionMinor = 0, appVersionPatch = 0; int appVersionMajor = 0, appVersionMinor = 0, appVersionPatch = 0;
assert(versionFromCharArray(appVersion, &appVersionMajor, &appVersionMinor, &appVersionPatch)); versionFromCharArray(appVersion, &appVersionMajor, &appVersionMinor, &appVersionPatch);
int engineVersionMajor = 0, engineVersionMinor = 0, engineVersionPatch = 0; int engineVersionMajor = 0, engineVersionMinor = 0, engineVersionPatch = 0;
assert(versionFromCharArray(ENGINE_VERSION, &engineVersionMajor, &engineVersionMinor, &engineVersionPatch)); versionFromCharArray(ENGINE_VERSION, &engineVersionMajor, &engineVersionMinor, &engineVersionPatch);
VkApplicationInfo applicationInfo{ VkApplicationInfo applicationInfo{
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
@ -1134,7 +1143,8 @@ namespace engine {
{ {
VkDebugUtilsMessengerCreateInfoEXT createInfo = getDebugMessengerCreateInfo(); VkDebugUtilsMessengerCreateInfoEXT createInfo = getDebugMessengerCreateInfo();
VkResult res = vkCreateDebugUtilsMessengerEXT(pimpl->instance, &createInfo, nullptr, &pimpl->debugMessenger); [[maybe_unused]] VkResult res;
res = vkCreateDebugUtilsMessengerEXT(pimpl->instance, &createInfo, nullptr, &pimpl->debugMessenger);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
} }
@ -1311,8 +1321,8 @@ namespace engine {
.flags = 0, .flags = 0,
.queueCreateInfoCount = (uint32_t)queueCreateInfos.size(), .queueCreateInfoCount = (uint32_t)queueCreateInfos.size(),
.pQueueCreateInfos = queueCreateInfos.data(), .pQueueCreateInfos = queueCreateInfos.data(),
// IGNORED: .enabledLayerCount .enabledLayerCount = 0,
// IGNORED: .ppEnabledLayerNames .ppEnabledLayerNames = nullptr,
.enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(), .enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(),
.ppEnabledExtensionNames = requiredDeviceExtensions.data(), .ppEnabledExtensionNames = requiredDeviceExtensions.data(),
.pEnabledFeatures = &deviceFeatures, .pEnabledFeatures = &deviceFeatures,
@ -1335,8 +1345,9 @@ namespace engine {
VkCommandPoolCreateInfo gfxCmdPoolInfo{ VkCommandPoolCreateInfo gfxCmdPoolInfo{
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.pNext = nullptr,
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
.queueFamilyIndex = pimpl->gfxQueue.familyIndex, .queueFamilyIndex = pimpl->gfxQueue.familyIndex
}; };
res = vkCreateCommandPool(pimpl->device, &gfxCmdPoolInfo, nullptr, &pimpl->commandPool); res = vkCreateCommandPool(pimpl->device, &gfxCmdPoolInfo, nullptr, &pimpl->commandPool);
@ -1344,12 +1355,13 @@ namespace engine {
VkCommandBufferAllocateInfo gfxCmdBufInfo{ VkCommandBufferAllocateInfo gfxCmdBufInfo{
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = nullptr,
.commandPool = pimpl->commandPool, .commandPool = pimpl->commandPool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1 .commandBufferCount = 1
}; };
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
res = vkAllocateCommandBuffers(pimpl->device, &gfxCmdBufInfo, &pimpl->commandBuffers[i]); res = vkAllocateCommandBuffers(pimpl->device, &gfxCmdBufInfo, &pimpl->commandBuffers[i]);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
} }
@ -1402,14 +1414,15 @@ namespace engine {
.pTypeExternalMemoryHandleTypes = nullptr .pTypeExternalMemoryHandleTypes = nullptr
}; };
VkResult res = vmaCreateAllocator(&createInfo, &pimpl->allocator); [[maybe_unused]] VkResult res;
res = vmaCreateAllocator(&createInfo, &pimpl->allocator);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
} }
// Now make the swapchain // Now make the swapchain
createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->allocator, pimpl->queues, window, pimpl->surface, &pimpl->swapchain, pimpl->vsync); createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->allocator, pimpl->queues, window, pimpl->surface, pimpl->vsync, &pimpl->swapchain);
@ -1417,7 +1430,7 @@ namespace engine {
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
fenceInfo.pNext = nullptr; fenceInfo.pNext = nullptr;
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
res = vkCreateFence(pimpl->device, &fenceInfo, nullptr, &pimpl->inFlightFences[i]); res = vkCreateFence(pimpl->device, &fenceInfo, nullptr, &pimpl->inFlightFences[i]);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
} }
@ -1429,7 +1442,8 @@ namespace engine {
pimpl->uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; pimpl->uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
pimpl->uboLayoutBinding.pImmutableSamplers = nullptr; pimpl->uboLayoutBinding.pImmutableSamplers = nullptr;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{};
descriptorSetLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutInfo.bindingCount = 1; descriptorSetLayoutInfo.bindingCount = 1;
descriptorSetLayoutInfo.pBindings = &pimpl->uboLayoutBinding; descriptorSetLayoutInfo.pBindings = &pimpl->uboLayoutBinding;
res = vkCreateDescriptorSetLayout(pimpl->device, &descriptorSetLayoutInfo, nullptr, &pimpl->descriptorSetLayout); res = vkCreateDescriptorSetLayout(pimpl->device, &descriptorSetLayoutInfo, nullptr, &pimpl->descriptorSetLayout);
@ -1442,7 +1456,8 @@ namespace engine {
pimpl->samplerLayoutBinding.pImmutableSamplers = nullptr; pimpl->samplerLayoutBinding.pImmutableSamplers = nullptr;
pimpl->samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; pimpl->samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo samplerSetLayoutInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; VkDescriptorSetLayoutCreateInfo samplerSetLayoutInfo{};
samplerSetLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
samplerSetLayoutInfo.bindingCount = 1; samplerSetLayoutInfo.bindingCount = 1;
samplerSetLayoutInfo.pBindings = &pimpl->samplerLayoutBinding; samplerSetLayoutInfo.pBindings = &pimpl->samplerLayoutBinding;
res = vkCreateDescriptorSetLayout(pimpl->device, &samplerSetLayoutInfo, nullptr, &pimpl->samplerSetLayout); res = vkCreateDescriptorSetLayout(pimpl->device, &samplerSetLayoutInfo, nullptr, &pimpl->samplerSetLayout);
@ -1456,7 +1471,7 @@ namespace engine {
vkDestroyDescriptorSetLayout(pimpl->device, pimpl->samplerSetLayout, nullptr); vkDestroyDescriptorSetLayout(pimpl->device, pimpl->samplerSetLayout, nullptr);
vkDestroyDescriptorSetLayout(pimpl->device, pimpl->descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(pimpl->device, pimpl->descriptorSetLayout, nullptr);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
vkDestroyFence(pimpl->device, pimpl->inFlightFences[i], nullptr); vkDestroyFence(pimpl->device, pimpl->inFlightFences[i], nullptr);
vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphores[i], nullptr); vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphores[i], nullptr);
vkDestroySemaphore(pimpl->device, pimpl->swapchain.acquireSemaphores[i], nullptr); vkDestroySemaphore(pimpl->device, pimpl->swapchain.acquireSemaphores[i], nullptr);
@ -1509,6 +1524,7 @@ namespace engine {
.vertexBuffer = vertexBuffer, .vertexBuffer = vertexBuffer,
.indexBuffer = indexBuffer, // will be ignored if nullptr .indexBuffer = indexBuffer, // will be ignored if nullptr
.count = count, .count = count,
.pushConstantData{}
}; };
memcpy(call.pushConstantData, pushConstantData, pushConstantSize); memcpy(call.pushConstantData, pushConstantData, pushConstantSize);
@ -1535,7 +1551,7 @@ namespace engine {
if (res == VK_ERROR_OUT_OF_DATE_KHR) { if (res == VK_ERROR_OUT_OF_DATE_KHR) {
// recreate swapchain // recreate swapchain
waitIdle(); waitIdle();
createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->allocator, pimpl->queues, pimpl->window, pimpl->surface, &pimpl->swapchain, &pimpl->vsync); createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->allocator, pimpl->queues, pimpl->window, pimpl->surface, pimpl->vsync, &pimpl->swapchain);
return; return;
} }
else { else {
@ -1547,13 +1563,15 @@ namespace engine {
// now record command buffer // now record command buffer
{ {
VkCommandBufferBeginInfo beginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = 0; beginInfo.flags = 0;
beginInfo.pInheritanceInfo = nullptr; beginInfo.pInheritanceInfo = nullptr;
res = vkBeginCommandBuffer(pimpl->commandBuffers[frameIndex], &beginInfo); res = vkBeginCommandBuffer(pimpl->commandBuffers[frameIndex], &beginInfo);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
VkRenderPassBeginInfo renderPassInfo{ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = pimpl->swapchain.renderpass; renderPassInfo.renderPass = pimpl->swapchain.renderpass;
renderPassInfo.framebuffer = pimpl->swapchain.framebuffers[imageIndex]; renderPassInfo.framebuffer = pimpl->swapchain.framebuffers[imageIndex];
renderPassInfo.renderArea.offset = { 0, 0 }; renderPassInfo.renderArea.offset = { 0, 0 };
@ -1636,7 +1654,8 @@ namespace engine {
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
} }
VkSubmitInfo submitInfo{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
submitInfo.waitSemaphoreCount = 1; submitInfo.waitSemaphoreCount = 1;
@ -1650,7 +1669,8 @@ namespace engine {
res = vkQueueSubmit(pimpl->gfxQueue.handle, 1, &submitInfo, pimpl->inFlightFences[frameIndex]); res = vkQueueSubmit(pimpl->gfxQueue.handle, 1, &submitInfo, pimpl->inFlightFences[frameIndex]);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
VkPresentInfoKHR presentInfo{ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; VkPresentInfoKHR presentInfo{};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1; presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &pimpl->swapchain.releaseSemaphores[frameIndex]; presentInfo.pWaitSemaphores = &pimpl->swapchain.releaseSemaphores[frameIndex];
@ -1664,7 +1684,7 @@ namespace engine {
if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) { if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) {
// recreate swapchain // recreate swapchain
waitIdle(); waitIdle();
createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->allocator, pimpl->queues, pimpl->window, pimpl->surface, &pimpl->swapchain, &pimpl->vsync); createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->allocator, pimpl->queues, pimpl->window, pimpl->surface, pimpl->vsync, &pimpl->swapchain);
} }
else { else {
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
@ -1676,7 +1696,7 @@ namespace engine {
gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize, bool alphaBlending, bool backfaceCulling) gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize, bool alphaBlending, bool backfaceCulling)
{ {
VkResult res; [[maybe_unused]] VkResult res;
gfx::Pipeline* pipeline = new gfx::Pipeline; gfx::Pipeline* pipeline = new gfx::Pipeline;
@ -1689,12 +1709,13 @@ namespace engine {
// create uniform buffers // create uniform buffers
pipeline->uniformBuffers.resize(FRAMES_IN_FLIGHT); pipeline->uniformBuffers.resize(FRAMES_IN_FLIGHT);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
auto buf = new gfx::Buffer{}; auto buf = new gfx::Buffer{};
buf->size = uniformBufferSize; buf->size = uniformBufferSize;
buf->type = gfx::BufferType::UNIFORM; buf->type = gfx::BufferType::UNIFORM;
VkBufferCreateInfo bufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = buf->size; bufferInfo.size = buf->size;
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@ -1734,7 +1755,7 @@ namespace engine {
res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, pipeline->descriptorSets.data()); res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, pipeline->descriptorSets.data());
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
VkDescriptorBufferInfo bufferInfo{}; VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = pipeline->uniformBuffers[i]->buffer; bufferInfo.buffer = pipeline->uniformBuffers[i]->buffer;
bufferInfo.offset = 0; bufferInfo.offset = 0;
@ -1771,13 +1792,15 @@ namespace engine {
attribDescs.push_back(vulkanAttribDesc); attribDescs.push_back(vulkanAttribDesc);
} }
VkPipelineShaderStageCreateInfo vertShaderStageInfo{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertShaderStageInfo.module = vertShaderModule; vertShaderStageInfo.module = vertShaderModule;
vertShaderStageInfo.pName = "main"; vertShaderStageInfo.pName = "main";
vertShaderStageInfo.pSpecializationInfo = nullptr; vertShaderStageInfo.pSpecializationInfo = nullptr;
VkPipelineShaderStageCreateInfo fragShaderStageInfo{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShaderStageInfo.module = fragShaderModule; fragShaderStageInfo.module = fragShaderModule;
fragShaderStageInfo.pName = "main"; fragShaderStageInfo.pName = "main";
@ -1949,21 +1972,21 @@ namespace engine {
vkDestroyDescriptorPool(pimpl->device, pipeline->descriptorPool, nullptr); vkDestroyDescriptorPool(pimpl->device, pipeline->descriptorPool, nullptr);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
destroyBuffer(pipeline->uniformBuffers[i]); destroyBuffer(pipeline->uniformBuffers[i]);
} }
delete pipeline; delete pipeline;
} }
void GFXDevice::updateUniformBuffer(const gfx::Pipeline* pipeline, void* data, size_t size, uint32_t offset) void GFXDevice::updateUniformBuffer(const gfx::Pipeline* pipeline, const void* data, size_t size, uint32_t offset)
{ {
assert(size <= pipeline->uniformBuffers[0]->size); assert(size <= pipeline->uniformBuffers[0]->size);
VkResult res; [[maybe_unused]] VkResult res;
for (gfx::Buffer* buffer : pipeline->uniformBuffers) { for (gfx::Buffer* buffer : pipeline->uniformBuffers) {
void* uniformDest; void* uniformDest = nullptr;
res = vmaMapMemory(pimpl->allocator, buffer->allocation, &uniformDest); res = vmaMapMemory(pimpl->allocator, buffer->allocation, &uniformDest);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
memcpy((uint8_t*)uniformDest + offset, data, size); memcpy((uint8_t*)uniformDest + offset, data, size);
@ -1974,7 +1997,7 @@ namespace engine {
gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data) gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data)
{ {
VkResult res; [[maybe_unused]] VkResult res;
auto out = new gfx::Buffer{}; auto out = new gfx::Buffer{};
out->size = size; out->size = size;
@ -1986,7 +2009,8 @@ namespace engine {
// first create the staging buffer // first create the staging buffer
{ {
VkBufferCreateInfo stagingBufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo stagingBufferInfo{};
stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
stagingBufferInfo.size = out->size; stagingBufferInfo.size = out->size;
stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@ -2009,7 +2033,8 @@ namespace engine {
// create the actual buffer on the GPU // create the actual buffer on the GPU
{ {
VkBufferCreateInfo gpuBufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo gpuBufferInfo{};
gpuBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
gpuBufferInfo.size = out->size; gpuBufferInfo.size = out->size;
gpuBufferInfo.usage = vkinternal::getBufferUsageFlag(type) | VK_BUFFER_USAGE_TRANSFER_DST_BIT; gpuBufferInfo.usage = vkinternal::getBufferUsageFlag(type) | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
gpuBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; gpuBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@ -2042,7 +2067,7 @@ namespace engine {
{ {
auto out = new gfx::Texture; auto out = new gfx::Texture;
VkResult res; [[maybe_unused]] VkResult res;
size_t imageSize = w * h * 4; size_t imageSize = w * h * 4;
@ -2052,7 +2077,8 @@ namespace engine {
VkBuffer stagingBuffer; VkBuffer stagingBuffer;
VmaAllocation stagingAllocation; VmaAllocation stagingAllocation;
{ {
VkBufferCreateInfo stagingBufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo stagingBufferInfo{};
stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
stagingBufferInfo.size = imageSize; stagingBufferInfo.size = imageSize;
stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@ -2074,7 +2100,8 @@ namespace engine {
} }
// create the image // create the image
VkImageCreateInfo imageInfo{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D; imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = w; imageInfo.extent.width = w;
imageInfo.extent.height = h; imageInfo.extent.height = h;
@ -2097,7 +2124,7 @@ namespace engine {
// transition the image layout // transition the image layout
{ {
VkCommandBuffer commandBuffer = beginOneTimeCommands(pimpl->device, pimpl->commandPool, pimpl->gfxQueue.handle); VkCommandBuffer commandBuffer = beginOneTimeCommands(pimpl->device, pimpl->commandPool);
// begin cmd buffer // begin cmd buffer
@ -2130,7 +2157,8 @@ namespace engine {
vmaDestroyBuffer(pimpl->allocator, stagingBuffer, stagingAllocation); vmaDestroyBuffer(pimpl->allocator, stagingBuffer, stagingAllocation);
// create image view // create image view
VkImageViewCreateInfo imageViewInfo{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; VkImageViewCreateInfo imageViewInfo{};
imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewInfo.image = out->image; imageViewInfo.image = out->image;
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewInfo.format = VK_FORMAT_R8G8B8A8_SRGB; imageViewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
@ -2151,7 +2179,8 @@ namespace engine {
VkFilter magFilterInternal = vkinternal::getTextureFilter(magFilter); VkFilter magFilterInternal = vkinternal::getTextureFilter(magFilter);
VkFilter minFilterInternal = vkinternal::getTextureFilter(minFilter); VkFilter minFilterInternal = vkinternal::getTextureFilter(minFilter);
VkSamplerCreateInfo samplerInfo{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = magFilterInternal; samplerInfo.magFilter = magFilterInternal;
samplerInfo.minFilter = minFilterInternal; samplerInfo.minFilter = minFilterInternal;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
@ -2201,7 +2230,7 @@ namespace engine {
res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, out->descriptorSets.data()); res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, out->descriptorSets.data());
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
VkDescriptorImageInfo imageInfo{}; VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = out->imageView; imageInfo.imageView = out->imageView;

View File

@ -25,7 +25,7 @@ namespace engine {
void SceneManager::updateActiveScene(float ts) void SceneManager::updateActiveScene(float ts)
{ {
if (m_activeSceneIndex >= 0) { if (m_activeSceneIndex >= 0) {
assert(m_activeSceneIndex < m_scenes.size()); assert((size_t)m_activeSceneIndex < m_scenes.size());
m_scenes[m_activeSceneIndex]->update(ts); m_scenes[m_activeSceneIndex]->update(ts);
} }
} }

View File

@ -1,6 +1,7 @@
#include "systems/render.hpp" #include "systems/render.hpp"
#include "application.hpp" #include "application.hpp"
#include "window.hpp"
#include "gfx_device.hpp" #include "gfx_device.hpp"
#include "resources/material.hpp" #include "resources/material.hpp"
@ -13,27 +14,43 @@
namespace engine { namespace engine {
RenderSystem::RenderSystem(Scene* scene)
: System(scene, { typeid(TransformComponent).hash_code(), typeid(RenderableComponent).hash_code() })
{
}
void RenderSystem::onUpdate(float ts) void RenderSystem::onUpdate(float ts)
{ {
(void)ts;
GFXDevice* const gfx = m_scene->app()->gfx(); GFXDevice* const gfx = m_scene->app()->gfx();
constexpr float FOV_H = 75.0f; /* camera stuff */
constexpr float CLIP_NEAR = 0.1f;
constexpr float CLIP_FAR = 100.0f;
const auto cameraTransform = m_scene->getComponent<TransformComponent>(m_camera.camEntity);
// do not render if camera is not set
if (cameraTransform == nullptr) return;
glm::mat4 viewMatrix = glm::inverse(cameraTransform->worldMatrix);
if (m_scene->app()->window()->getWindowResized()) {
uint32_t w, h; uint32_t w, h;
gfx->getViewportSize(&w, &h); gfx->getViewportSize(&w, &h);
float aspect = w / h; m_viewportAspectRatio = (float)w / (float)h;
float verticalFOV = FOV_H / aspect; }
glm::mat4 projMatrix = glm::perspectiveZO(verticalFOV, aspect, CLIP_NEAR, CLIP_FAR); const float horizontalFovRadians = glm::radians(m_camera.horizontalFovDegrees);
const float verticalFov = glm::atan( glm::tan(horizontalFovRadians / 2.0f) / m_viewportAspectRatio ) * 2.0f;
const glm::mat4 projMatrix = glm::perspectiveZO(verticalFov, m_viewportAspectRatio, m_camera.clipNear, m_camera.clipFar);
/* render all renderable entities */
for (uint32_t entity : m_entities) { for (uint32_t entity : m_entities) {
auto t = m_scene->getComponent<TransformComponent>(entity); auto t = m_scene->getComponent<TransformComponent>(entity);
auto r = m_scene->getComponent<RenderableComponent>(entity); auto r = m_scene->getComponent<RenderableComponent>(entity);
// TRACE("rendering {}", t->tag);
gfx->updateUniformBuffer(r->material->getShader()->getPipeline(), &projMatrix, sizeof(projMatrix), 0); gfx->updateUniformBuffer(r->material->getShader()->getPipeline(), &projMatrix, sizeof(projMatrix), 0);
struct { struct {
@ -42,7 +59,7 @@ namespace engine {
} pushConsts{}; } pushConsts{};
pushConsts.model = t->worldMatrix; pushConsts.model = t->worldMatrix;
pushConsts.view = glm::mat4{ 1.0f }; pushConsts.view = viewMatrix;
gfx->draw( gfx->draw(
r->material->getShader()->getPipeline(), r->material->getShader()->getPipeline(),
@ -53,6 +70,7 @@ namespace engine {
sizeof(pushConsts), sizeof(pushConsts),
r->material->m_texture->getHandle() r->material->m_texture->getHandle()
); );
} }
} }

56
src/systems/transform.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "systems/transform.hpp"
#include "scene.hpp"
#include "components/transform.hpp"
#include <typeinfo>
namespace engine {
TransformSystem::TransformSystem(Scene* scene)
: System(scene, { typeid(TransformComponent).hash_code() })
{
}
void TransformSystem::onUpdate(float ts)
{
(void)ts;
for (uint32_t entity : m_entities) {
auto t = m_scene->getComponent<TransformComponent>(entity);
glm::mat4 transform;
// rotation
transform = glm::mat4_cast(t->rotation);
// position
reinterpret_cast<glm::vec3&>(transform[3]) = t->position;
// scale (effectively applied first)
transform = glm::scale(transform, t->scale);
if (t->parent != 0) {
transform = m_scene->getComponent<TransformComponent>(t->parent)->worldMatrix * transform;
}
t->worldMatrix = transform;
}
}
uint32_t TransformSystem::getChildEntity(uint32_t parent, const std::string& tag)
{
for (uint32_t entity : m_entities) {
auto t = m_scene->getComponent<TransformComponent>(entity);
if (t->parent == parent) {
if (t->tag == tag) {
return entity;
}
}
}
return 0;
}
}

235
src/util/model_loader.cpp Normal file
View File

@ -0,0 +1,235 @@
#include "util/model_loader.hpp"
#include "log.hpp"
#include "application.hpp"
#include "components/transform.hpp"
#include "components/renderable.hpp"
#include "resources/texture.hpp"
#include "resources/material.hpp"
#include "resources/shader.hpp"
#include "resources/mesh.hpp"
#include <assimp/Importer.hpp>
#include <assimp/LogStream.hpp>
#include <assimp/Logger.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/postprocess.h>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include <glm/gtc/quaternion.hpp>
#include <map>
#include <filesystem>
namespace engine::util {
static void buildGraph(
const std::map<int, std::shared_ptr<resources::Texture>>& textures,
const std::vector<std::shared_ptr<resources::Mesh>>& meshes,
const std::vector<unsigned int>& meshTextureIndices,
aiNode* parentNode, Scene* scene, uint32_t parentObj)
{
// convert to glm column major
glm::mat4 transform;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
transform[i][j] = parentNode->mTransformation[j][i];
}
}
// get position
glm::vec3 position{ transform[3][0], transform[3][1], transform[3][2] };
// remove position from matrix
transform[3][0] = 0.0f;
transform[3][1] = 0.0f;
transform[3][2] = 0.0f;
// get scale
glm::vec3 scale{};
scale.x = sqrt(transform[0][0] * transform[0][0] + transform[0][1] * transform[0][1] + transform[0][2] * transform[0][2]);
scale.y = sqrt(transform[1][0] * transform[1][0] + transform[1][1] * transform[1][1] + transform[1][2] * transform[1][2]);
scale.z = sqrt(transform[2][0] * transform[2][0] + transform[2][1] * transform[2][1] + transform[2][2] * transform[2][2]);
// remove scaling from matrix
for (int row = 0; row < 3; row++) {
transform[0][row] /= scale.x;
transform[1][row] /= scale.y;
transform[2][row] /= scale.z;
}
// get rotation
glm::quat rotation = glm::quat_cast(transform);
// update position, scale, rotation
auto parentTransform = scene->getComponent<TransformComponent>(parentObj);
parentTransform->position = position;
parentTransform->scale = scale;
parentTransform->rotation = rotation;
for (uint32_t i = 0; i < parentNode->mNumMeshes; i++) {
// create child node for each mesh
auto child = scene->createEntity("_mesh" + std::to_string(i), parentObj);
auto childRenderer = scene->addComponent<RenderableComponent>(child);
childRenderer->mesh = meshes[parentNode->mMeshes[i]];
childRenderer->material = std::make_shared<resources::Material>(scene->getResource<resources::Shader>("theShader"));
if (textures.contains(meshTextureIndices[parentNode->mMeshes[i]])) {
childRenderer->material->m_texture = textures.at(meshTextureIndices[parentNode->mMeshes[i]]);
} else {
childRenderer->material->m_texture = scene->getResource<resources::Texture>("whiteTexture");
}
}
for (uint32_t i = 0; i < parentNode->mNumChildren; i++) {
buildGraph(
textures,
meshes,
meshTextureIndices,
parentNode->mChildren[i],
scene,
scene->createEntity("child" + std::to_string(i), parentObj)
);
}
}
uint32_t loadMeshFromFile(Scene* parent, const std::string& path)
{
Assimp::Importer importer;
class myStream : public Assimp::LogStream {
public:
void write(const char* message) override {
(void)message;
DEBUG("ASSIMP: {}", message);
}
};
const unsigned int severity = Assimp::Logger::Debugging | Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn;
Assimp::DefaultLogger::get()->attachStream(new myStream, severity);
// remove everything but texcoords, normals, meshes, materials
importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
aiComponent_ANIMATIONS |
aiComponent_BONEWEIGHTS |
aiComponent_CAMERAS |
aiComponent_COLORS |
aiComponent_LIGHTS |
aiComponent_TANGENTS_AND_BITANGENTS |
aiComponent_TEXTURES |
0
);
importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,
aiPrimitiveType_POINT |
aiPrimitiveType_LINE |
aiPrimitiveType_POLYGON
);
const aiScene* scene = importer.ReadFile(path,
aiProcess_JoinIdenticalVertices |
aiProcess_Triangulate |
aiProcess_SortByPType |
aiProcess_RemoveComponent |
aiProcess_SplitLargeMeshes | // leave at default maximum
aiProcess_ValidateDataStructure | // make sure to log the output
aiProcess_ImproveCacheLocality |
aiProcess_RemoveRedundantMaterials |
aiProcess_FindInvalidData |
aiProcess_GenSmoothNormals |
aiProcess_GenUVCoords |
aiProcess_TransformUVCoords |
aiProcess_FlipUVs | // Maybe?
0
);
const char* errString = importer.GetErrorString();
if (errString[0] != '\0' || scene == nullptr) {
throw std::runtime_error(errString);
}
if (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) {
throw std::runtime_error(errString);
}
assert(scene->HasAnimations() == false);
assert(scene->HasCameras() == false);
assert(scene->HasLights() == false);
assert(scene->hasSkeletons() == false);
INFO("material count: {}, mesh count: {}", scene->mNumMaterials, scene->mNumMeshes);
std::map<int, std::shared_ptr<resources::Texture>> textures{};
for (uint32_t i = 0; i < scene->mNumMaterials; i++) {
const aiMaterial* m = scene->mMaterials[i];
INFO("Material {}:", i);
INFO(" Name: {}", m->GetName().C_Str());
for (uint32_t j = 0; j < m->mNumProperties; j++) {
const aiMaterialProperty* p = m->mProperties[j];
INFO(" prop {}, key: {}", j, p->mKey.C_Str());
}
if (aiGetMaterialTextureCount(m, aiTextureType_DIFFUSE) >= 1) {
aiString texPath{};
aiGetMaterialTexture(m, aiTextureType_DIFFUSE, 0, &texPath);
INFO(" Diffuse tex: {}", texPath.C_Str());
std::filesystem::path absPath = path;
absPath = absPath.parent_path();
absPath /= texPath.C_Str();
try {
textures[i] = std::make_shared<resources::Texture>(parent->app()->gfx(), absPath);
} catch (const std::runtime_error& e) {
textures[i] = parent->getResource<resources::Texture>("textures/white.png");
}
}
}
std::vector<std::shared_ptr<resources::Mesh>> meshes{};
std::vector<unsigned int> meshMaterialIndices{};
for (uint32_t i = 0; i < scene->mNumMeshes; i++) {
const aiMesh* m = scene->mMeshes[i];
meshMaterialIndices.push_back(m->mMaterialIndex);
std::vector<Vertex> vertices(m->mNumVertices);
std::vector<uint32_t> indices(m->mNumFaces * 3);
INFO("Mesh {}: vertex count {}", i, vertices.size());
INFO("Mesh {}: index count {}", i, indices.size());
for (uint32_t j = 0; j < vertices.size(); j++) {
Vertex v{};
v.pos.x = m->mVertices[j].x;
v.pos.y = m->mVertices[j].y;
v.pos.z = m->mVertices[j].z;
v.norm.x = m->mNormals[j].x;
v.norm.y = m->mNormals[j].y;
v.norm.z = m->mNormals[j].z;
vertices[j] = v;
}
if (m->mNumUVComponents[0] >= 2) {
for (uint32_t j = 0; j < vertices.size(); j++) {
vertices[j].uv.x = m->mTextureCoords[0][j].x;
vertices[j].uv.y = m->mTextureCoords[0][j].y;
}
}
for (uint32_t j = 0; j < indices.size() / 3; j++) {
indices[j * 3 + 0] = m->mFaces[j].mIndices[0];
indices[j * 3 + 1] = m->mFaces[j].mIndices[1];
indices[j * 3 + 2] = m->mFaces[j].mIndices[2];
}
meshes.push_back(std::make_shared<resources::Mesh>(parent->app()->gfx(), vertices, indices));
}
uint32_t obj = parent->createEntity(scene->GetShortFilename(path.c_str()));
buildGraph(textures, meshes, meshMaterialIndices, scene->mRootNode, parent, obj);
Assimp::DefaultLogger::kill();
return obj;
}
}

View File

@ -53,17 +53,15 @@ namespace engine {
throw std::runtime_error("Unable to create window: " + std::string(SDL_GetError())); throw std::runtime_error("Unable to create window: " + std::string(SDL_GetError()));
} }
// get window size
int winWidth, winHeight;
SDL_GetWindowSize(m_handle, &winWidth, &winHeight);
m_winSize.x = winWidth;
m_winSize.y = winHeight;
const int WINDOWED_MIN_WIDTH = 640; const int WINDOWED_MIN_WIDTH = 640;
const int WINDOWED_MIN_HEIGHT = 480; const int WINDOWED_MIN_HEIGHT = 480;
SDL_SetWindowMinimumSize(m_handle, WINDOWED_MIN_WIDTH, WINDOWED_MIN_HEIGHT); SDL_SetWindowMinimumSize(m_handle, WINDOWED_MIN_WIDTH, WINDOWED_MIN_HEIGHT);
// onResize(m_winSize.x, m_winSize.y); // get window size
int winWidth, winHeight;
SDL_GetWindowSize(m_handle, &winWidth, &winHeight);
onResize(winWidth, winHeight);
} }

View File

@ -11,6 +11,8 @@ set(GAME_SOURCES
src/main.cpp src/main.cpp
src/game.cpp src/game.cpp
src/game.hpp src/game.hpp
src/camera_controller.cpp
src/camera_controller.hpp
) )
@ -29,6 +31,9 @@ set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
if (MSVC) if (MSVC)
target_compile_options(${PROJECT_NAME} PRIVATE /W3) target_compile_options(${PROJECT_NAME} PRIVATE /W3)
target_compile_options(${PROJECT_NAME} PRIVATE /MP) target_compile_options(${PROJECT_NAME} PRIVATE /MP)
target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS)
else()
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic)
endif() endif()
target_include_directories(${PROJECT_NAME} PRIVATE src) target_include_directories(${PROJECT_NAME} PRIVATE src)

View File

@ -1,9 +1,11 @@
#include "camera_controller.hpp" #include "camera_controller.hpp"
#include "object.hpp" #include "application.hpp"
#include "window.hpp" #include "window.hpp"
#include "input.hpp" #include "input_manager.hpp"
#include "scene.hpp"
#include "components/transform.hpp"
#include <glm/trigonometric.hpp> #include <glm/trigonometric.hpp>
#include <glm/gtc/constants.hpp> #include <glm/gtc/constants.hpp>
@ -12,91 +14,99 @@
#include <log.hpp> #include <log.hpp>
CameraController::CameraController(engine::Object* parent) : CameraControllerSystem::CameraControllerSystem(engine::Scene* scene)
CustomComponent(parent) : System(scene, { typeid(engine::TransformComponent).hash_code(), typeid(CameraControllerComponent).hash_code() })
{ {
standingHeight = parent->transform.position.y;
m_yaw = glm::half_pi<float>();
} }
void CameraController::onUpdate(glm::mat4 t) void CameraControllerSystem::onUpdate(float ts)
{ {
engine::TransformComponent* t = nullptr;
CameraControllerComponent* c = nullptr;
for (uint32_t entity : m_entities) {
t = m_scene->getComponent<engine::TransformComponent>(entity);
c = m_scene->getComponent<CameraControllerComponent>(entity);
break;
}
if (t == nullptr) return;
if (c == nullptr) return;
// calculate new position // calculate new position
// use one unit per meter // use one unit per meter
const float dt = win.dt(); const float dt = ts;
// jumping // jumping
constexpr float G = 9.8f; constexpr float G = 9.8f;
constexpr float JUMPHEIGHT = 16.0f * 25.4f / 1000.0f; // 16 inches // constexpr float JUMPHEIGHT = 16.0f * 25.4f / 1000.0f; // 16 inches
constexpr float JUMPVEL = (float)2.82231110971133017648; //std::sqrt(2 * G * JUMPHEIGHT); constexpr float JUMPVEL = (float)2.82231110971133017648; //std::sqrt(2 * G * JUMPHEIGHT);
//constexpr float JUMPDURATION = 0.5f; //constexpr float JUMPDURATION = 0.5f;
//constexpr float JUMPVEL = G * JUMPDURATION / 2.0f; //constexpr float JUMPVEL = G * JUMPDURATION / 2.0f;
if (inp.getButton("jump") && isJumping == false) { if (m_scene->app()->inputManager()->getButton("jump") && c->isJumping == false) {
isJumping = true; c->isJumping = true;
dy = JUMPVEL; c->dy = JUMPVEL;
//standingHeight = tcomp->position.y; //standingHeight = tcomp->position.y;
} }
if (isJumping) { if (c->isJumping) {
dy -= G * dt; c->dy -= G * dt;
parent.transform.position.y += dy * dt; t->position.y += c->dy * dt;
if (parent.transform.position.y < standingHeight) { if (t->position.y < c->standingHeight) {
isJumping = false; c->isJumping = false;
dy = 0.0f; c->dy = 0.0f;
parent.transform.position.y = standingHeight; t->position.y = c->standingHeight;
} }
} }
if (win.getButton(engine::inputs::MouseButton::M_LEFT)) { if (m_scene->app()->window()->getButton(engine::inputs::MouseButton::M_LEFT)) {
//standingHeight = tcomp->position.y; //standingHeight = tcomp->position.y;
dy += dt * thrust; c->dy += dt * c->thrust;
isJumping = true; c->isJumping = true;
} }
// in metres per second // in metres per second
//constexpr float SPEED = 1.5f; //constexpr float SPEED = 1.5f;
float SPEED = walk_speed; float SPEED = c->walk_speed;
if (win.getKey(engine::inputs::Key::LSHIFT)) SPEED *= 10.0f; if (m_scene->app()->inputManager()->getButton("sprint")) SPEED *= 10.0f;
const float dx = inp.getAxis("movex") * SPEED; const float dx = m_scene->app()->inputManager()->getAxis("movex") * SPEED;
const float dz = (-inp.getAxis("movey")) * SPEED; const float dz = (-m_scene->app()->inputManager()->getAxis("movey")) * SPEED;
// calculate new pitch and yaw // calculate new pitch and yaw
constexpr float MAX_PITCH = glm::half_pi<float>(); constexpr float MAX_PITCH = glm::half_pi<float>();
constexpr float MIN_PITCH = -MAX_PITCH; constexpr float MIN_PITCH = -MAX_PITCH;
float dPitch = inp.getAxis("looky") * -1.0f * m_cameraSensitivity; float dPitch = m_scene->app()->inputManager()->getAxis("looky") * -1.0f * c->m_cameraSensitivity;
m_pitch += dPitch; c->m_pitch += dPitch;
if (m_pitch <= MIN_PITCH || m_pitch >= MAX_PITCH) { if (c->m_pitch <= MIN_PITCH || c->m_pitch >= MAX_PITCH) {
m_pitch -= dPitch; c->m_pitch -= dPitch;
} }
m_yaw += inp.getAxis("lookx") * -1.0f * m_cameraSensitivity; c->m_yaw += m_scene->app()->inputManager()->getAxis("lookx") * -1.0f * c->m_cameraSensitivity;
// update position relative to camera direction in xz plane // update position relative to camera direction in xz plane
const glm::vec3 d2xRotated = glm::rotateY(glm::vec3{ dx, 0.0f, 0.0f }, m_yaw); const glm::vec3 d2xRotated = glm::rotateY(glm::vec3{ dx, 0.0f, 0.0f }, c->m_yaw);
const glm::vec3 d2zRotated = glm::rotateY(glm::vec3{ 0.0f, 0.0f, dz }, m_yaw); const glm::vec3 d2zRotated = glm::rotateY(glm::vec3{ 0.0f, 0.0f, dz }, c->m_yaw);
parent.transform.position += (d2xRotated + d2zRotated) * dt; t->position += (d2xRotated + d2zRotated) * dt;
parent.transform.position.y += dy * dt; t->position.y += c->dy * dt;
constexpr float MAX_DISTANCE_FROM_ORIGIN = 1000.0f; constexpr float MAX_DISTANCE_FROM_ORIGIN = 1000.0f;
if (glm::length(parent.transform.position) > MAX_DISTANCE_FROM_ORIGIN) { if (glm::length(t->position) > MAX_DISTANCE_FROM_ORIGIN) {
parent.transform.position = { 0.0f, standingHeight, 0.0f }; t->position = { 0.0f, c->standingHeight, 0.0f };
dy = 0.0f; c->dy = 0.0f;
isJumping = false; c->isJumping = false;
} }
/* ROTATION STUFF */ /* ROTATION STUFF */
// pitch quaternion // pitch quaternion
const float halfPitch = m_pitch / 2.0f; const float halfPitch = c->m_pitch / 2.0f;
glm::quat pitchQuat{}; glm::quat pitchQuat{};
pitchQuat.x = glm::sin(halfPitch); pitchQuat.x = glm::sin(halfPitch);
pitchQuat.y = 0.0f; pitchQuat.y = 0.0f;
@ -104,7 +114,7 @@ void CameraController::onUpdate(glm::mat4 t)
pitchQuat.w = glm::cos(halfPitch); pitchQuat.w = glm::cos(halfPitch);
// yaw quaternion // yaw quaternion
const float halfYaw = m_yaw / 2.0f; const float halfYaw = c->m_yaw / 2.0f;
glm::quat yawQuat{}; glm::quat yawQuat{};
yawQuat.x = 0.0f; yawQuat.x = 0.0f;
yawQuat.y = glm::sin(halfYaw); yawQuat.y = glm::sin(halfYaw);
@ -112,18 +122,24 @@ void CameraController::onUpdate(glm::mat4 t)
yawQuat.w = glm::cos(halfYaw); yawQuat.w = glm::cos(halfYaw);
// update rotation // update rotation
parent.transform.rotation = yawQuat * pitchQuat; t->rotation = yawQuat * pitchQuat;
if (win.getKeyPress(engine::inputs::Key::P)) {
/* user interface inputs */
if (m_scene->app()->window()->getKeyPress(engine::inputs::Key::K_P)) {
std::string pos_string{ std::string pos_string{
"x: " + std::to_string(parent.transform.position.x) + "x: " + std::to_string(t->position.x) +
" y: " + std::to_string(parent.transform.position.y) + " y: " + std::to_string(t->position.y) +
" z: " + std::to_string(parent.transform.position.z) " z: " + std::to_string(t->position.z)
}; };
#ifdef NDEBUG m_scene->app()->window()->infoBox("POSITION", pos_string);
win.infoBox("POSITION", pos_string);
#endif
INFO("position: " + pos_string); INFO("position: " + pos_string);
} }
if (m_scene->app()->inputManager()->getButtonPress("fullscreen")) {
m_scene->app()->window()->toggleFullscreen();
}
} }

View File

@ -1,16 +1,10 @@
#pragma once #pragma once
#include "components/custom.hpp" #include "ecs_system.hpp"
class CameraController : public engine::components::CustomComponent {
public:
CameraController(engine::Object* parent);
void onUpdate(glm::mat4 t) override;
struct CameraControllerComponent {
float m_cameraSensitivity = 0.007f; float m_cameraSensitivity = 0.007f;
private:
float m_yaw = 0.0f; float m_yaw = 0.0f;
float m_pitch = 0.0f; float m_pitch = 0.0f;
@ -20,5 +14,12 @@ private:
float dy = 0.0f; float dy = 0.0f;
float standingHeight = 0.0f; float standingHeight = 0.0f;
const float thrust = 25.0f; const float thrust = 25.0f;
};
class CameraControllerSystem : public engine::System {
public:
CameraControllerSystem(engine::Scene* scene);
void onUpdate(float ts) override;
}; };

View File

@ -1,7 +1,10 @@
#include "config.h" #include "config.h"
#include "camera_controller.hpp"
#include "application.hpp" #include "application.hpp"
#include "window.hpp" #include "window.hpp"
#include "input_manager.hpp"
#include "scene_manager.hpp" #include "scene_manager.hpp"
#include "scene.hpp" #include "scene.hpp"
@ -9,27 +12,88 @@
#include "components/renderable.hpp" #include "components/renderable.hpp"
#include "systems/transform.hpp" #include "systems/transform.hpp"
#include "systems/render.hpp"
#include "resources/mesh.hpp" #include "resources/mesh.hpp"
#include "resources/material.hpp" #include "resources/material.hpp"
#include "resources/shader.hpp" #include "resources/shader.hpp"
#include "resources/texture.hpp" #include "resources/texture.hpp"
#include "util/model_loader.hpp"
struct RotateComponent {
float rotation = 0.0f;
};
class RotateSystem : public engine::System {
public:
RotateSystem(engine::Scene* scene)
: System(scene, { typeid(engine::TransformComponent).hash_code(), typeid(RotateComponent).hash_code() })
{
}
void onUpdate(float ts) override
{
for (uint32_t entity : m_entities) {
auto t = m_scene->getComponent<engine::TransformComponent>(entity);
auto r = m_scene->getComponent<RotateComponent>(entity);
r->rotation += ts;
r->rotation = glm::mod(r->rotation, glm::two_pi<float>());
t->rotation = glm::angleAxis(r->rotation, glm::vec3{0.0f, 0.0f, 1.0f});
}
}
};
void playGame() void playGame()
{ {
engine::Application app(PROJECT_NAME, PROJECT_VERSION); engine::Application app(PROJECT_NAME, PROJECT_VERSION);
app.setFrameLimiter(false);
// configure window // configure window
app.window()->setRelativeMouseMode(true); app.window()->setRelativeMouseMode(true);
// input config
// user interface mappings
app.inputManager()->addInputButton("fullscreen", engine::inputs::Key::K_F11);
// game buttons
app.inputManager()->addInputButton("fire", engine::inputs::MouseButton::M_LEFT);
app.inputManager()->addInputButton("aim", engine::inputs::MouseButton::M_RIGHT);
app.inputManager()->addInputButton("jump", engine::inputs::Key::K_SPACE);
app.inputManager()->addInputButton("sprint", engine::inputs::Key::K_LSHIFT);
// game movement
app.inputManager()->addInputButtonAsAxis("movex", engine::inputs::Key::K_D, engine::inputs::Key::K_A);
app.inputManager()->addInputButtonAsAxis("movey", engine::inputs::Key::K_W, engine::inputs::Key::K_S);
// looking around
app.inputManager()->addInputAxis("lookx", engine::inputs::MouseAxis::X);
app.inputManager()->addInputAxis("looky", engine::inputs::MouseAxis::Y);
auto myScene = app.sceneManager()->createEmptyScene(); auto myScene = app.sceneManager()->createEmptyScene();
std::shared_ptr<engine::resources::Material> myMaterial; myScene->registerComponent<RotateComponent>();
{ myScene->registerComponent<CameraControllerComponent>();
myScene->registerSystem<RotateSystem>();
myScene->registerSystem<CameraControllerSystem>();
myScene->registerResourceManager<engine::resources::Shader>();
myScene->registerResourceManager<engine::resources::Texture>();
auto camera = myScene->createEntity("camera");
myScene->addComponent<CameraControllerComponent>(camera);
myScene->getSystem<engine::RenderSystem>()->setCameraEntity(camera);
engine::resources::Shader::VertexParams vertParams{}; engine::resources::Shader::VertexParams vertParams{};
vertParams.hasNormal = true; vertParams.hasNormal = true;
vertParams.hasUV0 = true; vertParams.hasUV0 = true;
auto myShader = std::make_unique<engine::resources::Shader>( auto theShader = std::make_unique<engine::resources::Shader>(
app.gfx(), app.gfx(),
app.getResourcePath("engine/shaders/texture.vert").c_str(), app.getResourcePath("engine/shaders/texture.vert").c_str(),
app.getResourcePath("engine/shaders/texture.frag").c_str(), app.getResourcePath("engine/shaders/texture.frag").c_str(),
@ -37,41 +101,16 @@ void playGame()
false, false,
true true
); );
myMaterial = std::make_shared<engine::resources::Material>(std::move(myShader)); auto whiteTexture = std::make_unique<engine::resources::Texture>(
myMaterial->m_texture = std::make_shared<engine::resources::Texture>(
app.gfx(), app.gfx(),
app.getResourcePath("engine/textures/white.png") app.getResourcePath("engine/textures/white.png")
); );
} auto keepTexture = myScene->addResource<engine::resources::Texture>("whiteTexture", std::move(whiteTexture));
auto keepShader = myScene->addResource<engine::resources::Shader>("theShader", std::move(theShader));
auto myMesh = std::make_shared<engine::resources::Mesh>( engine::util::loadMeshFromFile(myScene, app.getResourcePath("models/lego/lego.dae"));
app.gfx(),
std::vector<engine::Vertex>{
{ { 0.5f, 0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } },
{ { -0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } },
{ { 0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } },
}
);
constexpr int N = 100;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
auto entity = myScene->createEntity(std::to_string(i * 10 + j));
auto t = myScene->getComponent<engine::TransformComponent>(entity);
float x = ((float)(i) * 10.0f / (float)(N) ) - 5.0f;
float y = ((float)(j) * 10.0f / (float)(N) ) - 5.0f;
t->position = {x, y, -35.0f};
t->scale /= (float)(N) / 4.0f;
auto r = myScene->addComponent<engine::RenderableComponent>(entity);
r->material = myMaterial;
r->mesh = myMesh;
}
}
app.gameLoop(); app.gameLoop();
INFO("texture addr: {}, shader addr: {}", (void*)keepTexture->getHandle(), (void*)keepShader->getPipeline());
} }

View File

@ -7,7 +7,7 @@
#include <exception> #include <exception>
int main(int argc, char *argv[]) int main(int, char *[])
{ {
engine::setupLog(PROJECT_NAME); engine::setupLog(PROJECT_NAME);