vaiorabbit / ruby-opengl

Yet another OpenGL wrapper for Ruby (and wrapper code generator).
Other
88 stars 12 forks source link

opengl-bindings with Gtk::GLArea from ruby-gnome2 #17

Closed cedlemo closed 9 years ago

cedlemo commented 9 years ago

Hi @vaiorabbit,

I am trying to find out how to use your bindings with the gtk3 bindings from ruby-gnome2. Unfortunately, I am not an expert in OpenGl so I have written those 2 little scripts :

This one which should display a white triangle on a black background:

=begin
  gtkglarea1.rb draw a white triangle on a default black background
  sources:
  http://antongerdelan.net/opengl/hellotriangle.html
  opengl-bindings/sample/RedBook/varray
  http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/
=end

require "gtk3"
require 'glfw'
require 'opengl'
require 'glu'

case OpenGL.get_platform
when :OPENGL_PLATFORM_WINDOWS
  OpenGL.load_lib('opengl32.dll', 'C:/Windows/System32')
  GLU.load_lib('GLU32.dll', 'C:/Windows/System32')
  GLFW.load_lib('glfw3.dll', '..')
when :OPENGL_PLATFORM_MACOSX
  OpenGL.load_lib('libGL.dylib', '/System/Library/Frameworks/OpenGL.framework/Libraries')
  GLU.load_lib('libGLU.dylib', '/System/Library/Frameworks/OpenGL.framework/Libraries')
  GLFW.load_lib('libglfw.dylib', '..')
when :OPENGL_PLATFORM_LINUX
  OpenGL.load_lib('libGL.so', '/usr/lib')
  GLU.load_lib('libGLU.so', '/usr/lib')
  GLFW.load_lib('libglfw.so', '/usr/lib')
else
  raise RuntimeError, "Unsupported platform."
end

include GLFW
include OpenGL
include GLU

window = Gtk::Window.new("OpenGL widget test")

window.set_size_request(400, 400)
glarea = Gtk::GLArea.new

window.add(glarea)

glarea.signal_connect("realize") do |widget|
  widget.make_current
  puts "realize"
  # Define a triangle in a vertex buffer ( Vertex Buffer Object)

  points = [
    0.0, 0.5, 0.0,  #x1, y1, z1
    0.5, -0.5, 0.0, #x2, y2, z2
    -0.5, -0.5, 0.0 #x3, y3, z3
  ]
  # We copy those points onto the graphics card in a unit called vertex buffer object (vbo).
  # Create an empty buffer
  vbo_buf = '    '
  glGenBuffers(1, vbo_buf)
  g_vbo = vbo_buf.unpack('L')[0]
  # Set the empty buffer as the current OpenGL's state machine by "binding"
  glBindBuffer(GL_ARRAY_BUFFER, g_vbo)
  # Copy the points in the currently bound buffer
  glBufferData(GL_ARRAY_BUFFER, 3 * 4 * Fiddle::SIZEOF_FLOAT, points.pack('F*'), GL_STATIC_DRAW)

  # First attribute buffer : vertices
  glVertexAttribPointer(0,        # No particular reason for 0 
                        3,        # size
                        GL_FLOAT, # type
                        GL_FALSE, # normalized?
                        0,        # stride
                        0         # array buffer offset
                        )
  glEnableVertexAttribArray(0)
end
glarea.signal_connect("render") do |widget, context|
  puts "render"
  glClearColor(0.3, 0.3, 0.3, 1)
  glClear(GL_COLOR_BUFFER_BIT)
  glDrawArrays(GL_TRIANGLES, 0, 3)
  glDisableVertexAttribArray(0)
  true
end
window.signal_connect("destroy") { Gtk.main_quit }

window.show_all

Gtk.main

And this one that use shaders

=begin
  gtkglarea2.rb draw a white triangle on a default black background
  sources:
  http://antongerdelan.net/opengl/hellotriangle.html
  opengl-bindings/sample/RedBook/varray
  opengl-bindings/sample/GLES/gles.rb
  http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/
  https://developer.gnome.org/gtk3/stable/GtkGLArea.html
=end

require "gtk3"
require 'glfw'
require 'opengl'
require 'glu'

case OpenGL.get_platform
when :OPENGL_PLATFORM_WINDOWS
  OpenGL.load_lib('opengl32.dll', 'C:/Windows/System32')
  GLU.load_lib('GLU32.dll', 'C:/Windows/System32')
  GLFW.load_lib('glfw3.dll', '..')
