272 lines
9.9 KiB
C++
272 lines
9.9 KiB
C++
#pragma once
|
|
#ifndef _NB_WINDOW
|
|
#define _NB_WINDOW
|
|
|
|
#include <NBGraphics/GLLoad.hpp>
|
|
#include <NBGraphics/OGLObjects.hpp>
|
|
|
|
#include <array>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <NBCore/Errors.hpp>
|
|
#include <NBCore/Utils.hpp>
|
|
|
|
namespace nb {
|
|
|
|
class GLFWError : public Error<GLFWError> {
|
|
using Base = Error<GLFWError>;
|
|
|
|
public:
|
|
using Base::Base;
|
|
|
|
enum Codes : unsigned int {
|
|
UNDEFINED, INIT_FAILED, GLFW_INTIALIZED, GLAD_FAILED,
|
|
NOT_MAIN, WINDOW_FAILED
|
|
};
|
|
|
|
static const std::string type;
|
|
static const ErrorCodeMap ErrorMessages;
|
|
};
|
|
|
|
class OGLWindow;
|
|
|
|
enum WindowCallbacks {
|
|
KEY, CHAR, CHAR_MODS, MOUSE_BUTTON, CURSOR_POS, CURSOR_ENTER,
|
|
SCROLL, DROP, WINDOW_POS, WINDOW_SIZE, WINDOW_CLOSE, WINDOW_REFRESH,
|
|
WINDOW_FOCUS, WINDOW_ICONIFY, WINDOW_MAX, FRAMEBUFFER_SIZE, WINDOW_SCALE,
|
|
};
|
|
|
|
template<WindowCallbacks>
|
|
struct OGLWindowCallbacks;
|
|
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::KEY> {
|
|
using type = typename std::function<void(OGLWindow*, int, int, int, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::CHAR> {
|
|
using type = typename std::function<void(OGLWindow*, unsigned int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::CHAR_MODS> {
|
|
using type = typename std::function<void(OGLWindow*, unsigned int, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::CURSOR_ENTER> {
|
|
using type = typename std::function<void(OGLWindow*, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::CURSOR_POS> {
|
|
using type = typename std::function<void(OGLWindow*, double, double)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::MOUSE_BUTTON> {
|
|
using type = typename std::function<void(OGLWindow*, int, int, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::SCROLL> {
|
|
using type = typename std::function<void(OGLWindow*, double, double)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::DROP> {
|
|
using type = typename std::function<void(OGLWindow*, int, const char**)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::WINDOW_POS> {
|
|
using type = typename std::function<void(OGLWindow*, int, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::WINDOW_SIZE> {
|
|
using type = typename std::function<void(OGLWindow*, int, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::WINDOW_CLOSE> {
|
|
using type = typename std::function<void(OGLWindow*)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::WINDOW_REFRESH> {
|
|
using type = typename std::function<void(OGLWindow*)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::WINDOW_FOCUS> {
|
|
using type = typename std::function<void(OGLWindow*, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::WINDOW_ICONIFY> {
|
|
using type = typename std::function<void(OGLWindow*, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::WINDOW_MAX> {
|
|
using type = typename std::function<void(OGLWindow*, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::FRAMEBUFFER_SIZE> {
|
|
using type = typename std::function<void(OGLWindow*, int, int)>;
|
|
};
|
|
template<>
|
|
struct OGLWindowCallbacks<WindowCallbacks::WINDOW_SCALE> {
|
|
using type = typename std::function<void(OGLWindow*, int)>;
|
|
};
|
|
|
|
class OGLWindow {
|
|
using GLFWHint = std::array<int, 2>;
|
|
private:
|
|
static inline void CheckForMainThread() {
|
|
if (nb::CurrentTID != nb::MainTID) {
|
|
THROW(GLFWError(GLFWError::Codes::NOT_MAIN));
|
|
}
|
|
}
|
|
|
|
protected:
|
|
static std::atomic<unsigned int> _count;
|
|
static std::atomic<bool> _glfwInitialized;
|
|
static thread_local GLFWwindow* _currWindow;
|
|
static thread_local const GLFWwindow* _currArena;
|
|
|
|
static void SetHintInteger(const std::array<int, 2>&);
|
|
static void SetHintString(const std::tuple<int, std::string>&);
|
|
|
|
std::string _title;
|
|
GLFWwindow* _window_ptr;
|
|
const GLFWwindow* _arena;
|
|
|
|
OGLWindow(
|
|
unsigned int,
|
|
unsigned int,
|
|
const std::string&,
|
|
const std::vector<std::array<int, 2>>& integerWindowHints,
|
|
const std::vector<std::tuple<int, std::string>>& stringWindowHints={},
|
|
GLFWwindow* sharingContext = NULL
|
|
);
|
|
GLFWwindow* makeCurrent() const;
|
|
void detachWindow();
|
|
|
|
public:
|
|
|
|
static inline bool IsGLFWInitialized() { return _glfwInitialized; }
|
|
static bool InitGLFW(const std::vector<GLFWHint>& hints={});
|
|
static bool TerminateGLFW();
|
|
static inline GLFWwindow* GetCurrentWindow() { return _currWindow; }
|
|
static inline const GLFWwindow* GetCurrentObjectArena() { return _currArena; }
|
|
static GLFWwindow* MakeCurrent(const std::shared_ptr<OGLWindow>&);
|
|
static inline GLFWwindow* DropCurrent() { return MakeCurrent(nullptr); }
|
|
static void DestroyWindow(std::shared_ptr<OGLWindow>&);
|
|
static std::shared_ptr<OGLWindow> CreateWindow(
|
|
unsigned int x,
|
|
unsigned int y,
|
|
const std::string& title,
|
|
const std::vector<std::array<int, 2>>& integerHints={},
|
|
const std::vector<std::tuple<int, std::string>>& stringHints={}
|
|
);
|
|
static std::shared_ptr<OGLWindow> CreateSharedWindow(
|
|
unsigned int x,
|
|
unsigned int y,
|
|
const std::string& title,
|
|
std::shared_ptr<OGLWindow> sharingWindow,
|
|
const std::vector<std::array<int, 2>>& integerHints={},
|
|
const std::vector<std::tuple<int, std::string>>& stringHints={}
|
|
);
|
|
|
|
OGLWindow(OGLWindow&&) = delete;
|
|
OGLWindow(const OGLWindow&) = delete;
|
|
~OGLWindow();
|
|
inline bool operator==(const OGLWindow& rhs) { return _window_ptr==rhs._window_ptr; }
|
|
|
|
int getWindowAttribute(int) const;
|
|
inline GLFWwindow* getWindowPtr() const { return _window_ptr; }
|
|
inline const GLFWwindow* getObjectArena() const { return _arena; }
|
|
inline std::string getTitle() const { return _title; }
|
|
std::array<int, 2> getSize() const;
|
|
bool shouldClose() const;
|
|
inline void pollEvents() const { CheckForMainThread(); glfwPollEvents(); }
|
|
inline void swapBuffers() const { glfwSwapBuffers(_window_ptr); }
|
|
|
|
void setSize(unsigned int x, unsigned int y);
|
|
void setTitle(const std::string&);
|
|
void shouldClose(bool);
|
|
|
|
template<WindowCallbacks CallbackType, typename CallbackFunc>
|
|
void setCallback(CallbackFunc callback) {
|
|
CheckForMainThread();
|
|
auto tmp = makeCurrent();
|
|
static auto this_ptr = this;
|
|
static typename OGLWindowCallbacks<CallbackType>::type tmp_callback = callback;
|
|
if constexpr (CallbackType == KEY) {
|
|
glfwSetKeyCallback(_window_ptr, [](GLFWwindow*, int a, int b, int c, int d){
|
|
tmp_callback(this_ptr, a,b,c,d);
|
|
});
|
|
} else if constexpr (CallbackType == CHAR) {
|
|
glfwSetCharCallback(_window_ptr, [](GLFWwindow*, int a) {
|
|
tmp_callback(this_ptr, a);
|
|
});
|
|
} else if constexpr (CallbackType == CHAR_MODS) {
|
|
glfwSetCharModsCallback(_window_ptr, [](GLFWwindow*, unsigned int a, int b) {
|
|
tmp_callback(this_ptr, a, b);
|
|
});
|
|
} else if constexpr (CallbackType == CURSOR_ENTER) {
|
|
glfwSetCursorEnterCallback(_window_ptr, [](GLFWwindow*, int a) {
|
|
tmp_callback(this_ptr, a);
|
|
});
|
|
} else if constexpr (CallbackType == CURSOR_POS) {
|
|
glfwSetCursorPosCallback(_window_ptr, [](GLFWwindow*, double a, double b){
|
|
tmp_callback(this_ptr, a,b);
|
|
});
|
|
} else if constexpr (CallbackType == MOUSE_BUTTON) {
|
|
glfwSetMouseButtonCallback(_window_ptr, [](GLFWwindow*, int a, int b, int c){
|
|
tmp_callback(this_ptr, a,b,c);
|
|
});
|
|
} else if constexpr (CallbackType == SCROLL) {
|
|
glfwSetScrollCallback(_window_ptr, [](GLFWwindow*, double a, double b) {
|
|
tmp_callback(this_ptr, a,b);
|
|
});
|
|
} else if constexpr (CallbackType == DROP) {
|
|
glfwSetDropCallback(_window_ptr, [](GLFWwindow*, int a, const char** b) {
|
|
tmp_callback(this_ptr, a, b);
|
|
});
|
|
} else if constexpr (CallbackType == WINDOW_POS) {
|
|
glfwSetWindowPosCallback(_window_ptr, [](GLFWwindow*, int a, int b){
|
|
tmp_callback(this_ptr, a,b);
|
|
});
|
|
} else if constexpr (CallbackType == WINDOW_SIZE) {
|
|
glfwSetWindowSizeCallback(_window_ptr, [](GLFWwindow*, int a, int b){
|
|
tmp_callback(this_ptr, a,b);
|
|
});
|
|
} else if constexpr (CallbackType == WINDOW_CLOSE) {
|
|
glfwSetWindowCloseCallback(_window_ptr, [](GLFWwindow*){
|
|
tmp_callback(this_ptr);
|
|
});
|
|
} else if constexpr (CallbackType == WINDOW_REFRESH) {
|
|
glfwSetWindowRefreshCallback(_window_ptr, [](GLFWwindow*){
|
|
tmp_callback(this_ptr);
|
|
});
|
|
} else if constexpr (CallbackType == WINDOW_FOCUS) {
|
|
glfwSetWindowFocusCallback(_window_ptr, [](GLFWwindow*, int a) {
|
|
tmp_callback(this_ptr, a);
|
|
});
|
|
} else if constexpr (CallbackType == WINDOW_ICONIFY) {
|
|
glfwSetWindowIconifyCallback(_window_ptr, [](GLFWwindow*, int a) {
|
|
tmp_callback(this_ptr, a);
|
|
});
|
|
} else if constexpr (CallbackType == WINDOW_MAX) {
|
|
glfwSetWindowMaximizeCallback(_window_ptr, [](GLFWwindow*, int a) {
|
|
tmp_callback(this_ptr, a);
|
|
});
|
|
} else if constexpr (CallbackType == FRAMEBUFFER_SIZE) {
|
|
glfwSetFramebufferSizeCallback(_window_ptr, [](GLFWwindow*, int a, int b) {
|
|
tmp_callback(this_ptr, a, b);
|
|
});
|
|
} else if constexpr (CallbackType == WINDOW_SCALE) {
|
|
glfwSetWindowContentScaleCallback(_window_ptr, [](GLFWwindow*, int a, int b) {
|
|
tmp_callback(this_ptr, a, b);
|
|
});
|
|
} else {
|
|
static_assert(false, "No matching callback.");
|
|
}
|
|
}
|
|
};
|
|
|
|
};
|
|
#endif |