Can robot.rb be written a ruby way?

This site gives the c code from robot.c in its
robot-framework-1.3.tar.gz file
http://yallara.cs.rmit.edu.au/~aholkner/Interactive3D/

and this site gives a ruby code for the same program in robot.rb in its
folder sample in version 0.32g
http://www2.giganet.net/~yoshi/

The c program is structured as follows:
void init(void)
void display(void)
void reshape (int w, int h)
void keyboard (unsigned char key, int x, int y)
int main(int argc, char** argv)
{ …
/* Tell GLUT to create and display the window, with the given title
*/
glutCreateWindow(“Robot Arm Demo”);

/* Call our own init function to set up the background color and
shading
* model. */
init ();

/* Tell GLUT where each of our functions are. We are passing in the
name
* of each function, which it will then call as required. */
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);

/* All initialisation is finished, tell GLUT to run the application
forever
* (or until we tell it to quit) */
glutMainLoop();
…}

and the ruby program is set up as
def init
display = Proc.new {
reshape = Proc.new {|w, h|
keyboard = Proc.new {|key, x, y|

GLUT.CreateWindow($0);
init();
GLUT.DisplayFunc(display);
GLUT.ReshapeFunc(reshape);
GLUT.KeyboardFunc(keyboard);
GLUT.MainLoop();

I was surprised to find that robot.rb is a litteral translation of
robot.c. No objects talking to each other here!

On the other hand, GLUT has a function ReshapeFunc which requires a
function, and so reshape is going to be a function, etc, so there may
not be a lot of room for ruby like programming.

Is it the case here, that because it is calling opengl and GLUT code,
the structure is going to have to be “C” like, and not “Object OOP”
like? Or is there a way of writing robot.rb a more ruby like way?

Actually, maybe it is display which I would like to see more ruby like

display = Proc.new {
GL.Clear(GL::COLOR_BUFFER_BIT);
GL.PushMatrix();
GL.Translate(-1.0, 0.0, 0.0);
GL.Rotate($shoulder, 0.0, 0.0, 1.0);
GL.Translate(1.0, 0.0, 0.0);
GL.PushMatrix();
GL.Scale(2.0, 0.4, 1.0);
GLUT.WireCube (1.0);
GL.PopMatrix();

GL.Translate(1.0, 0.0, 0.0);
GL.Rotate($elbow, 0.0, 0.0, 1.0);
GL.Translate(1.0, 0.0, 0.0);
GL.PushMatrix();
GL.Scale(2.0, 0.4, 1.0);
GLUT.WireCube(1.0);
GL.PopMatrix();

GL.PopMatrix();
GLUT.SwapBuffers();
}
In this simple example, the arms are represented by a scaled cube.
so the basic drawing takes two lines
GL.Scale(2.0, 0.4, 1.0);
GLUT.WireCube(1.0);

But the figures I have seen on the internet have a long list of parts,
for ex

Typically, data like info in ruby would be stored in an object? So I
should create an object for each body part, with in this case a method
made of those two lines?

The other problem with this program is that it draws the upper arm, and
then draws the fore arm at the end of the upper arm. So whatever
rotation the arm went through the forearm will stay attached to the
arm. But with a whole body, this way of drawing does not generalise. It
seems to me that ruby’s object oriented hierarchies would be perfect
for this.

So in the object Arm, I should create a forearmobject, and in
forearmobject, I should create a hand object. The method draw arm
object would draw the arm, and proceed to call the draw forearm method,
which would draw the forearm, and call the draw hand method.

This program seems to redraw the whole figure from scratch, even if
only the forearm was changed. I wonder if the computation could be
saved so only the part changed is redrawn, but it does not sound like
it, because push and pop suggests a giant laundry list which it would
not be easy to access in organised pieces.

If this is the case, I just need to figure out who is at the top of the
hierarchy, probably the hip, and build the thing.

are those thoughts on the right track for a ruby way version of
robot.rb?

On 2/1/06, anne001 [email protected] wrote:

Typically, data like info in ruby would be stored in an object? So I
should create an object for each body part, with in this case a method
made of those two lines?

The other problem with this program is that it draws the upper arm, and
then draws the fore arm at the end of the upper arm. So whatever
rotation the arm went through the forearm will stay attached to the
arm. But with a whole body, this way of drawing does not generalise. It
seems to me that ruby’s object oriented hierarchies would be perfect
for this.

The usual way is to have a scenegraph, which is a tree that describes
the scene you’re drawing. You then attach models and transformations
and material information to the nodes in the graph. When you draw it,
the
renderer (for example) traverses the graph depth-first, calling the
state
setting functions and drawing functions. Other way would be to collect
the scene objects into a list and collapse their transforms into world
coordinates and then draw the list.

This way you can e.g. create a room object for the scene root, attach
some box objects to it, and put some books in the boxes. Now when
you move a box, all the books in it move too.

Here’s some pseudocode:
room = Room.new
boxes = (1…3).each{
box = Box.new(:position => random_position)
box.attach StackOfBooks.new
box
}
room.attach(*boxes)
renderer.draw(room)

hmm, one box too many

room.detach(boxes.last)
renderer.draw(room)

The renderer#draw could be something like:

def draw(scene)
clear_frame
setup_default_state
setup_camera
setup_lights
draw_object(scene)
swap_buffers
end

def draw_object
stack_state{
transform(obj)
set_material(obj)
draw_geometry(obj)
obj.children.each{|c| draw_object(c) }
}
end

This program seems to redraw the whole figure from scratch, even if
only the forearm was changed. I wonder if the computation could be
saved so only the part changed is redrawn, but it does not sound like
it, because push and pop suggests a giant laundry list which it would
not be easy to access in organised pieces.

With OpenGL, it’s going to be a lot slower to figure out what parts of
the
frame have changed and need updating, than just clearing the frame and
drawing everything again. There are some situations where this doesn’t
apply (like if there’s a huge background scene in the horizon; it can be
just drawn to a texture once and the texture then used as an impostor),
but generally it’s not something to worry about.

HTH,
Ilmari