#include "gl3w.h" #include "GLBuffer.h" #include "ruby.h" #include "Window.h" #include #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); }