add GL module; move OpenGL loading from Window to GL

This commit is contained in:
Josh Holtrop 2014-08-04 14:21:10 -04:00
parent f620f2b335
commit e2608b1d29
7 changed files with 156 additions and 120 deletions

34
runtime/lib/gl.rb Normal file
View File

@ -0,0 +1,34 @@
module GL
@programs = {}
class << self
def load_shaders
program_sources = {
text: ["text.v.glsl", "text.f.glsl"],
basic: ["basic.v.glsl", "basic.f.glsl"],
rect: ["rect.v.glsl", "basic.f.glsl"],
}
program_sources.each do |program, (v_src_fname, f_src_fname)|
v_src = Runtime.read(:shader, v_src_fname)
v_shader = GLShader.new(:vertex, v_src)
v_shader or raise "Could not find shader #{v_src_fname}"
f_src = Runtime.read(:shader, f_src_fname)
f_shader = GLShader.new(:fragment, f_src)
f_shader or raise "Could not find shader #{f_src_fname}"
uniforms = (v_src + f_src).lines.map do |line|
if line =~ /\buniform\s.*\s(\S+);/
$1
end
end.compact
@programs[program] = GLProgram.new(v_shader, f_shader,
uniforms: uniforms)
end
end
end
end

View File

@ -1,6 +1,7 @@
require "set" require "set"
class Window class Window
include Widget include Widget
@windows = Set.new @windows = Set.new
@ -16,42 +17,12 @@ class Window
end end
def initialize def initialize
super
@programs = {}
load_shaders
Window.register(self) Window.register(self)
super
end end
def close def close
Window.remove(self) Window.remove(self)
end end
private
def load_shaders
program_sources = {
text: ["text.v.glsl", "text.f.glsl"],
basic: ["basic.v.glsl", "basic.f.glsl"],
rect: ["rect.v.glsl", "basic.f.glsl"],
}
program_sources.each do |program, (v_src_fname, f_src_fname)|
v_src = Runtime.read(:shader, v_src_fname)
v_shader = GLShader.new(:vertex, v_src)
v_shader or raise "Could not find shader #{v_src_fname}"
f_src = Runtime.read(:shader, f_src_fname)
f_shader = GLShader.new(:fragment, f_src)
f_shader or raise "Could not find shader #{f_src_fname}"
uniforms = (v_src + f_src).lines.map do |line|
if line =~ /\buniform\s.*\s(\S+);/
$1
end
end.compact
@programs[program] = GLProgram.new(v_shader, f_shader,
uniforms: uniforms)
end
end
end end

View File

@ -3,6 +3,7 @@ def init_loadpath
end end
def load_lib_files def load_lib_files
require "gl"
require "gl_program" require "gl_program"
require "runtime" require "runtime"
require "widget" require "widget"

101
src/GL.cc Normal file
View File

@ -0,0 +1,101 @@
#include "GL.h"
#include "gl3w.h"
#include "ruby.h"
#include "GLBuffer.h"
#include "GLProgram.h"
enum
{
PROGRAM_TEXT,
PROGRAM_BASIC,
PROGRAM_RECT,
PROGRAM_COUNT
};
static const char * program_names[PROGRAM_COUNT] = {
"text",
"basic",
"rect",
};
static VALUE ruby_module;
static GLBufferRef rect_buffer;
static GLProgram * programs[PROGRAM_COUNT];
void GL_Init()
{
ruby_module = rb_define_module("GL");
}
static void load_gl_buffers()
{
static const GLint rect_coords[4][2] = {
{0, 0},
{1, 0},
{0, 1},
{1, 1},
};
rect_buffer = new GLBuffer();
if (!rect_buffer->create(GL_ARRAY_BUFFER, GL_STATIC_DRAW,
&rect_coords, sizeof(rect_coords)))
{
rb_raise(rb_eRuntimeError, "Failed to create rectangle VBO");
}
}
void GL_Load()
{
static bool loaded = false;
if (loaded)
return;
if (gl3wInit() != 0)
{
rb_raise(rb_eRuntimeError, "Failed to gl3wInit()");
}
if (!gl3wIsSupported(3, 0))
{
rb_raise(rb_eRuntimeError, "OpenGL 3.0 is not supported");
}
load_gl_buffers();
rb_funcall(ruby_module, rb_intern("load_shaders"), 0);
VALUE programs_hash = rb_iv_get(ruby_module, "@programs");
for (int i = 0; i < PROGRAM_COUNT; i++)
{
VALUE program = rb_funcall(programs_hash,
rb_intern("[]"),
1,
ID2SYM(rb_intern(program_names[i])));
if (RTEST(program))
{
programs[i] = GLProgram_FromRuby(program);
}
else
{
rb_raise(rb_eLoadError,
"Error resolving %s program",
program_names[i]);
}
}
glEnable(GL_SCISSOR_TEST);
loaded = true;
}
void GL_Resize(int width, int height)
{
GLint viewport_size[] = {width, height};
glViewport(0, 0, width, height);
for (int i = 0; i < PROGRAM_COUNT; i++)
{
glUseProgram(programs[i]->id);
glUniform2iv(programs[i]->uniforms[UNIFORM_VIEWPORT_SIZE], 1, &viewport_size[0]);
}
}

