FOX provides extensive support for OpenGL through its FXGLCanvas and FXGLViewer widgets, and FXRuby in turn provides interfaces to those classes. By combining FXRuby with the OpenGL interface for Ruby (described below) you can develop very powerful 3-D graphics applications. This chapter gives you the information you'll need to get started.
OpenGL is a platform-independent API for 2D and 3D graphics. The home page is http://www.opengl.org. Because it's a fairly open standard, highly optimized OpenGL drivers are available for most operating systems (including Windows and Linux).
This extension module, developed by Yoshiyuki Kusano, provides interfaces to not only the basic OpenGL API, but also the GLU and GLUT APIs. As of this writing, the currently released version is 0.32d and is available for download from http://www2.giganet.net/~yoshi/rbogl-0.32d.tgz. Be sure to check the Ruby Application Archive for the latest version of this extension as it is still under development.
Once you've downloaded the tarball, you should extract its contents to the working directory of your choice by typing:
$ tar xzf rbogl-0.32d.tgz
After executing this command you should have a new opengl (not rbogl-0.32b) subdirectory. Change to this directory and then type:
$ ruby extconf.rb
This should create a Makefile configured appropriately for your local Ruby installation. To now build the OpenGL module, type:
You can safely ignore the warning(s) about glut_KeyboardFunc when it's compiling glut.c. Well, I ignore them and it hasn't hurt me yet ;) Assuming you get an otherwise clean build, install the OpenGL extensions by typing:
$ make site-install
Please note that I'm not the maintainer of this particular Ruby extension, so I can't really accept bug fixes for it. But if you're having trouble integrating Ruby/OpenGL with FXRuby, let me know and we'll see what we can do.
An FXGLVisual object describes the capabilities of an FXGLCanvas or FXGLViewer window. Typically, an X server supports many different visuals with varying capabilities, but the ones with greater capabilities require more resources than those with fewer capbilities. To construct an FXGLVisual object, just call FXGLVisual.new:
aVisual = FXGLVisual.new(theApp, VISUAL_DOUBLEBUFFER)
The first argument to FXGLVisual.new is a reference to the application object. The second argument is a set of options indicating the requested capabilities for the visual. If one or more of the requested capabilities aren't available, FOX will try to gracefully degrade to a working GL visual; but if you're counting on a specific capability, be sure to check the returned visual to see if it actually supports that capability. For example, say you request a visual with double-buffering and stereographic capabilities:
anotherVisual = FXGLVisual.new(theApp, VISUAL_DOUBLEBUFFER | VISUAL_STEREO)
Double-buffering is pretty commonplace these days, but stereo may not be available on the system. We can check to see whether the visual we got supports these capabilities by calling the FXGLVisual#doubleBuffered? and FXGLVisual#stereo? methods:
anotherVisual = FXGLVisual.new(theApp, VISUAL_DOUBLEBUFFER | VISUAL_STEREO) if anotherVisual.doubleBuffered? puts "It's double-buffered." else puts "It's single-buffered." end if anotherVisual.stereo? puts "It's stereo." else puts "It isn't stereo." end
Some FXGLVisual object must be associated with every FXGLCanvas or FXGLViewer window, but you don't need to have a separate FXGLVisual object for each window. For most applications, you can just construct a single FXGLVisual object that's shared among all the OpenGL windows.
The FXGLCanvas widget provides a very simple OpenGL-capable window with minimal functionality. To construct an FXGLCanvas, call FXGLCanvas.new:
glCanvas = FXGLCanvas.new(parent, vis)
The first argument to FXGLCanvas.new is the parent (container) widget and the second argument is the FXGLVisual that should be used for this window.
The FXGLViewer widget provides a higher-level OpenGL-capable window with a lot of built-in functionality. To construct an FXGLViewer, call FXGLViewer.new:
glViewer = FXGLViewer.new(parent, vis)
The first argument to FXGLViewer.new is the parent (container) widget and the second argument is the FXGLVisual that should be used for this window.