Merge pull request #2 from bailwillharr/vulkan

Merge vulkan into master
This commit is contained in:
Bailey Harrison 2022-11-01 16:31:30 +00:00 committed by GitHub
commit 98e49448ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 3433 additions and 1681 deletions

6
.gitmodules vendored
View File

@ -16,3 +16,9 @@
[submodule "dependencies/freetype"] [submodule "dependencies/freetype"]
path = dependencies/freetype path = dependencies/freetype
url = https://gitlab.freedesktop.org/freetype/freetype.git url = https://gitlab.freedesktop.org/freetype/freetype.git
[submodule "dependencies/volk"]
path = dependencies/volk
url = https://github.com/zeux/volk
[submodule "dependencies/VulkanMemoryAllocator"]
path = dependencies/VulkanMemoryAllocator
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.4) cmake_minimum_required(VERSION 3.8)
# options # options
@ -6,8 +6,7 @@ project(engine LANGUAGES CXX
VERSION "0.1.0" VERSION "0.1.0"
) )
add_library(${PROJECT_NAME} SHARED set(SRC_FILES
"src/engine.cpp" "src/engine.cpp"
"src/window.cpp" "src/window.cpp"
"src/input.cpp" #TODO make input_manager "src/input.cpp" #TODO make input_manager
@ -31,13 +30,18 @@ add_library(${PROJECT_NAME} SHARED
"src/resource_manager.cpp" "src/resource_manager.cpp"
"src/gfx_device_vulkan.cpp" "src/gfx_device_vulkan.cpp"
"src/gfx_device_null.cpp"
"src/gfx_device_opengl45.cpp"
)
# PUBLIC API set(INCLUDE_FILES
"include/engine_api.h" "include/engine_api.h"
"include/engine.hpp" "include/engine.hpp"
"include/util.hpp"
"include/log.hpp" "include/log.hpp"
"include/window.hpp" "include/window.hpp"
@ -67,19 +71,32 @@ add_library(${PROJECT_NAME} SHARED
"include/gfx.hpp" "include/gfx.hpp"
"include/gfx_device.hpp" "include/gfx_device.hpp"
)
add_library(${PROJECT_NAME} STATIC
${SRC_FILES}
${INCLUDE_FILES}
) )
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" PREFIX "Source" FILES ${SRC_FILES})
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/include" PREFIX "Include" FILES ${INCLUDE_FILES})
# compiling options: # compiling options:
target_compile_definitions(${PROJECT_NAME} PRIVATE DEFINITIONS "ENGINE_EXPORTS") target_compile_definitions(${PROJECT_NAME} PRIVATE DEFINITIONS "ENGINE_EXPORTS")
set_property(TARGET ${PROJECT_NAME} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) 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)
endif() endif()
target_include_directories(${PROJECT_NAME} PUBLIC include) target_include_directories(${PROJECT_NAME} PUBLIC include)
@ -98,10 +115,31 @@ if (MINGW)
target_link_libraries(${PROJECT_NAME} PUBLIC mingw32) target_link_libraries(${PROJECT_NAME} PUBLIC mingw32)
endif() endif()
# Vulkan # GLAD:
find_package(Vulkan REQUIRED) set(GLAD_PROFILE "core" CACHE INTERNAL "" FORCE)
target_include_directories(${PROJECT_NAME} PRIVATE ${Vulkan_INCLUDE_DIRS}) set(GLAD_API "gl=3.3" CACHE INTERNAL "" FORCE)
target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan) if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(GLAD_GENERATOR "c-debug" CACHE INTERNAL "" FORCE)
else()
set(GLAD_GENERATOR "c" CACHE INTERNAL "" FORCE)
endif()
set(GLAD_SPEC "gl" CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(dependencies/glad)
set_property(TARGET glad PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(${PROJECT_NAME} PUBLIC glad)
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glad/include)
# Volk
set(VOLK_STATIC_DEFINES "")
set(VOLK_PULL_IN_VULKAN ON)
set(VOLK_INSTALL OFF)
set(VOLK_HEADERS_ONLY ON)
add_subdirectory(dependencies/volk)
target_link_libraries(${PROJECT_NAME} PRIVATE volk_headers)
# Vulkan Memory Allocator
target_include_directories(${PROJECT_NAME} PRIVATE dependencies/VulkanMemoryAllocator/include)
# SDL2: # SDL2:
find_package(SDL2) find_package(SDL2)
@ -124,24 +162,9 @@ 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} PUBLIC dependencies/glm)
# GLAD:
set(GLAD_PROFILE "core" CACHE INTERNAL "" FORCE)
set(GLAD_API "gl=3.3" CACHE INTERNAL "" FORCE)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(GLAD_GENERATOR "c-debug" CACHE INTERNAL "" FORCE)
else()
set(GLAD_GENERATOR "c" CACHE INTERNAL "" FORCE)
endif()
set(GLAD_SPEC "gl" CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(dependencies/glad)
set_property(TARGET glad PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(${PROJECT_NAME} PUBLIC glad)
target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glad/include)
# spdlog # spdlog
set(SPDLOG_BUILD_SHARED ON CACHE INTERNAL "" FORCE) set(SPDLOG_BUILD_SHARED OFF CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS ON) 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} PUBLIC dependencies/spdlog/include)

3
TODO
View File

@ -15,3 +15,6 @@ Add support for shadows and other complex lighting. Also add post-processing.
For font rendering, put all ASCII characters in one large texture and use For font rendering, put all ASCII characters in one large texture and use
'instancing' (and uniform buffer objects?) to reduce draw calls. 'instancing' (and uniform buffer objects?) to reduce draw calls.
# VULKAN #
The entire vulkan backend needs redesigning without so many classes

1
dependencies/VulkanMemoryAllocator vendored Submodule

@ -0,0 +1 @@
Subproject commit c351692490513cdb0e5a2c925aaf7ea4a9b672f4

1
dependencies/volk vendored Submodule

@ -0,0 +1 @@
Subproject commit 121a4584f69056d2c6db2eb4104650ce749d4c72

View File

