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"]
path = dependencies/freetype
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
@ -6,8 +6,7 @@ project(engine LANGUAGES CXX
VERSION "0.1.0"
)
add_library(${PROJECT_NAME} SHARED
set(SRC_FILES
"src/engine.cpp"
"src/window.cpp"
"src/input.cpp" #TODO make input_manager
@ -31,13 +30,18 @@ add_library(${PROJECT_NAME} SHARED
"src/resource_manager.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.hpp"
"include/util.hpp"
"include/log.hpp"
"include/window.hpp"
@ -67,19 +71,32 @@ add_library(${PROJECT_NAME} SHARED
"include/gfx.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:
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_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)
endif()
target_include_directories(${PROJECT_NAME} PUBLIC include)
@ -98,10 +115,31 @@ if (MINGW)
target_link_libraries(${PROJECT_NAME} PUBLIC mingw32)
endif()
# Vulkan
find_package(Vulkan REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE ${Vulkan_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan)
# 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)
# 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:
find_package(SDL2)
@ -124,24 +162,9 @@ set(BUILD_SHARED_LIBS OFF)
add_subdirectory(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
set(SPDLOG_BUILD_SHARED ON CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS ON)
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)

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
'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 <glm/glm.hpp>
#include <glm/ext.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>
namespace components {
namespace engine::components {
class ENGINE_API Camera : public Component {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,53 @@
#pragma once
#include <filesystem>
#include "log.hpp"
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <memory>
namespace engine {
struct AppInfo {
const char* name;
const char* version;
class Window;
class Input;
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
/*
#ifndef ENGINE_API
# ifdef _MSC_VER
# ifdef ENGINE_EXPORTS
@ -11,3 +12,6 @@
# define ENGINE_API
# endif
#endif
*/
#define ENGINE_API

View File

@ -2,29 +2,19 @@
#include <cstdint>
#include <cstddef>
#include <vector>
namespace gfx {
namespace engine::gfx {
enum class ShaderType {
VERTEX,
FRAGMENT,
};
struct Shader {
ShaderType type;
uint32_t handle;
};
typedef uint32_t Program;
enum class BufferType {
VERTEX,
INDEX,
};
struct Buffer {
BufferType type;
uint32_t handle;
UNIFORM,
};
enum class Primitive {
@ -35,10 +25,28 @@ namespace gfx {
TRIANGLE_STRIP,
};
enum class IndexBufferFormat {
UNSIGNED_8_BITS,
UNSIGNED_16_BITS,
UNSIGNED_32_BITS,
enum class VertexAttribFormat {
VEC2,
VEC3,
};
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.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);
~Device();
class ENGINE_API GFXDevice {
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:
class Impl;
std::unique_ptr<Impl> pimpl{};
struct Impl;
std::unique_ptr<Impl> pimpl;
};
extern GFXDevice* gfxdev;
}

View File

@ -9,6 +9,8 @@
#include <array>
#include <string>
namespace engine {
class Window;
enum class InputDevice : int {
@ -87,3 +89,5 @@ private:
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
namespace inputs {
namespace engine::inputs {
enum class Key : int {
UNKNOWN = 0,

View File

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

View File

@ -6,12 +6,15 @@
#include "transform.hpp"
#include "components/component.hpp"
#include <list>
#include <vector>
#include <string>
#include <memory>
#include <stdexcept>
namespace engine {
class Window;
class Input;
class ResourceManager;
@ -20,7 +23,6 @@ class SceneRoot;
class Component;
namespace components {
class Transform;
class Camera;
class Renderer;
class UI;
@ -28,9 +30,9 @@ namespace components {
}
struct GameIO {
Window * const win;
Input * const input;
ResourceManager * const resMan;
Window* win;
Input* input;
ResourceManager* resMan;
};
// 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;
ResourceManager& res;
SceneRoot& root;
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.");
}
}

View File

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

View File

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

View File

@ -4,9 +4,7 @@
#include "resource.hpp"
#include "resources/shader.hpp"
#include <glad/glad.h>
#include "gfx.hpp"
#include <glm/vec3.hpp>
#include <glm/vec2.hpp>
@ -20,34 +18,23 @@ struct Vertex {
glm::vec2 uv;
};
namespace resources {
namespace engine::resources {
class ENGINE_API Mesh : public Resource {
public:
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() override;
void drawMesh(const Shader& shader);
static void invalidate()
{
s_active_vao = -1;
}
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:
static int s_active_vao;
GLuint m_vao;
GLuint m_vbo;
GLuint m_ebo;
void bindVAO() const;
void initMesh();

View File

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

View File

@ -4,14 +4,16 @@
#include "resource.hpp"
#include <glad/glad.h>
#include <glm/mat4x4.hpp>
#include <string>
#include <map>
namespace resources {
namespace engine::gfx {
struct Pipeline;
}
namespace engine::resources {
class ENGINE_API Shader : public Resource {
@ -19,58 +21,18 @@ public:
Shader(const std::filesystem::path& resPath);
~Shader() override;
enum class UniformType {
FLOAT_MAT4 = GL_FLOAT_MAT4,
FLOAT_VEC2 = GL_FLOAT_VEC2,
FLOAT_VEC3 = GL_FLOAT_VEC3,
SAMPLER_2D = GL_SAMPLER_2D,
NOTFOUND
struct UniformBuffer {
glm::mat4 v;
glm::mat4 p;
};
void makeActive() const;
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()
gfx::Pipeline* getPipeline()
{
s_activeProgram = -1;
return m_pipeline;
}
private:
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;
gfx::Pipeline* m_pipeline = nullptr;
};

View File

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

View File

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

View File

@ -6,6 +6,8 @@
#include <glm/vec3.hpp>
#include <glm/ext/quaternion_float.hpp>
namespace engine {
struct ENGINE_API Transform {
// Scale, rotate (XYZ), translate
@ -15,3 +17,5 @@ struct ENGINE_API Transform {
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;
namespace engine {
class ENGINE_API Window {
public:
Window(const std::string& title);
Window(const std::string& title, bool resizable = true);
Window(const Window&) = delete;
Window& operator=(const Window&) = delete;
~Window();
SDL_Window* getHandle() const;
// Return the title name
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.
// Run this on every frame.
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);
// Hides the window (it will appear closed to the user).
@ -63,7 +52,7 @@ public:
// Returns true if the window should remain open
bool isRunning() const;
void setFullscreen(bool fullscreen, bool exclusive=true);
void setFullscreen(bool fullscreen, bool exclusive = false);
void toggleFullscreen();
bool isFullscreen() const;
@ -139,27 +128,25 @@ public:
bool infoBox(const std::string& title, const std::string& msg);
std::vector<const char*> getRequiredVulkanExtensions() const;
/* STATIC METHODS */
static void errorBox(const std::string& message);
private:
SDL_Window* m_handle;
SDL_GLContext m_glContext;
bool m_shouldClose = false;
std::string m_title;
bool m_resizable;
bool m_fullscreen = false;
bool m_justResized = false;
bool m_keyboardFocus = true;
// size in screen coordinates
glm::ivec2 m_winSize = glm::vec2(640, 480);
// actual framebuffer size
glm::ivec2 m_fbSize;
// performance counter frequency
uint64_t m_counterFreq;
@ -214,5 +201,6 @@ public:
void onMouseButtonEvent(SDL_MouseButtonEvent& e);
void onMouseMotionEvent(SDL_MouseMotionEvent& e);
void onMouseWheelEvent(SDL_MouseWheelEvent& e);
};
}

View File

@ -7,24 +7,17 @@
#include "window.hpp"
#include "gfx_device.hpp"
#include "log.hpp"
static const std::string VIEW_MAT_UNIFORM = "viewMat";
static const std::string PROJ_MAT_UNIFORM = "projMat";
static const std::string WINDOW_SIZE_UNIFORM = "windowSize";
namespace components {
namespace engine::components {
glm::vec4 Camera::s_clearColor{-999.0f, -999.0f, -999.0f, -999.0f};
Camera::Camera(Object* parent) : Component(parent, TypeEnum::CAMERA)
{
parent->root.activateCam(getID());
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glEnable(GL_CULL_FACE);
}
Camera::~Camera()
@ -45,6 +38,14 @@ void Camera::updateCam(glm::mat4 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;
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
auto lockedPtr = resPtr.lock();
auto shader = dynamic_cast<Shader*>(lockedPtr.get());
shader->setUniform_m4(VIEW_MAT_UNIFORM, viewMatrix);
shader->setUniform_m4(PROJ_MAT_UNIFORM, m_projMatrix);
shader->setUniform_v2(WINDOW_SIZE_UNIFORM, win.getViewportSize());
shader->setUniform_v3("lightPos", m_lightPos);
// SET VIEW TRANSFORM HERE
gfxdev->updateUniformBuffer(shader->getPipeline(), &uniformData);
}
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()
{
GLint64 viewportParams[4];
glGetInteger64v(GL_VIEWPORT, viewportParams);
return { viewportParams[2], viewportParams[3] };
uint32_t width;
uint32_t height;
gfxdev->getViewportSize(&width, &height);
return {width, height};
}
void Camera::usePerspective(float fovDeg)
@ -85,7 +78,8 @@ void Camera::usePerspective(float fovDeg)
glm::vec2 viewportDim = getViewportSize();
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()
@ -95,7 +89,8 @@ void Camera::useOrtho()
glm::vec2 viewportDim = getViewportSize();
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>
namespace engine {
int Component::s_next_component_id = 0;
Component::Component(Object* parent, TypeEnum type) :
@ -28,3 +30,5 @@ Component::TypeEnum Component::getType()
{
return m_type;
}
}

View File

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

View File

@ -4,14 +4,18 @@
#include "resource_manager.hpp"
#include "gfx_device.hpp"
#include "log.hpp"
#include <iostream>
namespace components {
namespace engine::components {
Renderer::Renderer(Object* parent) : Component(parent, TypeEnum::RENDERER)
{
m_shader = this->parent.res.get<resources::Shader>("shaders/basic.glsl");
m_texture = this->parent.res.get<resources::Texture>("textures/missing.png");
m_shader = this->parent.res.get<resources::Shader>("shader.glsl");
// m_texture = this->parent.res.get<resources::Texture>("textures/missing.png");
}
Renderer::~Renderer()
@ -21,20 +25,7 @@ Renderer::~Renderer()
void Renderer::render(glm::mat4 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);
gfxdev->draw(m_shader->getPipeline(), m_mesh->vb, m_mesh->ib, m_mesh->m_vertices.size(), &transform);
}
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)
{
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 "resources/texture.hpp"
namespace components {
namespace engine::components {
UI::UI(Object* parent) : Component(parent, TypeEnum::UI)
{
@ -23,12 +23,15 @@ UI::~UI()
void UI::render(glm::mat4 transform)
{
/*
glActiveTexture(GL_TEXTURE0);
m_shader->setUniform_m4("modelMat", transform);
m_shader->setUniform_v3("textColor", m_color);
m_shader->setUniform_i("textScaling", (int)m_scaled);
*/
std::vector<resources::Font::Character> glyphs;
for (char c : m_text) {
glyphs.push_back(m_font->getChar(c));
@ -57,6 +60,7 @@ void UI::render(glm::mat4 transform)
float w = glyph.size.x * scale;
float h = glyph.size.y * scale;
/*
resources::Mesh mesh({
{{xpos, ypos + h, 0.0f}, {}, {0.0f, 0.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 + w, ypos, 0.0f}, {}, {1.0f, 1.0f}},
{{xpos + w, ypos + h, 0.0f}, {}, {1.0f, 0.0f}},
});
});*/
glBindTexture(GL_TEXTURE_2D, glyph.textureID);
mesh.drawMesh(*m_shader);
// mesh.drawMesh(*m_shader);
x += (glyph.advance >> 6) * scale;

View File

@ -1,16 +1,87 @@
#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 {
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) {
*major = 0;
*minor = 0;
*patch = 0;
return false;
m_win = new Window(appName, true);
gfxdev = new GFXDevice(appName, appVersion, m_win->getHandle());
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 <stdexcept>
namespace engine {
Input::Input(const Window& win) : m_win(win)
{
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 (e.isButtonAxis) {
return getButtonAxis(e.device, e.high, e.low);
} else {
}
else {
return getDeviceAxis(e.device, e.axis);
}
}
@ -230,3 +233,5 @@ bool Input::getButtonRelease(const std::string& buttonName) const
}
return isReleased;
}
}

View File

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

View File

@ -8,6 +8,8 @@
#include "log.hpp"
namespace engine {
ResourceManager::ResourceManager()
{
#ifdef _MSC_VER
@ -21,7 +23,8 @@ ResourceManager::ResourceManager()
if (std::filesystem::is_directory(cwd / "res")) {
m_resourcesPath = cwd / "res";
} else {
}
else {
m_resourcesPath = cwd.parent_path() / "share" / "sdltest";
}
@ -32,6 +35,8 @@ ResourceManager::ResourceManager()
if (std::filesystem::is_directory(m_resourcesPath) == false) {
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()
@ -73,3 +78,5 @@ std::filesystem::path ResourceManager::getFilePath(const std::string& name)
{
return m_resourcesPath / name;
}
}

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
#include "resources/shader.hpp"
#include <glad/glad.h>
#include "log.hpp"
#include <log.hpp>
#include "gfx_device.hpp"
#include <string>
#include <fstream>
@ -24,200 +24,27 @@ static std::unique_ptr<std::vector<char>> readFile(const char * path)
return buf;
}
static GLuint compile(const char *path, GLenum type)
{
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;
namespace engine::resources {
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();
const std::string fragmentShaderPath = (resPath.parent_path()/std::filesystem::path(resPath.stem().string() + ".frag")).string();
GLuint vs = compile(vertexShaderPath.c_str(), GL_VERTEX_SHADER);
GLuint fs = compile(fragmentShaderPath.c_str(), GL_FRAGMENT_SHADER);
m_program = glCreateProgram();
glAttachShader(m_program, vs);
glAttachShader(m_program, fs);
glLinkProgram(m_program);
glValidateProgram(m_program);
gfx::VertexFormat vertexFormat {};
vertexFormat.stride = 8 * sizeof(float);
vertexFormat.attributeDescriptions.emplace_back(0, gfx::VertexAttribFormat::VEC3, 0); // pos
vertexFormat.attributeDescriptions.emplace_back(1, gfx::VertexAttribFormat::VEC3, sizeof(glm::vec3)); // norm
vertexFormat.attributeDescriptions.emplace_back(2, gfx::VertexAttribFormat::VEC2, sizeof(glm::vec3) + sizeof(glm::vec3)); // uv
// flag shader objects for deletion, this does not take effect until the program is deleted
glDeleteShader(vs);
glDeleteShader(fs);
const std::string vertexShaderPath = (resPath.parent_path()/std::filesystem::path(resPath.stem().string() + ".vert.spv")).string();
const std::string fragmentShaderPath = (resPath.parent_path()/std::filesystem::path(resPath.stem().string() + ".frag.spv")).string();
GLint linked, validated;
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);
}
m_pipeline = gfxdev->createPipeline(vertexShaderPath.c_str(), fragmentShaderPath.c_str(), vertexFormat, sizeof(UniformBuffer));
}
Shader::~Shader()
{
glDeleteProgram(m_program);
}
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;
gfxdev->destroyPipeline(m_pipeline);
}
}

View File

@ -7,7 +7,7 @@
#include <vector>
namespace resources {
namespace engine::resources {
// -1 means invalid / no bind
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;
}
const size_t size = x * y * n;
const size_t size = (size_t)x * (size_t)y * (size_t)n;
texbuf.resize(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);
texbuf.resize(end);
fseek(fp, tex_data_offset, SEEK_SET);
fseek(fp, (long)tex_data_offset, SEEK_SET);
fread(texbuf.data(), 1, end, fp);
fclose(fp);

View File

@ -7,6 +7,8 @@
#include "components/mesh_renderer.hpp"
#include "components/text_ui_renderer.hpp"
#include "gfx_device.hpp"
#include <glm/mat4x4.hpp>
#include <iostream>
@ -14,16 +16,12 @@
#include "log.hpp"
namespace engine {
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()
{
}
@ -50,12 +48,12 @@ void SceneRoot::updateStuff()
// render
for (const auto& [c, t] : compList.cameras) {
for (const auto& [c, camt] : compList.cameras) {
for (int id : m_activeCameras) {
if (c->getID() == id) {
c->updateCam(t);
for (const auto& [c, t] : compList.renderers) {
c->render(t);
c->updateCam(camt);
for (const auto& [ren, ren_t] : compList.renderers) {
ren->render(ren_t);
}
break;
@ -88,3 +86,5 @@ void SceneRoot::deactivateCam(int id)
}
}
}
}

View File

@ -1,17 +1,15 @@
#include "window.hpp"
#include <glad/glad.h>
#include "log.hpp"
#include <iostream>
#include <stdexcept>
#ifdef ENGINE_BUILD_VULKAN
#include <SDL2/SDL_vulkan.h>
#endif
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
@ -28,9 +26,15 @@ Window::Window(const std::string& title) : m_title(title)
m_lastFrameStamp = m_startTime - 1;
m_avgFpsStart = m_startTime;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
Uint32 windowFlags = SDL_WINDOW_SHOWN;
#ifdef ENGINE_BUILD_VULKAN
windowFlags |= SDL_WINDOW_VULKAN;
#endif
if (m_resizable) {
windowFlags |= SDL_WINDOW_RESIZABLE;
}
// create the window
m_handle = SDL_CreateWindow(
@ -38,7 +42,7 @@ Window::Window(const std::string& title) : m_title(title)
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
static_cast<int>(m_winSize.x),
static_cast<int>(m_winSize.y),
SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI);
windowFlags);
if (m_handle == NULL) {
SDL_Quit();
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;
SDL_SetWindowMinimumSize(m_handle, WINDOWED_MIN_WIDTH, WINDOWED_MIN_HEIGHT);
/*
m_glContext = SDL_GL_CreateContext(m_handle);
if (m_glContext == NULL) {
SDL_DestroyWindow(m_handle);
@ -66,14 +71,14 @@ Window::Window(const std::string& title) : m_title(title)
SDL_Quit();
throw std::runtime_error("Unable to initialise GLAD");
}
*/
onResize(m_winSize.x, m_winSize.y);
// onResize(m_winSize.x, m_winSize.y);
}
Window::~Window()
{
SDL_GL_DeleteContext(m_glContext);
SDL_DestroyWindow(m_handle);
SDL_Quit();
}
@ -86,13 +91,6 @@ void Window::onResize(Sint32 width, Sint32 height)
m_winSize.x = static_cast<int>(width);
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;
}
@ -103,8 +101,8 @@ void Window::resetInputDeltas()
m_keyboard.deltas.fill(ButtonDelta::SAME);
m_mouse.deltas.fill(ButtonDelta::SAME);
m_mouse.dx = 0.0f;
m_mouse.dy = 0.0f;
m_mouse.dx = 0;
m_mouse.dy = 0;
m_mouse.xscroll = 0.0f;
m_mouse.yscroll = 0.0f;
}
@ -157,14 +155,14 @@ void Window::onMouseButtonEvent(SDL_MouseButtonEvent &e)
button = inputs::MouseButton::M_X2;
break;
}
bool buttonWasDown = m_mouse.buttons[static_cast<int>(button)];
int buttonIndex = static_cast<int>(button);
bool buttonWasDown = m_mouse.buttons.at(buttonIndex);
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)
// 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) {
m_mouse.deltas[static_cast<int>(button)] = buttonIsDown ? ButtonDelta::PRESSED : ButtonDelta::RELEASED;
if (m_mouse.deltas[buttonIndex] == ButtonDelta::SAME) {
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) {
m_mouse.xscroll = e.preciseX;
m_mouse.yscroll = e.preciseY;
} else { // flipped
}
else { // flipped
m_mouse.xscroll = -e.preciseX;
m_mouse.yscroll = -e.preciseY;
}
@ -190,31 +189,23 @@ void Window::onMouseWheelEvent(SDL_MouseWheelEvent &e)
// public methods
SDL_Window* Window::getHandle() const
{
return m_handle;
}
std::string Window::getTitle() const
{
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++;
uint64_t currentFrameStamp = getNanos();
m_lastFrameTime = currentFrameStamp - m_lastFrameStamp;
m_lastFrameStamp = currentFrameStamp;
}
void Window::getInputAndEvents()
{
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)
{
SDL_SetWindowTitle(m_handle, title.c_str());
@ -314,6 +288,7 @@ bool Window::isRunning() const
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) {
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);
}
}
}
void Window::toggleFullscreen()
{
@ -341,7 +317,8 @@ bool Window::setRelativeMouseMode(bool enabled)
int code = SDL_SetRelativeMouseMode(static_cast<SDL_bool>(enabled));
if (code != 0) {
throw std::runtime_error("Unable to set relative mouse mode");
} else {
}
else {
return true;
}
}
@ -435,7 +412,8 @@ uint64_t Window::getNanos() const
count = SDL_GetPerformanceCounter();
if (m_counterFreq == BILLION) {
return count;
} else {
}
else {
return count * (BILLION / m_counterFreq);
}
}
@ -484,25 +462,12 @@ bool Window::infoBox(const std::string& title, const std::string& msg)
if (isFullscreen() == false) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, title.c_str(), msg.c_str(), m_handle);
return true;
} else {
}
else {
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 */
// 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);
}
}