mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Merge pull request #2 from bailwillharr/vulkan
Merge vulkan into master
This commit is contained in:
commit
98e49448ad
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -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
|
||||
|
@ -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
3
TODO
@ -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
1
dependencies/VulkanMemoryAllocator
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c351692490513cdb0e5a2c925aaf7ea4a9b672f4
|
1
dependencies/volk
vendored
Submodule
1
dependencies/volk
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 121a4584f69056d2c6db2eb4104650ce749d4c72
|
@ -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 {
|
||||
|
||||
|
@ -2,42 +2,46 @@
|
||||
|
||||
#include "engine_api.h"
|
||||
|
||||
class Object;
|
||||
class Window;
|
||||
class Input;
|
||||
class ResourceManager;
|
||||
namespace engine {
|
||||
class Window;
|
||||
class Input;
|
||||
|
||||
class ENGINE_API Component {
|
||||
class Object;
|
||||
class ResourceManager;
|
||||
|
||||
public:
|
||||
class ENGINE_API Component {
|
||||
|
||||
public:
|
||||
|
||||
enum class TypeEnum {
|
||||
TRANSFORM,
|
||||
CAMERA,
|
||||
RENDERER,
|
||||
UI,
|
||||
CUSTOM,
|
||||
};
|
||||
|
||||
Component(Object* parent, TypeEnum type);
|
||||
Component(const Component&) = delete;
|
||||
Component& operator=(const Component&) = delete;
|
||||
virtual ~Component() = 0;
|
||||
|
||||
int getID();
|
||||
TypeEnum getType();
|
||||
|
||||
Object& parent;
|
||||
|
||||
protected:
|
||||
engine::Window& win;
|
||||
engine::Input& inp;
|
||||
ResourceManager& res;
|
||||
|
||||
private:
|
||||
static int s_next_component_id;
|
||||
|
||||
int m_id = s_next_component_id;
|
||||
TypeEnum m_type;
|
||||
|
||||
enum class TypeEnum {
|
||||
TRANSFORM,
|
||||
CAMERA,
|
||||
RENDERER,
|
||||
UI,
|
||||
CUSTOM,
|
||||
};
|
||||
|
||||
Component(Object* parent, TypeEnum type);
|
||||
Component(const Component&) = delete;
|
||||
Component& operator=(const Component&) = delete;
|
||||
virtual ~Component() = 0;
|
||||
|
||||
int getID();
|
||||
TypeEnum getType();
|
||||
|
||||
Object& parent;
|
||||
|
||||
protected:
|
||||
Window& win;
|
||||
Input& inp;
|
||||
ResourceManager& res;
|
||||
|
||||
private:
|
||||
static int s_next_component_id;
|
||||
|
||||
int m_id = s_next_component_id;
|
||||
TypeEnum m_type;
|
||||
|
||||
};
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
|
||||
namespace components {
|
||||
namespace engine::components {
|
||||
|
||||
class ENGINE_API CustomComponent : public Component {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -2,21 +2,50 @@
|
||||
|
||||
#include "engine_api.h"
|
||||
|
||||
#include "engine.hpp"
|
||||
#include "gfx.hpp"
|
||||
|
||||
class Window;
|
||||
#include <memory>
|
||||
|
||||
namespace engine::gfx {
|
||||
struct SDL_Window;
|
||||
|
||||
namespace engine {
|
||||
|
||||
struct ENGINE_API Device {
|
||||
class ENGINE_API GFXDevice {
|
||||
|
||||
Device(AppInfo appInfo, const Window& window);
|
||||
~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:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl{};
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
|
||||
};
|
||||
|
||||
extern GFXDevice* gfxdev;
|
||||
|
||||
}
|
||||
|
@ -9,81 +9,85 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
class Window;
|
||||
namespace engine {
|
||||
|
||||
enum class InputDevice : int {
|
||||
MOUSE,
|
||||
KEYBOARD,
|
||||
CONTROLLER,
|
||||
SIZE
|
||||
};
|
||||
class Window;
|
||||
|
||||
// This class should be used to get platform/input-device independent input
|
||||
class ENGINE_API Input {
|
||||
|
||||
public:
|
||||
|
||||
// requires a window reference to get input from
|
||||
Input(const Window& win);
|
||||
Input(const Input&) = delete;
|
||||
Input& operator=(const Input&) = delete;
|
||||
~Input();
|
||||
|
||||
// Add a mouse input
|
||||
void addInputButton(const std::string& name, inputs::MouseButton button);
|
||||
void addInputAxis(const std::string& name, inputs::MouseAxis axis);
|
||||
void addInputButtonAsAxis(const std::string& name, inputs::MouseButton high, inputs::MouseButton low);
|
||||
// Add a keyboard input
|
||||
void addInputButton(const std::string& name, inputs::Key button);
|
||||
void addInputButtonAsAxis(const std::string& name, inputs::Key high, inputs::Key low);
|
||||
|
||||
void delInputButton(int index);
|
||||
void delInputAxis(int index);
|
||||
|
||||
void setDeviceActive(enum InputDevice device, bool active);
|
||||
bool getDeviceActive(enum InputDevice device) const;
|
||||
|
||||
float getAxis(const std::string& axisName) const;
|
||||
bool getButton(const std::string& buttonName) const;
|
||||
bool getButtonPress(const std::string& buttonName) const;
|
||||
bool getButtonRelease(const std::string& buttonName) const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
struct ButtonEntry {
|
||||
std::string name;
|
||||
enum InputDevice device;
|
||||
int button; // enumeration of device buttons or axes
|
||||
enum class InputDevice : int {
|
||||
MOUSE,
|
||||
KEYBOARD,
|
||||
CONTROLLER,
|
||||
SIZE
|
||||
};
|
||||
|
||||
struct AxisEntry {
|
||||
std::string name;
|
||||
enum InputDevice device;
|
||||
int axis;
|
||||
bool isButtonAxis;
|
||||
int high;
|
||||
int low;
|
||||
// This class should be used to get platform/input-device independent input
|
||||
class ENGINE_API Input {
|
||||
|
||||
public:
|
||||
|
||||
// requires a window reference to get input from
|
||||
Input(const Window& win);
|
||||
Input(const Input&) = delete;
|
||||
Input& operator=(const Input&) = delete;
|
||||
~Input();
|
||||
|
||||
// Add a mouse input
|
||||
void addInputButton(const std::string& name, inputs::MouseButton button);
|
||||
void addInputAxis(const std::string& name, inputs::MouseAxis axis);
|
||||
void addInputButtonAsAxis(const std::string& name, inputs::MouseButton high, inputs::MouseButton low);
|
||||
// Add a keyboard input
|
||||
void addInputButton(const std::string& name, inputs::Key button);
|
||||
void addInputButtonAsAxis(const std::string& name, inputs::Key high, inputs::Key low);
|
||||
|
||||
void delInputButton(int index);
|
||||
void delInputAxis(int index);
|
||||
|
||||
void setDeviceActive(enum InputDevice device, bool active);
|
||||
bool getDeviceActive(enum InputDevice device) const;
|
||||
|
||||
float getAxis(const std::string& axisName) const;
|
||||
bool getButton(const std::string& buttonName) const;
|
||||
bool getButtonPress(const std::string& buttonName) const;
|
||||
bool getButtonRelease(const std::string& buttonName) const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
struct ButtonEntry {
|
||||
std::string name;
|
||||
enum InputDevice device;
|
||||
int button; // enumeration of device buttons or axes
|
||||
};
|
||||
|
||||
struct AxisEntry {
|
||||
std::string name;
|
||||
enum InputDevice device;
|
||||
int axis;
|
||||
bool isButtonAxis;
|
||||
int high;
|
||||
int low;
|
||||
};
|
||||
|
||||
const Window& m_win;
|
||||
|
||||
std::vector<struct ButtonEntry> m_buttonEntries;
|
||||
std::vector<struct AxisEntry> m_axisEntries;
|
||||
|
||||
std::array<bool, static_cast<int>(InputDevice::SIZE)> m_enabledDevices;
|
||||
|
||||
// private methods
|
||||
|
||||
float getDeviceAxis(enum InputDevice device, int axis) const;
|
||||
bool getDeviceButton(enum InputDevice device, int button) const;
|
||||
bool getDeviceButtonDown(enum InputDevice device, int button) const;
|
||||
bool getDeviceButtonUp(enum InputDevice device, int button) const;
|
||||
|
||||
float getButtonAxis(enum InputDevice device, int high, int low) const;
|
||||
|
||||
void addInputButton(const std::string& name, InputDevice device, int button);
|
||||
void addInputAxis(const std::string& name, InputDevice device, int axis);
|
||||
void addInputButtonAsAxis(const std::string& name, InputDevice device, int high, int low);
|
||||
|
||||
};
|
||||
|
||||
const Window& m_win;
|
||||
|
||||
std::vector<struct ButtonEntry> m_buttonEntries;
|
||||
std::vector<struct AxisEntry> m_axisEntries;
|
||||
|
||||
std::array<bool, static_cast<int>(InputDevice::SIZE)> m_enabledDevices;
|
||||
|
||||
// private methods
|
||||
|
||||
float getDeviceAxis(enum InputDevice device, int axis) const;
|
||||
bool getDeviceButton(enum InputDevice device, int button) const;
|
||||
bool getDeviceButtonDown(enum InputDevice device, int button) const;
|
||||
bool getDeviceButtonUp(enum InputDevice device, int button) const;
|
||||
|
||||
float getButtonAxis(enum InputDevice device, int high, int low) const;
|
||||
|
||||
void addInputButton(const std::string& name, InputDevice device, int button);
|
||||
void addInputAxis(const std::string& name, InputDevice device, int axis);
|
||||
void addInputButtonAsAxis(const std::string& name, InputDevice device, int high, int low);
|
||||
|
||||
};
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
// Keyboard scancodes, taken from SDL_scancode.h
|
||||
|
||||
namespace inputs {
|
||||
namespace engine::inputs {
|
||||
|
||||
enum class Key : int {
|
||||
UNKNOWN = 0,
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace inputs {
|
||||
namespace engine::inputs {
|
||||
|
||||
enum class MouseButton : int {
|
||||
M_LEFT,
|
||||
|
@ -6,135 +6,140 @@
|
||||
|
||||
#include "transform.hpp"
|
||||
|
||||
#include "components/component.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
class Window;
|
||||
class Input;
|
||||
class ResourceManager;
|
||||
namespace engine {
|
||||
class Window;
|
||||
class Input;
|
||||
class ResourceManager;
|
||||
|
||||
class SceneRoot;
|
||||
class Component;
|
||||
class SceneRoot;
|
||||
class Component;
|
||||
|
||||
namespace components {
|
||||
class Transform;
|
||||
class Camera;
|
||||
class Renderer;
|
||||
class UI;
|
||||
class CustomComponent;
|
||||
}
|
||||
namespace components {
|
||||
class Camera;
|
||||
class Renderer;
|
||||
class UI;
|
||||
class CustomComponent;
|
||||
}
|
||||
|
||||
struct GameIO {
|
||||
Window * const win;
|
||||
Input * const input;
|
||||
ResourceManager * const resMan;
|
||||
};
|
||||
|
||||
// This object lives until it is deleted by its parent(s) or finally when the "Scene" is destroyed.
|
||||
// Therefore it is safe to return raw pointers
|
||||
class ENGINE_API Object {
|
||||
|
||||
public:
|
||||
Object(std::string name, Object* parent, SceneRoot& root, struct GameIO things);
|
||||
Object(const Object&) = delete;
|
||||
Object& operator=(const Object&) = delete;
|
||||
~Object();
|
||||
|
||||
Window& win;
|
||||
Input& inp;
|
||||
ResourceManager& res;
|
||||
|
||||
SceneRoot& root;
|
||||
|
||||
std::string getName();
|
||||
|
||||
Object* getParent();
|
||||
|
||||
Object* getChild(std::string name);
|
||||
std::vector<Object*> getChildren();
|
||||
|
||||
Object* createChild(std::string name);
|
||||
void deleteChild(std::string name);
|
||||
|
||||
void printTree(int level = 0);
|
||||
|
||||
// Returns the component of type T
|
||||
// Returns nullptr if the component is not found.
|
||||
template<class T> T* getComponent();
|
||||
|
||||
// returns the component added
|
||||
template<class T> T* createComponent();
|
||||
|
||||
template<class T> void deleteComponent();
|
||||
|
||||
struct CompList {
|
||||
std::vector<std::pair<components::Camera*, glm::mat4>> cameras;
|
||||
std::vector<std::pair<components::Renderer*, glm::mat4>> renderers;
|
||||
std::vector<std::pair<components::UI*, glm::mat4>> uis;
|
||||
std::vector<std::pair<components::CustomComponent*, glm::mat4>> customs;
|
||||
struct GameIO {
|
||||
Window* win;
|
||||
Input* input;
|
||||
ResourceManager* resMan;
|
||||
};
|
||||
|
||||
// Adds to the provided vector all components of this object and of its children recursively.
|
||||
// Ignores 'Transform'
|
||||
void getAllSubComponents(struct CompList& compList, glm::mat4 t);
|
||||
|
||||
Transform transform;
|
||||
// This object lives until it is deleted by its parent(s) or finally when the "Scene" is destroyed.
|
||||
// Therefore it is safe to return raw pointers
|
||||
class ENGINE_API Object {
|
||||
|
||||
private:
|
||||
static int s_object_count;
|
||||
int m_id = s_object_count;
|
||||
std::string m_name;
|
||||
public:
|
||||
Object(std::string name, Object* parent, SceneRoot& root, struct GameIO things);
|
||||
Object(const Object&) = delete;
|
||||
Object& operator=(const Object&) = delete;
|
||||
~Object();
|
||||
|
||||
std::list<std::unique_ptr<Object>> m_children{};
|
||||
std::list<std::unique_ptr<Component>> m_components{};
|
||||
Window& win;
|
||||
Input& inp;
|
||||
ResourceManager& res;
|
||||
|
||||
// If nullptr, this is the root object
|
||||
Object* const m_parent;
|
||||
struct GameIO m_gameIO;
|
||||
|
||||
};
|
||||
SceneRoot& root;
|
||||
|
||||
// implementation of template functions
|
||||
std::string getName();
|
||||
|
||||
template<class T> T* Object::getComponent()
|
||||
{
|
||||
if (std::is_base_of<Component, T>::value == false) {
|
||||
throw std::runtime_error("getComponent() error: specified type is not a subclass of 'Component'");
|
||||
}
|
||||
for (const auto& component : m_components) {
|
||||
T* derived = dynamic_cast<T*>(component.get());
|
||||
if (derived != nullptr) {
|
||||
return derived;
|
||||
Object* getParent();
|
||||
|
||||
Object* getChild(std::string name);
|
||||
std::vector<Object*> getChildren();
|
||||
|
||||
Object* createChild(std::string name);
|
||||
void deleteChild(std::string name);
|
||||
|
||||
void printTree(int level = 0);
|
||||
|
||||
// Returns the component of type T
|
||||
// Returns nullptr if the component is not found.
|
||||
template<class T> T* getComponent();
|
||||
|
||||
// returns the component added
|
||||
template<class T> T* createComponent();
|
||||
|
||||
template<class T> void deleteComponent();
|
||||
|
||||
struct CompList {
|
||||
std::vector<std::pair<components::Camera*, glm::mat4>> cameras;
|
||||
std::vector<std::pair<components::Renderer*, glm::mat4>> renderers;
|
||||
std::vector<std::pair<components::UI*, glm::mat4>> uis;
|
||||
std::vector<std::pair<components::CustomComponent*, glm::mat4>> customs;
|
||||
};
|
||||
|
||||
// Adds to the provided vector all components of this object and of its children recursively.
|
||||
// Ignores 'Transform'
|
||||
void getAllSubComponents(struct CompList& compList, glm::mat4 t);
|
||||
|
||||
Transform transform;
|
||||
|
||||
private:
|
||||
static int s_object_count;
|
||||
int m_id = s_object_count;
|
||||
std::string m_name;
|
||||
|
||||
std::list<std::unique_ptr<Object>> m_children{};
|
||||
std::list<std::unique_ptr<Component>> m_components{};
|
||||
|
||||
// If nullptr, this is the root object
|
||||
Object* const m_parent;
|
||||
struct GameIO m_gameIO;
|
||||
|
||||
};
|
||||
|
||||
// implementation of template functions
|
||||
|
||||
template<class T> T* Object::getComponent()
|
||||
{
|
||||
if (std::is_base_of<Component, T>::value == false) {
|
||||
throw std::runtime_error("getComponent() error: specified type is not a subclass of 'Component'");
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T> T* Object::createComponent()
|
||||
{
|
||||
if (std::is_base_of<Component, T>::value == false) {
|
||||
throw std::runtime_error("addComponent() error: specified type is not a subclass of 'Component'");
|
||||
}
|
||||
if (getComponent<T>() != nullptr) {
|
||||
throw std::runtime_error("addComponent() error: attempt to add component of a type already present");
|
||||
}
|
||||
m_components.emplace_back(std::make_unique<T>(this));
|
||||
return dynamic_cast<T*>(m_components.back().get());
|
||||
}
|
||||
|
||||
template<class T> void Object::deleteComponent()
|
||||
{
|
||||
if (std::is_base_of<Component, T>::value == false) {
|
||||
throw std::runtime_error("deleteComponent() error: specified type is not a subclass of 'Component'");
|
||||
}
|
||||
for (auto itr = m_components.begin(); itr != m_components.end(); ++itr) {
|
||||
if (dynamic_cast<T*>((*itr).get()) != nullptr) {
|
||||
m_components.erase(itr);
|
||||
return;
|
||||
for (const auto& component : m_components) {
|
||||
T* derived = dynamic_cast<T*>(component.get());
|
||||
if (derived != nullptr) {
|
||||
return derived;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
throw std::runtime_error("deleteComponent() error: attempt to delete component that is not present.");
|
||||
|
||||
template <class T> T* Object::createComponent()
|
||||
{
|
||||
if (std::is_base_of<Component, T>::value == false) {
|
||||
throw std::runtime_error("addComponent() error: specified type is not a subclass of 'Component'");
|
||||
}
|
||||
if (getComponent<T>() != nullptr) {
|
||||
throw std::runtime_error("addComponent() error: attempt to add component of a type already present");
|
||||
}
|
||||
m_components.emplace_back(std::make_unique<T>(this));
|
||||
return dynamic_cast<T*>(m_components.back().get());
|
||||
}
|
||||
|
||||
template<class T> void Object::deleteComponent()
|
||||
{
|
||||
if (std::is_base_of<Component, T>::value == false) {
|
||||
throw std::runtime_error("deleteComponent() error: specified type is not a subclass of 'Component'");
|
||||
}
|
||||
for (auto itr = m_components.begin(); itr != m_components.end(); ++itr) {
|
||||
if (dynamic_cast<T*>((*itr).get()) != nullptr) {
|
||||
m_components.erase(itr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("deleteComponent() error: attempt to delete component that is not present.");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,73 +9,77 @@
|
||||
|
||||
// Doesn't own resources, only holds weak_ptrs
|
||||
|
||||
class ENGINE_API ResourceManager {
|
||||
namespace engine {
|
||||
|
||||
public:
|
||||
ResourceManager();
|
||||
ResourceManager(const ResourceManager&) = delete;
|
||||
ResourceManager& operator=(const ResourceManager&) = delete;
|
||||
~ResourceManager() = default;
|
||||
class ENGINE_API ResourceManager {
|
||||
|
||||
public:
|
||||
ResourceManager();
|
||||
ResourceManager(const ResourceManager&) = delete;
|
||||
ResourceManager& operator=(const ResourceManager&) = delete;
|
||||
~ResourceManager() = default;
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> create(const std::string& name);
|
||||
|
||||
// creates the resource if it is not in the map or the weak_ptr has expired
|
||||
template <class T>
|
||||
std::shared_ptr<T> get(const std::string& name);
|
||||
|
||||
std::unique_ptr<std::string> getResourcesListString();
|
||||
|
||||
std::vector<std::weak_ptr<Resource>> getAllResourcesOfType(const std::string& type);
|
||||
|
||||
std::filesystem::path getFilePath(const std::string& name);
|
||||
|
||||
private:
|
||||
std::filesystem::path m_resourcesPath;
|
||||
std::unordered_map<std::string, std::weak_ptr<Resource>> m_resources;
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> create(const std::string& name);
|
||||
std::shared_ptr<T> ResourceManager::create(const std::string& name)
|
||||
{
|
||||
if (std::is_base_of<Resource, T>::value == false) {
|
||||
throw std::runtime_error("ResourceManager::create() error: specified type is not a subclass of 'Resource'");
|
||||
}
|
||||
auto resource = std::make_shared<T>(getFilePath(name));
|
||||
m_resources.emplace(name, std::dynamic_pointer_cast<Resource>(resource));
|
||||
return resource;
|
||||
}
|
||||
|
||||
// creates the resource if it is not in the map or the weak_ptr has expired
|
||||
template <class T>
|
||||
std::shared_ptr<T> get(const std::string& name);
|
||||
std::shared_ptr<T> ResourceManager::get(const std::string& name)
|
||||
{
|
||||
|
||||
std::unique_ptr<std::string> getResourcesListString();
|
||||
if (std::is_base_of<Resource, T>::value == false) {
|
||||
throw std::runtime_error("ResourceManager::get() error: specified type is not a subclass of 'Resource'");
|
||||
}
|
||||
|
||||
std::vector<std::weak_ptr<Resource>> getAllResourcesOfType(const std::string& type);
|
||||
if (m_resources.contains(name)) {
|
||||
|
||||
std::filesystem::path getFilePath(const std::string& name);
|
||||
std::weak_ptr<Resource> res = m_resources.at(name);
|
||||
|
||||
private:
|
||||
std::filesystem::path m_resourcesPath;
|
||||
std::unordered_map<std::string, std::weak_ptr<Resource>> m_resources;
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> ResourceManager::create(const std::string& name)
|
||||
{
|
||||
if (std::is_base_of<Resource, T>::value == false) {
|
||||
throw std::runtime_error("ResourceManager::create() error: specified type is not a subclass of 'Resource'");
|
||||
}
|
||||
auto resource = std::make_shared<T>(getFilePath(name));
|
||||
m_resources.emplace(name, std::dynamic_pointer_cast<Resource>(resource));
|
||||
return resource;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> ResourceManager::get(const std::string& name)
|
||||
{
|
||||
|
||||
if (std::is_base_of<Resource, T>::value == false) {
|
||||
throw std::runtime_error("ResourceManager::get() error: specified type is not a subclass of 'Resource'");
|
||||
}
|
||||
|
||||
if (m_resources.contains(name)) {
|
||||
|
||||
std::weak_ptr<Resource> res = m_resources.at(name);
|
||||
|
||||
if (res.expired() == false) {
|
||||
// resource definitely exists
|
||||
auto castedSharedPtr = std::dynamic_pointer_cast<T>(res.lock());
|
||||
if (castedSharedPtr == nullptr) {
|
||||
throw std::runtime_error("error: attempt to get Resource which already exists as another type");
|
||||
if (res.expired() == false) {
|
||||
// resource definitely exists
|
||||
auto castedSharedPtr = std::dynamic_pointer_cast<T>(res.lock());
|
||||
if (castedSharedPtr == nullptr) {
|
||||
throw std::runtime_error("error: attempt to get Resource which already exists as another type");
|
||||
}
|
||||
else {
|
||||
return castedSharedPtr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return castedSharedPtr;
|
||||
// Resource in map but no longer exists. Delete it.
|
||||
m_resources.erase(name);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
// Resource in map but no longer exists. Delete it.
|
||||
m_resources.erase(name);
|
||||
}
|
||||
|
||||
return create<T>(name);
|
||||
|
||||
}
|
||||
|
||||
return create<T>(name);
|
||||
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace resources {
|
||||
namespace engine::resources {
|
||||
|
||||
class ENGINE_API Font : public Resource {
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -5,20 +5,24 @@
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
class ENGINE_API Resource {
|
||||
namespace engine {
|
||||
|
||||
public:
|
||||
Resource(const std::filesystem::path& resPath, const std::string& type);
|
||||
Resource(const Resource&) = delete;
|
||||
Resource& operator=(const Resource&) = delete;
|
||||
virtual ~Resource() = 0;
|
||||
class ENGINE_API Resource {
|
||||
|
||||
std::string getType();
|
||||
public:
|
||||
Resource(const std::filesystem::path& resPath, const std::string& type);
|
||||
Resource(const Resource&) = delete;
|
||||
Resource& operator=(const Resource&) = delete;
|
||||
virtual ~Resource() = 0;
|
||||
|
||||
protected:
|
||||
std::filesystem::path m_resourcePath;
|
||||
std::string getType();
|
||||
|
||||
private:
|
||||
const std::string m_type;
|
||||
protected:
|
||||
std::filesystem::path m_resourcePath;
|
||||
|
||||
};
|
||||
private:
|
||||
const std::string m_type;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
namespace resources {
|
||||
namespace engine::resources {
|
||||
|
||||
class ENGINE_API Texture : public Resource {
|
||||
|
||||
|
@ -6,24 +6,27 @@
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
// Holds everything you would expect to find in a game scene
|
||||
class ENGINE_API SceneRoot : public Object {
|
||||
namespace engine {
|
||||
|
||||
public:
|
||||
// create a new empty scene
|
||||
SceneRoot(struct GameIO things);
|
||||
SceneRoot(const std::filesystem::path& file, struct GameIO things);
|
||||
// Holds everything you would expect to find in a game scene
|
||||
class ENGINE_API SceneRoot : public Object {
|
||||
|
||||
SceneRoot(const SceneRoot&) = delete;
|
||||
SceneRoot& operator=(const SceneRoot&) = delete;
|
||||
~SceneRoot();
|
||||
public:
|
||||
// create a new empty scene
|
||||
SceneRoot(struct GameIO things);
|
||||
|
||||
void updateStuff();
|
||||
SceneRoot(const SceneRoot&) = delete;
|
||||
SceneRoot& operator=(const SceneRoot&) = delete;
|
||||
~SceneRoot();
|
||||
|
||||
void activateCam(int id);
|
||||
void deactivateCam(int id);
|
||||
void updateStuff();
|
||||
|
||||
private:
|
||||
std::vector<int> m_activeCameras{};
|
||||
void activateCam(int id);
|
||||
void deactivateCam(int id);
|
||||
|
||||
};
|
||||
private:
|
||||
std::vector<int> m_activeCameras{};
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -6,12 +6,16 @@
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/ext/quaternion_float.hpp>
|
||||
|
||||
struct ENGINE_API Transform {
|
||||
namespace engine {
|
||||
|
||||
// Scale, rotate (XYZ), translate
|
||||
struct ENGINE_API Transform {
|
||||
|
||||
glm::vec3 position{0.0f};
|
||||
glm::quat rotation{};
|
||||
glm::vec3 scale{1.0f};
|
||||
// Scale, rotate (XYZ), translate
|
||||
|
||||
};
|
||||
glm::vec3 position{ 0.0f };
|
||||
glm::quat rotation{};
|
||||
glm::vec3 scale{ 1.0f };
|
||||
|
||||
};
|
||||
|
||||
}
|
18
include/util.hpp
Normal file
18
include/util.hpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -17,149 +17,136 @@
|
||||
|
||||
ENGINE_API extern const uint64_t BILLION;
|
||||
|
||||
class ENGINE_API Window {
|
||||
namespace engine {
|
||||
|
||||
public:
|
||||
Window(const std::string& title);
|
||||
Window(const Window&) = delete;
|
||||
Window& operator=(const Window&) = delete;
|
||||
~Window();
|
||||
class ENGINE_API Window {
|
||||
|
||||
// Return the title name
|
||||
std::string getTitle() const;
|
||||
public:
|
||||
Window(const std::string& title, bool resizable = true);
|
||||
Window(const Window&) = delete;
|
||||
Window& operator=(const Window&) = delete;
|
||||
~Window();
|
||||
|
||||
// Make this window the current OpenGL context.
|
||||
// This is already done in window initialisation.
|
||||
void makeContextCurrent();
|
||||
SDL_Window* getHandle() const;
|
||||
|
||||
// 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();
|
||||
// Return the title name
|
||||
std::string getTitle() const;
|
||||
|
||||
// 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;
|
||||
// Update the window state to capture any events that have occurred.
|
||||
// Run this on every frame.
|
||||
void getInputAndEvents();
|
||||
|
||||
glm::ivec2 getViewportSize();
|
||||
void setTitle(std::string title);
|
||||
|
||||
void setTitle(std::string title);
|
||||
// Hides the window (it will appear closed to the user).
|
||||
void hide();
|
||||
// Shows the window again.
|
||||
void show();
|
||||
// Raises the window above other windows and sets the input focus
|
||||
void focus();
|
||||
// Returns true if the window has focus
|
||||
bool hasFocus() const;
|
||||
|
||||
// Hides the window (it will appear closed to the user).
|
||||
void hide();
|
||||
// Shows the window again.
|
||||
void show();
|
||||
// Raises the window above other windows and sets the input focus
|
||||
void focus();
|
||||
// Returns true if the window has focus
|
||||
bool hasFocus() const;
|
||||
// Sets the close flag, check this with shouldClose()
|
||||
void setCloseFlag();
|
||||
// Returns true if the window should remain open
|
||||
bool isRunning() const;
|
||||
|
||||
// Sets the close flag, check this with shouldClose()
|
||||
void setCloseFlag();
|
||||
// Returns true if the window should remain open
|
||||
bool isRunning() const;
|
||||
void setFullscreen(bool fullscreen, bool exclusive = false);
|
||||
void toggleFullscreen();
|
||||
|
||||
void setFullscreen(bool fullscreen, bool exclusive=true);
|
||||
void toggleFullscreen();
|
||||
bool isFullscreen() const;
|
||||
|
||||
bool isFullscreen() const;
|
||||
// Relative mouse mode captures the cursor for FPS style use. Returns false if unsupported.
|
||||
bool setRelativeMouseMode(bool enabled);
|
||||
|
||||
// Relative mouse mode captures the cursor for FPS style use. Returns false if unsupported.
|
||||
bool setRelativeMouseMode(bool enabled);
|
||||
// returns true if relative mouse mode is enabled
|
||||
bool mouseCaptured();
|
||||
|
||||
// returns true if relative mouse mode is enabled
|
||||
bool mouseCaptured();
|
||||
// window events
|
||||
|
||||
// window events
|
||||
// Returns true if the window was just resized during the previous frame
|
||||
bool getWindowResized() const;
|
||||
// Set the window resized flag (to recalculate aspect ratios and such)
|
||||
inline void setResizedFlag()
|
||||
{
|
||||
m_justResized = true;
|
||||
}
|
||||
|
||||
// Returns true if the window was just resized during the previous frame
|
||||
bool getWindowResized() const;
|
||||
// Set the window resized flag (to recalculate aspect ratios and such)
|
||||
inline void setResizedFlag()
|
||||
{
|
||||
m_justResized = true;
|
||||
}
|
||||
// keyboard events
|
||||
|
||||
// keyboard events
|
||||
// returns true if key is down
|
||||
bool getKey(inputs::Key key) const;
|
||||
// returns true if key was just pressed
|
||||
bool getKeyPress(inputs::Key key) const;
|
||||
// returns true if key was just released
|
||||
bool getKeyRelease(inputs::Key key) const;
|
||||
|
||||
// returns true if key is down
|
||||
bool getKey(inputs::Key key) const;
|
||||
// returns true if key was just pressed
|
||||
bool getKeyPress(inputs::Key key) const;
|
||||
// returns true if key was just released
|
||||
bool getKeyRelease(inputs::Key key) const;
|
||||
// mouse events
|
||||
|
||||
// mouse events
|
||||
// returns true if button is down
|
||||
bool getButton(inputs::MouseButton button) const;
|
||||
// returns true if button was just pressed
|
||||
bool getButtonPress(inputs::MouseButton button) const;
|
||||
// returns true if button was just released
|
||||
bool getButtonRelease(inputs::MouseButton button) const;
|
||||
|
||||
// returns true if button is down
|
||||
bool getButton(inputs::MouseButton button) const;
|
||||
// returns true if button was just pressed
|
||||
bool getButtonPress(inputs::MouseButton button) const;
|
||||
// returns true if button was just released
|
||||
bool getButtonRelease(inputs::MouseButton button) const;
|
||||
// retrieves x coordinate of the mouse
|
||||
int getMouseX() const;
|
||||
// retrieves y coordinate of the mouse
|
||||
int getMouseY() const;
|
||||
// retrieves mouse x coordinate normalised for OpenGL
|
||||
float getMouseNormX() const;
|
||||
// retrieves mouse y coordinate normalised for OpenGL
|
||||
float getMouseNormY() const;
|
||||
// retrieves dx of the mouse since the last frame
|
||||
int getMouseDX() const;
|
||||
// retrieves dy of the mouse since the last frame
|
||||
int getMouseDY() const;
|
||||
// retrieves amount scrolled vertically
|
||||
float getMouseScrollX() const;
|
||||
// retrieves amount scrolled horizontally
|
||||
float getMouseScrollY() const;
|
||||
|
||||
// retrieves x coordinate of the mouse
|
||||
int getMouseX() const;
|
||||
// retrieves y coordinate of the mouse
|
||||
int getMouseY() const;
|
||||
// retrieves mouse x coordinate normalised for OpenGL
|
||||
float getMouseNormX() const;
|
||||
// retrieves mouse y coordinate normalised for OpenGL
|
||||
float getMouseNormY() const;
|
||||
// retrieves dx of the mouse since the last frame
|
||||
int getMouseDX() const;
|
||||
// retrieves dy of the mouse since the last frame
|
||||
int getMouseDY() const;
|
||||
// retrieves amount scrolled vertically
|
||||
float getMouseScrollX() const;
|
||||
// retrieves amount scrolled horizontally
|
||||
float getMouseScrollY() const;
|
||||
|
||||
// joystick/gamepad events (maybe), other misc events
|
||||
// joystick/gamepad events (maybe), other misc events
|
||||
|
||||
|
||||
|
||||
// returns the performance counter value in nanoseconds;
|
||||
uint64_t getNanos() const;
|
||||
// get the time recorded at the end of the last frame
|
||||
uint64_t getLastFrameStamp() const;
|
||||
// returns the performance counter value in nanoseconds;
|
||||
uint64_t getNanos() const;
|
||||
// get the time recorded at the end of the last frame
|
||||
uint64_t getLastFrameStamp() const;
|
||||
|
||||
// returns the number of frames elapsed since window creation
|
||||
uint64_t getFrameCount() const;
|
||||
uint64_t getStartTime() const;;
|
||||
float dt() const; // returns delta time in seconds
|
||||
uint64_t getFPS() const;
|
||||
uint64_t getAvgFPS() const;
|
||||
// returns the number of frames elapsed since window creation
|
||||
uint64_t getFrameCount() const;
|
||||
uint64_t getStartTime() const;;
|
||||
float dt() const; // returns delta time in seconds
|
||||
uint64_t getFPS() const;
|
||||
uint64_t getAvgFPS() const;
|
||||
|
||||
void resetAvgFPS();
|
||||
void resetAvgFPS();
|
||||
|
||||
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 void errorBox(const std::string& message);
|
||||
/* 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);
|
||||
};
|
||||
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,27 +4,31 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int Component::s_next_component_id = 0;
|
||||
namespace engine {
|
||||
|
||||
Component::Component(Object* parent, TypeEnum type) :
|
||||
m_type(type), parent(*parent),
|
||||
win(parent->win),
|
||||
inp(parent->inp),
|
||||
res(parent->res)
|
||||
{
|
||||
s_next_component_id++;
|
||||
}
|
||||
int Component::s_next_component_id = 0;
|
||||
|
||||
Component::~Component()
|
||||
{
|
||||
}
|
||||
Component::Component(Object* parent, TypeEnum type) :
|
||||
m_type(type), parent(*parent),
|
||||
win(parent->win),
|
||||
inp(parent->inp),
|
||||
res(parent->res)
|
||||
{
|
||||
s_next_component_id++;
|
||||
}
|
||||
|
||||
int Component::getID()
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
Component::~Component()
|
||||
{
|
||||
}
|
||||
|
||||
Component::TypeEnum Component::getType()
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
int Component::getID()
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
Component::TypeEnum Component::getType()
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include "components/custom.hpp"
|
||||
|
||||
namespace components {
|
||||
namespace engine::components {
|
||||
|
||||
CustomComponent::CustomComponent(Object* parent) : Component(parent, TypeEnum::CUSTOM)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
if (sscanf(version, "%d.%d.%d", major, minor, patch) != 3) {
|
||||
*major = 0;
|
||||
*minor = 0;
|
||||
*patch = 0;
|
||||
return false;
|
||||
Application::Application(const char* appName, const char* appVersion)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
79
src/gfx_device_null.cpp
Normal file
79
src/gfx_device_null.cpp
Normal 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
105
src/gfx_device_opengl45.cpp
Normal 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
297
src/input.cpp
297
src/input.cpp
@ -5,31 +5,33 @@
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
Input::Input(const Window &win) : m_win(win)
|
||||
{
|
||||
m_enabledDevices.fill(true);
|
||||
}
|
||||
namespace engine {
|
||||
|
||||
Input::~Input()
|
||||
{
|
||||
}
|
||||
Input::Input(const Window& win) : m_win(win)
|
||||
{
|
||||
m_enabledDevices.fill(true);
|
||||
}
|
||||
|
||||
// private methods
|
||||
Input::~Input()
|
||||
{
|
||||
}
|
||||
|
||||
float Input::getDeviceAxis(enum InputDevice device, int axis) const
|
||||
{
|
||||
switch (device) {
|
||||
// private methods
|
||||
|
||||
float Input::getDeviceAxis(enum InputDevice device, int axis) const
|
||||
{
|
||||
switch (device) {
|
||||
case InputDevice::MOUSE:
|
||||
switch (static_cast<inputs::MouseAxis>(axis)) {
|
||||
case inputs::MouseAxis::X:
|
||||
return static_cast<float>(m_win.getMouseDX());
|
||||
case inputs::MouseAxis::Y:
|
||||
return static_cast<float>(m_win.getMouseDY());
|
||||
case inputs::MouseAxis::X_SCR:
|
||||
return m_win.getMouseScrollX();
|
||||
case inputs::MouseAxis::Y_SCR:
|
||||
return m_win.getMouseScrollY();
|
||||
default: break;
|
||||
case inputs::MouseAxis::X:
|
||||
return static_cast<float>(m_win.getMouseDX());
|
||||
case inputs::MouseAxis::Y:
|
||||
return static_cast<float>(m_win.getMouseDY());
|
||||
case inputs::MouseAxis::X_SCR:
|
||||
return m_win.getMouseScrollX();
|
||||
case inputs::MouseAxis::Y_SCR:
|
||||
return m_win.getMouseScrollY();
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case InputDevice::KEYBOARD:
|
||||
@ -37,13 +39,13 @@ float Input::getDeviceAxis(enum InputDevice device, int axis) const
|
||||
case InputDevice::CONTROLLER:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error("Error getting device axis");
|
||||
}
|
||||
throw std::runtime_error("Error getting device axis");
|
||||
}
|
||||
|
||||
bool Input::getDeviceButton(enum InputDevice device, int button) const
|
||||
{
|
||||
switch (device) {
|
||||
bool Input::getDeviceButton(enum InputDevice device, int button) const
|
||||
{
|
||||
switch (device) {
|
||||
case InputDevice::MOUSE:
|
||||
return m_win.getButton(static_cast<inputs::MouseButton>(button));
|
||||
case InputDevice::KEYBOARD:
|
||||
@ -51,13 +53,13 @@ bool Input::getDeviceButton(enum InputDevice device, int button) const
|
||||
case InputDevice::CONTROLLER:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error("Error getting device button");
|
||||
}
|
||||
throw std::runtime_error("Error getting device button");
|
||||
}
|
||||
|
||||
bool Input::getDeviceButtonDown(enum InputDevice device, int button) const
|
||||
{
|
||||
switch (device) {
|
||||
bool Input::getDeviceButtonDown(enum InputDevice device, int button) const
|
||||
{
|
||||
switch (device) {
|
||||
case InputDevice::MOUSE:
|
||||
return m_win.getButtonPress(static_cast<enum inputs::MouseButton>(button));
|
||||
case InputDevice::KEYBOARD:
|
||||
@ -65,13 +67,13 @@ bool Input::getDeviceButtonDown(enum InputDevice device, int button) const
|
||||
case InputDevice::CONTROLLER:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error("Error getting device button");
|
||||
}
|
||||
throw std::runtime_error("Error getting device button");
|
||||
}
|
||||
|
||||
bool Input::getDeviceButtonUp(enum InputDevice device, int button) const
|
||||
{
|
||||
switch (device) {
|
||||
bool Input::getDeviceButtonUp(enum InputDevice device, int button) const
|
||||
{
|
||||
switch (device) {
|
||||
case InputDevice::MOUSE:
|
||||
return m_win.getButtonRelease(static_cast<enum inputs::MouseButton>(button));
|
||||
case InputDevice::KEYBOARD:
|
||||
@ -79,154 +81,157 @@ bool Input::getDeviceButtonUp(enum InputDevice device, int button) const
|
||||
case InputDevice::CONTROLLER:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error("Error getting device button");
|
||||
}
|
||||
throw std::runtime_error("Error getting device button");
|
||||
}
|
||||
|
||||
float Input::getButtonAxis(enum InputDevice device, int high, int low) const
|
||||
{
|
||||
float value = 0.0f;
|
||||
if (getDeviceButton(device, high)) value += 1.0f;
|
||||
if (low != 0) {
|
||||
if (getDeviceButton(device, low)) value += -1.0f;
|
||||
float Input::getButtonAxis(enum InputDevice device, int high, int low) const
|
||||
{
|
||||
float value = 0.0f;
|
||||
if (getDeviceButton(device, high)) value += 1.0f;
|
||||
if (low != 0) {
|
||||
if (getDeviceButton(device, low)) value += -1.0f;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// public methods
|
||||
// public methods
|
||||
|
||||
void Input::addInputButton(const std::string& name, InputDevice device, int button)
|
||||
{
|
||||
m_buttonEntries.push_back( { name, device, button } );
|
||||
}
|
||||
void Input::addInputButton(const std::string& name, InputDevice device, int button)
|
||||
{
|
||||
m_buttonEntries.push_back({ name, device, button });
|
||||
}
|
||||
|
||||
void Input::addInputAxis(const std::string& name, InputDevice device, int axis)
|
||||
{
|
||||
m_axisEntries.push_back( { name, device, axis, false, 0, 0 } );
|
||||
}
|
||||
void Input::addInputAxis(const std::string& name, InputDevice device, int axis)
|
||||
{
|
||||
m_axisEntries.push_back({ name, device, axis, false, 0, 0 });
|
||||
}
|
||||
|
||||
void Input::addInputButtonAsAxis(const std::string& name, InputDevice device, int high, int low)
|
||||
{
|
||||
m_axisEntries.push_back( { name, device, 0, true, high, low } );
|
||||
}
|
||||
void Input::addInputButtonAsAxis(const std::string& name, InputDevice device, int high, int low)
|
||||
{
|
||||
m_axisEntries.push_back({ name, device, 0, true, high, low });
|
||||
}
|
||||
|
||||
// OVERLOADS:
|
||||
// OVERLOADS:
|
||||
|
||||
// Add a mouse input
|
||||
void Input::addInputButton(const std::string& name, inputs::MouseButton button)
|
||||
{
|
||||
addInputButton(name, InputDevice::MOUSE, static_cast<int>(button));
|
||||
}
|
||||
// Add a mouse input
|
||||
void Input::addInputButton(const std::string& name, inputs::MouseButton button)
|
||||
{
|
||||
addInputButton(name, InputDevice::MOUSE, static_cast<int>(button));
|
||||
}
|
||||
|
||||
void Input::addInputAxis(const std::string& name, inputs::MouseAxis axis)
|
||||
{
|
||||
addInputAxis(name, InputDevice::MOUSE, static_cast<int>(axis));
|
||||
}
|
||||
void Input::addInputAxis(const std::string& name, inputs::MouseAxis axis)
|
||||
{
|
||||
addInputAxis(name, InputDevice::MOUSE, static_cast<int>(axis));
|
||||
}
|
||||
|
||||
void Input::addInputButtonAsAxis(const std::string& name, inputs::MouseButton high, inputs::MouseButton low)
|
||||
{
|
||||
addInputButtonAsAxis(name, InputDevice::MOUSE, static_cast<int>(high), static_cast<int>(low));
|
||||
}
|
||||
void Input::addInputButtonAsAxis(const std::string& name, inputs::MouseButton high, inputs::MouseButton low)
|
||||
{
|
||||
addInputButtonAsAxis(name, InputDevice::MOUSE, static_cast<int>(high), static_cast<int>(low));
|
||||
}
|
||||
|
||||
// Add a keyboard input (TODO: add KeyboardButton enum class)
|
||||
void Input::addInputButton(const std::string& name, inputs::Key button)
|
||||
{
|
||||
addInputButton(name, InputDevice::KEYBOARD, static_cast<int>(button));
|
||||
}
|
||||
// Add a keyboard input (TODO: add KeyboardButton enum class)
|
||||
void Input::addInputButton(const std::string& name, inputs::Key button)
|
||||
{
|
||||
addInputButton(name, InputDevice::KEYBOARD, static_cast<int>(button));
|
||||
}
|
||||
|
||||
void Input::addInputButtonAsAxis(const std::string& name, inputs::Key high, inputs::Key low)
|
||||
{
|
||||
addInputButtonAsAxis(name, InputDevice::KEYBOARD, static_cast<int>(high), static_cast<int>(low));
|
||||
}
|
||||
void Input::addInputButtonAsAxis(const std::string& name, inputs::Key high, inputs::Key low)
|
||||
{
|
||||
addInputButtonAsAxis(name, InputDevice::KEYBOARD, static_cast<int>(high), static_cast<int>(low));
|
||||
}
|
||||
|
||||
void Input::delInputButton(int index)
|
||||
{
|
||||
std::vector<struct ButtonEntry>::iterator it = m_buttonEntries.begin();
|
||||
std::advance(it, index);
|
||||
m_buttonEntries.erase(it);
|
||||
}
|
||||
void Input::delInputButton(int index)
|
||||
{
|
||||
std::vector<struct ButtonEntry>::iterator it = m_buttonEntries.begin();
|
||||
std::advance(it, index);
|
||||
m_buttonEntries.erase(it);
|
||||
}
|
||||
|
||||
void Input::delInputAxis(int index)
|
||||
{
|
||||
std::vector<struct AxisEntry>::iterator it = m_axisEntries.begin();
|
||||
std::advance(it, index);
|
||||
m_axisEntries.erase(it);
|
||||
}
|
||||
void Input::delInputAxis(int index)
|
||||
{
|
||||
std::vector<struct AxisEntry>::iterator it = m_axisEntries.begin();
|
||||
std::advance(it, index);
|
||||
m_axisEntries.erase(it);
|
||||
}
|
||||
|
||||
void Input::setDeviceActive(enum InputDevice device, bool active)
|
||||
{
|
||||
m_enabledDevices[static_cast<int>(device)] = active;
|
||||
}
|
||||
void Input::setDeviceActive(enum InputDevice device, bool active)
|
||||
{
|
||||
m_enabledDevices[static_cast<int>(device)] = active;
|
||||
}
|
||||
|
||||
bool Input::getDeviceActive(enum InputDevice device) const
|
||||
{
|
||||
return m_enabledDevices[static_cast<int>(device)];
|
||||
}
|
||||
bool Input::getDeviceActive(enum InputDevice device) const
|
||||
{
|
||||
return m_enabledDevices[static_cast<int>(device)];
|
||||
}
|
||||
|
||||
float Input::getAxis(const std::string& axisName) const
|
||||
{
|
||||
for (const AxisEntry& e : m_axisEntries) {
|
||||
if (e.name == axisName) {
|
||||
if (m_enabledDevices[static_cast<int>(e.device)]) {
|
||||
if (e.isButtonAxis) {
|
||||
return getButtonAxis(e.device, e.high, e.low);
|
||||
} else {
|
||||
return getDeviceAxis(e.device, e.axis);
|
||||
float Input::getAxis(const std::string& axisName) const
|
||||
{
|
||||
for (const AxisEntry& e : m_axisEntries) {
|
||||
if (e.name == axisName) {
|
||||
if (m_enabledDevices[static_cast<int>(e.device)]) {
|
||||
if (e.isButtonAxis) {
|
||||
return getButtonAxis(e.device, e.high, e.low);
|
||||
}
|
||||
else {
|
||||
return getDeviceAxis(e.device, e.axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0.0f; // instead of throwing an exception, just return nothing
|
||||
// throw std::runtime_error("Unable to find mapping in input table");
|
||||
}
|
||||
return 0.0f; // instead of throwing an exception, just return nothing
|
||||
// throw std::runtime_error("Unable to find mapping in input table");
|
||||
}
|
||||
|
||||
bool Input::getButton(const std::string& buttonName) const
|
||||
{
|
||||
bool isDown = false;
|
||||
bool Input::getButton(const std::string& buttonName) const
|
||||
{
|
||||
bool isDown = false;
|
||||
|
||||
for (const ButtonEntry& e : m_buttonEntries) {
|
||||
if (e.name == buttonName) {
|
||||
if (m_enabledDevices[static_cast<int>(e.device)]) {
|
||||
if (getDeviceButton(e.device, e.button) == true) {
|
||||
isDown = true;
|
||||
break;
|
||||
for (const ButtonEntry& e : m_buttonEntries) {
|
||||
if (e.name == buttonName) {
|
||||
if (m_enabledDevices[static_cast<int>(e.device)]) {
|
||||
if (getDeviceButton(e.device, e.button) == true) {
|
||||
isDown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isDown;
|
||||
}
|
||||
return isDown;
|
||||
}
|
||||
|
||||
bool Input::getButtonPress(const std::string& buttonName) const
|
||||
{
|
||||
bool isPressed = false;
|
||||
bool Input::getButtonPress(const std::string& buttonName) const
|
||||
{
|
||||
bool isPressed = false;
|
||||
|
||||
for (const ButtonEntry& e : m_buttonEntries) {
|
||||
if (e.name == buttonName) {
|
||||
if (m_enabledDevices[static_cast<int>(e.device)]) {
|
||||
if (getDeviceButtonDown(e.device, e.button) == true) {
|
||||
isPressed = true;
|
||||
break;
|
||||
for (const ButtonEntry& e : m_buttonEntries) {
|
||||
if (e.name == buttonName) {
|
||||
if (m_enabledDevices[static_cast<int>(e.device)]) {
|
||||
if (getDeviceButtonDown(e.device, e.button) == true) {
|
||||
isPressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isPressed;
|
||||
}
|
||||
return isPressed;
|
||||
}
|
||||
|
||||
bool Input::getButtonRelease(const std::string& buttonName) const
|
||||
{
|
||||
bool isReleased = false;
|
||||
bool Input::getButtonRelease(const std::string& buttonName) const
|
||||
{
|
||||
bool isReleased = false;
|
||||
|
||||
for (const ButtonEntry& e : m_buttonEntries) {
|
||||
if (e.name == buttonName) {
|
||||
if (m_enabledDevices[static_cast<int>(e.device)]) {
|
||||
if (getDeviceButtonUp(e.device, e.button) == true) {
|
||||
isReleased = true;
|
||||
break;
|
||||
for (const ButtonEntry& e : m_buttonEntries) {
|
||||
if (e.name == buttonName) {
|
||||
if (m_enabledDevices[static_cast<int>(e.device)]) {
|
||||
if (getDeviceButtonUp(e.device, e.button) == true) {
|
||||
isReleased = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isReleased;
|
||||
}
|
||||
return isReleased;
|
||||
}
|
||||
|
||||
}
|
229
src/object.cpp
229
src/object.cpp
@ -7,127 +7,134 @@
|
||||
|
||||
#include <log.hpp>
|
||||
|
||||
int Object::s_object_count = 0;
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
Object::Object(std::string name, Object* parent, SceneRoot& root, struct GameIO things)
|
||||
: m_name(name), m_parent(parent), root(root),
|
||||
m_gameIO(things),
|
||||
win(*things.win),
|
||||
inp(*things.input),
|
||||
res(*things.resMan)
|
||||
{
|
||||
s_object_count++;
|
||||
}
|
||||
namespace engine {
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
}
|
||||
int Object::s_object_count = 0;
|
||||
|
||||
std::string Object::getName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
Object::Object(std::string name, Object* parent, SceneRoot& root, struct GameIO things)
|
||||
: m_name(name), m_parent(parent), root(root),
|
||||
m_gameIO(things),
|
||||
win(*things.win),
|
||||
inp(*things.input),
|
||||
res(*things.resMan)
|
||||
{
|
||||
s_object_count++;
|
||||
}
|
||||
|
||||
Object* Object::getParent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
Object::~Object()
|
||||
{
|
||||
}
|
||||
|
||||
Object* Object::getChild(std::string name)
|
||||
{
|
||||
for (const auto& child : m_children) {
|
||||
if (name == child->getName()) {
|
||||
return child.get();
|
||||
std::string Object::getName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
Object* Object::getParent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
Object* Object::getChild(std::string name)
|
||||
{
|
||||
for (const auto& child : m_children) {
|
||||
if (name == child->getName()) {
|
||||
return child.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Object*> Object::getChildren()
|
||||
{
|
||||
std::vector<Object*> newVector{};
|
||||
for (const auto& child : m_children) {
|
||||
newVector.push_back(child.get());
|
||||
}
|
||||
return newVector;
|
||||
}
|
||||
|
||||
Object* Object::createChild(std::string name)
|
||||
{
|
||||
if (getChild(name) != nullptr) {
|
||||
throw std::runtime_error("Attempt to create child object with existing name");
|
||||
}
|
||||
m_children.emplace_back(std::make_unique<Object>(name, this, root, m_gameIO));
|
||||
return m_children.back().get();
|
||||
}
|
||||
|
||||
void Object::deleteChild(std::string name)
|
||||
{
|
||||
for (auto itr = m_children.begin(); itr != m_children.end(); ++itr) {
|
||||
if ((*itr)->getName() == name) {
|
||||
m_children.erase(itr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Unable to delete child '" + name + "' as it does not exist");
|
||||
}
|
||||
|
||||
void Object::printTree(int level)
|
||||
{
|
||||
std::string buf;
|
||||
for (int i = 0; i < level; i++) {
|
||||
if (i + 1 == level) {
|
||||
buf += "\\_______";
|
||||
}
|
||||
else {
|
||||
buf += " ";
|
||||
}
|
||||
}
|
||||
buf += m_name;
|
||||
INFO(buf);
|
||||
for (const auto& child : this->getChildren()) {
|
||||
child->printTree(level + 1);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Object*> Object::getChildren()
|
||||
{
|
||||
std::vector<Object*> newVector{};
|
||||
for (const auto& child : m_children) {
|
||||
newVector.push_back(child.get());
|
||||
}
|
||||
return newVector;
|
||||
}
|
||||
void Object::getAllSubComponents(struct CompList& compList, glm::mat4 parentTransform)
|
||||
{
|
||||
using namespace components;
|
||||
|
||||
Object* Object::createChild(std::string name)
|
||||
{
|
||||
if (getChild(name) != nullptr) {
|
||||
throw std::runtime_error("Attempt to create child object with existing name");
|
||||
}
|
||||
m_children.emplace_back(std::make_unique<Object>(name, this, root, m_gameIO));
|
||||
return m_children.back().get();
|
||||
}
|
||||
glm::mat4 objTransform{ 1.0f };
|
||||
|
||||
void Object::deleteChild(std::string name)
|
||||
{
|
||||
for (auto itr = m_children.begin(); itr != m_children.end(); ++itr) {
|
||||
if ((*itr)->getName() == name) {
|
||||
m_children.erase(itr);
|
||||
return;
|
||||
auto t = transform;
|
||||
|
||||
// rotation
|
||||
objTransform = glm::mat4_cast(t.rotation);
|
||||
|
||||
// position
|
||||
reinterpret_cast<glm::vec3&>(objTransform[3]) = t.position;
|
||||
|
||||
// scale (effectively applied first
|
||||
objTransform = glm::scale(objTransform, t.scale);
|
||||
|
||||
glm::mat4 newTransform = parentTransform * objTransform;
|
||||
|
||||
for (const auto& compUnq : m_components) {
|
||||
const auto comp = compUnq.get();
|
||||
switch (comp->getType()) {
|
||||
case Component::TypeEnum::CAMERA:
|
||||
compList.cameras.emplace_back(dynamic_cast<Camera*>(comp), newTransform);
|
||||
break;
|
||||
case Component::TypeEnum::RENDERER:
|
||||
compList.renderers.emplace_back(dynamic_cast<Renderer*>(comp), newTransform);
|
||||
break;
|
||||
case Component::TypeEnum::UI:
|
||||
compList.uis.emplace_back(dynamic_cast<UI*>(comp), newTransform);
|
||||
break;
|
||||
case Component::TypeEnum::CUSTOM:
|
||||
compList.customs.emplace_back(dynamic_cast<CustomComponent*>(comp), newTransform);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const auto& child : m_children) {
|
||||
child->getAllSubComponents(compList, newTransform);
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Unable to delete child '" + name + "' as it does not exist");
|
||||
}
|
||||
|
||||
void Object::printTree(int level)
|
||||
{
|
||||
std::string buf;
|
||||
for (int i = 0; i < level; i++) {
|
||||
if (i+1 == level) {
|
||||
buf += "\\_______";
|
||||
} else {
|
||||
buf += " ";
|
||||
}
|
||||
}
|
||||
buf += m_name;
|
||||
INFO(buf);
|
||||
for (const auto& child : this->getChildren()) {
|
||||
child->printTree(level+1);
|
||||
}
|
||||
}
|
||||
|
||||
void Object::getAllSubComponents(struct CompList& compList, glm::mat4 parentTransform)
|
||||
{
|
||||
using namespace components;
|
||||
|
||||
glm::mat4 objTransform{1.0f};
|
||||
|
||||
auto t = transform;
|
||||
|
||||
// rotation
|
||||
objTransform = glm::mat4_cast(t.rotation);
|
||||
|
||||
// position
|
||||
reinterpret_cast<glm::vec3&>(objTransform[3]) = t.position;
|
||||
|
||||
// scale (effectively applied first
|
||||
objTransform = glm::scale(objTransform, t.scale);
|
||||
|
||||
const glm::mat4 newTransform = parentTransform * objTransform;
|
||||
|
||||
for (const auto& compUnq : m_components) {
|
||||
const auto comp = compUnq.get();
|
||||
switch (comp->getType()) {
|
||||
case Component::TypeEnum::CAMERA:
|
||||
compList.cameras.emplace_back(dynamic_cast<Camera*>(comp), newTransform);
|
||||
break;
|
||||
case Component::TypeEnum::RENDERER:
|
||||
compList.renderers.emplace_back(dynamic_cast<Renderer*>(comp), newTransform);
|
||||
break;
|
||||
case Component::TypeEnum::UI:
|
||||
compList.uis.emplace_back(dynamic_cast<UI*>(comp), newTransform);
|
||||
break;
|
||||
case Component::TypeEnum::CUSTOM:
|
||||
compList.customs.emplace_back(dynamic_cast<CustomComponent*>(comp), newTransform);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const auto& child : m_children) {
|
||||
child->getAllSubComponents(compList, newTransform);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,68 +8,75 @@
|
||||
|
||||
#include "log.hpp"
|
||||
|
||||
ResourceManager::ResourceManager()
|
||||
{
|
||||
namespace engine {
|
||||
|
||||
ResourceManager::ResourceManager()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
CHAR exeDirBuf[MAX_PATH + 1];
|
||||
GetModuleFileNameA(NULL, exeDirBuf, MAX_PATH + 1);
|
||||
std::filesystem::path cwd = std::filesystem::path(exeDirBuf).parent_path();
|
||||
(void)_chdir((const char*)std::filesystem::absolute(cwd).c_str());
|
||||
CHAR exeDirBuf[MAX_PATH + 1];
|
||||
GetModuleFileNameA(NULL, exeDirBuf, MAX_PATH + 1);
|
||||
std::filesystem::path cwd = std::filesystem::path(exeDirBuf).parent_path();
|
||||
(void)_chdir((const char*)std::filesystem::absolute(cwd).c_str());
|
||||
#else
|
||||
std::filesystem::path cwd = std::filesystem::current_path();
|
||||
std::filesystem::path cwd = std::filesystem::current_path();
|
||||
#endif
|
||||
|
||||
if (std::filesystem::is_directory(cwd / "res")) {
|
||||
m_resourcesPath = cwd / "res";
|
||||
} else {
|
||||
m_resourcesPath = cwd.parent_path() / "share" / "sdltest";
|
||||
}
|
||||
|
||||
if (std::filesystem::is_directory(m_resourcesPath) == false) {
|
||||
m_resourcesPath = cwd.root_path() / "usr" / "local" / "share" / "sdltest";
|
||||
}
|
||||
|
||||
if (std::filesystem::is_directory(m_resourcesPath) == false) {
|
||||
throw std::runtime_error("Unable to determine resources location. CWD: " + cwd.string());
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<std::string> ResourceManager::getResourcesListString()
|
||||
{
|
||||
auto bufPtr = std::make_unique<std::string>();
|
||||
std::string& buf = *bufPtr;
|
||||
int maxLength = 0;
|
||||
for (const auto& [name, ptr] : m_resources) {
|
||||
if (name.length() > maxLength)
|
||||
maxLength = name.length();
|
||||
}
|
||||
for (const auto& [name, ptr] : m_resources) {
|
||||
buf += name;
|
||||
for (int i = 0; i < (maxLength - name.length() + 4); i++) {
|
||||
buf += " ";
|
||||
if (std::filesystem::is_directory(cwd / "res")) {
|
||||
m_resourcesPath = cwd / "res";
|
||||
}
|
||||
buf += std::to_string(ptr.use_count()) + "\n";
|
||||
else {
|
||||
m_resourcesPath = cwd.parent_path() / "share" / "sdltest";
|
||||
}
|
||||
|
||||
if (std::filesystem::is_directory(m_resourcesPath) == false) {
|
||||
m_resourcesPath = cwd.root_path() / "usr" / "local" / "share" / "sdltest";
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
auto bufPtr = std::make_unique<std::string>();
|
||||
std::string& buf = *bufPtr;
|
||||
int maxLength = 0;
|
||||
for (const auto& [name, ptr] : m_resources) {
|
||||
if (name.length() > maxLength)
|
||||
maxLength = name.length();
|
||||
}
|
||||
for (const auto& [name, ptr] : m_resources) {
|
||||
buf += name;
|
||||
for (int i = 0; i < (maxLength - name.length() + 4); i++) {
|
||||
buf += " ";
|
||||
}
|
||||
buf += std::to_string(ptr.use_count()) + "\n";
|
||||
}
|
||||
return bufPtr;
|
||||
}
|
||||
return bufPtr;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::weak_ptr<Resource>> ResourceManager::getAllResourcesOfType(const std::string& type)
|
||||
{
|
||||
std::vector<std::weak_ptr<Resource>> resources;
|
||||
for (const auto& [name, ptr] : m_resources) {
|
||||
if (ptr.expired() == false) {
|
||||
if (ptr.lock()->getType() == type) {
|
||||
resources.push_back(ptr);
|
||||
std::vector<std::weak_ptr<Resource>> ResourceManager::getAllResourcesOfType(const std::string& type)
|
||||
{
|
||||
std::vector<std::weak_ptr<Resource>> resources;
|
||||
for (const auto& [name, ptr] : m_resources) {
|
||||
if (ptr.expired() == false) {
|
||||
if (ptr.lock()->getType() == type) {
|
||||
resources.push_back(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
// private
|
||||
// private
|
||||
|
||||
std::filesystem::path ResourceManager::getFilePath(const std::string& name)
|
||||
{
|
||||
return m_resourcesPath / name;
|
||||
}
|
||||
std::filesystem::path ResourceManager::getFilePath(const std::string& name)
|
||||
{
|
||||
return m_resourcesPath / name;
|
||||
}
|
||||
|
||||
}
|
@ -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")
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
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);
|
||||
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());
|
||||
|
||||
// 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("VB PTR in mesh: {}", (void*)vb);
|
||||
|
||||
}
|
||||
TRACE("Vertices:");
|
||||
|
||||
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
|
||||
for (const auto& v : m_vertices) {
|
||||
TRACE("pos: {}, {}, {}", v.pos.x, v.pos.y, v.pos.z);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,19 +2,23 @@
|
||||
|
||||
#include <log.hpp>
|
||||
|
||||
Resource::Resource(const std::filesystem::path& resPath, const std::string& type) : m_resourcePath(resPath), m_type(type)
|
||||
{
|
||||
if (m_type != "mesh")
|
||||
TRACE("Creating {} resource: {}", type, resPath.filename().string());
|
||||
}
|
||||
namespace engine {
|
||||
|
||||
Resource::~Resource()
|
||||
{
|
||||
if (m_type != "mesh")
|
||||
TRACE("Destroyed {} resource: {}", m_type, m_resourcePath.filename().string());
|
||||
}
|
||||
Resource::Resource(const std::filesystem::path& resPath, const std::string& type) : m_resourcePath(resPath), m_type(type)
|
||||
{
|
||||
if (m_type != "mesh")
|
||||
TRACE("Creating {} resource: {}", type, resPath.filename().string());
|
||||
}
|
||||
|
||||
std::string Resource::getType()
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
Resource::~Resource()
|
||||
{
|
||||
if (m_type != "mesh")
|
||||
TRACE("Destroyed {} resource: {}", m_type, m_resourcePath.filename().string());
|
||||
}
|
||||
|
||||
std::string Resource::getType()
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,77 +16,75 @@
|
||||
|
||||
#include "log.hpp"
|
||||
|
||||
SceneRoot::SceneRoot(struct GameIO things) : Object("root", nullptr, *this, things)
|
||||
{
|
||||
}
|
||||
namespace engine {
|
||||
|
||||
SceneRoot::SceneRoot(const std::filesystem::path& file, struct GameIO things) : SceneRoot(things)
|
||||
{
|
||||
// TODO: make this a resource
|
||||
//loadFromSceneFile(file);
|
||||
}
|
||||
|
||||
SceneRoot::~SceneRoot()
|
||||
{
|
||||
}
|
||||
|
||||
// private methods
|
||||
|
||||
// public methods
|
||||
|
||||
void SceneRoot::updateStuff()
|
||||
{
|
||||
|
||||
using namespace components;
|
||||
using namespace glm;
|
||||
|
||||
struct CompList compList{};
|
||||
|
||||
getAllSubComponents(compList, glm::mat4{1.0f});
|
||||
|
||||
// update
|
||||
|
||||
for (const auto& [c, t] : compList.customs) {
|
||||
c->onUpdate(t);
|
||||
SceneRoot::SceneRoot(struct GameIO things) : Object("root", nullptr, *this, things)
|
||||
{
|
||||
}
|
||||
|
||||
// render
|
||||
SceneRoot::~SceneRoot()
|
||||
{
|
||||
}
|
||||
|
||||
for (const auto& [c, t] : compList.cameras) {
|
||||
for (int id : m_activeCameras) {
|
||||
if (c->getID() == id) {
|
||||
c->updateCam(t);
|
||||
for (const auto& [c, t] : compList.renderers) {
|
||||
c->render(t);
|
||||
// private methods
|
||||
|
||||
// public methods
|
||||
|
||||
void SceneRoot::updateStuff()
|
||||
{
|
||||
|
||||
using namespace components;
|
||||
using namespace glm;
|
||||
|
||||
struct CompList compList {};
|
||||
|
||||
getAllSubComponents(compList, glm::mat4{ 1.0f });
|
||||
|
||||
// update
|
||||
|
||||
for (const auto& [c, t] : compList.customs) {
|
||||
c->onUpdate(t);
|
||||
}
|
||||
|
||||
// render
|
||||
|
||||
for (const auto& [c, camt] : compList.cameras) {
|
||||
for (int id : m_activeCameras) {
|
||||
if (c->getID() == id) {
|
||||
c->updateCam(camt);
|
||||
for (const auto& [ren, ren_t] : compList.renderers) {
|
||||
ren->render(ren_t);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
for (const auto& [c, t] : compList.uis) {
|
||||
c->render(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SceneRoot::activateCam(int id)
|
||||
{
|
||||
auto& v = m_activeCameras;
|
||||
|
||||
if (std::find(v.begin(), v.end(), id) == v.end()) {
|
||||
v.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneRoot::deactivateCam(int id)
|
||||
{
|
||||
auto& v = m_activeCameras;
|
||||
|
||||
for (auto it = v.begin(); it != v.end(); it++) {
|
||||
if (*it == id) {
|
||||
v.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& [c, t] : compList.uis) {
|
||||
c->render(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SceneRoot::activateCam(int id)
|
||||
{
|
||||
auto& v = m_activeCameras;
|
||||
|
||||
if (std::find(v.begin(), v.end(), id) == v.end()) {
|
||||
v.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneRoot::deactivateCam(int id)
|
||||
{
|
||||
auto& v = m_activeCameras;
|
||||
|
||||
for (auto it = v.begin(); it != v.end(); it++) {
|
||||
if (*it == id) {
|
||||
v.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
765
src/window.cpp
765
src/window.cpp
@ -1,120 +1,118 @@
|
||||
#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 {
|
||||
|
||||
// init SDL
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
const std::string errMsg("Unable to initialise SDL: " + std::string(SDL_GetError()));
|
||||
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL error", errMsg.c_str(), NULL) != 0) {
|
||||
std::cerr << errMsg << "\nAre you in a graphical environment?\n";
|
||||
Window::Window(const std::string& title, bool resizable) : m_title(title), m_resizable(resizable)
|
||||
{
|
||||
|
||||
// init SDL
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
const std::string errMsg("Unable to initialise SDL: " + std::string(SDL_GetError()));
|
||||
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL error", errMsg.c_str(), NULL) != 0) {
|
||||
std::cerr << errMsg << "\nAre you in a graphical environment?\n";
|
||||
}
|
||||
throw std::runtime_error(errMsg);
|
||||
}
|
||||
throw std::runtime_error(errMsg);
|
||||
}
|
||||
|
||||
m_counterFreq = SDL_GetPerformanceFrequency();
|
||||
m_startTime = getNanos();
|
||||
m_lastFrameStamp = m_startTime - 1;
|
||||
m_avgFpsStart = m_startTime;
|
||||
m_counterFreq = SDL_GetPerformanceFrequency();
|
||||
m_startTime = getNanos();
|
||||
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;
|
||||
|
||||
// create the window
|
||||
m_handle = SDL_CreateWindow(
|
||||
#ifdef ENGINE_BUILD_VULKAN
|
||||
windowFlags |= SDL_WINDOW_VULKAN;
|
||||
#endif
|
||||
|
||||
if (m_resizable) {
|
||||
windowFlags |= SDL_WINDOW_RESIZABLE;
|
||||
}
|
||||
|
||||
// create the window
|
||||
m_handle = SDL_CreateWindow(
|
||||
m_title.c_str(),
|
||||
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);
|
||||
if (m_handle == NULL) {
|
||||
SDL_Quit();
|
||||
throw std::runtime_error("Unable to create window: " + std::string(SDL_GetError()));
|
||||
windowFlags);
|
||||
if (m_handle == NULL) {
|
||||
SDL_Quit();
|
||||
throw std::runtime_error("Unable to create window: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
// get window size
|
||||
int winWidth, winHeight;
|
||||
SDL_GetWindowSize(m_handle, &winWidth, &winHeight);
|
||||
m_winSize.x = winWidth;
|
||||
m_winSize.y = winHeight;
|
||||
|
||||
const int WINDOWED_MIN_WIDTH = 640;
|
||||
const int WINDOWED_MIN_HEIGHT = 480;
|
||||
SDL_SetWindowMinimumSize(m_handle, WINDOWED_MIN_WIDTH, WINDOWED_MIN_HEIGHT);
|
||||
|
||||
/*
|
||||
m_glContext = SDL_GL_CreateContext(m_handle);
|
||||
if (m_glContext == NULL) {
|
||||
SDL_DestroyWindow(m_handle);
|
||||
SDL_Quit();
|
||||
throw std::runtime_error("Unable to create OpenGL context: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||
SDL_DestroyWindow(m_handle);
|
||||
SDL_Quit();
|
||||
throw std::runtime_error("Unable to initialise GLAD");
|
||||
}
|
||||
*/
|
||||
|
||||
// onResize(m_winSize.x, m_winSize.y);
|
||||
|
||||
}
|
||||
|
||||
// get window size
|
||||
int winWidth, winHeight;
|
||||
SDL_GetWindowSize(m_handle, &winWidth, &winHeight);
|
||||
m_winSize.x = winWidth;
|
||||
m_winSize.y = winHeight;
|
||||
|
||||
const int WINDOWED_MIN_WIDTH = 640;
|
||||
const int WINDOWED_MIN_HEIGHT = 480;
|
||||
SDL_SetWindowMinimumSize(m_handle, WINDOWED_MIN_WIDTH, WINDOWED_MIN_HEIGHT);
|
||||
|
||||
m_glContext = SDL_GL_CreateContext(m_handle);
|
||||
if (m_glContext == NULL) {
|
||||
Window::~Window()
|
||||
{
|
||||
SDL_DestroyWindow(m_handle);
|
||||
SDL_Quit();
|
||||
throw std::runtime_error("Unable to create OpenGL context: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||
SDL_DestroyWindow(m_handle);
|
||||
SDL_Quit();
|
||||
throw std::runtime_error("Unable to initialise GLAD");
|
||||
// private methods
|
||||
|
||||
void Window::onResize(Sint32 width, Sint32 height)
|
||||
{
|
||||
// get window size
|
||||
m_winSize.x = static_cast<int>(width);
|
||||
m_winSize.y = static_cast<int>(height);
|
||||
|
||||
m_justResized = true;
|
||||
}
|
||||
|
||||
onResize(m_winSize.x, m_winSize.y);
|
||||
void Window::resetInputDeltas()
|
||||
{
|
||||
m_justResized = false;
|
||||
|
||||
}
|
||||
m_keyboard.deltas.fill(ButtonDelta::SAME);
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
SDL_GL_DeleteContext(m_glContext);
|
||||
SDL_DestroyWindow(m_handle);
|
||||
SDL_Quit();
|
||||
}
|
||||
m_mouse.deltas.fill(ButtonDelta::SAME);
|
||||
m_mouse.dx = 0;
|
||||
m_mouse.dy = 0;
|
||||
m_mouse.xscroll = 0.0f;
|
||||
m_mouse.yscroll = 0.0f;
|
||||
}
|
||||
|
||||
// private methods
|
||||
// TODO event methods (like callbacks)
|
||||
|
||||
void Window::onResize(Sint32 width, Sint32 height)
|
||||
{
|
||||
// get window size
|
||||
m_winSize.x = static_cast<int>(width);
|
||||
m_winSize.y = static_cast<int>(height);
|
||||
void Window::onWindowEvent(SDL_WindowEvent& e)
|
||||
{
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void Window::resetInputDeltas()
|
||||
{
|
||||
m_justResized = false;
|
||||
|
||||
m_keyboard.deltas.fill(ButtonDelta::SAME);
|
||||
|
||||
m_mouse.deltas.fill(ButtonDelta::SAME);
|
||||
m_mouse.dx = 0.0f;
|
||||
m_mouse.dy = 0.0f;
|
||||
m_mouse.xscroll = 0.0f;
|
||||
m_mouse.yscroll = 0.0f;
|
||||
}
|
||||
|
||||
// TODO event methods (like callbacks)
|
||||
|
||||
void Window::onWindowEvent(SDL_WindowEvent &e)
|
||||
{
|
||||
|
||||
switch (e.event) {
|
||||
switch (e.event) {
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
onResize(e.data1, e.data2);
|
||||
break;
|
||||
@ -124,23 +122,23 @@ void Window::onWindowEvent(SDL_WindowEvent &e)
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
m_keyboardFocus = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::onKeyEvent(SDL_KeyboardEvent &e)
|
||||
{
|
||||
bool keyWasDown = m_keyboard.keys[e.keysym.scancode];
|
||||
bool keyIsDown = (e.state == SDL_PRESSED);
|
||||
m_keyboard.keys[e.keysym.scancode] = keyIsDown;
|
||||
if (keyIsDown != keyWasDown) { // (if key was pressed or released)
|
||||
m_keyboard.deltas[e.keysym.scancode] = keyIsDown ? ButtonDelta::PRESSED : ButtonDelta::RELEASED;
|
||||
void Window::onKeyEvent(SDL_KeyboardEvent& e)
|
||||
{
|
||||
bool keyWasDown = m_keyboard.keys[e.keysym.scancode];
|
||||
bool keyIsDown = (e.state == SDL_PRESSED);
|
||||
m_keyboard.keys[e.keysym.scancode] = keyIsDown;
|
||||
if (keyIsDown != keyWasDown) { // (if key was pressed or released)
|
||||
m_keyboard.deltas[e.keysym.scancode] = keyIsDown ? ButtonDelta::PRESSED : ButtonDelta::RELEASED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::onMouseButtonEvent(SDL_MouseButtonEvent &e)
|
||||
{
|
||||
enum inputs::MouseButton button = inputs::MouseButton::M_INVALID;
|
||||
switch (e.button) {
|
||||
void Window::onMouseButtonEvent(SDL_MouseButtonEvent& e)
|
||||
{
|
||||
enum inputs::MouseButton button = inputs::MouseButton::M_INVALID;
|
||||
switch (e.button) {
|
||||
case SDL_BUTTON_LEFT:
|
||||
button = inputs::MouseButton::M_LEFT;
|
||||
break;
|
||||
@ -156,72 +154,65 @@ void Window::onMouseButtonEvent(SDL_MouseButtonEvent &e)
|
||||
case SDL_BUTTON_X2:
|
||||
button = inputs::MouseButton::M_X2;
|
||||
break;
|
||||
}
|
||||
|
||||
bool buttonWasDown = m_mouse.buttons[static_cast<int>(button)];
|
||||
bool buttonIsDown = (e.state == SDL_PRESSED);
|
||||
m_mouse.buttons[static_cast<int>(button)] = 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;
|
||||
}
|
||||
int buttonIndex = static_cast<int>(button);
|
||||
bool buttonWasDown = m_mouse.buttons.at(buttonIndex);
|
||||
bool buttonIsDown = (e.state == SDL_PRESSED);
|
||||
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[buttonIndex] == ButtonDelta::SAME) {
|
||||
m_mouse.deltas[buttonIndex] = buttonIsDown ? ButtonDelta::PRESSED : ButtonDelta::RELEASED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::onMouseMotionEvent(SDL_MouseMotionEvent &e)
|
||||
{
|
||||
m_mouse.x = e.x;
|
||||
m_mouse.y = e.y;
|
||||
m_mouse.dx = e.xrel;
|
||||
m_mouse.dy = e.yrel;
|
||||
}
|
||||
|
||||
void Window::onMouseWheelEvent(SDL_MouseWheelEvent &e)
|
||||
{
|
||||
if (e.direction == SDL_MOUSEWHEEL_NORMAL) {
|
||||
m_mouse.xscroll = e.preciseX;
|
||||
m_mouse.yscroll = e.preciseY;
|
||||
} else { // flipped
|
||||
m_mouse.xscroll = -e.preciseX;
|
||||
m_mouse.yscroll = -e.preciseY;
|
||||
void Window::onMouseMotionEvent(SDL_MouseMotionEvent& e)
|
||||
{
|
||||
m_mouse.x = e.x;
|
||||
m_mouse.y = e.y;
|
||||
m_mouse.dx = e.xrel;
|
||||
m_mouse.dy = e.yrel;
|
||||
}
|
||||
}
|
||||
|
||||
// public methods
|
||||
|
||||
std::string Window::getTitle() const
|
||||
{
|
||||
return m_title;
|
||||
}
|
||||
|
||||
void Window::makeContextCurrent()
|
||||
{
|
||||
if (SDL_GL_MakeCurrent(m_handle, m_glContext) != 0) {
|
||||
throw std::runtime_error("Failed to make GL context current");
|
||||
void Window::onMouseWheelEvent(SDL_MouseWheelEvent& e)
|
||||
{
|
||||
if (e.direction == SDL_MOUSEWHEEL_NORMAL) {
|
||||
m_mouse.xscroll = e.preciseX;
|
||||
m_mouse.yscroll = e.preciseY;
|
||||
}
|
||||
else { // flipped
|
||||
m_mouse.xscroll = -e.preciseX;
|
||||
m_mouse.yscroll = -e.preciseY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// public methods
|
||||
|
||||
void Window::getInputAndEvents()
|
||||
{
|
||||
SDL_Window* Window::getHandle() const
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
resetInputDeltas();
|
||||
std::string Window::getTitle() const
|
||||
{
|
||||
return m_title;
|
||||
}
|
||||
|
||||
// loop through all available events
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
void Window::getInputAndEvents()
|
||||
{
|
||||
|
||||
m_frames++;
|
||||
uint64_t currentFrameStamp = getNanos();
|
||||
m_lastFrameTime = currentFrameStamp - m_lastFrameStamp;
|
||||
m_lastFrameStamp = currentFrameStamp;
|
||||
|
||||
resetInputDeltas();
|
||||
|
||||
// loop through all available events
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
|
||||
case SDL_QUIT:
|
||||
setCloseFlag();
|
||||
@ -249,264 +240,240 @@ void Window::getInputAndEvents()
|
||||
onMouseWheelEvent(e.wheel);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Window::setTitle(std::string title)
|
||||
{
|
||||
SDL_SetWindowTitle(m_handle, title.c_str());
|
||||
}
|
||||
|
||||
bool Window::getWindowResized() const
|
||||
{
|
||||
return m_justResized;
|
||||
}
|
||||
|
||||
void Window::show()
|
||||
{
|
||||
SDL_ShowWindow(m_handle);
|
||||
}
|
||||
|
||||
void Window::hide()
|
||||
{
|
||||
SDL_HideWindow(m_handle);
|
||||
}
|
||||
|
||||
void Window::focus()
|
||||
{
|
||||
SDL_RaiseWindow(m_handle);
|
||||
m_keyboardFocus = true;
|
||||
}
|
||||
|
||||
bool Window::hasFocus() const
|
||||
{
|
||||
return m_keyboardFocus;
|
||||
}
|
||||
|
||||
void Window::setCloseFlag()
|
||||
{
|
||||
m_shouldClose = true;
|
||||
}
|
||||
|
||||
bool Window::isRunning() const
|
||||
{
|
||||
return !m_shouldClose;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
m_fullscreen = fullscreen;
|
||||
if (fullscreen) {
|
||||
int width, height;
|
||||
SDL_GetWindowSize(m_handle, &width, &height);
|
||||
onResize(width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Window::setVSync(bool enable)
|
||||
{
|
||||
if (SDL_GL_SetSwapInterval(enable ? 1 : 0) != 0) {
|
||||
throw std::runtime_error("Failed to set swap interval");
|
||||
void Window::toggleFullscreen()
|
||||
{
|
||||
setFullscreen(!m_fullscreen);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
bool Window::getWindowResized() const
|
||||
{
|
||||
return m_justResized;
|
||||
}
|
||||
|
||||
void Window::show()
|
||||
{
|
||||
SDL_ShowWindow(m_handle);
|
||||
}
|
||||
|
||||
void Window::hide()
|
||||
{
|
||||
SDL_HideWindow(m_handle);
|
||||
}
|
||||
|
||||
void Window::focus()
|
||||
{
|
||||
SDL_RaiseWindow(m_handle);
|
||||
m_keyboardFocus = true;
|
||||
}
|
||||
|
||||
bool Window::hasFocus() const
|
||||
{
|
||||
return m_keyboardFocus;
|
||||
}
|
||||
|
||||
void Window::setCloseFlag()
|
||||
{
|
||||
m_shouldClose = true;
|
||||
}
|
||||
|
||||
bool Window::isRunning() const
|
||||
{
|
||||
return !m_shouldClose;
|
||||
}
|
||||
|
||||
void Window::setFullscreen(bool fullscreen, bool exclusive)
|
||||
{
|
||||
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");
|
||||
bool Window::isFullscreen() const
|
||||
{
|
||||
return m_fullscreen;
|
||||
}
|
||||
m_fullscreen = fullscreen;
|
||||
if (fullscreen) {
|
||||
int width, height;
|
||||
SDL_GetWindowSize(m_handle, &width, &height);
|
||||
onResize(width, height);
|
||||
|
||||
bool Window::setRelativeMouseMode(bool enabled)
|
||||
{
|
||||
m_mouse.captured = enabled;
|
||||
int code = SDL_SetRelativeMouseMode(static_cast<SDL_bool>(enabled));
|
||||
if (code != 0) {
|
||||
throw std::runtime_error("Unable to set relative mouse mode");
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::toggleFullscreen()
|
||||
{
|
||||
setFullscreen(!m_fullscreen);
|
||||
}
|
||||
|
||||
bool Window::isFullscreen() const
|
||||
{
|
||||
return m_fullscreen;
|
||||
}
|
||||
|
||||
bool Window::setRelativeMouseMode(bool enabled)
|
||||
{
|
||||
m_mouse.captured = enabled;
|
||||
int code = SDL_SetRelativeMouseMode(static_cast<SDL_bool>(enabled));
|
||||
if (code != 0) {
|
||||
throw std::runtime_error("Unable to set relative mouse mode");
|
||||
} else {
|
||||
return true;
|
||||
bool Window::mouseCaptured()
|
||||
{
|
||||
return m_mouse.captured;
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::mouseCaptured()
|
||||
{
|
||||
return m_mouse.captured;
|
||||
}
|
||||
// getting input
|
||||
|
||||
// getting input
|
||||
|
||||
bool Window::getKey(inputs::Key key) const
|
||||
{
|
||||
return m_keyboard.keys[static_cast<int>(key)];
|
||||
}
|
||||
|
||||
bool Window::getKeyPress(inputs::Key key) const
|
||||
{
|
||||
return m_keyboard.deltas[static_cast<int>(key)] == ButtonDelta::PRESSED;
|
||||
}
|
||||
|
||||
bool Window::getKeyRelease(inputs::Key key) const
|
||||
{
|
||||
return m_keyboard.deltas[static_cast<int>(key)] == ButtonDelta::RELEASED;
|
||||
}
|
||||
|
||||
// TODO mouse input
|
||||
|
||||
bool Window::getButton(inputs::MouseButton button) const
|
||||
{
|
||||
return m_mouse.buttons[static_cast<int>(button)];
|
||||
}
|
||||
|
||||
bool Window::getButtonPress(inputs::MouseButton button) const
|
||||
{
|
||||
return m_mouse.deltas[static_cast<int>(button)] == ButtonDelta::PRESSED;
|
||||
}
|
||||
|
||||
bool Window::getButtonRelease(inputs::MouseButton button) const
|
||||
{
|
||||
return m_mouse.deltas[static_cast<int>(button)] == ButtonDelta::RELEASED;
|
||||
}
|
||||
|
||||
int Window::getMouseX() const
|
||||
{
|
||||
return static_cast<int>(m_mouse.x);
|
||||
}
|
||||
|
||||
int Window::getMouseY() const
|
||||
{
|
||||
return static_cast<int>(m_mouse.y);
|
||||
}
|
||||
|
||||
float Window::getMouseNormX() const
|
||||
{
|
||||
return ((float)m_mouse.x * 2.0f / (float)m_winSize.x) - 1.0f;
|
||||
}
|
||||
|
||||
float Window::getMouseNormY() const
|
||||
{
|
||||
return ((float)m_mouse.y * -2.0f / (float)m_winSize.y) + 1.0f;
|
||||
}
|
||||
|
||||
int Window::getMouseDX() const
|
||||
{
|
||||
return static_cast<int>(m_mouse.dx);
|
||||
}
|
||||
|
||||
int Window::getMouseDY() const
|
||||
{
|
||||
return static_cast<int>(m_mouse.dy);
|
||||
}
|
||||
|
||||
float Window::getMouseScrollX() const
|
||||
{
|
||||
return m_mouse.xscroll;
|
||||
}
|
||||
|
||||
float Window::getMouseScrollY() const
|
||||
{
|
||||
return m_mouse.yscroll;
|
||||
}
|
||||
|
||||
// TODO game pad
|
||||
|
||||
// get timer value
|
||||
uint64_t Window::getNanos() const
|
||||
{
|
||||
uint64_t count;
|
||||
|
||||
count = SDL_GetPerformanceCounter();
|
||||
if (m_counterFreq == BILLION) {
|
||||
return count;
|
||||
} else {
|
||||
return count * (BILLION / m_counterFreq);
|
||||
bool Window::getKey(inputs::Key key) const
|
||||
{
|
||||
return m_keyboard.keys[static_cast<int>(key)];
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Window::getLastFrameStamp() const
|
||||
{
|
||||
return m_lastFrameStamp;
|
||||
}
|
||||
|
||||
uint64_t Window::getFrameCount() const
|
||||
{
|
||||
return m_frames;
|
||||
}
|
||||
|
||||
uint64_t Window::getStartTime() const
|
||||
{
|
||||
return m_startTime;
|
||||
}
|
||||
|
||||
float Window::dt() const
|
||||
{
|
||||
return (float)m_lastFrameTime / (float)BILLION;
|
||||
}
|
||||
|
||||
uint64_t Window::getFPS() const
|
||||
{
|
||||
if (m_lastFrameTime == 0) return 0;
|
||||
return BILLION / m_lastFrameTime;
|
||||
}
|
||||
|
||||
uint64_t Window::getAvgFPS() const
|
||||
{
|
||||
uint64_t delta_t = getNanos() - m_avgFpsStart;
|
||||
if (delta_t == 0) return 0;
|
||||
return BILLION * (m_frames - m_avgFpsStartCount) / delta_t;
|
||||
}
|
||||
|
||||
void Window::resetAvgFPS()
|
||||
{
|
||||
m_avgFpsStart = getNanos();
|
||||
m_avgFpsStartCount = getFrameCount();
|
||||
}
|
||||
|
||||
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 {
|
||||
return false;
|
||||
bool Window::getKeyPress(inputs::Key key) const
|
||||
{
|
||||
return m_keyboard.deltas[static_cast<int>(key)] == ButtonDelta::PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
bool Window::getKeyRelease(inputs::Key key) const
|
||||
{
|
||||
return m_keyboard.deltas[static_cast<int>(key)] == ButtonDelta::RELEASED;
|
||||
}
|
||||
|
||||
return requiredExtensions;
|
||||
#else
|
||||
return std::vector<const char*>{};
|
||||
#endif
|
||||
}
|
||||
// TODO mouse input
|
||||
|
||||
/* STATIC METHODS */
|
||||
bool Window::getButton(inputs::MouseButton button) const
|
||||
{
|
||||
return m_mouse.buttons[static_cast<int>(button)];
|
||||
}
|
||||
|
||||
// Display an error message box
|
||||
void Window::errorBox(const std::string& message)
|
||||
{
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Game Error", message.c_str(), NULL);
|
||||
}
|
||||
bool Window::getButtonPress(inputs::MouseButton button) const
|
||||
{
|
||||
return m_mouse.deltas[static_cast<int>(button)] == ButtonDelta::PRESSED;
|
||||
}
|
||||
|
||||
bool Window::getButtonRelease(inputs::MouseButton button) const
|
||||
{
|
||||
return m_mouse.deltas[static_cast<int>(button)] == ButtonDelta::RELEASED;
|
||||
}
|
||||
|
||||
int Window::getMouseX() const
|
||||
{
|
||||
return static_cast<int>(m_mouse.x);
|
||||
}
|
||||
|
||||
int Window::getMouseY() const
|
||||
{
|
||||
return static_cast<int>(m_mouse.y);
|
||||
}
|
||||
|
||||
float Window::getMouseNormX() const
|
||||
{
|
||||
return ((float)m_mouse.x * 2.0f / (float)m_winSize.x) - 1.0f;
|
||||
}
|
||||
|
||||
float Window::getMouseNormY() const
|
||||
{
|
||||
return ((float)m_mouse.y * -2.0f / (float)m_winSize.y) + 1.0f;
|
||||
}
|
||||
|
||||
int Window::getMouseDX() const
|
||||
{
|
||||
return static_cast<int>(m_mouse.dx);
|
||||
}
|
||||
|
||||
int Window::getMouseDY() const
|
||||
{
|
||||
return static_cast<int>(m_mouse.dy);
|
||||
}
|
||||
|
||||
float Window::getMouseScrollX() const
|
||||
{
|
||||
return m_mouse.xscroll;
|
||||
}
|
||||
|
||||
float Window::getMouseScrollY() const
|
||||
{
|
||||
return m_mouse.yscroll;
|
||||
}
|
||||
|
||||
// TODO game pad
|
||||
|
||||
// get timer value
|
||||
uint64_t Window::getNanos() const
|
||||
{
|
||||
uint64_t count;
|
||||
|
||||
count = SDL_GetPerformanceCounter();
|
||||
if (m_counterFreq == BILLION) {
|
||||
return count;
|
||||
}
|
||||
else {
|
||||
return count * (BILLION / m_counterFreq);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Window::getLastFrameStamp() const
|
||||
{
|
||||
return m_lastFrameStamp;
|
||||
}
|
||||
|
||||
uint64_t Window::getFrameCount() const
|
||||
{
|
||||
return m_frames;
|
||||
}
|
||||
|
||||
uint64_t Window::getStartTime() const
|
||||
{
|
||||
return m_startTime;
|
||||
}
|
||||
|
||||
float Window::dt() const
|
||||
{
|
||||
return (float)m_lastFrameTime / (float)BILLION;
|
||||
}
|
||||
|
||||
uint64_t Window::getFPS() const
|
||||
{
|
||||
if (m_lastFrameTime == 0) return 0;
|
||||
return BILLION / m_lastFrameTime;
|
||||
}
|
||||
|
||||
uint64_t Window::getAvgFPS() const
|
||||
{
|
||||
uint64_t delta_t = getNanos() - m_avgFpsStart;
|
||||
if (delta_t == 0) return 0;
|
||||
return BILLION * (m_frames - m_avgFpsStartCount) / delta_t;
|
||||
}
|
||||
|
||||
void Window::resetAvgFPS()
|
||||
{
|
||||
m_avgFpsStart = getNanos();
|
||||
m_avgFpsStartCount = getFrameCount();
|
||||
}
|
||||
|
||||
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 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* STATIC METHODS */
|
||||
|
||||
// Display an error message box
|
||||
void Window::errorBox(const std::string& message)
|
||||
{
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Game Error", message.c_str(), NULL);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user