when :OPENGL_PLATFORM_MACOSX
  OpenGL.load_lib('libGL.dylib', '/System/Library/Frameworks/OpenGL.framework/Libraries')
  GLU.load_lib('libGLU.dylib', '/System/Library/Frameworks/OpenGL.framework/Libraries')
  GLFW.load_lib('libglfw.dylib', '..')
when :OPENGL_PLATFORM_LINUX
  OpenGL.load_lib('libGL.so', '/usr/lib')
  GLU.load_lib('libGLU.so', '/usr/lib')
  GLFW.load_lib('libglfw.so', '/usr/lib')
else
  raise RuntimeError, "Unsupported platform."
end

include GLFW
include OpenGL
include GLU

window = Gtk::Window.new("OpenGL widget test")

window.set_size_request(400, 400)
glarea = Gtk::GLArea.new

window.add(glarea)

vertex_shader = <<EOF
#version 400
in vec3 vp;
void main () {
  gl_Position = vec4 (vp, 1.0);
};
EOF

fragment_shader = <<EOF
#version 400
out vec4 frag_colour;
void main () {
  frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);
};
EOF

def setup_shaders(vertex, fragment)

  # Load the shaders sources
  vs_handle = glCreateShader(GL_VERTEX_SHADER)
  fs_handle = glCreateShader(GL_FRAGMENT_SHADER)

  glShaderSource(vs_handle, 1, [vertex].pack("p"), [vertex.bytesize].pack("I"))

  glShaderSource(fs_handle, 1, [fragment].pack("p"), [fragment.bytesize].pack("I"))

  # Compile the vertex shader
  glCompileShader(vs_handle)
  # Check the vertex shader compilation
  vertCompiled_buf = '    '
  glGetShaderiv(vs_handle, GL_COMPILE_STATUS, vertCompiled_buf)
  vertCompiled = vertCompiled_buf.unpack('L')[0]
  if vertCompiled == 0
    infoLog = ' ' * 1024
    glGetShaderInfoLog(vs_handle, 1023, nil, infoLog)
    puts "Shader InfoLog:\n#{infoLog}\n"
  end

  # Compile the fragment shader
  glCompileShader(fs_handle)
  # Check the fragment shader compilation
  fragCompiled_buf = '    '
  glGetShaderiv(fs_handle, GL_COMPILE_STATUS, fragCompiled_buf)
  fragCompiled = fragCompiled_buf.unpack('L')[0]
  if fragCompiled == 0
    infoLog = ' ' * 1024
    glGetShaderInfoLog(fs_handle, 1023, nil, infoLog)
    puts "Shader InfoLog:\n#{infoLog}\n"
  end
  return false if (vertCompiled == 0 || fragCompiled == 0)

  # Load those 2 shaders (vertex and fragment) into a GPU shader program
  prog_handle = glCreateProgram()
  glAttachShader(prog_handle,vs_handle)
  glAttachShader(prog_handle,fs_handle)

  glLinkProgram(prog_handle)

  # Check if the program is valid
  linked_buf = '    '
  glGetProgramiv(prog_handle, GL_LINK_STATUS, linked_buf)
  linked = linked_buf.unpack('L')[0]
  if linked == 0
    infoLog = ' ' * 1024
    glGetProgramInfoLog(prog_handle, 1023, nil, infoLog)
    puts "Program InfoLog:\n#{infoLog}\n"
  end
  return false if linked==0

  # Set the created shader program as current
  glUseProgram(prog_handle)

  return true, prog_handle
end

shader_program = nil

glarea.signal_connect("realize") do |widget|
#  widget.make_current
  puts "realize"
  # Define a triangle in a vertex buffer ( Vertex Buffer Object)

  points = [
    0.0, 0.5, 0.0,  #x1, y1, z1
    0.5, -0.5, 0.0, #x2, y2, z2
    -0.5, -0.5, 0.0 #x3, y3, z3
  ]
  # We copy those points onto the graphics card in a unit called vertex buffer object (vbo).
  # Create an empty buffer
  vbo_buf = '    '
  glGenBuffers(1, vbo_buf)
  g_vbo = vbo_buf.unpack('L')[0]
  # Set the empty buffer as the current OpenGL's state machine by "binding"
  glBindBuffer(GL_ARRAY_BUFFER, g_vbo)
  # Copy the points in the currently bound buffer
  glBufferData(GL_ARRAY_BUFFER, 3 * 4 * Fiddle::SIZEOF_FLOAT, points.pack('F*'), GL_STATIC_DRAW)

  # First attribute buffer : vertices
  glVertexAttribPointer(0,        # No particular reason for 0 
                        3,        # size
                        GL_FLOAT, # type
                        GL_FALSE, # normalized?
                        0,        # stride
                        0         # array buffer offset
                        )
  glEnableVertexAttribArray(0)

  # Load the shaders:
  ok, shader_program = setup_shaders(vertex_shader, fragment_shader)