8
src/GL.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef GL_H
#define GL_H
void GL_Init();
void GL_Load();
void GL_Resize(int width, int height);
#endif

View File

@ -1,4 +1,5 @@
#include "gl3w.h" #include "gl3w.h"
#include "GL.h"
#include "GLBuffer.h" #include "GLBuffer.h"
#include "GLProgram.h" #include "GLProgram.h"
#include "ruby.h" #include "ruby.h"
@ -8,25 +9,9 @@
#define WIDTH 500 #define WIDTH 500
#define HEIGHT 500 #define HEIGHT 500
enum
{
PROGRAM_TEXT,
PROGRAM_BASIC,
PROGRAM_RECT,
PROGRAM_COUNT
};
const char * program_names[PROGRAM_COUNT] = {
"text",
"basic",
"rect",
};
typedef struct typedef struct
{ {
SDL_Window * sdl_window; SDL_Window * sdl_window;
GLBufferRef rect_buffer;
GLProgram * programs[PROGRAM_COUNT];
} Window; } Window;
static VALUE ruby_class; static VALUE ruby_class;
@ -49,47 +34,6 @@ static void Init_SDL()
initialized = true; 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");
}
glEnable(GL_SCISSOR_TEST);
initialized = true;
}
static void Window_free(void * ptr) static void Window_free(void * ptr)
{ {
Window * window = (Window *)ptr; Window * window = (Window *)ptr;
@ -102,23 +46,19 @@ static void Window_free(void * ptr)
static void resize() static void resize()
{ {
GLint viewport_size[2]; int width;
int height;
Window * window; Window * window;
Data_Get_Struct(window_instance, Window, window); Data_Get_Struct(window_instance, Window, window);
SDL_GetWindowSize(window->sdl_window, &viewport_size[0], &viewport_size[1]); SDL_GetWindowSize(window->sdl_window, &width, &height);
glViewport(0, 0, viewport_size[0], viewport_size[1]); GL_Resize(width, height);
for (int i = 0; i < PROGRAM_COUNT; i++)
{
glUseProgram(window->programs[i]->id);
glUniform2iv(window->programs[i]->uniforms[UNIFORM_VIEWPORT_SIZE], 1, &viewport_size[0]);
}
rb_funcall(window_instance, rb_funcall(window_instance,
rb_intern("resize"), rb_intern("resize"),
4, 4,
INT2FIX(0), INT2FIX(0),
INT2FIX(0), INT2FIX(0),
INT2FIX(viewport_size[0]), INT2FIX(width),
INT2FIX(viewport_size[1])); INT2FIX(height));
} }
static VALUE Window_new(VALUE klass) static VALUE Window_new(VALUE klass)
@ -149,33 +89,12 @@ static VALUE Window_new(VALUE klass)
(void)SDL_GL_CreateContext(window->sdl_window); (void)SDL_GL_CreateContext(window->sdl_window);
Init_OpenGL(); GL_Load();
load_gl_buffers(window);
one_created = true; one_created = true;
VALUE rv = Data_Wrap_Struct(ruby_class, NULL, Window_free, window); VALUE rv = Data_Wrap_Struct(ruby_class, NULL, Window_free, window);
rb_obj_call_init(rv, 0, NULL); rb_obj_call_init(rv, 0, NULL);
VALUE programs = rb_iv_get(rv, "@programs");
for (int i = 0; i < PROGRAM_COUNT; i++)
{
VALUE program = rb_funcall(programs,
rb_intern("[]"),
1,
ID2SYM(rb_intern(program_names[i])));
if (RTEST(program))
{
window->programs[i] = GLProgram_FromRuby(program);
}
else
{
delete window;
rb_raise(rb_eLoadError,
"Error resolving %s program",
program_names[i]);
}
}
/* TODO: remove window_instance and map SDL_Window * to Window Ruby object /* TODO: remove window_instance and map SDL_Window * to Window Ruby object
* to support multiple windows. */ * to support multiple windows. */

View File

@ -2,6 +2,7 @@
#include "ruby.h" #include "ruby.h"
#include "Font.h" #include "Font.h"
#include "GL.h"
#include "GLProgram.h" #include "GLProgram.h"
#include "GLShader.h" #include "GLShader.h"
#include "Widget.h" #include "Widget.h"
@ -54,6 +55,7 @@ static int bootstrap()
int err_state = 0; int err_state = 0;
Font_Init(); Font_Init();
GL_Init();
GLProgram_Init(); GLProgram_Init();
GLShader_Init(); GLShader_Init();
Widget_Init(); Widget_Init();