mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Re-add model loading and clean up code
This commit is contained in:
parent
eac852eb93
commit
b2831e2b5d
@ -12,6 +12,7 @@ set(SRC_FILES
|
||||
"src/ecs_system.cpp"
|
||||
"src/application.cpp"
|
||||
|
||||
"src/systems/transform.cpp"
|
||||
"src/systems/render.cpp"
|
||||
|
||||
"src/resources/material.cpp"
|
||||
@ -21,6 +22,7 @@ set(SRC_FILES
|
||||
"src/gfx_device_vulkan.cpp"
|
||||
|
||||
"src/util/files.cpp"
|
||||
"src/util/model_loader.cpp"
|
||||
|
||||
"src/scene_manager.cpp"
|
||||
"src/input_manager.cpp"
|
||||
@ -46,6 +48,7 @@ set(INCLUDE_FILES
|
||||
"include/engine_api.h"
|
||||
|
||||
"include/util/files.hpp"
|
||||
"include/util/model_loader.hpp"
|
||||
|
||||
"include/util.hpp"
|
||||
"include/logger.hpp"
|
||||
@ -81,8 +84,9 @@ set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
if (MSVC)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /W3)
|
||||
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()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC include)
|
||||
@ -125,7 +129,7 @@ if(ENGINE_BUILD_OPENGL)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(dependencies/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()
|
||||
|
||||
if(ENGINE_BUILD_VULKAN)
|
||||
@ -137,7 +141,7 @@ if(ENGINE_BUILD_VULKAN)
|
||||
add_subdirectory(dependencies/volk)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE volk_headers)
|
||||
# Vulkan Memory Allocator
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE dependencies/VulkanMemoryAllocator/include)
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE dependencies/VulkanMemoryAllocator/include)
|
||||
# shaderc
|
||||
if (MSVC)
|
||||
include(FindVulkan)
|
||||
@ -151,7 +155,7 @@ endif()
|
||||
# SDL2:
|
||||
find_package(SDL2)
|
||||
if (SDL2_FOUND)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${SDL2_INCLUDE_DIRS})
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS})
|
||||
else()
|
||||
set(SDL2_DISABLE_INSTALL ON CACHE INTERNAL "" FORCE)
|
||||
set(SDL_SHARED ON CACHE INTERNAL "" FORCE)
|
||||
@ -159,7 +163,7 @@ else()
|
||||
set(SDL_TEST OFF CACHE INTERNAL "" FORCE)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
add_subdirectory(dependencies/SDL)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/SDL/include)
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/SDL/include)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2main)
|
||||
@ -167,14 +171,14 @@ target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2main)
|
||||
# GLM:
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(dependencies/glm)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glm)
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/glm)
|
||||
|
||||
# spdlog
|
||||
set(SPDLOG_BUILD_SHARED OFF CACHE INTERNAL "" FORCE)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(dependencies/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
|
||||
#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)
|
||||
|
||||
# stb
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE dependencies/stb)
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE dependencies/stb)
|
||||
|
||||
# assimp
|
||||
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_INSTALL OFF CACHE INTERNAL "" FORCE)
|
||||
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)
|
||||
|
@ -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);
|
||||
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);
|
||||
void destroyBuffer(const gfx::Buffer* buffer);
|
||||
|
@ -7,15 +7,15 @@
|
||||
|
||||
namespace engine {
|
||||
|
||||
class IResourceManager {
|
||||
public:
|
||||
virtual ~IResourceManager() = default;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ResourceManager {
|
||||
class ResourceManager : public IResourceManager {
|
||||
|
||||
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)
|
||||
{
|
||||
if (m_resources.contains(name) == false) {
|
||||
@ -34,8 +34,12 @@ namespace engine {
|
||||
std::weak_ptr<T> ptr = m_resources.at(name);
|
||||
if (ptr.expired() == false) {
|
||||
return ptr.lock();
|
||||
} else {
|
||||
m_resources.erase(name);
|
||||
}
|
||||
}
|
||||
// resource doesn't exist:
|
||||
throw std::runtime_error("Resource doesn't exist: " + name);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -29,11 +29,18 @@ public:
|
||||
m_vb = m_gfx->createBuffer(gfx::BufferType::VERTEX, vertices.size() * sizeof(Vertex), vertices.data());
|
||||
|
||||
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;
|
||||
}
|
||||
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()
|
||||
{
|
||||
m_gfx->destroyBuffer(m_ib);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "log.hpp"
|
||||
|
||||
#include "resource_manager.hpp"
|
||||
#include "ecs_system.hpp"
|
||||
|
||||
#include <map>
|
||||
@ -23,6 +24,34 @@ namespace engine {
|
||||
|
||||
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 getEntity(const std::string& tag, uint32_t parent = 0);
|
||||
@ -97,12 +126,30 @@ namespace engine {
|
||||
return castedPtr;
|
||||
}
|
||||
|
||||
Application* app() { return m_app; }
|
||||
|
||||
private:
|
||||
Application* const m_app;
|
||||
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;
|
||||
// maps component hashes to signature positions
|
||||
std::map<size_t, size_t> m_componentSignaturePositions{};
|
||||
|
@ -12,13 +12,23 @@ namespace engine {
|
||||
class RenderSystem : public System {
|
||||
|
||||
public:
|
||||
RenderSystem(Scene* scene)
|
||||
: System(scene, { typeid(TransformComponent).hash_code(), typeid(RenderableComponent).hash_code() })
|
||||
{
|
||||
}
|
||||
RenderSystem(Scene* scene);
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,65 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#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 {
|
||||
|
||||
class TransformSystem : public System {
|
||||
|
||||
public:
|
||||
TransformSystem(Scene* scene)
|
||||
: System(scene, { typeid(TransformComponent).hash_code() })
|
||||
{
|
||||
}
|
||||
TransformSystem(Scene* scene);
|
||||
|
||||
void onUpdate(float ts) override
|
||||
{
|
||||
for (uint32_t entity : m_entities) {
|
||||
void onUpdate(float ts) override;
|
||||
|
||||
auto t = m_scene->getComponent<TransformComponent>(entity);
|
||||
|
||||
// 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;
|
||||
}
|
||||
uint32_t getChildEntity(uint32_t parent, const std::string& tag);
|
||||
|
||||
};
|
||||
|
||||
|
13
include/util/model_loader.hpp
Normal file
13
include/util/model_loader.hpp
Normal 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);
|
||||
|
||||
}
|
@ -114,7 +114,7 @@ namespace engine {
|
||||
|
||||
// returns the number of frames elapsed since window creation
|
||||
uint64_t getFrameCount() const;
|
||||
uint64_t getStartTime() const;;
|
||||
uint64_t getStartTime() const;
|
||||
float dt() const; // returns delta time in seconds
|
||||
uint64_t getFPS() const;
|
||||
uint64_t getAvgFPS() const;
|
||||
|
@ -73,6 +73,8 @@ namespace engine {
|
||||
auto beginFrame = std::chrono::steady_clock::now();
|
||||
auto endFrame = beginFrame + FRAMETIME_LIMIT;
|
||||
|
||||
auto lastTick = m_window->getNanos();
|
||||
|
||||
// single-threaded game loop
|
||||
while (m_window->isRunning()) {
|
||||
|
||||
@ -91,6 +93,12 @@ namespace engine {
|
||||
m_window->getInputAndEvents();
|
||||
|
||||
/* 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) {
|
||||
std::this_thread::sleep_until(endFrame);
|
||||
}
|
||||
|
@ -155,8 +155,9 @@ namespace engine {
|
||||
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
case gfx::BufferType::INDEX:
|
||||
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)
|
||||
@ -222,7 +223,7 @@ namespace engine {
|
||||
|
||||
static std::vector<const char*> getRequiredVulkanExtensions(SDL_Window* window)
|
||||
{
|
||||
SDL_bool res;
|
||||
[[maybe_unused]] SDL_bool res;
|
||||
|
||||
unsigned int sdlExtensionCount = 0;
|
||||
res = SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, nullptr);
|
||||
@ -239,7 +240,7 @@ namespace engine {
|
||||
constexpr const char* VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation";
|
||||
|
||||
LayerInfo info;
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
|
||||
uint32_t layerCount;
|
||||
res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||
@ -269,6 +270,7 @@ namespace engine {
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData)
|
||||
{
|
||||
(void)pUserData;
|
||||
|
||||
std::string msgType{};
|
||||
|
||||
@ -357,7 +359,7 @@ namespace engine {
|
||||
{
|
||||
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 (queues[i].supportsGraphics == false) continue;
|
||||
@ -382,7 +384,7 @@ namespace engine {
|
||||
{
|
||||
Swapchain::MSTarget target{};
|
||||
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
@ -408,7 +410,8 @@ namespace engine {
|
||||
res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &target.colorImage, &target.colorImageAllocation, nullptr);
|
||||
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.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
imageViewInfo.format = colorFormat;
|
||||
@ -433,7 +436,7 @@ namespace engine {
|
||||
{
|
||||
DepthBuffer db{};
|
||||
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
@ -459,7 +462,8 @@ namespace engine {
|
||||
res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &db.image, &db.allocation, nullptr);
|
||||
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.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
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.
|
||||
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
|
||||
VkSurfaceCapabilitiesKHR caps;
|
||||
@ -723,7 +727,7 @@ namespace engine {
|
||||
|
||||
swapchain->imageViews.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{};
|
||||
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)
|
||||
{
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
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.commandPool = commandPool;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
@ -841,7 +846,8 @@ namespace engine {
|
||||
res = vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
|
||||
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;
|
||||
|
||||
res = vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||
@ -852,11 +858,12 @@ namespace engine {
|
||||
|
||||
static void endOneTimeCommands(VkDevice device, VkCommandPool commandPool, VkCommandBuffer commandBuffer, VkQueue queue)
|
||||
{
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
res = vkEndCommandBuffer(commandBuffer);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
VkSubmitInfo submitInfo{ VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
|
||||
@ -871,7 +878,8 @@ namespace engine {
|
||||
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.newLayout = newLayout;
|
||||
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)
|
||||
{
|
||||
|
||||
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.image = image;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
@ -1052,9 +1061,9 @@ namespace engine {
|
||||
|
||||
// get the both the engine and application versions
|
||||
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;
|
||||
assert(versionFromCharArray(ENGINE_VERSION, &engineVersionMajor, &engineVersionMinor, &engineVersionPatch));
|
||||
versionFromCharArray(ENGINE_VERSION, &engineVersionMajor, &engineVersionMinor, &engineVersionPatch);
|
||||
|
||||
VkApplicationInfo applicationInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
@ -1134,7 +1143,8 @@ namespace engine {
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1311,8 +1321,8 @@ namespace engine {
|
||||
.flags = 0,
|
||||
.queueCreateInfoCount = (uint32_t)queueCreateInfos.size(),
|
||||
.pQueueCreateInfos = queueCreateInfos.data(),
|
||||
// IGNORED: .enabledLayerCount
|
||||
// IGNORED: .ppEnabledLayerNames
|
||||
.enabledLayerCount = 0,
|
||||
.ppEnabledLayerNames = nullptr,
|
||||
.enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(),
|
||||
.ppEnabledExtensionNames = requiredDeviceExtensions.data(),
|
||||
.pEnabledFeatures = &deviceFeatures,
|
||||
@ -1335,8 +1345,9 @@ namespace engine {
|
||||
|
||||
VkCommandPoolCreateInfo gfxCmdPoolInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.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);
|
||||
@ -1344,12 +1355,13 @@ namespace engine {
|
||||
|
||||
VkCommandBufferAllocateInfo gfxCmdBufInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.commandPool = pimpl->commandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.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]);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
@ -1402,14 +1414,15 @@ namespace engine {
|
||||
.pTypeExternalMemoryHandleTypes = nullptr
|
||||
};
|
||||
|
||||
VkResult res = vmaCreateAllocator(&createInfo, &pimpl->allocator);
|
||||
[[maybe_unused]] VkResult res;
|
||||
res = vmaCreateAllocator(&createInfo, &pimpl->allocator);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
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]);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
@ -1429,7 +1442,8 @@ namespace engine {
|
||||
pimpl->uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
|
||||
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.pBindings = &pimpl->uboLayoutBinding;
|
||||
res = vkCreateDescriptorSetLayout(pimpl->device, &descriptorSetLayoutInfo, nullptr, &pimpl->descriptorSetLayout);
|
||||
@ -1442,7 +1456,8 @@ namespace engine {
|
||||
pimpl->samplerLayoutBinding.pImmutableSamplers = nullptr;
|
||||
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.pBindings = &pimpl->samplerLayoutBinding;
|
||||
res = vkCreateDescriptorSetLayout(pimpl->device, &samplerSetLayoutInfo, nullptr, &pimpl->samplerSetLayout);
|
||||
@ -1456,7 +1471,7 @@ namespace engine {
|
||||
vkDestroyDescriptorSetLayout(pimpl->device, pimpl->samplerSetLayout, 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);
|
||||
vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphores[i], nullptr);
|
||||
vkDestroySemaphore(pimpl->device, pimpl->swapchain.acquireSemaphores[i], nullptr);
|
||||
@ -1509,6 +1524,7 @@ namespace engine {
|
||||
.vertexBuffer = vertexBuffer,
|
||||
.indexBuffer = indexBuffer, // will be ignored if nullptr
|
||||
.count = count,
|
||||
.pushConstantData{}
|
||||
};
|
||||
|
||||
memcpy(call.pushConstantData, pushConstantData, pushConstantSize);
|
||||
@ -1535,7 +1551,7 @@ namespace engine {
|
||||
if (res == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
// recreate swapchain
|
||||
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;
|
||||
}
|
||||
else {
|
||||
@ -1547,13 +1563,15 @@ namespace engine {
|
||||
|
||||
// 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.pInheritanceInfo = nullptr;
|
||||
res = vkBeginCommandBuffer(pimpl->commandBuffers[frameIndex], &beginInfo);
|
||||
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.framebuffer = pimpl->swapchain.framebuffers[imageIndex];
|
||||
renderPassInfo.renderArea.offset = { 0, 0 };
|
||||
@ -1636,7 +1654,8 @@ namespace engine {
|
||||
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 };
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
@ -1650,7 +1669,8 @@ namespace engine {
|
||||
res = vkQueueSubmit(pimpl->gfxQueue.handle, 1, &submitInfo, pimpl->inFlightFences[frameIndex]);
|
||||
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.pWaitSemaphores = &pimpl->swapchain.releaseSemaphores[frameIndex];
|
||||
|
||||
@ -1664,7 +1684,7 @@ namespace engine {
|
||||
if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
// recreate swapchain
|
||||
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 {
|
||||
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)
|
||||
{
|
||||
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
|
||||
gfx::Pipeline* pipeline = new gfx::Pipeline;
|
||||
|
||||
@ -1689,12 +1709,13 @@ namespace engine {
|
||||
|
||||
// create uniform buffers
|
||||
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{};
|
||||
buf->size = uniformBufferSize;
|
||||
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.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
@ -1734,7 +1755,7 @@ namespace engine {
|
||||
res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, pipeline->descriptorSets.data());
|
||||
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{};
|
||||
bufferInfo.buffer = pipeline->uniformBuffers[i]->buffer;
|
||||
bufferInfo.offset = 0;
|
||||
@ -1771,13 +1792,15 @@ namespace engine {
|
||||
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.module = vertShaderModule;
|
||||
vertShaderStageInfo.pName = "main";
|
||||
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.module = fragShaderModule;
|
||||
fragShaderStageInfo.pName = "main";
|
||||
@ -1949,21 +1972,21 @@ namespace engine {
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
|
||||
for (gfx::Buffer* buffer : pipeline->uniformBuffers) {
|
||||
void* uniformDest;
|
||||
void* uniformDest = nullptr;
|
||||
res = vmaMapMemory(pimpl->allocator, buffer->allocation, &uniformDest);
|
||||
assert(res == VK_SUCCESS);
|
||||
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)
|
||||
{
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
|
||||
auto out = new gfx::Buffer{};
|
||||
out->size = size;
|
||||
@ -1986,7 +2009,8 @@ namespace engine {
|
||||
|
||||
// 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.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
@ -2009,7 +2033,8 @@ namespace engine {
|
||||
|
||||
// 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.usage = vkinternal::getBufferUsageFlag(type) | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
gpuBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
@ -2042,7 +2067,7 @@ namespace engine {
|
||||
{
|
||||
auto out = new gfx::Texture;
|
||||
|
||||
VkResult res;
|
||||
[[maybe_unused]] VkResult res;
|
||||
|
||||
size_t imageSize = w * h * 4;
|
||||
|
||||
@ -2052,7 +2077,8 @@ namespace engine {
|
||||
VkBuffer stagingBuffer;
|
||||
VmaAllocation stagingAllocation;
|
||||
{
|
||||
VkBufferCreateInfo stagingBufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
VkBufferCreateInfo stagingBufferInfo{};
|
||||
stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
stagingBufferInfo.size = imageSize;
|
||||
stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
@ -2074,7 +2100,8 @@ namespace engine {
|
||||
}
|
||||
|
||||
// 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.extent.width = w;
|
||||
imageInfo.extent.height = h;
|
||||
@ -2097,7 +2124,7 @@ namespace engine {
|
||||
|
||||
// transition the image layout
|
||||
{
|
||||
VkCommandBuffer commandBuffer = beginOneTimeCommands(pimpl->device, pimpl->commandPool, pimpl->gfxQueue.handle);
|
||||
VkCommandBuffer commandBuffer = beginOneTimeCommands(pimpl->device, pimpl->commandPool);
|
||||
|
||||
// begin cmd buffer
|
||||
|
||||
@ -2130,7 +2157,8 @@ namespace engine {
|
||||
vmaDestroyBuffer(pimpl->allocator, stagingBuffer, stagingAllocation);
|
||||
|
||||
// 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.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
imageViewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
@ -2151,7 +2179,8 @@ namespace engine {
|
||||
VkFilter magFilterInternal = vkinternal::getTextureFilter(magFilter);
|
||||
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.minFilter = minFilterInternal;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
@ -2201,7 +2230,7 @@ namespace engine {
|
||||
res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, out->descriptorSets.data());
|
||||
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{};
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageInfo.imageView = out->imageView;
|
||||
|
@ -25,7 +25,7 @@ namespace engine {
|
||||
void SceneManager::updateActiveScene(float ts)
|
||||
{
|
||||
if (m_activeSceneIndex >= 0) {
|
||||
assert(m_activeSceneIndex < m_scenes.size());
|
||||
assert((size_t)m_activeSceneIndex < m_scenes.size());
|
||||
m_scenes[m_activeSceneIndex]->update(ts);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "systems/render.hpp"
|
||||
|
||||
#include "application.hpp"
|
||||
#include "window.hpp"
|
||||
#include "gfx_device.hpp"
|
||||
|
||||
#include "resources/material.hpp"
|
||||
@ -13,27 +14,43 @@
|
||||
|
||||
namespace engine {
|
||||
|
||||
RenderSystem::RenderSystem(Scene* scene)
|
||||
: System(scene, { typeid(TransformComponent).hash_code(), typeid(RenderableComponent).hash_code() })
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RenderSystem::onUpdate(float ts)
|
||||
{
|
||||
(void)ts;
|
||||
|
||||
GFXDevice* const gfx = m_scene->app()->gfx();
|
||||
|
||||
constexpr float FOV_H = 75.0f;
|
||||
constexpr float CLIP_NEAR = 0.1f;
|
||||
constexpr float CLIP_FAR = 100.0f;
|
||||
/* camera stuff */
|
||||
|
||||
uint32_t w, h;
|
||||
gfx->getViewportSize(&w, &h);
|
||||
float aspect = w / h;
|
||||
float verticalFOV = FOV_H / aspect;
|
||||
glm::mat4 projMatrix = glm::perspectiveZO(verticalFOV, aspect, CLIP_NEAR, CLIP_FAR);
|
||||
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;
|
||||
gfx->getViewportSize(&w, &h);
|
||||
m_viewportAspectRatio = (float)w / (float)h;
|
||||
}
|
||||
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) {
|
||||
|
||||
auto t = m_scene->getComponent<TransformComponent>(entity);
|
||||
auto r = m_scene->getComponent<RenderableComponent>(entity);
|
||||
|
||||
// TRACE("rendering {}", t->tag);
|
||||
|
||||
gfx->updateUniformBuffer(r->material->getShader()->getPipeline(), &projMatrix, sizeof(projMatrix), 0);
|
||||
|
||||
struct {
|
||||
@ -42,7 +59,7 @@ namespace engine {
|
||||
} pushConsts{};
|
||||
|
||||
pushConsts.model = t->worldMatrix;
|
||||
pushConsts.view = glm::mat4{ 1.0f };
|
||||
pushConsts.view = viewMatrix;
|
||||
|
||||
gfx->draw(
|
||||
r->material->getShader()->getPipeline(),
|
||||
@ -53,6 +70,7 @@ namespace engine {
|
||||
sizeof(pushConsts),
|
||||
r->material->m_texture->getHandle()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
56
src/systems/transform.cpp
Normal file
56
src/systems/transform.cpp
Normal 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
235
src/util/model_loader.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -53,17 +53,15 @@ namespace engine {
|
||||
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_HEIGHT = 480;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,8 @@ set(GAME_SOURCES
|
||||
src/main.cpp
|
||||
src/game.cpp
|
||||
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)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /W3)
|
||||
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()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE src)
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include "camera_controller.hpp"
|
||||
|
||||
#include "object.hpp"
|
||||
|
||||
#include "application.hpp"
|
||||
#include "window.hpp"
|
||||
#include "input.hpp"
|
||||
#include "input_manager.hpp"
|
||||
#include "scene.hpp"
|
||||
|
||||
#include "components/transform.hpp"
|
||||
|
||||
#include <glm/trigonometric.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
@ -12,91 +14,99 @@
|
||||
|
||||
#include <log.hpp>
|
||||
|
||||
CameraController::CameraController(engine::Object* parent) :
|
||||
CustomComponent(parent)
|
||||
CameraControllerSystem::CameraControllerSystem(engine::Scene* scene)
|
||||
: 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
|
||||
|
||||
// use one unit per meter
|
||||
|
||||
const float dt = win.dt();
|
||||
const float dt = ts;
|
||||
|
||||
// jumping
|
||||
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 JUMPDURATION = 0.5f;
|
||||
//constexpr float JUMPVEL = G * JUMPDURATION / 2.0f;
|
||||
|
||||
if (inp.getButton("jump") && isJumping == false) {
|
||||
isJumping = true;
|
||||
dy = JUMPVEL;
|
||||
if (m_scene->app()->inputManager()->getButton("jump") && c->isJumping == false) {
|
||||
c->isJumping = true;
|
||||
c->dy = JUMPVEL;
|
||||
//standingHeight = tcomp->position.y;
|
||||
|
||||
}
|
||||
|
||||
if (isJumping) {
|
||||
dy -= G * dt;
|
||||
parent.transform.position.y += dy * dt;
|
||||
if (parent.transform.position.y < standingHeight) {
|
||||
isJumping = false;
|
||||
dy = 0.0f;
|
||||
parent.transform.position.y = standingHeight;
|
||||
if (c->isJumping) {
|
||||
c->dy -= G * dt;
|
||||
t->position.y += c->dy * dt;
|
||||
if (t->position.y < c->standingHeight) {
|
||||
c->isJumping = false;
|
||||
c->dy = 0.0f;
|
||||
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;
|
||||
dy += dt * thrust;
|
||||
isJumping = true;
|
||||
c->dy += dt * c->thrust;
|
||||
c->isJumping = true;
|
||||
}
|
||||
|
||||
// in metres per second
|
||||
//constexpr float SPEED = 1.5f;
|
||||
float SPEED = walk_speed;
|
||||
if (win.getKey(engine::inputs::Key::LSHIFT)) SPEED *= 10.0f;
|
||||
float SPEED = c->walk_speed;
|
||||
if (m_scene->app()->inputManager()->getButton("sprint")) SPEED *= 10.0f;
|
||||
|
||||
const float dx = inp.getAxis("movex") * SPEED;
|
||||
const float dz = (-inp.getAxis("movey")) * SPEED;
|
||||
const float dx = m_scene->app()->inputManager()->getAxis("movex") * SPEED;
|
||||
const float dz = (-m_scene->app()->inputManager()->getAxis("movey")) * SPEED;
|
||||
|
||||
// calculate new pitch and yaw
|
||||
|
||||
constexpr float MAX_PITCH = glm::half_pi<float>();
|
||||
constexpr float MIN_PITCH = -MAX_PITCH;
|
||||
|
||||
float dPitch = inp.getAxis("looky") * -1.0f * m_cameraSensitivity;
|
||||
m_pitch += dPitch;
|
||||
if (m_pitch <= MIN_PITCH || m_pitch >= MAX_PITCH) {
|
||||
m_pitch -= dPitch;
|
||||
float dPitch = m_scene->app()->inputManager()->getAxis("looky") * -1.0f * c->m_cameraSensitivity;
|
||||
c->m_pitch += dPitch;
|
||||
if (c->m_pitch <= MIN_PITCH || c->m_pitch >= MAX_PITCH) {
|
||||
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
|
||||
const glm::vec3 d2xRotated = glm::rotateY(glm::vec3{ dx, 0.0f, 0.0f }, m_yaw);
|
||||
const glm::vec3 d2zRotated = glm::rotateY(glm::vec3{ 0.0f, 0.0f, dz }, m_yaw);
|
||||
parent.transform.position += (d2xRotated + d2zRotated) * dt;
|
||||
parent.transform.position.y += dy * dt;
|
||||
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 }, c->m_yaw);
|
||||
t->position += (d2xRotated + d2zRotated) * dt;
|
||||
t->position.y += c->dy * dt;
|
||||
|
||||
constexpr float MAX_DISTANCE_FROM_ORIGIN = 1000.0f;
|
||||
|
||||
if (glm::length(parent.transform.position) > MAX_DISTANCE_FROM_ORIGIN) {
|
||||
parent.transform.position = { 0.0f, standingHeight, 0.0f };
|
||||
dy = 0.0f;
|
||||
isJumping = false;
|
||||
if (glm::length(t->position) > MAX_DISTANCE_FROM_ORIGIN) {
|
||||
t->position = { 0.0f, c->standingHeight, 0.0f };
|
||||
c->dy = 0.0f;
|
||||
c->isJumping = false;
|
||||
}
|
||||
|
||||
/* ROTATION STUFF */
|
||||
|
||||
// pitch quaternion
|
||||
const float halfPitch = m_pitch / 2.0f;
|
||||
const float halfPitch = c->m_pitch / 2.0f;
|
||||
glm::quat pitchQuat{};
|
||||
pitchQuat.x = glm::sin(halfPitch);
|
||||
pitchQuat.y = 0.0f;
|
||||
@ -104,7 +114,7 @@ void CameraController::onUpdate(glm::mat4 t)
|
||||
pitchQuat.w = glm::cos(halfPitch);
|
||||
|
||||
// yaw quaternion
|
||||
const float halfYaw = m_yaw / 2.0f;
|
||||
const float halfYaw = c->m_yaw / 2.0f;
|
||||
glm::quat yawQuat{};
|
||||
yawQuat.x = 0.0f;
|
||||
yawQuat.y = glm::sin(halfYaw);
|
||||
@ -112,18 +122,24 @@ void CameraController::onUpdate(glm::mat4 t)
|
||||
yawQuat.w = glm::cos(halfYaw);
|
||||
|
||||
// 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{
|
||||
"x: " + std::to_string(parent.transform.position.x) +
|
||||
" y: " + std::to_string(parent.transform.position.y) +
|
||||
" z: " + std::to_string(parent.transform.position.z)
|
||||
"x: " + std::to_string(t->position.x) +
|
||||
" y: " + std::to_string(t->position.y) +
|
||||
" z: " + std::to_string(t->position.z)
|
||||
};
|
||||
#ifdef NDEBUG
|
||||
win.infoBox("POSITION", pos_string);
|
||||
#endif
|
||||
m_scene->app()->window()->infoBox("POSITION", pos_string);
|
||||
INFO("position: " + pos_string);
|
||||
}
|
||||
|
||||
if (m_scene->app()->inputManager()->getButtonPress("fullscreen")) {
|
||||
m_scene->app()->window()->toggleFullscreen();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,16 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "components/custom.hpp"
|
||||
|
||||
class CameraController : public engine::components::CustomComponent {
|
||||
|
||||
public:
|
||||
CameraController(engine::Object* parent);
|
||||
void onUpdate(glm::mat4 t) override;
|
||||
#include "ecs_system.hpp"
|
||||
|
||||
struct CameraControllerComponent {
|
||||
float m_cameraSensitivity = 0.007f;
|
||||
|
||||
private:
|
||||
float m_yaw = 0.0f;
|
||||
float m_pitch = 0.0f;
|
||||
|
||||
@ -20,5 +14,12 @@ private:
|
||||
float dy = 0.0f;
|
||||
float standingHeight = 0.0f;
|
||||
const float thrust = 25.0f;
|
||||
|
||||
};
|
||||
|
||||
class CameraControllerSystem : public engine::System {
|
||||
|
||||
public:
|
||||
CameraControllerSystem(engine::Scene* scene);
|
||||
|
||||
void onUpdate(float ts) override;
|
||||
};
|
||||
|
@ -1,7 +1,10 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "camera_controller.hpp"
|
||||
|
||||
#include "application.hpp"
|
||||
#include "window.hpp"
|
||||
#include "input_manager.hpp"
|
||||
#include "scene_manager.hpp"
|
||||
#include "scene.hpp"
|
||||
|
||||
@ -9,69 +12,105 @@
|
||||
#include "components/renderable.hpp"
|
||||
|
||||
#include "systems/transform.hpp"
|
||||
#include "systems/render.hpp"
|
||||
|
||||
#include "resources/mesh.hpp"
|
||||
#include "resources/material.hpp"
|
||||
#include "resources/shader.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()
|
||||
{
|
||||
engine::Application app(PROJECT_NAME, PROJECT_VERSION);
|
||||
|
||||
app.setFrameLimiter(false);
|
||||
|
||||
// configure window
|
||||
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();
|
||||
|
||||
std::shared_ptr<engine::resources::Material> myMaterial;
|
||||
{
|
||||
engine::resources::Shader::VertexParams vertParams{};
|
||||
vertParams.hasNormal = true;
|
||||
vertParams.hasUV0 = true;
|
||||
auto myShader = std::make_unique<engine::resources::Shader>(
|
||||
app.gfx(),
|
||||
app.getResourcePath("engine/shaders/texture.vert").c_str(),
|
||||
app.getResourcePath("engine/shaders/texture.frag").c_str(),
|
||||
vertParams,
|
||||
false,
|
||||
true
|
||||
);
|
||||
myMaterial = std::make_shared<engine::resources::Material>(std::move(myShader));
|
||||
myMaterial->m_texture = std::make_shared<engine::resources::Texture>(
|
||||
app.gfx(),
|
||||
app.getResourcePath("engine/textures/white.png")
|
||||
);
|
||||
}
|
||||
myScene->registerComponent<RotateComponent>();
|
||||
myScene->registerComponent<CameraControllerComponent>();
|
||||
|
||||
auto myMesh = std::make_shared<engine::resources::Mesh>(
|
||||
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{};
|
||||
vertParams.hasNormal = true;
|
||||
vertParams.hasUV0 = true;
|
||||
auto theShader = std::make_unique<engine::resources::Shader>(
|
||||
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 } },
|
||||
}
|
||||
app.getResourcePath("engine/shaders/texture.vert").c_str(),
|
||||
app.getResourcePath("engine/shaders/texture.frag").c_str(),
|
||||
vertParams,
|
||||
false,
|
||||
true
|
||||
);
|
||||
auto whiteTexture = std::make_unique<engine::resources::Texture>(
|
||||
app.gfx(),
|
||||
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));
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
engine::util::loadMeshFromFile(myScene, app.getResourcePath("models/lego/lego.dae"));
|
||||
|
||||
app.gameLoop();
|
||||
|
||||
INFO("texture addr: {}, shader addr: {}", (void*)keepTexture->getHandle(), (void*)keepShader->getPipeline());
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include <exception>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(int, char *[])
|
||||
{
|
||||
|
||||
engine::setupLog(PROJECT_NAME);
|
||||
|
Loading…
Reference in New Issue
Block a user