Files
NBEngine/engine/NBGraphics/src/Window.cpp
T

335 lines
9.2 KiB
C++

#include <NBGraphics/Window.hpp>
namespace nb {
std::map<GLFWwindow*, Window*> Window::WindowContexts = {};
std::map<int, int> Window::GLFWHints = {};
bool Window::StrictInitialization = true;
bool Window::_glfw_init = false;
Window* Window::_current = nullptr;
static std::map<int, int> defailt_window_hints = {
{GLFW_CONTEXT_VERSION_MAJOR, 3},
{GLFW_CONTEXT_VERSION_MINOR, 1},
{GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE}
#ifdef _NB_GL_DEBUG_ON
, {GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE}
#endif
};
using GLFWCodes = GLFWError::Codes;
const std::string GLFWError::type = "nb::GLFWError";
const ErrorCodeMap GLFWError::ErrorMessages = {
{GLFWCodes::UNDEFINED, "Error"},
{GLFWCodes::INIT_FAILED, "GLFW initialization failed"},
{GLFWCodes::GLFW_INTIALIZED, "GLFW has already been initialized"},
{GLFWCodes::GLAD_FAILED, "GLAD initialization failed"},
{GLFWCodes::NOT_MAIN, "Action can only be done on main thread"},
{GLFWCodes::WINDOW_FAILED, "Failed to initialize window"}
};
using WindowErrorCodes = WindowError::Codes;
const std::string WindowError::type = "nb::WindowError";
const ErrorCodeMap WindowError::ErrorMessages = {
{WindowErrorCodes::UNDEFINED, "Error"},
{WindowErrorCodes::INITIALIZED_WINDOW, "Window already initialized"},
{WindowErrorCodes::NO_GLFW, "GLFW has not been initialized"},
{WindowErrorCodes::INIT_FAILED, "Could not intialized window"}
};
// class Window
int Window::getGLFWHint(int hint_key) {
if (GLFWHints.find(hint_key) == GLFWHints.end()) {
return 0;
} else {
return GLFWHints.at(hint_key);
}
}
int Window::setGLFWHint(int hint_key, int hint_val) {
if (Window::_glfw_init) {
THROW(GLFWError(GLFWCodes::GLFW_INTIALIZED));
} else {
GLFWHints[hint_key] = hint_val;
}
return GLFWHints[hint_key];
}
Window* Window::getCurrent() {
return _current;
}
bool Window::checkKillGLFW() {
if(Window::WindowContexts.size() == 0 && _glfw_init) {
glfwTerminate();
Window::_glfw_init = false;
return true;
}
return false;
}
Window::Window(const uint16_t x, const uint16_t y, const char* initName, GLFWmonitor* initMonitor, GLFWwindow* initWindow) {
if (!Window::_glfw_init) {
for (const auto& hint : Window::GLFWHints) {
glfwInitHint(hint.first, hint.second);
}
int glfwResponse = glfwInit();
if (glfwResponse) {
Window::_glfw_init = true;
} else {
if (Window::StrictInitialization) {
THROW(GLFWError(GLFWCodes::INIT_FAILED));
}
}
}
windowSize = {x, y};
_aspect_ratio = float(x)/float(y);
windowName = std::string(initName);
monitor = initMonitor;
shareWindow = initWindow;
for (const auto& hint: defailt_window_hints) {
windowHints[hint.first] = hint.second;
}
}
Window::Window(const std::array<uint16_t, 2> initSize, const char* initName, GLFWmonitor* initMonitor, GLFWwindow* initWindow) :
Window(initSize[0], initSize[1], initName, initMonitor, initWindow){}
Window::~Window() {
glfwSetWindowShouldClose(window, true);
glfwDestroyWindow(window);
Window::WindowContexts.erase(window);
if (Window::WindowContexts.size()==0) {
glfwTerminate();
}
}
void Window::setCurrent() {
_current = this;
glfwMakeContextCurrent(window);
}
int Window::getWindowHint(int hint_key) const {
if (windowHints.find(hint_key) == windowHints.end()) {
return 0;
} else {
return windowHints.at(hint_key);
}
}
int Window::setWindowHint(int hint_key, int hint_val) {
if (_init) {
THROW(WindowError(WindowErrorCodes::INITIALIZED_WINDOW));
} else {
windowHints[hint_key] = hint_val;
}
return windowHints[hint_key];
}
int Window::init() {
if (!_glfw_init) {
THROW(WindowError(WindowErrorCodes::NO_GLFW));
}
for (const auto& hint : windowHints) {
glfwWindowHint(hint.first, hint.second);
}
window = glfwCreateWindow(windowSize[0], windowSize[1], windowName.c_str(), monitor, shareWindow);
if (window == NULL) {
Window::WindowContexts.erase(window);
if (Window::WindowContexts.size()==0 && Window::_glfw_init) { glfwTerminate(); }
if (Window::StrictInitialization) {
THROW(WindowError(WindowErrorCodes::INIT_FAILED));
}
}
glfwMakeContextCurrent(window);
Window::WindowContexts[window] = this;
gladResponse = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
if (!gladResponse) {
Window::checkKillGLFW();
if (Window::StrictInitialization) {
THROW(GLFWError(GLFWCodes::GLAD_FAILED));
}
}
_init = true;
OPENGL_CALL(
glViewport(0, 0, windowSize[0], windowSize[1])
);
return gladResponse;
}
GLFWwindow* Window::getWindow() const {
return window;
}
float Window::getAspectRatio() const { return _aspect_ratio; }
std::array<uint16_t, 2> Window::getSize() const {
return windowSize;
}
std::string Window::getName() const {
return windowName;
}
void Window::resize(const std::array<uint16_t, 2> newSize) {
windowSize = newSize;
_aspect_ratio = float(newSize[0]) / float(newSize[1]);
OPENGL_CALL(
glViewport(0, 0, windowSize[0], windowSize[1])
);
glfwSetWindowSize(window, windowSize[0], windowSize[1]);
}
void Window::resize(const uint16_t x, const uint16_t y) { resize({x, y}); }
// class OGLWindow
std::atomic<bool> OGLWindow::_glfwInitialized = false;
thread_local std::shared_ptr<OGLWindow> OGLWindow::_currWindow = nullptr;
thread_local GLFWwindow* OGLWindow::_currArena = nullptr;
std::atomic<unsigned int> OGLWindow::_count = 0;
bool OGLWindow::InitGLFW(const std::vector<GLFWHint>& hints) {
if (nb::MainTID != GetTID()) {
THROW(GLFWError(GLFWError::NOT_MAIN));
}
if (!IsGLFWInitialized()) {
for (const auto& hint : hints) {
glfwInitHint(hint[0], hint[1]);
}
if (glfwInit()) {
OGLWindow::_glfwInitialized.store(true, std::memory_order_release);
} else {
THROW(GLFWError(GLFWError::INIT_FAILED));
}
}
return IsGLFWInitialized();
}
bool OGLWindow::TerminateGLFW() {
if (nb::MainTID != GetTID()) {
THROW(GLFWError(GLFWError::NOT_MAIN));
}
if (IsGLFWInitialized()) {
glfwTerminate();
OGLWindow::_glfwInitialized.store(false, std::memory_order_release);
}
return !IsGLFWInitialized();
}
void OGLWindow::SetHintInteger(const std::array<int, 2>& hint) {
CheckForMainThread();
glfwWindowHint(hint[0], hint[1]);
}
void OGLWindow::SetHintString(const std::tuple<int, std::string>& hint) {
CheckForMainThread();
glfwWindowHintString(std::get<0>(hint), std::get<1>(hint).c_str());
}
std::shared_ptr<OGLWindow> OGLWindow::MakeCurrent(const std::shared_ptr<OGLWindow>& window) {
auto tmp = _currWindow;
_currWindow = window;
if (window) {
glfwMakeContextCurrent(_currWindow->_window_ptr);
_currArena = window->_arena;
} else {
glfwMakeContextCurrent(nullptr);
_currArena = nullptr;
}
return tmp;
}
OGLWindow::OGLWindow(
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
) : _title(title) {
CheckForMainThread();
InitGLFW();
for (const auto& hint : integerHints) {
SetHintInteger(hint);
}
for (const auto& hint : stringHints) {
SetHintString(hint);
}
_window_ptr = glfwCreateWindow(
x,
y,
_title.c_str(),
NULL,
NULL
);
if (_window_ptr == NULL) {
THROW(GLFWError(GLFWError::Codes::WINDOW_FAILED));
}
_arena = _window_ptr;
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
THROW(GLFWError(GLFWError::Codes::GLAD_FAILED));
}
OGLWindow::_count.fetch_add(1);
}
std::shared_ptr<OGLWindow> 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
) {
return std::shared_ptr<OGLWindow>( new OGLWindow(
x,
y,
title,
integerHints,
stringHints
) );
}
OGLWindow::~OGLWindow() {
CheckForMainThread();
if (_window_ptr) {
if (_window_ptr == _currWindow->_window_ptr) {
_currWindow = nullptr;
_currArena = nullptr;
}
glfwDestroyWindow(_window_ptr);
_count.fetch_add(-1);
if (!_count.load()) {
TerminateGLFW();
}
}
}
int OGLWindow::getWindowAttribute(int attr) const {
CheckForMainThread();
return glfwGetWindowAttrib(_window_ptr, attr);
}
std::array<int, 2> OGLWindow::getSize() const {
CheckForMainThread();
int x, y;
glfwGetWindowSize(_window_ptr, &x, &y);
return {x, y};
}
void OGLWindow::setSize(unsigned int x, unsigned int y) {
CheckForMainThread();
glfwSetWindowSize(_window_ptr, x, y);
}
void OGLWindow::setTitle(const std::string& name) {
CheckForMainThread();
_title = name;
glfwSetWindowTitle(_window_ptr, _title.c_str());
}
};