end

glarea.signal_connect("render") do |widget, context|
  puts "render"
  glClearColor(0.3, 0.3, 0.3, 1)
  glClear(GL_COLOR_BUFFER_BIT)
  glDrawArrays(GL_TRIANGLES, 0, 3)
  glFlush
  true
end

glarea.signal_connect("unrealize") do |widget|
  puts "unrealize"
  glDisableVertexAttribArray(0)
  true
end
window.signal_connect("destroy") { Gtk.main_quit }

window.show_all

Gtk.main

I haven't any issue except that the triangle is not drawing in the two scripts (the background is in grey like I set it with glClearColor. Maybe you could find an error in the opengl code that I use.

Thank

cedlemo commented 9 years ago

Good news!

After another tests I am able to display the triangle. Here is the script:

=begin
  gtkglarea2.rb draw a white triangle on a default black background
  sources:
  http://antongerdelan.net/opengl/hellotriangle.html
  opengl-bindings/sample/RedBook/varray
  opengl-bindings/sample/GLES/gles.rb
  http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/
  https://developer.gnome.org/gtk3/stable/GtkGLArea.html
  https://www.bassi.io/articles/2015/02/17/using-opengl-with-gtk/
  http://stackoverflow.com/questions/30337845/gldrawarrays-not-working-using-gtkglarea-in-gtk3
=end

require "gtk3"
require 'glfw'
require 'opengl'
require 'glu'

case OpenGL.get_platform
when :OPENGL_PLATFORM_WINDOWS
  OpenGL.load_lib('opengl32.dll', 'C:/Windows/System32')
  GLU.load_lib('GLU32.dll', 'C:/Windows/System32')
  GLFW.load_lib('glfw3.dll', '..')
when :OPENGL_PLATFORM_MACOSX
  OpenGL.load_lib('libGL.dylib', '/System/Library/Frameworks/OpenGL.framework/Libraries')
  GLU.load_lib('libGLU.dylib', '/System/Library/Frameworks/OpenGL.framework/Libraries')
  GLFW.load_lib('libglfw.dylib', '..')
when :OPENGL_PLATFORM_LINUX
  OpenGL.load_lib('libGL.so', '/usr/lib')
  GLU.load_lib('libGLU.so', '/usr/lib')
  GLFW.load_lib('libglfw.so', '/usr/lib')
else
  raise RuntimeError, "Unsupported platform."
end

include GLFW
include OpenGL
include GLU

window = Gtk::Window.new("OpenGL widget test")

window.set_size_request(400, 400)
glarea = Gtk::GLArea.new

window.add(glarea)

vertex_shader = <<EOF
#version 400
in vec3 vp;
void main () {
  gl_Position = vec4 (vp, 1.0);
};
EOF

fragment_shader = <<EOF
#version 400
out vec4 frag_colour;
void main () {
  frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);
};
EOF

def setup_shaders(vertex, fragment)

  # Load the shaders sources
  vs_handle = glCreateShader(GL_VERTEX_SHADER)
  fs_handle = glCreateShader(GL_FRAGMENT_SHADER)

  glShaderSource(vs_handle, 1, [vertex].pack("p"), [vertex.bytesize].pack("I"))

  glShaderSource(fs_handle, 1, [fragment].pack("p"), [fragment.bytesize].pack("I"))

  # Compile the vertex shader
  glCompileShader(vs_handle)
  # Check the vertex shader compilation
  vertCompiled_buf = '    '
  glGetShaderiv(vs_handle, GL_COMPILE_STATUS, vertCompiled_buf)
  vertCompiled = vertCompiled_buf.unpack('L')[0]
  if vertCompiled == 0
    infoLog = ' ' * 1024
    glGetShaderInfoLog(vs_handle, 1023, nil, infoLog)
    puts "Shader InfoLog:\n#{infoLog}\n"
  end

  # Compile the fragment shader
  glCompileShader(fs_handle)
  # Check the fragment shader compilation
  fragCompiled_buf = '    '
  glGetShaderiv(fs_handle, GL_COMPILE_STATUS, fragCompiled_buf)
  fragCompiled = fragCompiled_buf.unpack('L')[0]
  if fragCompiled == 0
    infoLog = ' ' * 1024
    glGetShaderInfoLog(fs_handle, 1023, nil, infoLog)
    puts "Shader InfoLog:\n#{infoLog}\n"
  end
  return false if (vertCompiled == 0 || fragCompiled == 0)

  # Load those 2 shaders (vertex and fragment) into a GPU shader program
  prog_handle = glCreateProgram()
  glAttachShader(prog_handle,vs_handle)
  glAttachShader(prog_handle,fs_handle)

  glLinkProgram(prog_handle)

  # Check if the program is valid
  linked_buf = '    '
  glGetProgramiv(prog_handle, GL_LINK_STATUS, linked_buf)
  linked = linked_buf.unpack('L')[0]
  if linked == 0
    infoLog = ' ' * 1024
    glGetProgramInfoLog(prog_handle, 1023, nil, infoLog)
    puts "Program InfoLog:\n#{infoLog}\n"
  end
  return false if linked==0

  # Set the created shader program as current
  #glUseProgram(prog_handle)

  return true, prog_handle
