Add RAII window class

This commit is contained in:
rexy712 2020-09-22 15:24:31 -07:00
parent d0fc25d3c2
commit fb692b80b4
5 changed files with 431 additions and 39 deletions

127
include/graphics/window.hpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<int>&);
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<int>&);
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<int> get_size()const;
int get_width()const;
int get_height()const;
vec2<int> get_pos()const;
int get_posx()const;
int get_posy()const;
vec2<int> get_context_version()const;
int get_context_vmaj()const;
int get_context_vmin()const;
int get_swap_interval()const;
vec2<double> 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

View File

@ -3,6 +3,7 @@
#include <cstdint>
#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();

279
src/graphics/window.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "graphics/window.hpp"
#include <utility> //exchange, swap, pair
#include <cstring> //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<int>& 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<int>& 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<int> window::get_size()const{
vec2<int> 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<int> window::get_pos()const{
vec2<int> 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<int> window::get_context_version()const{
return vec2<int>{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<double> window::get_cursor_pos()const{
vec2<double> 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;
}
}

View File

@ -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
}

View File

@ -1,6 +1,7 @@
#include "graphics/gl_include.hpp"
#include "render.hpp"
#include "config.hpp"
#include "graphics/window.hpp"
#include <cstdio>
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);
}