@ -8,10 +8,11 @@
#include <vector> #include <vector>
#include <glm/glm.hpp> #include <glm/vec3.hpp>
#include <glm/ext.hpp> #include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>
namespace components { namespace engine::components {
class ENGINE_API Camera : public Component { class ENGINE_API Camera : public Component {

View File

@ -2,9 +2,11 @@
#include "engine_api.h" #include "engine_api.h"
class Object; namespace engine {
class Window; class Window;
class Input; class Input;
class Object;
class ResourceManager; class ResourceManager;
class ENGINE_API Component { class ENGINE_API Component {
@ -30,8 +32,8 @@ public:
Object& parent; Object& parent;
protected: protected:
Window& win; engine::Window& win;
Input& inp; engine::Input& inp;
ResourceManager& res; ResourceManager& res;
private: private:
@ -41,3 +43,5 @@ private:
TypeEnum m_type; TypeEnum m_type;
}; };
}

View File

@ -6,7 +6,7 @@
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
namespace components { namespace engine::components {
class ENGINE_API CustomComponent : public Component { class ENGINE_API CustomComponent : public Component {

View File

@ -12,7 +12,7 @@
#include <string> #include <string>
#include <memory> #include <memory>
namespace components { namespace engine::components {
class ENGINE_API Renderer : public Component { class ENGINE_API Renderer : public Component {
@ -21,7 +21,7 @@ public:
~Renderer() override; ~Renderer() override;
// called every frame, do not call manually // called every frame, do not call manually
void render(glm::mat4 transform); void render(glm::mat4 model);
void setMesh(const std::string& name); void setMesh(const std::string& name);
void setTexture(const std::string& name); void setTexture(const std::string& name);

View File

@ -6,10 +6,11 @@
#include "resources/font.hpp" #include "resources/font.hpp"
#include "resources/mesh.hpp" #include "resources/mesh.hpp"
#include "resources/shader.hpp"
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
namespace components { namespace engine::components {
class ENGINE_API UI : public Component { class ENGINE_API UI : public Component {

View File

@ -1,19 +1,53 @@
#pragma once #pragma once
#include <filesystem> #include <memory>
#include "log.hpp"
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
namespace engine { namespace engine {
struct AppInfo { class Window;
const char* name; class Input;
const char* version; class ResourceManager;
class SceneRoot;
class Application {
public:
Application(const char* appName, const char* appVersion);
Application(const Application&) = delete;
Application& operator=(const Application&) = delete;
~Application();
void gameLoop();
Window* window()
{
return m_win;
}
Input* input()
{
return m_input;
}
ResourceManager* resources()
{
return m_res;
}
SceneRoot* scene()
{
return m_scene;
}
private:
Window* m_win;
Input* m_input;
ResourceManager* m_res;
SceneRoot* m_scene;
}; };
bool versionFromCharArray(const char* version, int* major, int* minor, int* patch);
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
/*
#ifndef ENGINE_API #ifndef ENGINE_API
# ifdef _MSC_VER # ifdef _MSC_VER
# ifdef ENGINE_EXPORTS # ifdef ENGINE_EXPORTS
@ -11,3 +12,6 @@
# define ENGINE_API # define ENGINE_API
# endif # endif
#endif #endif
*/
#define ENGINE_API

View File

@ -2,29 +2,19 @@
#include <cstdint> #include <cstdint>
#include <cstddef> #include <cstddef>
#include <vector>
namespace gfx { namespace engine::gfx {
enum class ShaderType { enum class ShaderType {
VERTEX, VERTEX,
FRAGMENT, FRAGMENT,
}; };
struct Shader {
ShaderType type;
uint32_t handle;
};
typedef uint32_t Program;
enum class BufferType { enum class BufferType {
VERTEX, VERTEX,
INDEX, INDEX,
}; UNIFORM,
struct Buffer {
BufferType type;
uint32_t handle;
}; };
enum class Primitive { enum class Primitive {
@ -35,10 +25,28 @@ namespace gfx {
TRIANGLE_STRIP, TRIANGLE_STRIP,
}; };
enum class IndexBufferFormat { enum class VertexAttribFormat {
UNSIGNED_8_BITS, VEC2,
UNSIGNED_16_BITS, VEC3,
UNSIGNED_32_BITS,
}; };
struct VertexBufferDesc {
uint64_t size;
};
struct VertexAttribDescription {
uint32_t location;
VertexAttribFormat format;
uint32_t offset;
};
struct VertexFormat {
uint32_t stride;
std::vector<VertexAttribDescription> attributeDescriptions;
};
// handles (incomplete types)
struct Pipeline;
struct Buffer;
} }

View File

@ -2,21 +2,50 @@
#include "engine_api.h" #include "engine_api.h"
#include "engine.hpp" #include "gfx.hpp"
class Window; #include <memory>
namespace engine::gfx { struct SDL_Window;
struct ENGINE_API Device { namespace engine {
Device(AppInfo appInfo, const Window& window); class ENGINE_API GFXDevice {
~Device();
public:
GFXDevice(const char* appName, const char* appVersion, SDL_Window* window);
GFXDevice(const GFXDevice&) = delete;
GFXDevice& operator=(const GFXDevice&) = delete;
~GFXDevice();
void getViewportSize(uint32_t *w, uint32_t *h);
// adds a draw call to the queue
// vertexBuffer is required, indexBuffer can be NULL, uniformData is required
void draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData);
// Call once per frame. Executes all queued draw calls and renders to the screen.
void renderFrame();
// creates the equivalent of an OpenGL shader program & vertex attrib configuration
gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize);
void destroyPipeline(const gfx::Pipeline* pipeline);
void updateUniformBuffer(const gfx::Pipeline* pipeline, void* data);
gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);
void destroyBuffer(const gfx::Buffer* buffer);
// wait until all the active GPU queues have finished working
void waitIdle();
private: private:
class Impl; struct Impl;
std::unique_ptr<Impl> pimpl{}; std::unique_ptr<Impl> pimpl;
}; };
extern GFXDevice* gfxdev;
} }

View File

@ -9,6 +9,8 @@
#include <array> #include <array>
#include <string> #include <string>
namespace engine {
class Window; class Window;
enum class InputDevice : int { enum class InputDevice : int {
@ -87,3 +89,5 @@ private:
void addInputButtonAsAxis(const std::string& name, InputDevice device, int high, int low); void addInputButtonAsAxis(const std::string& name, InputDevice device, int high, int low);
}; };
}

View File

@ -2,7 +2,7 @@
// Keyboard scancodes, taken from SDL_scancode.h // Keyboard scancodes, taken from SDL_scancode.h
namespace inputs { namespace engine::inputs {
enum class Key : int { enum class Key : int {
UNKNOWN = 0, UNKNOWN = 0,

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
namespace inputs { namespace engine::inputs {
enum class MouseButton : int { enum class MouseButton : int {
M_LEFT, M_LEFT,

View File

@ -6,12 +6,15 @@
#include "transform.hpp" #include "transform.hpp"
#include "components/component.hpp"
#include <list> #include <list>
#include <vector> #include <vector>
#include <string> #include <string>
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
namespace engine {
class Window; class Window;
class Input; class Input;
class ResourceManager; class ResourceManager;
@ -20,7 +23,6 @@ class SceneRoot;
class Component; class Component;
namespace components { namespace components {
class Transform;
class Camera; class Camera;
class Renderer; class Renderer;
class UI; class UI;
@ -28,9 +30,9 @@ namespace components {
} }
struct GameIO { struct GameIO {
Window * const win; Window* win;
Input * const input; Input* input;
ResourceManager * const resMan; ResourceManager* resMan;
}; };
// This object lives until it is deleted by its parent(s) or finally when the "Scene" is destroyed. // This object lives until it is deleted by its parent(s) or finally when the "Scene" is destroyed.
@ -47,6 +49,7 @@ public:
Input& inp; Input& inp;
ResourceManager& res; ResourceManager& res;
SceneRoot& root; SceneRoot& root;
std::string getName(); std::string getName();
@ -138,3 +141,5 @@ template<class T> void Object::deleteComponent()
} }
throw std::runtime_error("deleteComponent() error: attempt to delete component that is not present."); throw std::runtime_error("deleteComponent() error: attempt to delete component that is not present.");
} }
}

View File

@ -9,6 +9,8 @@
// Doesn't own resources, only holds weak_ptrs // Doesn't own resources, only holds weak_ptrs
namespace engine {
class ENGINE_API ResourceManager { class ENGINE_API ResourceManager {
public: public:
@ -79,3 +81,5 @@ std::shared_ptr<T> ResourceManager::get(const std::string& name)
return create<T>(name); return create<T>(name);
} }
}

View File

@ -10,7 +10,7 @@
#include <map> #include <map>
namespace resources { namespace engine::resources {
class ENGINE_API Font : public Resource { class ENGINE_API Font : public Resource {

View File

@ -4,9 +4,7 @@
#include "resource.hpp" #include "resource.hpp"
#include "resources/shader.hpp" #include "gfx.hpp"
#include <glad/glad.h>
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include <glm/vec2.hpp> #include <glm/vec2.hpp>
@ -20,34 +18,23 @@ struct Vertex {
glm::vec2 uv; glm::vec2 uv;
}; };
namespace resources { namespace engine::resources {
class ENGINE_API Mesh : public Resource { class ENGINE_API Mesh : public Resource {
public: public:
Mesh(const std::vector<Vertex>& vertices); Mesh(const std::vector<Vertex>& vertices);
Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices); Mesh(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices);
Mesh(const std::filesystem::path& resPath); Mesh(const std::filesystem::path& resPath);
~Mesh() override; ~Mesh() override;
void drawMesh(const Shader& shader);
static void invalidate()
{
s_active_vao = -1;
}
std::vector<Vertex> m_vertices; std::vector<Vertex> m_vertices;
std::vector<unsigned int> m_indices; std::vector<uint32_t> m_indices;
const gfx::Buffer* vb;
const gfx::Buffer* ib;
private: private:
static int s_active_vao;
GLuint m_vao;
GLuint m_vbo;
GLuint m_ebo;
void bindVAO() const;
void initMesh(); void initMesh();

View File

@ -5,6 +5,8 @@
#include <string> #include <string>
#include <filesystem> #include <filesystem>
namespace engine {
class ENGINE_API Resource { class ENGINE_API Resource {
public: public:
@ -22,3 +24,5 @@ private:
const std::string m_type; const std::string m_type;
}; };
}

View File

@ -4,14 +4,16 @@
#include "resource.hpp" #include "resource.hpp"
#include <glad/glad.h>
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
#include <string> #include <string>
#include <map> #include <map>
namespace resources { namespace engine::gfx {
struct Pipeline;
}
namespace engine::resources {
class ENGINE_API Shader : public Resource { class ENGINE_API Shader : public Resource {
@ -19,58 +21,18 @@ public:
Shader(const std::filesystem::path& resPath); Shader(const std::filesystem::path& resPath);
~Shader() override; ~Shader() override;
enum class UniformType { struct UniformBuffer {
FLOAT_MAT4 = GL_FLOAT_MAT4, glm::mat4 v;
FLOAT_VEC2 = GL_FLOAT_VEC2, glm::mat4 p;
FLOAT_VEC3 = GL_FLOAT_VEC3,
SAMPLER_2D = GL_SAMPLER_2D,
NOTFOUND
}; };
void makeActive() const; gfx::Pipeline* getPipeline()
bool setUniform_m4(const std::string& name, const glm::mat4&) const;
bool setUniform_v2(const std::string& name, const glm::vec2&) const;
bool setUniform_v3(const std::string& name, const glm::vec3&) const;
bool setUniform_i(const std::string& name, int) const;
bool setUniform_f(const std::string& name, float) const;
UniformType getUniformType(const std::string& name) const;
int getAttribLocation(const std::string& name) const;
static void invalidate()
{ {
s_activeProgram = -1; return m_pipeline;
} }
private: private:
gfx::Pipeline* m_pipeline = nullptr;
struct Uniform {
GLint size;
UniformType type;
GLuint location;
};
struct Attribute {
GLint size;
UniformType type;
GLuint location;
};
// fields
GLuint m_program;
std::map<std::string, Uniform> m_uniforms{};
std::map<std::string, Attribute> m_attributes{};
// static members
// Only valid if glUseProgram is never called outside this class's method
static GLuint s_activeProgram;
// -1 if not found
int getUniformLocation(const std::string& name) const;
}; };

View File

@ -6,7 +6,7 @@
#include <glad/glad.h> #include <glad/glad.h>
namespace resources { namespace engine::resources {
class ENGINE_API Texture : public Resource { class ENGINE_API Texture : public Resource {

View File

@ -6,13 +6,14 @@
#include <filesystem> #include <filesystem>
namespace engine {
// Holds everything you would expect to find in a game scene // Holds everything you would expect to find in a game scene
class ENGINE_API SceneRoot : public Object { class ENGINE_API SceneRoot : public Object {
public: public:
// create a new empty scene // create a new empty scene
SceneRoot(struct GameIO things); SceneRoot(struct GameIO things);
SceneRoot(const std::filesystem::path& file, struct GameIO things);
SceneRoot(const SceneRoot&) = delete; SceneRoot(const SceneRoot&) = delete;
SceneRoot& operator=(const SceneRoot&) = delete; SceneRoot& operator=(const SceneRoot&) = delete;
@ -27,3 +28,5 @@ private:
std::vector<int> m_activeCameras{}; std::vector<int> m_activeCameras{};
}; };
}

View File

@ -6,6 +6,8 @@
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include <glm/ext/quaternion_float.hpp> #include <glm/ext/quaternion_float.hpp>
namespace engine {
struct ENGINE_API Transform { struct ENGINE_API Transform {
// Scale, rotate (XYZ), translate // Scale, rotate (XYZ), translate
@ -15,3 +17,5 @@ struct ENGINE_API Transform {
glm::vec3 scale{ 1.0f }; glm::vec3 scale{ 1.0f };
}; };
}

18
include/util.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <cstdio>
namespace engine {
inline bool versionFromCharArray(const char* version, int* major, int* minor, int* patch)
{
if (sscanf(version, "%d.%d.%d", major, minor, patch) != 3) {
*major = 0;
*minor = 0;
*patch = 0;
return false;
}
return true;
}
}

View File

@ -17,36 +17,25 @@
ENGINE_API extern const uint64_t BILLION; ENGINE_API extern const uint64_t BILLION;
namespace engine {
class ENGINE_API Window { class ENGINE_API Window {
public: public:
Window(const std::string& title); Window(const std::string& title, bool resizable = true);
Window(const Window&) = delete; Window(const Window&) = delete;
Window& operator=(const Window&) = delete; Window& operator=(const Window&) = delete;
~Window(); ~Window();
SDL_Window* getHandle() const;
// Return the title name // Return the title name
std::string getTitle() const; std::string getTitle() const;
// Make this window the current OpenGL context.
// This is already done in window initialisation.
void makeContextCurrent();
// Tell the GPU to render the back buffer to the screen.
// Run this on every frame.
void swapBuffers();
// Update the window state to capture any events that have occurred. // Update the window state to capture any events that have occurred.
// Run this on every frame. // Run this on every frame.
void getInputAndEvents(); void getInputAndEvents();
// if 'true', swapBuffers() will wait in order to synchronise with the
// monitor's refresh rate.
void setVSync(bool enable);
// Returns true if VSync is enabled.
bool getVSync() const;
glm::ivec2 getViewportSize();
void setTitle(std::string title); void setTitle(std::string title);
// Hides the window (it will appear closed to the user). // Hides the window (it will appear closed to the user).
@ -63,7 +52,7 @@ public:
// Returns true if the window should remain open // Returns true if the window should remain open
bool isRunning() const; bool isRunning() const;
void setFullscreen(bool fullscreen, bool exclusive=true); void setFullscreen(bool fullscreen, bool exclusive = false);
void toggleFullscreen(); void toggleFullscreen();
bool isFullscreen() const; bool isFullscreen() const;
@ -139,27 +128,25 @@ public:
bool infoBox(const std::string& title, const std::string& msg); bool infoBox(const std::string& title, const std::string& msg);
std::vector<const char*> getRequiredVulkanExtensions() const;
/* STATIC METHODS */ /* STATIC METHODS */
static void errorBox(const std::string& message); static void errorBox(const std::string& message);
private: private:
SDL_Window* m_handle; SDL_Window* m_handle;
SDL_GLContext m_glContext;
bool m_shouldClose = false; bool m_shouldClose = false;
std::string m_title; std::string m_title;
bool m_resizable;
bool m_fullscreen = false; bool m_fullscreen = false;
bool m_justResized = false; bool m_justResized = false;
bool m_keyboardFocus = true; bool m_keyboardFocus = true;
// size in screen coordinates // size in screen coordinates
glm::ivec2 m_winSize = glm::vec2(640, 480); glm::ivec2 m_winSize = glm::vec2(640, 480);
// actual framebuffer size
glm::ivec2 m_fbSize;
// performance counter frequency // performance counter frequency
uint64_t m_counterFreq; uint64_t m_counterFreq;
@ -214,5 +201,6 @@ public:
void onMouseButtonEvent(SDL_MouseButtonEvent& e); void onMouseButtonEvent(SDL_MouseButtonEvent& e);
void onMouseMotionEvent(SDL_MouseMotionEvent& e); void onMouseMotionEvent(SDL_MouseMotionEvent& e);
void onMouseWheelEvent(SDL_MouseWheelEvent& e); void onMouseWheelEvent(SDL_MouseWheelEvent& e);
}; };
}

View File

@ -7,24 +7,17 @@
#include "window.hpp" #include "window.hpp"
#include "gfx_device.hpp"
#include "log.hpp" #include "log.hpp"
static const std::string VIEW_MAT_UNIFORM = "viewMat"; namespace engine::components {
static const std::string PROJ_MAT_UNIFORM = "projMat";
static const std::string WINDOW_SIZE_UNIFORM = "windowSize";
namespace components {
glm::vec4 Camera::s_clearColor{-999.0f, -999.0f, -999.0f, -999.0f}; glm::vec4 Camera::s_clearColor{-999.0f, -999.0f, -999.0f, -999.0f};
Camera::Camera(Object* parent) : Component(parent, TypeEnum::CAMERA) Camera::Camera(Object* parent) : Component(parent, TypeEnum::CAMERA)
{ {
parent->root.activateCam(getID()); parent->root.activateCam(getID());
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glEnable(GL_CULL_FACE);
} }
Camera::~Camera() Camera::~Camera()
@ -45,6 +38,14 @@ void Camera::updateCam(glm::mat4 transform)
glm::mat4 viewMatrix = glm::inverse(transform); glm::mat4 viewMatrix = glm::inverse(transform);
struct {
glm::mat4 view;
glm::mat4 proj;
} uniformData{};
uniformData.view = viewMatrix;
uniformData.proj = m_projMatrix;
using namespace resources; using namespace resources;
auto resPtrs = parent.res.getAllResourcesOfType("shader"); auto resPtrs = parent.res.getAllResourcesOfType("shader");
@ -52,26 +53,18 @@ void Camera::updateCam(glm::mat4 transform)
// shader ref count increased by 1, but only in this scope // shader ref count increased by 1, but only in this scope
auto lockedPtr = resPtr.lock(); auto lockedPtr = resPtr.lock();
auto shader = dynamic_cast<Shader*>(lockedPtr.get()); auto shader = dynamic_cast<Shader*>(lockedPtr.get());
shader->setUniform_m4(VIEW_MAT_UNIFORM, viewMatrix); // SET VIEW TRANSFORM HERE
shader->setUniform_m4(PROJ_MAT_UNIFORM, m_projMatrix); gfxdev->updateUniformBuffer(shader->getPipeline(), &uniformData);
shader->setUniform_v2(WINDOW_SIZE_UNIFORM, win.getViewportSize());
shader->setUniform_v3("lightPos", m_lightPos);
} }
if (s_clearColor != clearColor) {
s_clearColor = clearColor;
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
}
glClear((m_noClear ? 0 : GL_COLOR_BUFFER_BIT) | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
} }
static glm::vec2 getViewportSize() static glm::vec2 getViewportSize()
{ {
GLint64 viewportParams[4]; uint32_t width;
glGetInteger64v(GL_VIEWPORT, viewportParams); uint32_t height;
return { viewportParams[2], viewportParams[3] }; gfxdev->getViewportSize(&width, &height);
return {width, height};
} }
void Camera::usePerspective(float fovDeg) void Camera::usePerspective(float fovDeg)
@ -85,7 +78,8 @@ void Camera::usePerspective(float fovDeg)
glm::vec2 viewportDim = getViewportSize(); glm::vec2 viewportDim = getViewportSize();
float fovRad = glm::radians(fovDeg); float fovRad = glm::radians(fovDeg);
m_projMatrix = glm::perspectiveFov(fovRad, viewportDim.x, viewportDim.y, NEAR, FAR); m_projMatrix = glm::perspectiveFovRH_ZO(fovRad, viewportDim.x, viewportDim.y, NEAR, FAR);
m_projMatrix[1][1] *= -1;
} }
void Camera::useOrtho() void Camera::useOrtho()
@ -95,7 +89,8 @@ void Camera::useOrtho()
glm::vec2 viewportDim = getViewportSize(); glm::vec2 viewportDim = getViewportSize();
float aspect = viewportDim.x / viewportDim.y; float aspect = viewportDim.x / viewportDim.y;
m_projMatrix = glm::ortho(-10.0f * aspect, 10.0f * aspect, -10.0f, 10.0f, -100.0f, 100.0f); m_projMatrix = glm::orthoRH_ZO(-10.0f * aspect, 10.0f * aspect, -10.0f, 10.0f, -100.0f, 100.0f);
m_projMatrix[1][1] *= -1;
} }
} }

View File

@ -4,6 +4,8 @@
#include <iostream> #include <iostream>
namespace engine {
int Component::s_next_component_id = 0; int Component::s_next_component_id = 0;
Component::Component(Object* parent, TypeEnum type) : Component::Component(Object* parent, TypeEnum type) :
@ -28,3 +30,5 @@ Component::TypeEnum Component::getType()
{ {
return m_type; return m_type;
} }
}

View File

@ -1,6 +1,6 @@
#include "components/custom.hpp" #include "components/custom.hpp"
namespace components { namespace engine::components {
CustomComponent::CustomComponent(Object* parent) : Component(parent, TypeEnum::CUSTOM) CustomComponent::CustomComponent(Object* parent) : Component(parent, TypeEnum::CUSTOM)
{ {

View File

@ -4,14 +4,18 @@
#include "resource_manager.hpp" #include "resource_manager.hpp"
#include "gfx_device.hpp"
#include "log.hpp"
#include <iostream> #include <iostream>
namespace components { namespace engine::components {
Renderer::Renderer(Object* parent) : Component(parent, TypeEnum::RENDERER) Renderer::Renderer(Object* parent) : Component(parent, TypeEnum::RENDERER)
{ {
m_shader = this->parent.res.get<resources::Shader>("shaders/basic.glsl"); m_shader = this->parent.res.get<resources::Shader>("shader.glsl");
m_texture = this->parent.res.get<resources::Texture>("textures/missing.png"); // m_texture = this->parent.res.get<resources::Texture>("textures/missing.png");
} }
Renderer::~Renderer() Renderer::~Renderer()
@ -21,20 +25,7 @@ Renderer::~Renderer()
void Renderer::render(glm::mat4 transform) void Renderer::render(glm::mat4 transform)
{ {
gfxdev->draw(m_shader->getPipeline(), m_mesh->vb, m_mesh->ib, m_mesh->m_vertices.size(), &transform);
m_shader->setUniform_f("ambientStrength", 0.4f);
m_shader->setUniform_v3("ambientColor", { 1.0f, 1.0f, 1.0f });
m_shader->setUniform_v3("lightColor", { 1.0f, 1.0f, 1.0f });
m_shader->setUniform_m4("modelMat", transform );
m_texture->bindTexture();
m_shader->setUniform_v3("baseColor", m_color );
m_shader->setUniform_v3("emission", m_emission );
if (m_mesh)
m_mesh->drawMesh(*m_shader);
} }
void Renderer::setMesh(const std::string& name) void Renderer::setMesh(const std::string& name)
@ -44,7 +35,7 @@ void Renderer::setMesh(const std::string& name)
void Renderer::setTexture(const std::string& name) void Renderer::setTexture(const std::string& name)
{ {
m_texture = parent.res.get<resources::Texture>(name); // m_texture = parent.res.get<resources::Texture>(name);
} }
} }

View File

@ -4,7 +4,7 @@
#include "resource_manager.hpp" #include "resource_manager.hpp"
#include "resources/texture.hpp" #include "resources/texture.hpp"
namespace components { namespace engine::components {
UI::UI(Object* parent) : Component(parent, TypeEnum::UI) UI::UI(Object* parent) : Component(parent, TypeEnum::UI)
{ {
@ -23,12 +23,15 @@ UI::~UI()
void UI::render(glm::mat4 transform) void UI::render(glm::mat4 transform)
{ {
/*
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
m_shader->setUniform_m4("modelMat", transform); m_shader->setUniform_m4("modelMat", transform);
m_shader->setUniform_v3("textColor", m_color); m_shader->setUniform_v3("textColor", m_color);
m_shader->setUniform_i("textScaling", (int)m_scaled); m_shader->setUniform_i("textScaling", (int)m_scaled);
*/
std::vector<resources::Font::Character> glyphs; std::vector<resources::Font::Character> glyphs;
for (char c : m_text) { for (char c : m_text) {
glyphs.push_back(m_font->getChar(c)); glyphs.push_back(m_font->getChar(c));
@ -57,6 +60,7 @@ void UI::render(glm::mat4 transform)
float w = glyph.size.x * scale; float w = glyph.size.x * scale;
float h = glyph.size.y * scale; float h = glyph.size.y * scale;
/*
resources::Mesh mesh({ resources::Mesh mesh({
{{xpos, ypos + h, 0.0f}, {}, {0.0f, 0.0f}}, {{xpos, ypos + h, 0.0f}, {}, {0.0f, 0.0f}},
{{xpos, ypos , 0.0f}, {}, {0.0f, 1.0f}}, {{xpos, ypos , 0.0f}, {}, {0.0f, 1.0f}},
@ -64,11 +68,11 @@ void UI::render(glm::mat4 transform)
{{xpos, ypos + h, 0.0f}, {}, {0.0f, 0.0f}}, {{xpos, ypos + h, 0.0f}, {}, {0.0f, 0.0f}},
{{xpos + w, ypos, 0.0f}, {}, {1.0f, 1.0f}}, {{xpos + w, ypos, 0.0f}, {}, {1.0f, 1.0f}},
{{xpos + w, ypos + h, 0.0f}, {}, {1.0f, 0.0f}}, {{xpos + w, ypos + h, 0.0f}, {}, {1.0f, 0.0f}},
}); });*/
glBindTexture(GL_TEXTURE_2D, glyph.textureID); glBindTexture(GL_TEXTURE_2D, glyph.textureID);
mesh.drawMesh(*m_shader); // mesh.drawMesh(*m_shader);
x += (glyph.advance >> 6) * scale; x += (glyph.advance >> 6) * scale;

View File

@ -1,16 +1,87 @@
#include "engine.hpp" #include "engine.hpp"
#include "log.hpp"
#include "window.hpp"
#include "input.hpp"
#include "resource_manager.hpp"
#include "sceneroot.hpp"
#include "gfx_device.hpp"
#include "resources/mesh.hpp"
#include "components/mesh_renderer.hpp"
#include "components/camera.hpp"
namespace engine { namespace engine {
bool versionFromCharArray(const char* version, int* major, int* minor, int* patch) Application::Application(const char* appName, const char* appVersion)
{ {
if (sscanf(version, "%d.%d.%d", major, minor, patch) != 3) { m_win = new Window(appName, true);
*major = 0;
*minor = 0; gfxdev = new GFXDevice(appName, appVersion, m_win->getHandle());
*patch = 0;
return false; m_input = new Input(*m_win);
m_res = new ResourceManager();
GameIO things{
m_win,
m_input,
m_res
};
m_scene = new SceneRoot(things);
} }
return true;
Application::~Application()
{
delete m_scene;
delete m_res;
delete m_input;
delete gfxdev;
delete m_win;
}
void Application::gameLoop()
{
TRACE("Begin game loop...");
uint64_t lastTick = m_win->getNanos();
constexpr int TICKFREQ = 1; // in hz
// single-threaded game loop
while (m_win->isRunning()) {
/* logic */
if (m_win->getLastFrameStamp() >= lastTick + (BILLION / TICKFREQ)) {
lastTick = m_win->getLastFrameStamp();
// do tick stuff here
m_win->setTitle("frame time: " + std::to_string(m_win->dt() * 1000.0f) + " ms, " + std::to_string(m_win->getAvgFPS()) + " fps");
m_win->resetAvgFPS();
}
if (m_win->getKeyPress(inputs::Key::F11)) {
m_win->toggleFullscreen();
}
if (m_win->getKeyPress(inputs::Key::ESCAPE)) {
m_win->setCloseFlag();
}
m_scene->updateStuff();
/* draw */
gfxdev->renderFrame();
/* poll events */
m_win->getInputAndEvents();
}
gfxdev->waitIdle();
} }
} }

79
src/gfx_device_null.cpp Normal file
View File

@ -0,0 +1,79 @@
// This implementation of the graphics layer does nothing
//#define ENGINE_BUILD_NULLGFX
#ifdef ENGINE_BUILD_NULLGFX
#include "gfx_device.hpp"
#include "util.hpp"
#include "config.h"
#include "log.hpp"
#include <SDL2/SDL.h>
#include <assert.h>
#include <unordered_set>
#include <array>
#include <fstream>
#include <filesystem>
#include <optional>
namespace engine {
// structures and enums
// class definitions
struct GFXDevice::Impl {
};
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
{
pimpl = std::make_unique<Impl>();
}
GFXDevice::~GFXDevice()
{
TRACE("Destroying GFXDevice...");
}
void GFXDevice::drawBuffer(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, uint32_t count)
{
}
void GFXDevice::drawIndexed(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t indexCount)
{
}
void GFXDevice::renderFrame()
{
}
gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat)
{
return nullptr;
}
void GFXDevice::destroyPipeline(const gfx::Pipeline* pipeline)
{
}
gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data)
{
return nullptr;
}
void GFXDevice::destroyBuffer(const gfx::Buffer* buffer)
{
}
void GFXDevice::waitIdle()
{
}
}
#endif

105
src/gfx_device_opengl45.cpp Normal file
View File

@ -0,0 +1,105 @@
// The implementation of the graphics layer using OpenGL 4.5
// This uses SDL specific code
//#undef ENGINE_BUILD_OPENGL
#ifdef ENGINE_BUILD_OPENGL
#include "gfx_device.hpp"
#include "util.hpp"
#include "config.h"
#include "log.hpp"
#include <glad/glad.h>
#include <SDL2/SDL.h>
#include <assert.h>
#include <unordered_set>
#include <array>
#include <fstream>
#include <filesystem>
#include <optional>
namespace engine {
// structures and enums
static std::vector<char> readFile(const std::string& filename)
{
std::ifstream file(filename, std::ios::ate | std::ios::binary);
if (file.is_open() == false) {
throw std::runtime_error("Unable to open file " + filename);
}
std::vector<char> buffer(file.tellg());
file.seekg(0);
file.read(buffer.data(), buffer.size());
file.close();
return buffer;
}
// class definitions
struct GFXDevice::Impl {
SDL_GLContext context = nullptr;
};
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
{
pimpl = std::make_unique<Impl>();
pimpl->context = SDL_GL_CreateContext(window);
}
GFXDevice::~GFXDevice()
{
TRACE("Destroying GFXDevice...");
SDL_GL_DeleteContext(pimpl->context);
}
void GFXDevice::drawBuffer(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, uint32_t count)
{
}
void GFXDevice::drawIndexed(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t indexCount)
{
}
void GFXDevice::renderFrame()
{
}
gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat)
{
return nullptr;
}
void GFXDevice::destroyPipeline(const gfx::Pipeline* pipeline)
{
}
gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data)
{
return nullptr;
}
void GFXDevice::destroyBuffer(const gfx::Buffer* buffer)
{
}
void GFXDevice::waitIdle()
{
glFinish();
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,8 @@
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
namespace engine {
Input::Input(const Window& win) : m_win(win) Input::Input(const Window& win) : m_win(win)
{ {
m_enabledDevices.fill(true); m_enabledDevices.fill(true);
@ -170,7 +172,8 @@ float Input::getAxis(const std::string& axisName) const
if (m_enabledDevices[static_cast<int>(e.device)]) { if (m_enabledDevices[static_cast<int>(e.device)]) {
if (e.isButtonAxis) { if (e.isButtonAxis) {
return getButtonAxis(e.device, e.high, e.low); return getButtonAxis(e.device, e.high, e.low);
} else { }
else {
return getDeviceAxis(e.device, e.axis); return getDeviceAxis(e.device, e.axis);
} }
} }
@ -230,3 +233,5 @@ bool Input::getButtonRelease(const std::string& buttonName) const
} }
return isReleased; return isReleased;
} }
}

View File

@ -7,6 +7,10 @@
#include <log.hpp> #include <log.hpp>
#include <glm/gtc/quaternion.hpp>
namespace engine {
int Object::s_object_count = 0; int Object::s_object_count = 0;
Object::Object(std::string name, Object* parent, SceneRoot& root, struct GameIO things) Object::Object(std::string name, Object* parent, SceneRoot& root, struct GameIO things)
@ -78,7 +82,8 @@ void Object::printTree(int level)
for (int i = 0; i < level; i++) { for (int i = 0; i < level; i++) {
if (i + 1 == level) { if (i + 1 == level) {
buf += "\\_______"; buf += "\\_______";
} else { }
else {
buf += " "; buf += " ";
} }
} }
@ -106,7 +111,7 @@ void Object::getAllSubComponents(struct CompList& compList, glm::mat4 parentTran
// scale (effectively applied first // scale (effectively applied first
objTransform = glm::scale(objTransform, t.scale); objTransform = glm::scale(objTransform, t.scale);
const glm::mat4 newTransform = parentTransform * objTransform; glm::mat4 newTransform = parentTransform * objTransform;
for (const auto& compUnq : m_components) { for (const auto& compUnq : m_components) {
const auto comp = compUnq.get(); const auto comp = compUnq.get();
@ -131,3 +136,5 @@ void Object::getAllSubComponents(struct CompList& compList, glm::mat4 parentTran
child->getAllSubComponents(compList, newTransform); child->getAllSubComponents(compList, newTransform);
} }
} }
}

View File

@ -8,6 +8,8 @@
#include "log.hpp" #include "log.hpp"
namespace engine {
ResourceManager::ResourceManager() ResourceManager::ResourceManager()
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
@ -21,7 +23,8 @@ ResourceManager::ResourceManager()
if (std::filesystem::is_directory(cwd / "res")) { if (std::filesystem::is_directory(cwd / "res")) {
m_resourcesPath = cwd / "res"; m_resourcesPath = cwd / "res";
} else { }
else {
m_resourcesPath = cwd.parent_path() / "share" / "sdltest"; m_resourcesPath = cwd.parent_path() / "share" / "sdltest";
} }
@ -32,6 +35,8 @@ ResourceManager::ResourceManager()
if (std::filesystem::is_directory(m_resourcesPath) == false) { if (std::filesystem::is_directory(m_resourcesPath) == false) {
throw std::runtime_error("Unable to determine resources location. CWD: " + cwd.string()); throw std::runtime_error("Unable to determine resources location. CWD: " + cwd.string());
} }
m_resourcesPath = "C:/Users/Bailey/source/repos/game/res";
} }
std::unique_ptr<std::string> ResourceManager::getResourcesListString() std::unique_ptr<std::string> ResourceManager::getResourcesListString()
@ -73,3 +78,5 @@ std::filesystem::path ResourceManager::getFilePath(const std::string& name)
{ {
return m_resourcesPath / name; return m_resourcesPath / name;
} }
}

View File

@ -3,7 +3,7 @@
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
namespace resources { namespace engine::resources {
Font::Font(const std::filesystem::path& resPath) : Resource(resPath, "font") Font::Font(const std::filesystem::path& resPath) : Resource(resPath, "font")
{ {

View File

@ -1,14 +1,18 @@
#include "resources/mesh.hpp" #include "resources/mesh.hpp"
namespace resources { #include "gfx_device.hpp"
#include "log.hpp"
namespace engine::resources {
struct MeshFileHeader { struct MeshFileHeader {
unsigned int vertex_count; uint32_t vertex_count;
unsigned int index_count; uint32_t index_count;
int material; int32_t material;
}; };
static void loadMeshFromFile(const std::filesystem::path& path, std::vector<Vertex>* vertices, std::vector<unsigned int>* indices) static void loadMeshFromFile(const std::filesystem::path& path, std::vector<Vertex>* vertices, std::vector<uint32_t>* indices)
{ {
// TODO // TODO
@ -26,73 +30,43 @@ static void loadMeshFromFile(const std::filesystem::path& path, std::vector<Vert
indices->resize(header.index_count); indices->resize(header.index_count);
vertices->resize(header.vertex_count); vertices->resize(header.vertex_count);
fread(&(*indices)[0], sizeof(unsigned int) * header.index_count, 1, fp); fread(indices->data(), sizeof(uint32_t) * header.index_count, 1, fp);
fread(&((*vertices)[0].pos[0]), sizeof(float) * 8 * header.vertex_count, 1, fp); fread(vertices->data(), sizeof(float) * 8 * header.vertex_count, 1, fp);
fclose(fp); fclose(fp);
} }
static void loadObjFromFile(const std::filesystem::path& path, std::vector<Vertex>* vertices, std::vector<unsigned int>* indices)
{
}
// -1 means invalidated
int Mesh::s_active_vao = -1;
void Mesh::bindVAO() const
{
if (s_active_vao != m_vao) {
glBindVertexArray(m_vao);
s_active_vao = m_vao;
}
}
void Mesh::initMesh() void Mesh::initMesh()
{ {
glGenVertexArrays(1, &m_vao); vb = gfxdev->createBuffer(gfx::BufferType::VERTEX, m_vertices.size() * sizeof(Vertex), m_vertices.data());
bindVAO(); ib = gfxdev->createBuffer(gfx::BufferType::INDEX, m_indices.size() * sizeof(uint32_t), m_indices.data());
glGenBuffers(1, &m_vbo);
glGenBuffers(1, &m_ebo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo); TRACE("VB PTR in mesh: {}", (void*)vb);
glBufferData(GL_ARRAY_BUFFER, m_vertices.size()*sizeof(Vertex), &m_vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(unsigned int), &(m_indices[0]), GL_STATIC_DRAW);
// position TRACE("Vertices:");
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)offsetof(Vertex, pos));
// normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)offsetof(Vertex, norm));
// uv
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)offsetof(Vertex, uv));
for (const auto& v : m_vertices) {
TRACE("pos: {}, {}, {}", v.pos.x, v.pos.y, v.pos.z);
} }
void Mesh::drawMesh(const Shader& shader) TRACE("Indices:");
{
bindVAO(); for (const uint32_t i : m_indices) {
shader.makeActive(); TRACE("\t{}", i);
#ifndef SDLTEST_NOGFX }
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_indices.size()), GL_UNSIGNED_INT, 0);
#endif
} }
Mesh::Mesh(const std::vector<Vertex>& vertices) : Resource("", "mesh") Mesh::Mesh(const std::vector<Vertex>& vertices) : Resource("", "mesh")
{ {
// constructor for custom meshes without an index array // constructor for custom meshes without an index array
m_vertices = vertices; // COPY over vertices m_vertices = vertices; // COPY over vertices
for (int i = 0; i < m_vertices.size(); i++) { for (uint32_t i = 0; i < m_vertices.size(); i++) {
m_indices.push_back(i); m_indices.push_back(i);
} }
initMesh(); initMesh();
} }
Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices) : Resource("", "mesh") Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices) : Resource("", "mesh")
{ {
m_vertices = vertices; // COPY over vertices m_vertices = vertices; // COPY over vertices
m_indices = indices; // COPY over indices; m_indices = indices; // COPY over indices;
@ -108,12 +82,8 @@ Mesh::Mesh(const std::filesystem::path& resPath) : Resource(resPath, "mesh")
Mesh::~Mesh() Mesh::~Mesh()
{ {
glDeleteVertexArrays(1, &m_vao); gfxdev->destroyBuffer(ib);
glDeleteBuffers(1, &m_vbo); gfxdev->destroyBuffer(vb);
glDeleteBuffers(1, &m_ebo);
if (s_active_vao == m_vao) {
s_active_vao = -1;
}
} }
} }

View File

@ -2,6 +2,8 @@
#include <log.hpp> #include <log.hpp>
namespace engine {
Resource::Resource(const std::filesystem::path& resPath, const std::string& type) : m_resourcePath(resPath), m_type(type) Resource::Resource(const std::filesystem::path& resPath, const std::string& type) : m_resourcePath(resPath), m_type(type)
{ {
if (m_type != "mesh") if (m_type != "mesh")
@ -18,3 +20,5 @@ std::string Resource::getType()
{ {
return m_type; return m_type;
} }
}

View File

@ -1,8 +1,8 @@
#include "resources/shader.hpp" #include "resources/shader.hpp"
#include <glad/glad.h> #include "log.hpp"
#include <log.hpp> #include "gfx_device.hpp"
#include <string> #include <string>
#include <fstream> #include <fstream>
@ -24,200 +24,27 @@ static std::unique_ptr<std::vector<char>> readFile(const char * path)
return buf; return buf;
} }
static GLuint compile(const char *path, GLenum type) namespace engine::resources {
{
auto src = readFile(path);
// compile shader
GLuint handle = glCreateShader(type);
GLint size = src->size();
GLchar *data = src->data();
glShaderSource(handle, 1, &data, &size);
glCompileShader(handle);
// check for compilation error
GLint compiled;
glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled);
if (compiled == 0) {
GLint log_len;
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_len);
GLchar *log_msg = (GLchar *)calloc(1, log_len);
if (log_msg == NULL) {
throw std::runtime_error("Error allocating memory for shader compilation error log");
}
glGetShaderInfoLog(handle, log_len, NULL, log_msg);
throw std::runtime_error("Shader compilation error in " + std::string(path) + " log:\n" + std::string(log_msg));
} return handle;
}
namespace resources {
// I've got to do this because of GL's stupid state machine
GLuint Shader::s_activeProgram = 0;
Shader::Shader(const std::filesystem::path& resPath) : Resource(resPath, "shader") Shader::Shader(const std::filesystem::path& resPath) : Resource(resPath, "shader")
{ {
const std::string vertexShaderPath = (resPath.parent_path()/std::filesystem::path(resPath.stem().string() + ".vert")).string(); gfx::VertexFormat vertexFormat {};
const std::string fragmentShaderPath = (resPath.parent_path()/std::filesystem::path(resPath.stem().string() + ".frag")).string(); vertexFormat.stride = 8 * sizeof(float);
GLuint vs = compile(vertexShaderPath.c_str(), GL_VERTEX_SHADER); vertexFormat.attributeDescriptions.emplace_back(0, gfx::VertexAttribFormat::VEC3, 0); // pos
GLuint fs = compile(fragmentShaderPath.c_str(), GL_FRAGMENT_SHADER); vertexFormat.attributeDescriptions.emplace_back(1, gfx::VertexAttribFormat::VEC3, sizeof(glm::vec3)); // norm
m_program = glCreateProgram(); vertexFormat.attributeDescriptions.emplace_back(2, gfx::VertexAttribFormat::VEC2, sizeof(glm::vec3) + sizeof(glm::vec3)); // uv
glAttachShader(m_program, vs);
glAttachShader(m_program, fs);
glLinkProgram(m_program);
glValidateProgram(m_program);
// flag shader objects for deletion, this does not take effect until the program is deleted const std::string vertexShaderPath = (resPath.parent_path()/std::filesystem::path(resPath.stem().string() + ".vert.spv")).string();
glDeleteShader(vs); const std::string fragmentShaderPath = (resPath.parent_path()/std::filesystem::path(resPath.stem().string() + ".frag.spv")).string();
glDeleteShader(fs);
GLint linked, validated; m_pipeline = gfxdev->createPipeline(vertexShaderPath.c_str(), fragmentShaderPath.c_str(), vertexFormat, sizeof(UniformBuffer));
glGetProgramiv(m_program, GL_LINK_STATUS, &linked);
glGetProgramiv(m_program, GL_VALIDATE_STATUS, &validated);
if (linked == 0 || validated == 0) {
GLint log_len;
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &log_len);
GLchar *log_msg = (GLchar *)calloc(1, log_len);
if (log_msg == NULL) {
throw std::runtime_error("Error allocating memory for shader linking error log");
}
glGetProgramInfoLog(m_program, log_len, NULL, log_msg);
throw std::runtime_error("Program linking error with " + vertexShaderPath + " and " + fragmentShaderPath + " log:\n" + log_msg);
}
DEBUG("For shader {}:", resPath.filename().string());
// now get uniforms
GLint count;
glGetProgramiv(m_program, GL_ACTIVE_UNIFORMS, &count);
for (int i = 0; i < count; i++) {
char nameBuf[64] = {};
GLint size;
GLenum type;
glGetActiveUniform(m_program, i, 63, NULL, &size, &type, nameBuf);
m_uniforms[nameBuf] = Uniform{size, static_cast<UniformType>(type), (GLuint)i};
DEBUG("\tuniform {}", nameBuf);
}
// now get all attributes
glGetProgramiv(m_program, GL_ACTIVE_ATTRIBUTES, &count);
for (int i = 0; i < count; i++) {
char nameBuf[64] = {};
GLint size;
GLenum type;
glGetActiveAttrib(m_program, i, 63, NULL, &size, &type, nameBuf);
m_attributes[nameBuf] = Attribute{size, static_cast<UniformType>(type), (GLuint)i};
DEBUG("\tattrib {}", nameBuf);
}
} }
Shader::~Shader() Shader::~Shader()
{ {
glDeleteProgram(m_program); gfxdev->destroyPipeline(m_pipeline);
}
void Shader::makeActive() const
{
if (s_activeProgram != m_program) {
glUseProgram(m_program);
s_activeProgram = m_program;
}
}
int Shader::getUniformLocation(const std::string& name) const
{
auto it = m_uniforms.find(name);
if (it != m_uniforms.end()) {
Uniform u = it->second;
return u.location;
}
else {
return -1;
}
}
bool Shader::setUniform_m4(const std::string& name, const glm::mat4& m) const
{
makeActive();
int loc = getUniformLocation(name);
if (loc != -1) {
glUniformMatrix4fv(loc, 1, GL_FALSE, &m[0][0]);
return true;
}
else {
return false;
}
}
bool Shader::setUniform_v2(const std::string& name, const glm::vec2& v) const
{
makeActive();
int loc = getUniformLocation(name);
if (loc != -1) {
glUniform2f(loc, v.x, v.y);
return true;
}
else {
return false;
}
}
bool Shader::setUniform_v3(const std::string& name, const glm::vec3& v) const
{
makeActive();
int loc = getUniformLocation(name);
if (loc != -1) {
glUniform3f(loc, v.x, v.y, v.z);
return true;
}
else {
return false;
}
}
bool Shader::setUniform_i(const std::string& name, int n) const
{
makeActive();
int loc = getUniformLocation(name);
if (loc != -1) {
glUniform1i(loc, n);
return true;
}
else {
return false;
}
}
bool Shader::setUniform_f(const std::string& name, float n) const
{
makeActive();
int loc = getUniformLocation(name);
if (loc != -1) {
glUniform1f(loc, n);
return true;
}
else {
return false;
}
}
Shader::UniformType Shader::getUniformType(const std::string& name) const
{
auto it = m_uniforms.find(name);
if (it != m_uniforms.end()) {
return it->second.type;
}
else {
return UniformType::NOTFOUND;
}
}
int Shader::getAttribLocation(const std::string& name) const
{
return m_attributes.at(name).location;
} }
} }

View File

@ -7,7 +7,7 @@
#include <vector> #include <vector>
namespace resources { namespace engine::resources {
// -1 means invalid / no bind // -1 means invalid / no bind
GLuint Texture::s_binded_texture = -1; GLuint Texture::s_binded_texture = -1;
@ -28,7 +28,7 @@ static bool readPNG(const std::string& path, std::vector<uint8_t>& texbuf, int *
return false; return false;
} }
const size_t size = x * y * n; const size_t size = (size_t)x * (size_t)y * (size_t)n;
texbuf.resize(size); texbuf.resize(size);
memcpy(texbuf.data(), data, size); memcpy(texbuf.data(), data, size);
@ -62,7 +62,7 @@ static bool readGLRaw(const std::string& path, std::vector<uint8_t>& texbuf, int
uint64_t end = ftell(fp); uint64_t end = ftell(fp);
texbuf.resize(end); texbuf.resize(end);
fseek(fp, tex_data_offset, SEEK_SET); fseek(fp, (long)tex_data_offset, SEEK_SET);
fread(texbuf.data(), 1, end, fp); fread(texbuf.data(), 1, end, fp);
fclose(fp); fclose(fp);

View File

@ -7,6 +7,8 @@
#include "components/mesh_renderer.hpp" #include "components/mesh_renderer.hpp"
#include "components/text_ui_renderer.hpp" #include "components/text_ui_renderer.hpp"
#include "gfx_device.hpp"
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
#include <iostream> #include <iostream>
@ -14,16 +16,12 @@
#include "log.hpp" #include "log.hpp"
namespace engine {
SceneRoot::SceneRoot(struct GameIO things) : Object("root", nullptr, *this, things) SceneRoot::SceneRoot(struct GameIO things) : Object("root", nullptr, *this, things)
{ {
} }
SceneRoot::SceneRoot(const std::filesystem::path& file, struct GameIO things) : SceneRoot(things)
{
// TODO: make this a resource
//loadFromSceneFile(file);
}
SceneRoot::~SceneRoot() SceneRoot::~SceneRoot()
{ {
} }
@ -50,12 +48,12 @@ void SceneRoot::updateStuff()
// render // render
for (const auto& [c, t] : compList.cameras) { for (const auto& [c, camt] : compList.cameras) {
for (int id : m_activeCameras) { for (int id : m_activeCameras) {
if (c->getID() == id) { if (c->getID() == id) {
c->updateCam(t); c->updateCam(camt);
for (const auto& [c, t] : compList.renderers) { for (const auto& [ren, ren_t] : compList.renderers) {
c->render(t); ren->render(ren_t);
} }
break; break;
@ -88,3 +86,5 @@ void SceneRoot::deactivateCam(int id)
} }
} }
} }
}

View File

@ -1,17 +1,15 @@
#include "window.hpp" #include "window.hpp"
#include <glad/glad.h> #include "log.hpp"
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#ifdef ENGINE_BUILD_VULKAN
#include <SDL2/SDL_vulkan.h>
#endif
const uint64_t BILLION = 1000000000; const uint64_t BILLION = 1000000000;
Window::Window(const std::string& title) : m_title(title) namespace engine {
Window::Window(const std::string& title, bool resizable) : m_title(title), m_resizable(resizable)
{ {
// init SDL // init SDL
@ -28,9 +26,15 @@ Window::Window(const std::string& title) : m_title(title)
m_lastFrameStamp = m_startTime - 1; m_lastFrameStamp = m_startTime - 1;
m_avgFpsStart = m_startTime; m_avgFpsStart = m_startTime;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); Uint32 windowFlags = SDL_WINDOW_SHOWN;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); #ifdef ENGINE_BUILD_VULKAN
windowFlags |= SDL_WINDOW_VULKAN;
#endif
if (m_resizable) {
windowFlags |= SDL_WINDOW_RESIZABLE;
}
// create the window // create the window
m_handle = SDL_CreateWindow( m_handle = SDL_CreateWindow(
@ -38,7 +42,7 @@ Window::Window(const std::string& title) : m_title(title)
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
static_cast<int>(m_winSize.x), static_cast<int>(m_winSize.x),
static_cast<int>(m_winSize.y), static_cast<int>(m_winSize.y),
SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI); windowFlags);
if (m_handle == NULL) { if (m_handle == NULL) {
SDL_Quit(); SDL_Quit();
throw std::runtime_error("Unable to create window: " + std::string(SDL_GetError())); throw std::runtime_error("Unable to create window: " + std::string(SDL_GetError()));
@ -54,6 +58,7 @@ Window::Window(const std::string& title) : m_title(title)
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);
/*
m_glContext = SDL_GL_CreateContext(m_handle); m_glContext = SDL_GL_CreateContext(m_handle);
if (m_glContext == NULL) { if (m_glContext == NULL) {
SDL_DestroyWindow(m_handle); SDL_DestroyWindow(m_handle);
@ -66,14 +71,14 @@ Window::Window(const std::string& title) : m_title(title)
SDL_Quit(); SDL_Quit();
throw std::runtime_error("Unable to initialise GLAD"); throw std::runtime_error("Unable to initialise GLAD");
} }
*/
onResize(m_winSize.x, m_winSize.y); // onResize(m_winSize.x, m_winSize.y);
} }
Window::~Window() Window::~Window()
{ {
SDL_GL_DeleteContext(m_glContext);
SDL_DestroyWindow(m_handle); SDL_DestroyWindow(m_handle);
SDL_Quit(); SDL_Quit();
} }
@ -86,13 +91,6 @@ void Window::onResize(Sint32 width, Sint32 height)
m_winSize.x = static_cast<int>(width); m_winSize.x = static_cast<int>(width);
m_winSize.y = static_cast<int>(height); m_winSize.y = static_cast<int>(height);
// get framebuffer size
int fbWidth, fbHeight;
SDL_GL_GetDrawableSize(m_handle, &fbWidth, &fbHeight);
m_fbSize.x = static_cast<int>(fbWidth);
m_fbSize.y = static_cast<int>(fbHeight);
glViewport(0, 0, fbWidth, fbHeight);
m_justResized = true; m_justResized = true;
} }
@ -103,8 +101,8 @@ void Window::resetInputDeltas()
m_keyboard.deltas.fill(ButtonDelta::SAME); m_keyboard.deltas.fill(ButtonDelta::SAME);
m_mouse.deltas.fill(ButtonDelta::SAME); m_mouse.deltas.fill(ButtonDelta::SAME);
m_mouse.dx = 0.0f; m_mouse.dx = 0;
m_mouse.dy = 0.0f; m_mouse.dy = 0;
m_mouse.xscroll = 0.0f; m_mouse.xscroll = 0.0f;
m_mouse.yscroll = 0.0f; m_mouse.yscroll = 0.0f;
} }
@ -157,14 +155,14 @@ void Window::onMouseButtonEvent(SDL_MouseButtonEvent &e)
button = inputs::MouseButton::M_X2; button = inputs::MouseButton::M_X2;
break; break;
} }
int buttonIndex = static_cast<int>(button);
bool buttonWasDown = m_mouse.buttons[static_cast<int>(button)]; bool buttonWasDown = m_mouse.buttons.at(buttonIndex);
bool buttonIsDown = (e.state == SDL_PRESSED); bool buttonIsDown = (e.state == SDL_PRESSED);
m_mouse.buttons[static_cast<int>(button)] = buttonIsDown; m_mouse.buttons.at(buttonIndex) = buttonIsDown;
if (buttonIsDown != buttonWasDown) { // (if button was pressed or released) if (buttonIsDown != buttonWasDown) { // (if button was pressed or released)
// only sets delta if it hasn't already been set this frame (to detect very fast presses) // only sets delta if it hasn't already been set this frame (to detect very fast presses)
if (m_mouse.deltas[static_cast<int>(button)] == ButtonDelta::SAME) { if (m_mouse.deltas[buttonIndex] == ButtonDelta::SAME) {
m_mouse.deltas[static_cast<int>(button)] = buttonIsDown ? ButtonDelta::PRESSED : ButtonDelta::RELEASED; m_mouse.deltas[buttonIndex] = buttonIsDown ? ButtonDelta::PRESSED : ButtonDelta::RELEASED;
} }
} }
} }
@ -182,7 +180,8 @@ void Window::onMouseWheelEvent(SDL_MouseWheelEvent &e)
if (e.direction == SDL_MOUSEWHEEL_NORMAL) { if (e.direction == SDL_MOUSEWHEEL_NORMAL) {
m_mouse.xscroll = e.preciseX; m_mouse.xscroll = e.preciseX;
m_mouse.yscroll = e.preciseY; m_mouse.yscroll = e.preciseY;
} else { // flipped }
else { // flipped
m_mouse.xscroll = -e.preciseX; m_mouse.xscroll = -e.preciseX;
m_mouse.yscroll = -e.preciseY; m_mouse.yscroll = -e.preciseY;
} }
@ -190,31 +189,23 @@ void Window::onMouseWheelEvent(SDL_MouseWheelEvent &e)
// public methods // public methods
SDL_Window* Window::getHandle() const
{
return m_handle;
}
std::string Window::getTitle() const std::string Window::getTitle() const
{ {
return m_title; return m_title;
} }
void Window::makeContextCurrent() void Window::getInputAndEvents()
{ {
if (SDL_GL_MakeCurrent(m_handle, m_glContext) != 0) {
throw std::runtime_error("Failed to make GL context current");
}
}
void Window::swapBuffers()
{
#ifndef SDLTEST_NOGFX
SDL_GL_SwapWindow(m_handle);
#endif
m_frames++; m_frames++;
uint64_t currentFrameStamp = getNanos(); uint64_t currentFrameStamp = getNanos();
m_lastFrameTime = currentFrameStamp - m_lastFrameStamp; m_lastFrameTime = currentFrameStamp - m_lastFrameStamp;
m_lastFrameStamp = currentFrameStamp; m_lastFrameStamp = currentFrameStamp;
}
void Window::getInputAndEvents()
{
resetInputDeltas(); resetInputDeltas();
@ -254,23 +245,6 @@ void Window::getInputAndEvents()
} }
void Window::setVSync(bool enable)
{
if (SDL_GL_SetSwapInterval(enable ? 1 : 0) != 0) {
throw std::runtime_error("Failed to set swap interval");
}
}
bool Window::getVSync() const
{
return SDL_GL_GetSwapInterval() == 0 ? false : true;
}
glm::ivec2 Window::getViewportSize()
{
return m_fbSize;
}
void Window::setTitle(std::string title) void Window::setTitle(std::string title)
{ {
SDL_SetWindowTitle(m_handle, title.c_str()); SDL_SetWindowTitle(m_handle, title.c_str());
@ -314,6 +288,7 @@ bool Window::isRunning() const
void Window::setFullscreen(bool fullscreen, bool exclusive) void Window::setFullscreen(bool fullscreen, bool exclusive)
{ {
if (m_resizable) {
if (SDL_SetWindowFullscreen(m_handle, fullscreen ? (exclusive ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP) : 0) != 0) { if (SDL_SetWindowFullscreen(m_handle, fullscreen ? (exclusive ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP) : 0) != 0) {
throw std::runtime_error("Unable to set window to fullscreen/windowed"); throw std::runtime_error("Unable to set window to fullscreen/windowed");
} }
@ -324,6 +299,7 @@ void Window::setFullscreen(bool fullscreen, bool exclusive)
onResize(width, height); onResize(width, height);
} }
} }
}
void Window::toggleFullscreen() void Window::toggleFullscreen()
{ {
@ -341,7 +317,8 @@ bool Window::setRelativeMouseMode(bool enabled)
int code = SDL_SetRelativeMouseMode(static_cast<SDL_bool>(enabled)); int code = SDL_SetRelativeMouseMode(static_cast<SDL_bool>(enabled));
if (code != 0) { if (code != 0) {
throw std::runtime_error("Unable to set relative mouse mode"); throw std::runtime_error("Unable to set relative mouse mode");
} else { }
else {
return true; return true;
} }
} }
@ -435,7 +412,8 @@ uint64_t Window::getNanos() const
count = SDL_GetPerformanceCounter(); count = SDL_GetPerformanceCounter();
if (m_counterFreq == BILLION) { if (m_counterFreq == BILLION) {
return count; return count;
} else { }
else {
return count * (BILLION / m_counterFreq); return count * (BILLION / m_counterFreq);
} }
} }
@ -484,25 +462,12 @@ bool Window::infoBox(const std::string& title, const std::string& msg)
if (isFullscreen() == false) { if (isFullscreen() == false) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, title.c_str(), msg.c_str(), m_handle); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, title.c_str(), msg.c_str(), m_handle);
return true; return true;
} else { }
else {
return false; return false;
} }
} }
std::vector<const char*> Window::getRequiredVulkanExtensions() const
{
#ifdef ENGINE_BUILD_VULKAN
unsigned int sdlExtensionCount = 0;
SDL_Vulkan_GetInstanceExtensions(m_handle, &sdlExtensionCount, nullptr);
std::vector<const char*> requiredExtensions(sdlExtensionCount);
SDL_Vulkan_GetInstanceExtensions(m_handle, &sdlExtensionCount, requiredExtensions.data());
return requiredExtensions;
#else
return std::vector<const char*>{};
#endif
}
/* STATIC METHODS */ /* STATIC METHODS */
// Display an error message box // Display an error message box
@ -510,3 +475,5 @@ void Window::errorBox(const std::string& message)
{ {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Game Error", message.c_str(), NULL); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Game Error", message.c_str(), NULL);
} }
}