diff --git a/include/graphics/window.hpp b/include/graphics/window.hpp
new file mode 100644
index 0000000..2523c22
--- /dev/null
+++ b/include/graphics/window.hpp
@@ -0,0 +1,127 @@
+/**
+ This file is a part of our_dick
+ Copyright (C) 2020 rexy712
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef OUR_DICK_GRAPHICS_WINDOW_HPP
+#define OUR_DICK_GRAPHICS_WINDOW_HPP
+
+#include "gl_include.hpp"
+#include "math/math.hpp"
+
+namespace graphics{
+
+ using namespace math;
+
+ class window
+ {
+ public:
+ enum class mousemode : int{
+ DISABLED,
+ HIDDEN,
+ NORMAL,
+ };
+ private:
+ static constexpr int s_default_cver_maj = 3;
+ static constexpr int s_default_cver_min = 3;
+
+ private:
+ GLFWwindow* m_window = nullptr;
+ char* m_title = nullptr;
+ int m_antialias_level = 0;
+ int m_refresh_rate = GLFW_DONT_CARE;
+ int m_swap_interval = 1;
+
+ public:
+ window(int width, int height, const char* title);
+ window(int context_vmaj, int context_vmin, int width, int height, const char* title, int antialias = 0, int refresh = GLFW_DONT_CARE);
+ window(const window&);
+ window(window&&);
+ ~window();
+
+ window& operator=(const window&);
+ window& operator=(window&&);
+
+ GLFWwindow* raw();
+ const GLFWwindow* raw()const;
+
+ operator GLFWwindow*();
+ operator const GLFWwindow*()const;
+
+ void make_current();
+ void swap_buffers();
+
+ void destroy();
+
+ void set_size(const vec2&);
+ void set_size(int w, int h);
+ void set_width(int w);
+ void set_height(int h);
+ void set_title(const char* t);
+ void set_pos(const vec2&);
+ void set_pos(int x, int y);
+ void set_x(int x);
+ void set_y(int y);
+
+ void set_visible(bool b = true);
+ void toggle_visible();
+ void set_resizable(bool b = true);
+ void set_decorated(bool b = true);
+ void set_always_on_top(bool b = true);
+ void set_antialias(int level);
+ void set_refresh_rate(int rate);
+ void set_swap_interval(int i);
+ void set_should_close(bool b = true);
+ void set_mousemode(mousemode m);
+
+ void set_key_callback();
+ //TODO callbacks
+ void set_active();
+
+
+ vec2 get_size()const;
+ int get_width()const;
+ int get_height()const;
+
+ vec2 get_pos()const;
+ int get_posx()const;
+ int get_posy()const;
+
+ vec2 get_context_version()const;
+ int get_context_vmaj()const;
+ int get_context_vmin()const;
+ int get_swap_interval()const;
+
+ vec2 get_cursor_pos()const;
+ double get_cursor_posx()const;
+ double get_cursor_posy()const;
+ bool get_key(int key, int action)const;
+
+ bool is_visible()const;
+ bool is_resizable()const;
+ bool is_decorated()const;
+ bool is_always_on_top()const;
+ bool is_fullscreen()const;
+ bool should_close()const;
+ mousemode get_mousemode()const;
+
+ private:
+ void copy_title(const char* title, size_t titlelen);
+ };
+
+}
+
+#endif
diff --git a/include/render.hpp b/include/render.hpp
index 7e5a71e..f7399bf 100644
--- a/include/render.hpp
+++ b/include/render.hpp
@@ -3,6 +3,7 @@
#include
#include "graphics/gl_include.hpp"
+#include "graphics/window.hpp"
#define OPENGL_VERSION 400
#define GLSL_VERSION 400
@@ -11,12 +12,14 @@ class GLFWwindow;
class render_manager
{
+private:
+ static inline bool s_initialized = false;
private:
using close_callback = void(*)(void);
using input_callback = void(*)(GLFWwindow*, int, int, int, int);
close_callback m_window_close_callback;
input_callback m_input_handler;
- GLFWwindow* m_main_window;
+ graphics::window m_main_window;
public:
enum renderer_error{
@@ -29,8 +32,9 @@ public:
render_manager(const render_manager&) = delete;
render_manager(render_manager&&) = delete;
- render_manager();
- renderer_error init(int width, int height, const char* title); // Sets up the OpenGL environment
+ bool should_close()const;
+
+ render_manager(int width, int height, const char* title);
void update(); // Update the GL context and draw new frame
void request_exit();
diff --git a/src/graphics/window.cpp b/src/graphics/window.cpp
new file mode 100644
index 0000000..067a20c
--- /dev/null
+++ b/src/graphics/window.cpp
@@ -0,0 +1,279 @@
+/**
+ This file is a part of our_dick
+ Copyright (C) 2020 rexy712
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+#include "graphics/window.hpp"
+
+#include //exchange, swap, pair
+#include //strlen, strncpy
+
+namespace graphics{
+
+ window::window(int width, int height, const char* title):
+ window(s_default_cver_maj, s_default_cver_min, width, height, title){}
+ window::window(int cver_maj, int cver_min, int width, int height, const char* title, int antialias, int refresh):
+ m_antialias_level(antialias),
+ m_refresh_rate(refresh)
+ {
+ copy_title(title, strlen(title));
+
+ glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
+ glfwWindowHint(GLFW_DECORATED, GLFW_TRUE);
+ glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
+ glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
+ glfwWindowHint(GLFW_REFRESH_RATE, m_refresh_rate);
+ glfwWindowHint(GLFW_SAMPLES, m_antialias_level);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, cver_maj);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, cver_min);
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ m_window = glfwCreateWindow(width, height, title, nullptr, nullptr);
+ }
+ window::window(const window& w):
+ m_antialias_level(w.m_antialias_level),
+ m_refresh_rate(w.m_refresh_rate),
+ m_swap_interval(w.m_swap_interval)
+ {
+ GLFWwindow* current_context = glfwGetCurrentContext();
+
+ copy_title(w.m_title, strlen(w.m_title));
+
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, w.get_context_vmaj());
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, w.get_context_vmin());
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ glfwWindowHint(GLFW_RESIZABLE, w.is_resizable());
+ glfwWindowHint(GLFW_DECORATED, w.is_decorated());
+ glfwWindowHint(GLFW_FLOATING, w.is_always_on_top());
+ glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
+ glfwWindowHint(GLFW_REFRESH_RATE, w.m_refresh_rate);
+ glfwWindowHint(GLFW_SAMPLES, w.m_antialias_level);
+
+ auto size = w.get_size();
+ m_window = glfwCreateWindow(size.x(), size.y(), m_title, nullptr, nullptr);
+ make_current();
+ set_swap_interval(w.m_swap_interval);
+ set_pos(w.get_pos());
+ set_visible(w.is_visible());
+
+ glfwMakeContextCurrent(current_context);
+ }
+ window::window(window&& w):
+ m_window(std::exchange(w.m_window, nullptr)),
+ m_title(std::exchange(w.m_title, nullptr)),
+ m_antialias_level(w.m_antialias_level),
+ m_refresh_rate(w.m_refresh_rate),
+ m_swap_interval(w.m_swap_interval){}
+ window::~window(){
+ destroy();
+ }
+
+ window& window::operator=(const window& w){
+ return (*this = window(w));
+ }
+ window& window::operator=(window&& w){
+ std::swap(m_window, w.m_window);
+ m_antialias_level = w.m_antialias_level;
+ m_refresh_rate = w.m_refresh_rate;
+ m_swap_interval = w.m_swap_interval;
+ return *this;
+ }
+ GLFWwindow* window::raw(){
+ return m_window;
+ }
+ const GLFWwindow* window::raw()const{
+ return m_window;
+ }
+
+ window::operator GLFWwindow*(){
+ return m_window;
+ }
+ window::operator const GLFWwindow*()const{
+ return m_window;
+ }
+
+
+ void window::make_current(){
+ glfwMakeContextCurrent(m_window);
+ }
+ void window::swap_buffers(){
+ glfwSwapBuffers(m_window);
+ }
+
+ void window::destroy(){
+ if(m_window)
+ glfwDestroyWindow(m_window);
+ m_window = nullptr;
+
+ delete[] m_title;
+ m_title = nullptr;
+ }
+
+ void window::set_size(const vec2& v){
+ set_size(v.x(), v.y());
+ }
+ void window::set_size(int w, int h){
+ glfwSetWindowSize(m_window, w, h);
+ }
+ void window::set_width(int w){
+ set_size(w, get_height());
+ }
+ void window::set_height(int h){
+ set_size(get_width(), h);
+ }
+ void window::set_title(const char* t){
+ glfwSetWindowTitle(m_window, t);
+ }
+ void window::set_pos(const vec2& v){
+ set_pos(v.x(), v.y());
+ }
+ void window::set_pos(int x, int y){
+ glfwSetWindowPos(m_window, x, y);
+ }
+ void window::set_x(int x){
+ set_pos(x, get_posy());
+ }
+ void window::set_y(int y){
+ set_pos(get_posx(), y);
+ }
+
+ void window::set_visible(bool b){
+ if(b)
+ glfwShowWindow(m_window);
+ else
+ glfwHideWindow(m_window);
+ }
+ void window::toggle_visible(){
+ if(is_visible())
+ glfwHideWindow(m_window);
+ else
+ glfwShowWindow(m_window);
+ }
+ void window::set_resizable(bool b){
+ glfwSetWindowAttrib(m_window, GLFW_RESIZABLE, b);
+ }
+ void window::set_decorated(bool b){
+ glfwSetWindowAttrib(m_window, GLFW_DECORATED, b);
+ }
+ void window::set_always_on_top(bool b){
+ glfwSetWindowAttrib(m_window, GLFW_FLOATING, b);
+ }
+ void window::set_antialias(int level){
+ m_antialias_level = level;
+ }
+ void window::set_refresh_rate(int rate){
+ m_refresh_rate = rate;
+ }
+ void window::set_swap_interval(int i){
+ GLFWwindow* current_context = glfwGetCurrentContext();
+ glfwMakeContextCurrent(m_window);
+ glfwSwapInterval(i);
+ glfwMakeContextCurrent(current_context);
+ }
+
+ void window::set_should_close(bool b){
+ glfwSetWindowShouldClose(m_window, b);
+ }
+/*
+ void window::set_mousemode(mousemode m){
+ //TODO
+ }
+*/
+ void window::set_active(){
+ glfwMakeContextCurrent(m_window);
+ }
+
+
+ vec2 window::get_size()const{
+ vec2 retval;
+ glfwGetWindowSize(m_window, &retval.x(), &retval.y());
+ return retval;
+ }
+ int window::get_width()const{
+ return get_size().x();
+ }
+ int window::get_height()const{
+ return get_size().y();
+ }
+
+ vec2 window::get_pos()const{
+ vec2 retval;
+ glfwGetWindowPos(m_window, &retval.x(), &retval.y());
+ return retval;
+ }
+ int window::get_posx()const{
+ return get_pos().x();
+ }
+ int window::get_posy()const{
+ return get_pos().x();
+ }
+ vec2 window::get_context_version()const{
+ return vec2{get_context_vmaj(), get_context_vmin()};
+ }
+ int window::get_context_vmaj()const{
+ return glfwGetWindowAttrib(m_window, GLFW_CONTEXT_VERSION_MAJOR);
+ }
+ int window::get_context_vmin()const{
+ return glfwGetWindowAttrib(m_window, GLFW_CONTEXT_VERSION_MINOR);
+ }
+ int window::get_swap_interval()const{
+ return m_swap_interval;
+ }
+
+ vec2 window::get_cursor_pos()const{
+ vec2 retval;
+ glfwGetCursorPos(m_window, &retval.x(), &retval.y());
+ return retval;
+ }
+ double window::get_cursor_posx()const{
+ return get_cursor_pos().x();
+ }
+ double window::get_cursor_posy()const{
+ return get_cursor_pos().y();
+ }
+ bool window::get_key(int key, int action)const{
+ return glfwGetKey(m_window, key) == action;
+ }
+
+ bool window::is_visible()const{
+ return glfwGetWindowAttrib(m_window, GLFW_VISIBLE);
+ }
+ bool window::is_resizable()const{
+ return glfwGetWindowAttrib(m_window, GLFW_RESIZABLE);
+ }
+ bool window::is_decorated()const{
+ return glfwGetWindowAttrib(m_window, GLFW_DECORATED);
+ }
+ bool window::is_always_on_top()const{
+ return glfwGetWindowAttrib(m_window, GLFW_FLOATING);
+ }
+ bool window::should_close()const{
+ return glfwWindowShouldClose(m_window);
+ }
+/* bool window::is_fullscreen()const{
+ //TODO
+ }
+ auto window::get_mousemode()const -> mousemode{
+ //TODO
+ }
+*/
+ void window::copy_title(const char* title, size_t titlelen){
+ m_title = new char[titlelen + 1];
+ strncpy(m_title, title, titlelen);
+ m_title[titlelen] = 0;
+ }
+}
diff --git a/src/main.cpp b/src/main.cpp
index 10b219a..8b3e022 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -30,7 +30,6 @@
namespace{
bool running = true;
- render_manager manager;
}
int get_player_input(){
@@ -103,10 +102,10 @@ void handle_window_close(){
running = false;
}
-void handle_input_events(GLFWwindow*, int key, int, int, int){
+void handle_input_events(GLFWwindow* window, int key, int, int, int){
debug_print("[II] Recieved keycode %d\n", key);
if(key == 256)
- manager.request_exit();
+ glfwSetWindowShouldClose(window, GLFW_TRUE);
}
audio::mixchunk read_audio_file(const char* filename){
@@ -188,10 +187,11 @@ int main(){
};
srand(time(NULL));
+ glfwInit(); //TODO: handle in a similar way as PortAudio library initialization
game_state gs = {};
audio::mixer mix(audio::mixer::mode::STEREO, 1, 44100);
- manager.init(640, 480, "Tic-Tac-Gugh");
+ render_manager manager(640, 480, "Tic-Tac-Gugh");
manager.handle_window_close_event(handle_window_close);
manager.handle_keypress_event(handle_input_events);
@@ -213,7 +213,7 @@ int main(){
attrib.set_float_pointer(3, 3, 0);
attrib.enable_array_mode();
- while(running){
+ while(!manager.should_close()){
//render using program 'prog' with data from 'vao'
prog.use();
vao.bind();
@@ -226,4 +226,5 @@ int main(){
game_turn(gs, get_player_input());
}
t.join();
+ //TODO: cannot call glfwTerminate before the window is closed
}
diff --git a/src/render.cpp b/src/render.cpp
index 587a63b..f6d9d19 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -1,6 +1,7 @@
#include "graphics/gl_include.hpp"
#include "render.hpp"
#include "config.hpp"
+#include "graphics/window.hpp"
#include
namespace{
@@ -11,45 +12,25 @@ namespace{
}
-render_manager::render_manager() :
+render_manager::render_manager(int width, int height, const char* title):
m_window_close_callback(nullptr),
m_input_handler(nullptr),
- m_main_window(nullptr){}
-
-render_manager::renderer_error render_manager::init (int width, int height, const char* title){
- if(!glfwInit()){
- fprintf(stderr, "[EE] failed to initialize GLFW.\n");
- return RENDERER_INIT_ERROR;
- }
-
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-
- m_main_window = glfwCreateWindow(width, height, title, nullptr, nullptr);
- if(!m_main_window){
- fprintf(stderr, "[EE] Could not create window\n");
- return RENDERER_WINDOW_ERROR;
- }
-
- glfwMakeContextCurrent(m_main_window);
- if(gl3wInit()){
- fprintf(stderr, "[EE] failed to initialize OpenGL\n");
- return RENDERER_CONTEXT_ERROR;
- }
-
+ m_main_window(width, height, title)
+{
+ m_main_window.make_current();
+ gl3wInit();
glViewport(0, 0, width, height);
glClearColor(0, 0, 0, 1);
-
- debug_print("[DD] OpenGL %s, GLSL %s\n", glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION));
-
glfwSetFramebufferSizeCallback(m_main_window, handle_resize_event);
+ m_main_window.set_visible(true);
+}
- return RENDERER_OK;
+bool render_manager::should_close()const{
+ return m_main_window.should_close();
}
void render_manager::update(){
- glfwSwapBuffers(m_main_window);
+ m_main_window.swap_buffers();
glClear(GL_COLOR_BUFFER_BIT);
glfwPollEvents();
}
@@ -57,5 +38,5 @@ void render_manager::update(){
void render_manager::request_exit(){
if(m_window_close_callback)
m_window_close_callback();
- glfwSetWindowShouldClose(m_main_window, GLFW_TRUE);
+ m_main_window.set_should_close(true);
}