end

shader_program = nil
gl_vao = nil
glarea.signal_connect("realize") do |widget|
  widget.make_current
  puts "realize"
  # Define a triangle in a vertex buffer ( Vertex Buffer Object)

  points = [
    0.0, 0.5, 0.0,  #x1, y1, z1
    0.5, -0.5, 0.0, #x2, y2, z2
    -0.5, -0.5, 0.0 #x3, y3, z3
  ]
  vao_buf = '    '
  glGenVertexArrays(1, vao_buf)
  gl_vao = vao_buf.unpack('L')[0]
  glBindVertexArray(gl_vao)
  # We copy those points onto the graphics card in a unit called vertex buffer object (vbo).
  # Create an empty buffer
  vbo_buf = '    '
  glGenBuffers(1, vbo_buf)
  g_vbo = vbo_buf.unpack('L')[0]
  # Set the empty buffer as the current OpenGL's state machine by "binding"
  glBindBuffer(GL_ARRAY_BUFFER, g_vbo)
  # Copy the points in the currently bound buffer
  glBufferData(GL_ARRAY_BUFFER, 3 * 4 * Fiddle::SIZEOF_FLOAT, points.pack('F*'), GL_STATIC_DRAW)

  # First attribute buffer : vertices
  glEnableVertexAttribArray(0)
  glVertexAttribPointer(0,        # No particular reason for 0 
                        3,        # size
                        GL_FLOAT, # type
                        GL_FALSE, # normalized?
                        0,        # stride
                        0         # array buffer offset
                        )

  glBindVertexArray(0)
  # Load the shaders:
  ok, shader_program = setup_shaders(vertex_shader, fragment_shader)
end

glarea.signal_connect("render") do |widget, context|
  puts "render"
  glClearColor(0.3, 0.3, 0.3, 1)
  glClear(GL_COLOR_BUFFER_BIT)
  glUseProgram(shader_program)
  glBindVertexArray(gl_vao)
  glDrawArrays(GL_TRIANGLES, 0, 3)
  glFlush
  false
end

glarea.signal_connect("unrealize") do |widget|
  puts "unrealize"
  glDisableVertexAttribArray(0)
  true
end
window.signal_connect("destroy") { Gtk.main_quit }

window.show_all

Gtk.main

I will try to clean this and trully understand the differences (I found the solution here: http://stackoverflow.com/questions/30337845/gldrawarrays-not-working-using-gtkglarea-in-gtk3)

If you have any advices on this let me know .

vaiorabbit commented 9 years ago

Hi,

I think you can remove all GLFW and GLU initialization lines because this sample doesn't use any features of them.

require "gtk3"
require 'opengl'

case OpenGL.get_platform
when :OPENGL_PLATFORM_WINDOWS
  OpenGL.load_lib('opengl32.dll', 'C:/Windows/System32')
when :OPENGL_PLATFORM_MACOSX
  OpenGL.load_lib('libGL.dylib', '/System/Library/Frameworks/OpenGL.framework/Libraries')
when :OPENGL_PLATFORM_LINUX
  OpenGL.load_lib('libGL.so', '/usr/lib')
else
  raise RuntimeError, "Unsupported platform."
end

include OpenGL
#
# ...
#

Anyway, congratulations. I'm going to release opengl-bindings 1.4.0 that contains `load_lib' API. Thank you.

cedlemo commented 9 years ago

I think you can remove all GLFW and GLU initialization lines

Yes you are right.

You can find the first working script here : https://github.com/ruby-gnome2/ruby-gnome2/pull/499