next up previous
Next: 4 Benefits to OpenGL Up: Design of an OpenGL Previous: 2 Graphics Programming Using

3 A Sample Application: Rotating Cube with Color Interpolation

In order to describe how the OpenGL bindings are constructed, and gain an understanding of how the bindings can be utilized, an example that creates a rotating cube with color interpolation follows. The original C code will be presented first followed by the J code. Notice the J syntax closely resembles the C syntax enabling C programmers to make use of the OpenGL bindings with only minimal effort to learn J. Figure 1 illustrates a rendering from the example.

Figure 1: Rotating Cube
\includegraphics[height=2in]{cube1.ps}

Throughout the discussion that follows the following preliminary J bindings will be employed.

   monad =: 3
   define =: :
   script =: 0
   from =: {

Important to all graphics applications is the display function. The display function is executed as events occur requiring a refresh of the screen. In C, the code for the display function in the rotating cube example appears below.

void display(void)
 {
  /* display callback, clear frame buffer and z buffer,
     rotate cube and draw, swap buffers */
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity();
     glRotatef(theta[0], 1.0, 0.0, 0.0);
     glRotatef(theta[1], 0.0, 1.0, 0.0);
     glRotatef(theta[2], 0.0, 0.0, 1.0);
     colorcube();
     glFlush();
     glutSwapBuffers();
 }

The display function begins by clearing the color and depth buffers and loading the identity transformation matrix. Then the display function rotates the transformation matrix for the new position of the cube, and calls a function containing the cube geometry to render and color the cube. Finally, the display function calls glFlush to force complete execution of the preceding OpenGL calls and then swaps the buffers for smoother looking motion.

In J, the display function would look like the following.

display =. monad define script 
NB. display callback, clear frame buffer and z buffer,
NB. rotate cube and draw, swap buffers 
gl 'Clear' ; 'GL_COLOR_BUFFER_BIT' ; 'GL_DEPTH_BUFFER_BIT'
gl 'LoadIdentity'
gl 'Rotatef' ; (0 from theta) ; 1.0 ; 0.0 ; 0.0
gl 'Rotatef' ; (1 from theta) ; 0.0 ; 1.0 ; 0.0
gl 'Rotatef' ; (2 from theta) ; 0.0 ; 0.0 ; 1.0
colorcube ''
gl 'Flush'
glut 'SwapBuffers'
)

The structure of the OpenGL bindings for J centers around external conjunctions. An external conjunction, appropriately named gl following the naming conventions of OpenGL, is used to construct a J sentence that performs an OpenGL function. The gl external conjunction is followed by the rest of the OpenGL function name, like Translatef or Rotatef, and the argument list corresponding to the C version of the OpenGL function. The J syntax to construct the external conjunction looks similar to the folowing:

   gl =: 1024 !: 0

In J syntax, the description of the OpenGL function and its arguments are strung together through links forming a boxed list. A sample OpenGL sentence in J looks like the following:

   gl 'translate3f' ; 0.0 ; _1.0 ; 5.0

The first element of the boxed list corresponds to one of approximately 120 OpenGL functions and serves as a hash key used by the J system to identify the correct function [Nei 93]. Once the function has been identified, the J system has an idea of what proper arguments to the function should look like. The remaining elements in the boxed list constitute arguments to the OpenGL function. If the remainder of the boxed list contains an argument list inconsistent with that of the original C prototype, J will alert the user to the presence of an error. If the boxed list elements are consistent with the original C prototype, the J system proceeds to process the sentence and perform the graphical side effects associated with the OpenGL function.

Next, consider the code for the main function of the graphics application. The C code follows.

void main(int argc, char **argv)
{
   glutInit(&argc, argv);
/* need both double buffering and z buffer */
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize(500, 500);
   glutCreateWindow("colorcube");
   glutReshapeFunc(myReshape);
   glutDisplayFunc(display);
   glutIdleFunc(spinCube);
   glutMouseFunc(mouse);
   glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
   glutMainLoop();
}

Notice that the main function in the rotating cube example contains calls to the GLUT libraries. GLUT library calls are not a problem for the J system. The J system simply relies on another external conjunction to include GLUT functionality. The GLUT external conjunction is constructed in a manner similar to the gl external conjunction:

   glut =: 1024 !: 1

Also, notice the main C function uses callbacks. Callbacks constitute another case that the J system must handle, and therefore establishes a need for another external conjunction.

The callback external conjunction follows the same construction pattern as the previous OpenGL external conjunctions, but is processed a little differently. The callback external conjunction appears as follows:

   callback =: 1024 !: 4

The callback external conjunction produces a C function pointer to the function specified in the second element of the boxed list, for example display. When called with appropriate arguments, if any, the J function (in this example display) is executed. As a result, the callback function is properly executed for its side effect.

The J code for the main function of the rotating cube example therefore appears as follows.

   main =. monad define script
   ('argc' ; 'argv') =. y.
   glut 'Init' ; 'argc' ; 'argv'
   NB. need both double buffering and z buffer
   glut 'InitDisplayMode' ; 'GLUT_DOUBLE' ; 'GLUT_RGB' ; 'GLUT_DEPTH'
   glut 'InitWindowSize' ; 500 ; 500
   glut 'CreateWindow' ; callback 'colorcube'
   glut 'ReshapeFunc' ; callback 'myReshape'
   glut 'DisplayFunc' ; callback 'display' 
   glut 'IdleFunc' ; callback 'spinCube'
   glut 'MouseFunc' ; callback 'mouse'
   NB. Enable hidden--surface--removal
   gl 'Enable' ; 'GL_DEPTH_TEST' 
   glut 'MainLoop'
   )

The remainder of the rotating cube example code appears in the Appendix in both C and J. All that remains are the definitions of the callback functions, some global variables, and the cube geometry and color functions.


next up previous
Next: 4 Benefits to OpenGL Up: Design of an OpenGL Previous: 2 Graphics Programming Using
2002-09-30