I can't think that I'm the only person that has encountered this, but neither have I found any references to the issue (or clues in the distribution).
I have recently been playing with ruby1.9-opengl bindings, and I have found the following issues:-
1. Ruby Strings are no longer accepted (to give window title), my solution is to replace String with an empty array anything else (including no entry) seems to be interpreted as a String (input needs to be a CString, ie an array of C chars or possibly pointer thereof).
2. Properties such as color and position, in the Red Book and other examples (included with the source download) are given as an Array. When I've tried to run these examples, I get error messages that a Struct is required not an Array (see below for my coding of Struct to replace Array the name of the Struct and symbols chosen for the Struct variable is unimportant). Parameter Arrays with single float item seem to require a float replacement.
#
# Copyright (c) Mark J. Kilgard, 1994.
#
# (c) Copyright 1993, Silicon Graphics, Inc.
# ALL RIGHTS RESERVED
# Permission to use, copy, modify, and distribute this software for
# any purpose and without fee is hereby granted, provided that the above
# copyright notice appear in all copies and that both the copyright notice
# and this permission notice appear in supporting documentation, and that
# the name of Silicon Graphics, Inc. not be used in advertising
# or publicity pertaining to distribution of the software without specific,
# written prior permission.
#
# THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
# AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
# INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
# FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
# GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
# SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
# KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
# LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
# THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
# ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
# POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
#
# US Government Users Restricted Rights
# Use, duplication, or disclosure by the Government is subject to
# restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
# (c)(1)(ii) of the Rights in Technical Data and Computer Software
# clause at DFARS 252.227-7013 and/or in similar or successor
# clauses in the FAR or the DOD or NASA FAR Supplement.
# Unpublished-- rights reserved under the copyright laws of the
# United States. Contractor/manufacturer is Silicon Graphics,
# Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
#
# OpenGL(TM) is a trademark of Silicon Graphics, Inc.
#
# material.c
# This program demonstrates the use of the GL lighting model.
# Several objects are drawn using different material characteristics.
# A single light source illuminates the objects.
require 'opengl'
include Gl,Glu,Glut
Properties = Struct.new("Properties", :a, :b, :c, :d)
# Initialize z-buffer, projection matrix, light source,
# and lighting model. Do not specify a material property here.
def myinit
ambient = Properties.new(0.0, 0.0, 0.0, 1.0 )
diffuse = Properties.new(1.0, 1.0, 1.0, 1.0)
position = Properties.new(0.0, 3.0, 2.0, 0.0)
lmodel_ambient = Properties.new(0.4, 0.4, 0.4, 1.0)
local_view = 0.0
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LESS)
glLight(GL_LIGHT0, GL_AMBIENT, ambient)
glLight(GL_LIGHT0, GL_DIFFUSE, diffuse)
glLight(GL_LIGHT0, GL_POSITION, position)
glLightModel(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient)
glLightModel(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glClearColor(0.0, 0.1, 0.1, 0.0)
end
# Draw twelve spheres in 3 rows with 4 columns.
# The spheres in the first row have materials with no ambient reflection.
# The second row has materials with significant ambient reflection.
# The third row has materials with colored ambient reflection.
#
# The first column has materials with blue, diffuse reflection only.
# The second column has blue diffuse reflection, as well as specular
# reflection with a low shininess exponent.
# The third column has blue diffuse reflection, as well as specular
# reflection with a high shininess exponent (a more concentrated highlight).
# The fourth column has materials which also include an emissive component.
#
# glTranslatef() is used to move spheres to their appropriate locations.
display = proc do
no_mat = Properties.new( 0.0, 0.0, 0.0, 1.0)
mat_ambient = Properties.new(0.7, 0.7, 0.7, 1.0)
mat_ambient_color = Properties.new(0.8, 0.8, 0.2, 1.0)
mat_diffuse = Properties.new(0.1, 0.5, 0.8, 1.0)
mat_specular = Properties.new(1.0, 1.0, 1.0, 1.0)
no_shininess = 0.0
low_shininess = 5.0
high_shininess = 100.0
mat_emission = Properties.new(0.3, 0.2, 0.2, 0.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# draw sphere in first row, first column
# diffuse reflection only no ambient or specular
glPushMatrix()
glTranslate(-3.75, 3.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, no_mat)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, no_mat)
glMaterial(GL_FRONT, GL_SHININESS, no_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in first row, second column
# diffuse and specular reflection low shininess no ambient
glPushMatrix()
glTranslate(-1.25, 3.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, no_mat)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, mat_specular)
glMaterial(GL_FRONT, GL_SHININESS, low_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in first row, third column
# diffuse and specular reflection high shininess no ambient
glPushMatrix()
glTranslate(1.25, 3.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, no_mat)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, mat_specular)
glMaterial(GL_FRONT, GL_SHININESS, high_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in first row, fourth column
# diffuse reflection emission no ambient or specular reflection
glPushMatrix()
glTranslate(3.75, 3.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, no_mat)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, no_mat)
glMaterial(GL_FRONT, GL_SHININESS, no_shininess)
glMaterial(GL_FRONT, GL_EMISSION, mat_emission)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in second row, first column
# ambient and diffuse reflection no specular
glPushMatrix()
glTranslate(-3.75, 0.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, mat_ambient)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, no_mat)
glMaterial(GL_FRONT, GL_SHININESS, no_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in second row, second column
# ambient, diffuse and specular reflection low shininess
glPushMatrix()
glTranslate(-1.25, 0.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, mat_ambient)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, mat_specular)
glMaterial(GL_FRONT, GL_SHININESS, low_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in second row, third column
# ambient, diffuse and specular reflection high shininess
glPushMatrix()
glTranslate(1.25, 0.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, mat_ambient)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, mat_specular)
glMaterial(GL_FRONT, GL_SHININESS, high_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in second row, fourth column
# ambient and diffuse reflection emission no specular
glPushMatrix()
glTranslate(3.75, 0.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, mat_ambient)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, no_mat)
glMaterial(GL_FRONT, GL_SHININESS, no_shininess)
glMaterial(GL_FRONT, GL_EMISSION, mat_emission)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in third row, first column
# colored ambient and diffuse reflection no specular
glPushMatrix()
glTranslate(-3.75, -3.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, mat_ambient_color)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, no_mat)
glMaterial(GL_FRONT, GL_SHININESS, no_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in third row, second column
# colored ambient, diffuse and specular reflection low shininess
glPushMatrix()
glTranslate(-1.25, -3.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, mat_ambient_color)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, mat_specular)
glMaterial(GL_FRONT, GL_SHININESS, low_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in third row, third column
# colored ambient, diffuse and specular reflection high shininess
glPushMatrix()
glTranslate(1.25, -3.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, mat_ambient_color)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, mat_specular)
glMaterial(GL_FRONT, GL_SHININESS, high_shininess)
glMaterial(GL_FRONT, GL_EMISSION, no_mat)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
# draw sphere in third row, fourth column
# colored ambient and diffuse reflection emission no specular
glPushMatrix()
glTranslate(3.75, -3.0, 0.0)
glMaterial(GL_FRONT, GL_AMBIENT, mat_ambient_color)
glMaterial(GL_FRONT, GL_DIFFUSE, mat_diffuse)
glMaterial(GL_FRONT, GL_SPECULAR, no_mat)
glMaterial(GL_FRONT, GL_SHININESS, no_shininess)
glMaterial(GL_FRONT, GL_EMISSION, mat_emission)
glutSolidSphere(1.0, 16, 16)
glPopMatrix()
glutSwapBuffers()
end
myReshape = proc do |w, h|
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
if (w <= (h * 2))
glOrtho(-6.0, 6.0, -3.0*(h.to_f*2)/w, 3.0*(h.to_f*2)/w, -10.0, 10.0)
else
glOrtho(-6.0*w.to_f/(h*2), 6.0*w.to_f/(h*2), -3.0, 3.0, -10.0, 10.0)
end
glMatrixMode(GL_MODELVIEW)
end
keyboard = Proc.new do |key, x, y|
case (key)
when ?\e
exit(0);
end
end
# Main Loop
# Open window with initial window size, title bar,
# RGBA display mode, and handle input events.
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(600, 600)
glutInitWindowPosition(100, 100)
glutCreateWindow([])
myinit()
glutReshapeFunc(myReshape)
glutDisplayFunc(display)
glutKeyboardFunc(keyboard)
glutMainLoop()
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Saturday, 24 July 2010
Tuesday, 13 July 2010
Exploring java opengl calls in ruby-processing
Here I try out some calls to javax.media.opengl in ruby processing (to achieve back face culling). I do this with a disco version of my ruby-processing menger sponge.
# menger.rb (disco version) by Martin Prout
load_library 'opengl'
include_package 'javax.media.opengl'
# full_screen required for linux with OPENGL (a bug)
full_screen if java.lang.System.get_property('os.name') == "Linux"
ANGLE_STEP = Math::PI/180
DATA = [-1, 0, 1]
MIN_SIZE = 50
COL_1 = [0.6667, 1, 0.5]
COL_2 = [0.5, 1, 0.5]
COL_3 = [0.83333, 1, 0.5]
COL_4 = [0.16667, 1, 0.5]
def setup
size(600, 600, OPENGL)
library_loaded?(:opengl) ? setup_opengl : render_mode(P3D)
@start_t = Time.now.to_f
@data = [] # initialize empty array
cube(0, 0, 0, height * 0.4) # fill data array
@angle = 0
color_mode HSB, 1.0
end
def setup_opengl
render_mode(OPENGL)
hint DISABLE_OPENGL_ERROR_REPORT
hint ENABLE_OPENGL_4X_SMOOTH
end
def configure_gl # experimenting with some java opengl calls
pgl = g
gl = pgl.gl
pgl.beginGL
gl.gl_enable(GL::GL_CULL_FACE)
gl.gl_cull_face(GL::GL_BACK)
#gl.gl_enable(GL::GL_NORMALIZE)
pgl.endGL
end
# Fill @data array with cube center coordinate
# and size data (this can be done at setup)
def cube x, y, z, sz
unless (sz <= MIN_SIZE) then
u = sz/3.0
DATA.each do |i|
DATA.each do |j|
DATA.each do |k|
cube(x+(i*u), y+(j*u), z+(k*u), u) unless (i.abs + j.abs + k.abs) <= 1
end
end
end
end
@data.push [x, y, z, sz] unless sz > MIN_SIZE
end
# Render the cubes (data from @data) using
# translate and custom box function, uses ruby splat
def draw_cubes
@data.each do |point|
x, y, z, sz = *point
push_matrix
translate(x, y, z)
my_box(sz)
pop_matrix
end
end
def draw
configure_gl
background 0
ambient_light 0.8, 0.8, 0.8
directional_light 1.0, 1.0, 1.0, 1, 1, -1
@angle = (ANGLE_STEP + @angle) % (Math::PI * 2)
translate(width/2, height/2, 0)
rotate_x @angle
rotate_y @angle
rotate_z @angle
draw_cubes
end
def my_box sz
no_stroke
begin_shape QUADS
# +Z "front" face
fill *COL_1
vertex -sz/2, -sz/2, sz/2
fill *COL_2
vertex sz/2, -sz/2, sz/2
fill *COL_3
vertex sz/2, sz/2, sz/2
fill *COL_4
vertex -sz/2, sz/2, sz/2
# -Z "back" face
fill *COL_1
vertex sz/2, -sz/2, -sz/2
fill *COL_2
vertex -sz/2, -sz/2, -sz/2
fill *COL_3
vertex -sz/2, sz/2, -sz/2
fill *COL_4
vertex sz/2, sz/2, -sz/2
# +Y "bottom" face
fill *COL_1
vertex -sz/2, sz/2, sz/2
fill *COL_2
vertex sz/2, sz/2, sz/2
fill *COL_3
vertex sz/2, sz/2, -sz/2
fill *COL_4
vertex -sz/2, sz/2, -sz/2
# -Y "top" face
fill *COL_1
vertex -sz/2, -sz/2, -sz/2
fill *COL_2
vertex sz/2, -sz/2, -sz/2
fill *COL_3
vertex sz/2, -sz/2, sz/2
fill *COL_4
vertex -sz/2, -sz/2, sz/2
# +X "right" face
fill *COL_1
vertex sz/2, -sz/2, sz/2
fill *COL_2
vertex sz/2, -sz/2, -sz/2
fill *COL_3
vertex sz/2, sz/2, -sz/2
fill *COL_4
vertex sz/2, sz/2, sz/2
# -X "left" face
fill *COL_1
vertex -sz/2, -sz/2, -sz/2
fill *COL_2
vertex -sz/2, -sz/2, sz/2
fill *COL_3
vertex -sz/2, sz/2, sz/2
fill *COL_4
vertex -sz/2, sz/2, -sz/2
end_shape
end
# menger.rb (disco version) by Martin Prout
load_library 'opengl'
include_package 'javax.media.opengl'
# full_screen required for linux with OPENGL (a bug)
full_screen if java.lang.System.get_property('os.name') == "Linux"
ANGLE_STEP = Math::PI/180
DATA = [-1, 0, 1]
MIN_SIZE = 50
COL_1 = [0.6667, 1, 0.5]
COL_2 = [0.5, 1, 0.5]
COL_3 = [0.83333, 1, 0.5]
COL_4 = [0.16667, 1, 0.5]
def setup
size(600, 600, OPENGL)
library_loaded?(:opengl) ? setup_opengl : render_mode(P3D)
@start_t = Time.now.to_f
@data = [] # initialize empty array
cube(0, 0, 0, height * 0.4) # fill data array
@angle = 0
color_mode HSB, 1.0
end
def setup_opengl
render_mode(OPENGL)
hint DISABLE_OPENGL_ERROR_REPORT
hint ENABLE_OPENGL_4X_SMOOTH
end
def configure_gl # experimenting with some java opengl calls
pgl = g
gl = pgl.gl
pgl.beginGL
gl.gl_enable(GL::GL_CULL_FACE)
gl.gl_cull_face(GL::GL_BACK)
#gl.gl_enable(GL::GL_NORMALIZE)
pgl.endGL
end
# Fill @data array with cube center coordinate
# and size data (this can be done at setup)
def cube x, y, z, sz
unless (sz <= MIN_SIZE) then
u = sz/3.0
DATA.each do |i|
DATA.each do |j|
DATA.each do |k|
cube(x+(i*u), y+(j*u), z+(k*u), u) unless (i.abs + j.abs + k.abs) <= 1
end
end
end
end
@data.push [x, y, z, sz] unless sz > MIN_SIZE
end
# Render the cubes (data from @data) using
# translate and custom box function, uses ruby splat
def draw_cubes
@data.each do |point|
x, y, z, sz = *point
push_matrix
translate(x, y, z)
my_box(sz)
pop_matrix
end
end
def draw
configure_gl
background 0
ambient_light 0.8, 0.8, 0.8
directional_light 1.0, 1.0, 1.0, 1, 1, -1
@angle = (ANGLE_STEP + @angle) % (Math::PI * 2)
translate(width/2, height/2, 0)
rotate_x @angle
rotate_y @angle
rotate_z @angle
draw_cubes
end
def my_box sz
no_stroke
begin_shape QUADS
# +Z "front" face
fill *COL_1
vertex -sz/2, -sz/2, sz/2
fill *COL_2
vertex sz/2, -sz/2, sz/2
fill *COL_3
vertex sz/2, sz/2, sz/2
fill *COL_4
vertex -sz/2, sz/2, sz/2
# -Z "back" face
fill *COL_1
vertex sz/2, -sz/2, -sz/2
fill *COL_2
vertex -sz/2, -sz/2, -sz/2
fill *COL_3
vertex -sz/2, sz/2, -sz/2
fill *COL_4
vertex sz/2, sz/2, -sz/2
# +Y "bottom" face
fill *COL_1
vertex -sz/2, sz/2, sz/2
fill *COL_2
vertex sz/2, sz/2, sz/2
fill *COL_3
vertex sz/2, sz/2, -sz/2
fill *COL_4
vertex -sz/2, sz/2, -sz/2
# -Y "top" face
fill *COL_1
vertex -sz/2, -sz/2, -sz/2
fill *COL_2
vertex sz/2, -sz/2, -sz/2
fill *COL_3
vertex sz/2, -sz/2, sz/2
fill *COL_4
vertex -sz/2, -sz/2, sz/2
# +X "right" face
fill *COL_1
vertex sz/2, -sz/2, sz/2
fill *COL_2
vertex sz/2, -sz/2, -sz/2
fill *COL_3
vertex sz/2, sz/2, -sz/2
fill *COL_4
vertex sz/2, sz/2, sz/2
# -X "left" face
fill *COL_1
vertex -sz/2, -sz/2, -sz/2
fill *COL_2
vertex -sz/2, -sz/2, sz/2
fill *COL_3
vertex -sz/2, sz/2, sz/2
fill *COL_4
vertex -sz/2, sz/2, -sz/2
end_shape
end
Labels:
java,
opengl,
ruby processing
Saturday, 10 July 2010
More Ruby OpenGL explorations
This is an example taken from the ruby opengl examples, that I have modified to get to work with a compiled version of the library (ie not rubygem version) on my 64 bit linux box (Kubuntu 10.04 custom kernel with latest NVidia graphics driver). Two changes are 'required', string entry from ruby 1.9 is not accepted, and the properties require a Struct rather than array. I have also converted Proc.new and old style lambda to new style stabby lambda just for the hell of it. I don't want any hassle so I'm also including the original c-code copyright notice which now seems kind of pointless.
#!/usr/bin/env ruby
#/* Copyright (c) Mark J. Kilgard, 1994. */
#
#/*
# * (c) Copyright 1993, Silicon Graphics, Inc.
# * ALL RIGHTS RESERVED
# * Permission to use, copy, modify, and distribute this software for
# * any purpose and without fee is hereby granted, provided that the above
# * copyright notice appear in all copies and that both the copyright notice
# * and this permission notice appear in supporting documentation, and that
# * the name of Silicon Graphics, Inc. not be used in advertising
# * or publicity pertaining to distribution of the software without specific,
# * written prior permission.
# *
# * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
# * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
# * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
# * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
# * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
# * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
# * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
# * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
# * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
# * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
# * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
# * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
# *
# * US Government Users Restricted Rights
# * Use, duplication, or disclosure by the Government is subject to
# * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
# * (c)(1)(ii) of the Rights in Technical Data and Computer Software
# * clause at DFARS 252.227-7013 and/or in similar or successor
# * clauses in the FAR or the DOD or NASA FAR Supplement.
# * Unpublished-- rights reserved under the copyright laws of the
# * United States. Contractor/manufacturer is Silicon Graphics,
# * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
# *
# * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
# */
#/*
# * plane.c
# * This program demonstrates the use of local versus
# * infinite lighting on a flat plane.
# */
require "gl"
require "glut"
Property = Struct.new("Property", :a, :b, :c, :d)
# /* Initialize material property, light source, and lighting model.
# */
def myinit
mat_ambient = Property.new(0.0, 0.0, 0.0, 1.0)
#/* mat_specular and mat_shininess are NOT default values */
mat_diffuse = Property.new(0.4, 0.4, 0.4, 1.0)
mat_specular = Property.new(1.0, 1.0, 1.0, 1.0)
mat_shininess = 15.0
light_ambient = Property.new(0.0, 0.0, 0.0, 1.0)
light_diffuse = Property.new(1.0, 1.0, 1.0, 1.0)
light_specular = Property.new(1.0, 1.0, 1.0, 1.0)
lmodel_ambient = Property.new(0.2, 0.2, 0.2, 1.0)
Gl.glMaterial(Gl::GL_FRONT, Gl::GL_AMBIENT, mat_ambient)
Gl.glMaterial(Gl::GL_FRONT, Gl::GL_DIFFUSE, mat_diffuse)
Gl.glMaterial(Gl::GL_FRONT, Gl::GL_SPECULAR, mat_specular)
Gl.glMaterial(Gl::GL_FRONT, Gl::GL_SHININESS, mat_shininess)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_AMBIENT, light_ambient)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_DIFFUSE, light_diffuse)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_SPECULAR, light_specular)
Gl.glLightModel(Gl::GL_LIGHT_MODEL_AMBIENT, lmodel_ambient)
Gl.glEnable(Gl::GL_LIGHTING)
Gl.glEnable(Gl::GL_LIGHT0)
Gl.glDepthFunc(Gl::GL_LESS)
Gl.glEnable(Gl::GL_DEPTH_TEST)
end
def drawPlane
Gl.glBegin(Gl::GL_QUADS)
Gl.glNormal(0.0, 0.0, 1.0)
Gl.glVertex(-1.0, -1.0, 0.0)
Gl.glVertex(0.0, -1.0, 0.0)
Gl.glVertex(0.0, 0.0, 0.0)
Gl.glVertex(-1.0, 0.0, 0.0)
Gl.glNormal(0.0, 0.0, 1.0)
Gl.glVertex(0.0, -1.0, 0.0)
Gl.glVertex(1.0, -1.0, 0.0)
Gl.glVertex(1.0, 0.0, 0.0)
Gl.glVertex(0.0, 0.0, 0.0)
Gl.glNormal(0.0, 0.0, 1.0)
Gl.glVertex(0.0, 0.0, 0.0)
Gl.glVertex(1.0, 0.0, 0.0)
Gl.glVertex(1.0, 1.0, 0.0)
Gl.glVertex(0.0, 1.0, 0.0)
Gl.glNormal(0.0, 0.0, 1.0)
Gl.glVertex(0.0, 0.0, 0.0)
Gl.glVertex(0.0, 1.0, 0.0)
Gl.glVertex(-1.0, 1.0, 0.0)
Gl.glVertex(-1.0, 0.0, 0.0)
Gl.glEnd()
end
# Using ruby 1.9 stabby lambda syntax for callbacks
display = -> {
infinite_light = Property.new(1.0, 1.0, 1.0, 0.0)
local_light = Property.new(1.0, 1.0, 1.0, 1.0)
Gl.glClear(Gl::GL_COLOR_BUFFER_BIT | Gl::GL_DEPTH_BUFFER_BIT)
Gl.glPushMatrix()
Gl.glTranslate(-1.5, 0.0, 0.0)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_POSITION, infinite_light)
drawPlane()
Gl.glPopMatrix()
Gl.glPushMatrix()
Gl.glTranslate(1.5, 0.0, 0.0)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_POSITION, local_light)
drawPlane()
Gl.glPopMatrix()
Gl.glFlush()
}
myReshape = -> w, h {
Gl.glViewport(0, 0, w, h)
Gl.glMatrixMode(Gl::GL_PROJECTION)
Gl.glLoadIdentity()
(w <= h) ? Gl.glOrtho(-1.5, 1.5, -1.5*h/w, 1.5*h/w, -10.0, 10.0) : Gl.glOrtho(-1.5*w/h, 1.5*w/h, -1.5, 1.5, -10.0, 10.0)
Gl.glMatrixMode(Gl::GL_MODELVIEW)
}
# Keyboard handler to exit when ESC is typed
keyboard = -> key, x, y{
case(key)
when ?\e
exit(0)
end
}
Glut.glutInit
Glut.glutInitDisplayMode(Glut::GLUT_SINGLE | Glut::GLUT_RGB | Glut::GLUT_DEPTH)
Glut.glutInitWindowSize(500, 200)
Glut.glutCreateWindow([]) # empty array I can't figure out how to return cstring
myinit()
Glut.glutReshapeFunc(myReshape)
Glut.glutDisplayFunc(display)
Glut.glutKeyboardFunc(keyboard)
Glut.glutMainLoop()
#!/usr/bin/env ruby
#/* Copyright (c) Mark J. Kilgard, 1994. */
#
#/*
# * (c) Copyright 1993, Silicon Graphics, Inc.
# * ALL RIGHTS RESERVED
# * Permission to use, copy, modify, and distribute this software for
# * any purpose and without fee is hereby granted, provided that the above
# * copyright notice appear in all copies and that both the copyright notice
# * and this permission notice appear in supporting documentation, and that
# * the name of Silicon Graphics, Inc. not be used in advertising
# * or publicity pertaining to distribution of the software without specific,
# * written prior permission.
# *
# * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
# * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
# * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
# * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
# * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
# * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
# * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
# * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
# * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
# * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
# * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
# * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
# *
# * US Government Users Restricted Rights
# * Use, duplication, or disclosure by the Government is subject to
# * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
# * (c)(1)(ii) of the Rights in Technical Data and Computer Software
# * clause at DFARS 252.227-7013 and/or in similar or successor
# * clauses in the FAR or the DOD or NASA FAR Supplement.
# * Unpublished-- rights reserved under the copyright laws of the
# * United States. Contractor/manufacturer is Silicon Graphics,
# * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
# *
# * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
# */
#/*
# * plane.c
# * This program demonstrates the use of local versus
# * infinite lighting on a flat plane.
# */
require "gl"
require "glut"
Property = Struct.new("Property", :a, :b, :c, :d)
# /* Initialize material property, light source, and lighting model.
# */
def myinit
mat_ambient = Property.new(0.0, 0.0, 0.0, 1.0)
#/* mat_specular and mat_shininess are NOT default values */
mat_diffuse = Property.new(0.4, 0.4, 0.4, 1.0)
mat_specular = Property.new(1.0, 1.0, 1.0, 1.0)
mat_shininess = 15.0
light_ambient = Property.new(0.0, 0.0, 0.0, 1.0)
light_diffuse = Property.new(1.0, 1.0, 1.0, 1.0)
light_specular = Property.new(1.0, 1.0, 1.0, 1.0)
lmodel_ambient = Property.new(0.2, 0.2, 0.2, 1.0)
Gl.glMaterial(Gl::GL_FRONT, Gl::GL_AMBIENT, mat_ambient)
Gl.glMaterial(Gl::GL_FRONT, Gl::GL_DIFFUSE, mat_diffuse)
Gl.glMaterial(Gl::GL_FRONT, Gl::GL_SPECULAR, mat_specular)
Gl.glMaterial(Gl::GL_FRONT, Gl::GL_SHININESS, mat_shininess)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_AMBIENT, light_ambient)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_DIFFUSE, light_diffuse)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_SPECULAR, light_specular)
Gl.glLightModel(Gl::GL_LIGHT_MODEL_AMBIENT, lmodel_ambient)
Gl.glEnable(Gl::GL_LIGHTING)
Gl.glEnable(Gl::GL_LIGHT0)
Gl.glDepthFunc(Gl::GL_LESS)
Gl.glEnable(Gl::GL_DEPTH_TEST)
end
def drawPlane
Gl.glBegin(Gl::GL_QUADS)
Gl.glNormal(0.0, 0.0, 1.0)
Gl.glVertex(-1.0, -1.0, 0.0)
Gl.glVertex(0.0, -1.0, 0.0)
Gl.glVertex(0.0, 0.0, 0.0)
Gl.glVertex(-1.0, 0.0, 0.0)
Gl.glNormal(0.0, 0.0, 1.0)
Gl.glVertex(0.0, -1.0, 0.0)
Gl.glVertex(1.0, -1.0, 0.0)
Gl.glVertex(1.0, 0.0, 0.0)
Gl.glVertex(0.0, 0.0, 0.0)
Gl.glNormal(0.0, 0.0, 1.0)
Gl.glVertex(0.0, 0.0, 0.0)
Gl.glVertex(1.0, 0.0, 0.0)
Gl.glVertex(1.0, 1.0, 0.0)
Gl.glVertex(0.0, 1.0, 0.0)
Gl.glNormal(0.0, 0.0, 1.0)
Gl.glVertex(0.0, 0.0, 0.0)
Gl.glVertex(0.0, 1.0, 0.0)
Gl.glVertex(-1.0, 1.0, 0.0)
Gl.glVertex(-1.0, 0.0, 0.0)
Gl.glEnd()
end
# Using ruby 1.9 stabby lambda syntax for callbacks
display = -> {
infinite_light = Property.new(1.0, 1.0, 1.0, 0.0)
local_light = Property.new(1.0, 1.0, 1.0, 1.0)
Gl.glClear(Gl::GL_COLOR_BUFFER_BIT | Gl::GL_DEPTH_BUFFER_BIT)
Gl.glPushMatrix()
Gl.glTranslate(-1.5, 0.0, 0.0)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_POSITION, infinite_light)
drawPlane()
Gl.glPopMatrix()
Gl.glPushMatrix()
Gl.glTranslate(1.5, 0.0, 0.0)
Gl.glLight(Gl::GL_LIGHT0, Gl::GL_POSITION, local_light)
drawPlane()
Gl.glPopMatrix()
Gl.glFlush()
}
myReshape = -> w, h {
Gl.glViewport(0, 0, w, h)
Gl.glMatrixMode(Gl::GL_PROJECTION)
Gl.glLoadIdentity()
(w <= h) ? Gl.glOrtho(-1.5, 1.5, -1.5*h/w, 1.5*h/w, -10.0, 10.0) : Gl.glOrtho(-1.5*w/h, 1.5*w/h, -1.5, 1.5, -10.0, 10.0)
Gl.glMatrixMode(Gl::GL_MODELVIEW)
}
# Keyboard handler to exit when ESC is typed
keyboard = -> key, x, y{
case(key)
when ?\e
exit(0)
end
}
Glut.glutInit
Glut.glutInitDisplayMode(Glut::GLUT_SINGLE | Glut::GLUT_RGB | Glut::GLUT_DEPTH)
Glut.glutInitWindowSize(500, 200)
Glut.glutCreateWindow([]) # empty array I can't figure out how to return cstring
myinit()
Glut.glutReshapeFunc(myReshape)
Glut.glutDisplayFunc(display)
Glut.glutKeyboardFunc(keyboard)
Glut.glutMainLoop()
Labels:
opengl,
ruby1.9,
stabby-syntax
Tuesday, 6 July 2010
3D Gears: (exploring ruby 1.9 syntax, ruby-opengl bindings, lambda & Struct)
Recently I have been exploring a couple of Scheme implementations of cfdg, one of those used opengl as a back end. That got me interested in the idea of exploring ruby-opengl bindings and this is the result (I found this rather old example of glxgears by Arto Bendiken, which was in need of updating anyway, the array entry for color and light attributes are now Struct rather than array). I got a bit carried away as I've replaced the callback methods with new stabby ruby lambda syntax, anyway result is rather impressive. Main thing bugging is I can't give the window a title (the escape key now works for me, since I replace 27 with ?\e).
#!/usr/bin/env ruby1.9
# coding: utf-8
# 3-D gear wheels. This program is in the public domain.
#
# Command line options:
# -info print GL implementation information
# -exit automatically exit after 30 seconds
#
# 2005-05-01 Ruby version by Arto Bendiken based on gears.c rev 1.8.
# 2005-01-09 Original C version (gears.c) by Brian Paul et al.
# http://cvs.freedesktop.org/mesa/Mesa/progs/demos/gears.c?rev=1.8
# 2010-06-05 Revised Ruby Version Monkstone tested on AMD 64 bit linux with nvidia driver
# using lib-opengl-ruby1.9 (ie not the gem version)
require 'opengl'
class Gears
attr_reader :autoexit, :frames, :t0_idle, :t0
Position = Struct.new("Position", :x, :y, :z, :w) # Struct now replace Array
Color = Struct.new("Color", :red, :green, :blue, :alpha)
POS = Position.new(5.0, 5.0, 10.0, 0.0)
RED = Color.new(0.8, 0.1, 0.0, 1.0)
GREEN = Color.new(0.0, 0.8, 0.2, 1.0)
BLUE = Color.new(0.2, 0.2, 1.0, 1.0)
include GL
include GLUT
include Math
# Draw a gear wheel. You'll probably want to call this function when
# building a display list since we do a lot of trig here.
#
# Input: inner_radius - radius of hole at center
# outer_radius - radius at center of teeth
# width - width of gear
# teeth - number of teeth
# tooth_depth - depth of tooth
def gear(inner_radius, outer_radius, width, teeth, tooth_depth)
r0 = inner_radius
r1 = outer_radius - tooth_depth / 2.0
r2 = outer_radius + tooth_depth / 2.0
da = 2.0 * PI / teeth / 4.0
ShadeModel(GL::FLAT)
Normal(0.0, 0.0, 1.0)
# Draw front face
Begin(GL::QUAD_STRIP)
(0..teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5)
Vertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5)
if i < teeth
Vertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5)
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5)
end
end
End()
# Draw front sides of teeth
Begin(GL::QUADS)
(0...teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5)
Vertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5)
Vertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5)
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5)
end
End()
Normal(0.0, 0.0, -1.0)
# Draw back face
Begin(GL::QUAD_STRIP)
(0..teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5)
Vertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5)
if i < teeth
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5)
Vertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5)
end
end
End()
# Draw back sides of teeth
Begin(GL::QUADS)
(0...teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5)
Vertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5)
Vertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5)
Vertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5)
end
End()
# Draw outward faces of teeth
Begin(GL::QUAD_STRIP)
(0...teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5)
Vertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5)
u = r2 * cos(angle + da) - r1 * cos(angle)
v = r2 * sin(angle + da) - r1 * sin(angle)
len = sqrt(u * u + v * v)
u /= len
v /= len
Normal(v, -u, 0.0)
Vertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5)
Vertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5)
Normal(cos(angle), sin(angle), 0.0)
Vertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5)
Vertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5)
u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da)
v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da)
Normal(v, -u, 0.0)
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5)
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5)
Normal(cos(angle), sin(angle), 0.0)
end
Vertex3f(r1 * cos(0), r1 * sin(0), width * 0.5)
Vertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5)
End()
ShadeModel(GL::SMOOTH)
# Draw inside radius cylinder
Begin(GL::QUAD_STRIP)
(0..teeth).each do |i|
angle = i * 2.0 * PI / teeth
Normal(-cos(angle), -sin(angle), 0.0)
Vertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5)
Vertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5)
end
End()
end
def init
@angle = 0.0
@view_rotx, @view_roty, @view_rotz = 20.0, 30.0, 0.0
Lightfv(GL::LIGHT0, GL::POSITION, POS)
Enable(GL::CULL_FACE)
Enable(GL::LIGHTING)
Enable(GL::LIGHT0)
Enable(GL::DEPTH_TEST)
# Make the gears
@gear1 = GenLists(1)
NewList(@gear1, GL::COMPILE)
Material(GL::FRONT, GL::AMBIENT_AND_DIFFUSE, RED)
gear(1.0, 4.0, 1.0, 20, 0.7)
EndList()
@gear2 = GenLists(1)
NewList(@gear2, GL::COMPILE)
Material(GL::FRONT, GL::AMBIENT_AND_DIFFUSE, GREEN)
gear(0.5, 2.0, 2.0, 10, 0.7)
EndList()
@gear3 = GenLists(1)
NewList(@gear3, GL::COMPILE)
Material(GL::FRONT, GL::AMBIENT_AND_DIFFUSE, BLUE)
gear(1.3, 2.0, 0.5, 10, 0.7)
EndList()
Enable(GL::NORMALIZE)
ARGV.each do |arg|
case arg
when '-info'
puts "GL_RENDERER = #{GetString(GL::RENDERER)}"
puts "GL_VERSION = #{GetString(GL::VERSION)}"
puts "GL_VENDOR = #{GetString(GL::VENDOR)}"
puts "GL_EXTENSIONS = #{GetString(GL::EXTENSIONS)}"
when '-exit'
@autoexit = 30
puts "Auto Exit after #{@autoexit} seconds. "
end
end
end
def initialize
Init()
InitDisplayMode(GLUT::RGB | GLUT::DEPTH | GLUT::DOUBLE)
InitWindowPosition(0, 0)
InitWindowSize(300, 300)
CreateWindow([]) # want's C char array as entry
init()
glut_callbacks()
DisplayFunc(@draw)
ReshapeFunc(@reshape)
KeyboardFunc(@key)
SpecialFunc(@special)
VisibilityFunc(@visible)
MouseFunc(@mouse)
MotionFunc(@motion)
end
def start
MainLoop()
end
end
private
def glut_callbacks
# define GLUT callbacks as ruby 1.9 lambdas (could use Proc.new)
@idle = ->{
t = Get(GLUT::ELAPSED_TIME) / 1000.0
@t0_idle = t unless t0_idle
# 90 degrees per second
@angle += 70.0 * (t - t0_idle)
@t0_idle = t
PostRedisplay()
}
@visible = -> vis {
IdleFunc(vis == GLUT::VISIBLE ? @idle : nil)
}
@mouse = -> button, state, x, y {
@mouse = state
@x0, @y0 = x, y
}
@motion = -> x, y {
if @mouse == GLUT::DOWN
@view_roty += @x0 - x
@view_rotx += @y0 - y
end
@x0, @y0 = x, y
}
# begin draw
@draw = ->{
Clear(GL::COLOR_BUFFER_BIT | GL::DEPTH_BUFFER_BIT);
PushMatrix()
Rotate(@view_rotx, 1.0, 0.0, 0.0)
Rotate(@view_roty, 0.0, 1.0, 0.0)
Rotate(@view_rotz, 0.0, 0.0, 1.0)
PushMatrix()
Translate(-3.0, -2.0, 0.0)
Rotate(@angle, 0.0, 0.0, 1.0)
CallList(@gear1)
PopMatrix()
PushMatrix()
Translate(3.1, -2.0, 0.0)
Rotate(-2.0 * @angle -9.0, 0.0, 0.0, 1.0)
CallList(@gear2)
PopMatrix()
PushMatrix()
Translate(-3.1, 4.2, 0.0)
Rotate(-2.0 * @angle -25.0, 0.0, 0.0, 1.0)
CallList(@gear3)
PopMatrix()
PopMatrix()
SwapBuffers()
@frames = 0 unless frames
@t0 = 0 unless t0
@frames += 1
t = Get(GLUT::ELAPSED_TIME)
if t - t0 >= 5000
seconds = (t - t0) / 1000.0
fps = frames / seconds
puts sprintf("%d frames in %6.3f seconds = %6.3f FPS", frames, seconds, fps)
@t0, @frames = t, 0
autoexit.nil? ? nil : (t <= 999.0 * autoexit) ? nil : exit(0)
end
}
# end draw
# Change view angle, exit upon ESC
@key = -> k, x, y {
case k
when ?z
@view_rotz += 5.0
when ?Z
@view_rotz -= 5.0
when ?\e
exit(0)
end
PostRedisplay()
}
# Change view angle
@special = -> k, x, y{
case k
when GLUT::KEY_UP
@view_rotx += 5.0
when GLUT::KEY_DOWN
@view_rotx -= 5.0
when GLUT::KEY_LEFT
@view_roty += 5.0
when GLUT::KEY_RIGHT
@view_roty -= 5.0
end
PostRedisplay()
}
@reshape = -> width, height{
h = height.to_f / width
Viewport(0, 0, width, height)
MatrixMode(GL::PROJECTION)
LoadIdentity()
Frustum(-1.0, 1.0, -h, h, 5.0, 60.0)
MatrixMode(GL::MODELVIEW)
LoadIdentity()
Translate(0.0, 0.0, -40.0)
}
end
fred = Gears.new
#fred.SetWindowTitle( ###some cstring### ) # how?
fred.start
Unlike ruby-processing there is absolutely no problem resizing (on linux), indeed you can and should experiment with resizing the frame whilst the animation is running. Also the syntax is not too bad makes me think I should explore it a bit more!!!
#!/usr/bin/env ruby1.9
# coding: utf-8
# 3-D gear wheels. This program is in the public domain.
#
# Command line options:
# -info print GL implementation information
# -exit automatically exit after 30 seconds
#
# 2005-05-01 Ruby version by Arto Bendiken based on gears.c rev 1.8.
# 2005-01-09 Original C version (gears.c) by Brian Paul et al.
# http://cvs.freedesktop.org/mesa/Mesa/progs/demos/gears.c?rev=1.8
# 2010-06-05 Revised Ruby Version Monkstone tested on AMD 64 bit linux with nvidia driver
# using lib-opengl-ruby1.9 (ie not the gem version)
require 'opengl'
class Gears
attr_reader :autoexit, :frames, :t0_idle, :t0
Position = Struct.new("Position", :x, :y, :z, :w) # Struct now replace Array
Color = Struct.new("Color", :red, :green, :blue, :alpha)
POS = Position.new(5.0, 5.0, 10.0, 0.0)
RED = Color.new(0.8, 0.1, 0.0, 1.0)
GREEN = Color.new(0.0, 0.8, 0.2, 1.0)
BLUE = Color.new(0.2, 0.2, 1.0, 1.0)
include GL
include GLUT
include Math
# Draw a gear wheel. You'll probably want to call this function when
# building a display list since we do a lot of trig here.
#
# Input: inner_radius - radius of hole at center
# outer_radius - radius at center of teeth
# width - width of gear
# teeth - number of teeth
# tooth_depth - depth of tooth
def gear(inner_radius, outer_radius, width, teeth, tooth_depth)
r0 = inner_radius
r1 = outer_radius - tooth_depth / 2.0
r2 = outer_radius + tooth_depth / 2.0
da = 2.0 * PI / teeth / 4.0
ShadeModel(GL::FLAT)
Normal(0.0, 0.0, 1.0)
# Draw front face
Begin(GL::QUAD_STRIP)
(0..teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5)
Vertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5)
if i < teeth
Vertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5)
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5)
end
end
End()
# Draw front sides of teeth
Begin(GL::QUADS)
(0...teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5)
Vertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5)
Vertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5)
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5)
end
End()
Normal(0.0, 0.0, -1.0)
# Draw back face
Begin(GL::QUAD_STRIP)
(0..teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5)
Vertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5)
if i < teeth
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5)
Vertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5)
end
end
End()
# Draw back sides of teeth
Begin(GL::QUADS)
(0...teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5)
Vertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5)
Vertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5)
Vertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5)
end
End()
# Draw outward faces of teeth
Begin(GL::QUAD_STRIP)
(0...teeth).each do |i|
angle = i * 2.0 * PI / teeth
Vertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5)
Vertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5)
u = r2 * cos(angle + da) - r1 * cos(angle)
v = r2 * sin(angle + da) - r1 * sin(angle)
len = sqrt(u * u + v * v)
u /= len
v /= len
Normal(v, -u, 0.0)
Vertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5)
Vertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5)
Normal(cos(angle), sin(angle), 0.0)
Vertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5)
Vertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5)
u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da)
v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da)
Normal(v, -u, 0.0)
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5)
Vertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5)
Normal(cos(angle), sin(angle), 0.0)
end
Vertex3f(r1 * cos(0), r1 * sin(0), width * 0.5)
Vertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5)
End()
ShadeModel(GL::SMOOTH)
# Draw inside radius cylinder
Begin(GL::QUAD_STRIP)
(0..teeth).each do |i|
angle = i * 2.0 * PI / teeth
Normal(-cos(angle), -sin(angle), 0.0)
Vertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5)
Vertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5)
end
End()
end
def init
@angle = 0.0
@view_rotx, @view_roty, @view_rotz = 20.0, 30.0, 0.0
Lightfv(GL::LIGHT0, GL::POSITION, POS)
Enable(GL::CULL_FACE)
Enable(GL::LIGHTING)
Enable(GL::LIGHT0)
Enable(GL::DEPTH_TEST)
# Make the gears
@gear1 = GenLists(1)
NewList(@gear1, GL::COMPILE)
Material(GL::FRONT, GL::AMBIENT_AND_DIFFUSE, RED)
gear(1.0, 4.0, 1.0, 20, 0.7)
EndList()
@gear2 = GenLists(1)
NewList(@gear2, GL::COMPILE)
Material(GL::FRONT, GL::AMBIENT_AND_DIFFUSE, GREEN)
gear(0.5, 2.0, 2.0, 10, 0.7)
EndList()
@gear3 = GenLists(1)
NewList(@gear3, GL::COMPILE)
Material(GL::FRONT, GL::AMBIENT_AND_DIFFUSE, BLUE)
gear(1.3, 2.0, 0.5, 10, 0.7)
EndList()
Enable(GL::NORMALIZE)
ARGV.each do |arg|
case arg
when '-info'
puts "GL_RENDERER = #{GetString(GL::RENDERER)}"
puts "GL_VERSION = #{GetString(GL::VERSION)}"
puts "GL_VENDOR = #{GetString(GL::VENDOR)}"
puts "GL_EXTENSIONS = #{GetString(GL::EXTENSIONS)}"
when '-exit'
@autoexit = 30
puts "Auto Exit after #{@autoexit} seconds. "
end
end
end
def initialize
Init()
InitDisplayMode(GLUT::RGB | GLUT::DEPTH | GLUT::DOUBLE)
InitWindowPosition(0, 0)
InitWindowSize(300, 300)
CreateWindow([]) # want's C char array as entry
init()
glut_callbacks()
DisplayFunc(@draw)
ReshapeFunc(@reshape)
KeyboardFunc(@key)
SpecialFunc(@special)
VisibilityFunc(@visible)
MouseFunc(@mouse)
MotionFunc(@motion)
end
def start
MainLoop()
end
end
private
def glut_callbacks
# define GLUT callbacks as ruby 1.9 lambdas (could use Proc.new)
@idle = ->{
t = Get(GLUT::ELAPSED_TIME) / 1000.0
@t0_idle = t unless t0_idle
# 90 degrees per second
@angle += 70.0 * (t - t0_idle)
@t0_idle = t
PostRedisplay()
}
@visible = -> vis {
IdleFunc(vis == GLUT::VISIBLE ? @idle : nil)
}
@mouse = -> button, state, x, y {
@mouse = state
@x0, @y0 = x, y
}
@motion = -> x, y {
if @mouse == GLUT::DOWN
@view_roty += @x0 - x
@view_rotx += @y0 - y
end
@x0, @y0 = x, y
}
# begin draw
@draw = ->{
Clear(GL::COLOR_BUFFER_BIT | GL::DEPTH_BUFFER_BIT);
PushMatrix()
Rotate(@view_rotx, 1.0, 0.0, 0.0)
Rotate(@view_roty, 0.0, 1.0, 0.0)
Rotate(@view_rotz, 0.0, 0.0, 1.0)
PushMatrix()
Translate(-3.0, -2.0, 0.0)
Rotate(@angle, 0.0, 0.0, 1.0)
CallList(@gear1)
PopMatrix()
PushMatrix()
Translate(3.1, -2.0, 0.0)
Rotate(-2.0 * @angle -9.0, 0.0, 0.0, 1.0)
CallList(@gear2)
PopMatrix()
PushMatrix()
Translate(-3.1, 4.2, 0.0)
Rotate(-2.0 * @angle -25.0, 0.0, 0.0, 1.0)
CallList(@gear3)
PopMatrix()
PopMatrix()
SwapBuffers()
@frames = 0 unless frames
@t0 = 0 unless t0
@frames += 1
t = Get(GLUT::ELAPSED_TIME)
if t - t0 >= 5000
seconds = (t - t0) / 1000.0
fps = frames / seconds
puts sprintf("%d frames in %6.3f seconds = %6.3f FPS", frames, seconds, fps)
@t0, @frames = t, 0
autoexit.nil? ? nil : (t <= 999.0 * autoexit) ? nil : exit(0)
end
}
# end draw
# Change view angle, exit upon ESC
@key = -> k, x, y {
case k
when ?z
@view_rotz += 5.0
when ?Z
@view_rotz -= 5.0
when ?\e
exit(0)
end
PostRedisplay()
}
# Change view angle
@special = -> k, x, y{
case k
when GLUT::KEY_UP
@view_rotx += 5.0
when GLUT::KEY_DOWN
@view_rotx -= 5.0
when GLUT::KEY_LEFT
@view_roty += 5.0
when GLUT::KEY_RIGHT
@view_roty -= 5.0
end
PostRedisplay()
}
@reshape = -> width, height{
h = height.to_f / width
Viewport(0, 0, width, height)
MatrixMode(GL::PROJECTION)
LoadIdentity()
Frustum(-1.0, 1.0, -h, h, 5.0, 60.0)
MatrixMode(GL::MODELVIEW)
LoadIdentity()
Translate(0.0, 0.0, -40.0)
}
end
fred = Gears.new
#fred.SetWindowTitle( ###some cstring### ) # how?
fred.start
Unlike ruby-processing there is absolutely no problem resizing (on linux), indeed you can and should experiment with resizing the frame whilst the animation is running. Also the syntax is not too bad makes me think I should explore it a bit more!!!
Labels:
lambda,
opengl,
ruby,
stabby-syntax
Subscribe to:
Posts (Atom)
Followers
About Me
- monkstone
- I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2