jes-ruby/src/Window.cc

174 lines
3.7 KiB
C++

#include "gl3w.h"
#include "GLBuffer.h"
#include "ruby.h"
#include "Window.h"
#include <SDL.h>
#define WIDTH 500
#define HEIGHT 500
typedef struct
{
SDL_Window * sdl_window;
GLBufferRef rect_buffer;
} Window;
static VALUE ruby_class;
static VALUE window_instance;
static void Init_SDL()
{
static bool initialized = false;
if (initialized)
return;
if (SDL_Init(SDL_INIT_VIDEO))
{
rb_raise(rb_eRuntimeError, "Failed to initialize SDL");
}
atexit(SDL_Quit);
initialized = true;
}
static void load_gl_buffers(Window * window)
{
static const GLint rect_coords[4][2] = {
{0, 0},
{1, 0},
{0, 1},
{1, 1},
};
window->rect_buffer = new GLBuffer();
if (!window->rect_buffer->create(GL_ARRAY_BUFFER, GL_STATIC_DRAW,
&rect_coords, sizeof(rect_coords)))
{
rb_raise(rb_eRuntimeError, "Failed to create rectangle VBO");
}
}
static void Init_OpenGL()
{
static bool initialized = false;
if (initialized)
return;
if (gl3wInit() != 0)
{
SDL_Quit();
rb_raise(rb_eRuntimeError, "Failed to gl3wInit()");
}
if (!gl3wIsSupported(3, 0))
{
SDL_Quit();
rb_raise(rb_eRuntimeError, "OpenGL 3.0 is not supported");
}
initialized = true;
}
static void Window_free(void * ptr)
{
Window * window = (Window *)ptr;
if (window->sdl_window)
SDL_DestroyWindow(window->sdl_window);
delete window;
}
static VALUE Window_new(VALUE klass)
{
static bool one_created = false;
if (one_created)
{
rb_raise(rb_eRuntimeError, "Only one Window for now");
}
Init_SDL();
SDL_Window * sdl_window =
SDL_CreateWindow("jes",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WIDTH,
HEIGHT,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (sdl_window == NULL)
{
rb_raise(rb_eRuntimeError, "Failed to create SDL window");
}
Window * window = new Window();
window->sdl_window = sdl_window;
(void)SDL_GL_CreateContext(window->sdl_window);
Init_OpenGL();
load_gl_buffers(window);
one_created = true;
VALUE rv = Data_Wrap_Struct(ruby_class, NULL, Window_free, window);
rb_obj_call_init(rv, 0, NULL);
/* TODO: remove window_instance and map SDL_Window * to Window Ruby object
* to support multiple windows. */
window_instance = rv;
return rv;
}
static void resize()
{
GLint viewport_size[2];
Window * window;
Data_Get_Struct(window_instance, Window, window);
SDL_GetWindowSize(window->sdl_window, &viewport_size[0], &viewport_size[1]);
glViewport(0, 0, viewport_size[0], viewport_size[1]);
}
static VALUE Window_event_loop(VALUE klass)
{
SDL_Event event;
while (SDL_WaitEvent(&event))
{
if (event.type == SDL_QUIT)
break;
else if (event.type == SDL_KEYDOWN)
{
if (event.key.keysym.sym == SDLK_ESCAPE)
break;
}
else if (event.type == SDL_WINDOWEVENT)
{
switch (event.window.event)
{
case SDL_WINDOWEVENT_EXPOSED:
// draw();
break;
case SDL_WINDOWEVENT_RESIZED:
resize();
// draw();
break;
}
}
}
return Qnil;
}
void Window_Init(void)
{
ruby_class = rb_define_class("Window", rb_cObject);
rb_define_singleton_method(ruby_class, "new", (VALUE(*)(...))Window_new, 0);
rb_define_singleton_method(ruby_class, "event_loop", (VALUE(*)(...))Window_event_loop, 0);
}