#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]; static VALUE GL_draw_rect(VALUE klass, VALUE x, VALUE y, VALUE width, VALUE height, VALUE r, VALUE g, VALUE b, VALUE a) { glUseProgram(programs[PROGRAM_RECT]->id); glUniform2i(programs[PROGRAM_RECT]->uniforms[UNIFORM_POSITION], FIX2INT(x), FIX2INT(y)); glUniform2i(programs[PROGRAM_RECT]->uniforms[UNIFORM_SIZE], FIX2INT(width), FIX2INT(height)); glUniform4f(programs[PROGRAM_RECT]->uniforms[UNIFORM_COLOR], RFLOAT_VALUE(r), RFLOAT_VALUE(g), RFLOAT_VALUE(b), RFLOAT_VALUE(a)); rect_buffer->bind(); glEnableVertexAttribArray(0); glVertexAttribIPointer(0, 2, GL_INT, 0, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); return Qnil; } void GL_Init() { ruby_module = rb_define_module("GL"); rb_define_singleton_method(ruby_module, "draw_rect", (VALUE(*)(...))GL_draw_rect, 4); } 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]); } }