Re: XForms: Xforms & Mesa

Robert S. Mallozzi (mallors@crazyhorse.msfc.nasa.gov)
Wed, 18 Mar 1998 13:42:47 -0600 (CST)

# To subscribers of the xforms list from "Robert S. Mallozzi" <mallors@crazyhorse.msfc.nasa.gov> :

On 18 Mar, Miguel Monteiro de Sousa Frade wrote:
> # To subscribers of the xforms list from Miguel Monteiro de Sousa Frade <mfrade@ener1000.dee.uc.pt> :
>
>
> Hi, every one,
> I'm working with Xforms and a glcanvas. I'd like to know if exist any
> function or event (such as Expose, the only I know) to wich I could add a
> handler for specific things, such as:
> a resizing handler
> a display handler
>
> and others that appear in the mesa exmples.
>
> I've problems in redrawing the canvas when I add new objects or resize the
> window (that should call a redraw function).
>

Below is a full example of using GL and Xforms that I did for
a computer graphics class project. It uses canvas handlers for
expose (and resize), buttonpress, and keyboard events. Don't
forget to compile in gl.c that comes with Xforms.

-bob

---------------- begin: project2.c ---------------------------

/*
** CS 645 Fall, 1997
** Project 2 Hierarchical Modeling
**
** Robert S. Mallozzi
** <Robert.Mallozzi@msfc.nasa.gov>
** 1997 October
**
** * * * * * * * * * * * * * * * * * * * * * * * * * *
**
** This program builds a hierarchical model using OpenGL display lists, and
** implements simple animation of the model about the x,y,z WORLD coordinate
** system. Object rotations are performed about the object centroid.
** The viewpoint is fixed, and the projection reference point is located
** at (75, 150, 150). The projection is parallel with the projection plane at
** z = 0, and an infinite view volume is simulated. The default render mode
** is shaded, with lighting enabled. These options can be changed on the
** user interface. The user interface is implemented using the xforms library.
** See http://bragg.phys.uwm.edu/xforms for more information.
**
** Note that for key and mouse bindings to be recognized, the mouse cursor
** must be in the OpenGL viewport window.
**
** Parallel view volume:
**
** DOP = CW - PRP = (0, 0, 0) - (75, 150, 150) = (-75, -150, -150).
** Clipping planes are set at x = +/- 200, y = +/- 200, near
** clipping plane at z = 5000, far clipping plane at z = -5000.
**
** Key Bindings:
**
** V (^) Translate -10 (+10) units along y-axis
** R (r) Rotate smoothly -30 (+30) degrees around y-axis
** Q Quit
** h Print the key bindings to stdout
**
** Mouse Bindings:
**
** LEFT Inititate animation loop
**
** Interface Button Items:
**
** Quit Quit
** Show/Hide Axes Show/hide WORLD coordinate axes
** Disable/Enable Lighting Turn lighting off/on
** Background Color Set color of the window background
** Object Color Set color of the current object
** Render Mode Set render mode: solid, wireframe, or vertices
**
**
**
** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#include "X11/keysym.h"

#include "GL/gl.h"
#include "GL/glu.h"

#include "forms.h"

/*
** Define some colors for glColor4fv()
*/
const GLfloat white[4] = {1.0, 1.0, 1.0, 0.0};
const GLfloat red[4] = {1.0, 0.0, 0.0, 0.0};
const GLfloat green[4] = {0.0, 1.0, 0.0, 0.0};
const GLfloat blue[4] = {0.0, 0.0, 1.0, 0.0};
const GLfloat yellow[4] = {1.0, 1.0, 0.0, 0.0};
const GLfloat cyan[4] = {0.0, 1.0, 1.0, 0.0};
const GLfloat violet[4] = {1.0, 0.0, 1.0, 0.0};
const GLfloat black[4] = {0.0, 0.0, 0.0, 0.0};

/*
** User interface data
*/
typedef struct {
FL_FORM *form;
FL_OBJECT *canvas;
FL_OBJECT *quit;
void *vdata;
long ldata;
} FORM_S;

static FORM_S *build_form(void);

FORM_S *theForm;

/*
** Local function prototypes
*/
static void draw_axes(void);
static void draw_box(void);
static void draw_top(void);

static void usage(void);
static void initialize(void);
static void display(void);

static void doRotate(GLint angle, const char *axis);
static void doTranslate(GLint value, const char *axis);
static void setFgColor(const GLfloat color[4]);
static void setBgColor(const GLfloat color[4]);

/*
** Canvas event handlers
*/
static int expose(FL_OBJECT *ob, Window win, int w, int h,
XEvent *xev, void *udata);
static int buttonpress(FL_OBJECT *ob, Window win, int w, int h,
XEvent *xev, void *udata);
static int keyboard(FL_OBJECT *ob, Window win, int w, int h,
XEvent *xev, void *udata);

/*
** User interface callback functions
*/
static void AxesCB(FL_OBJECT *ob, long data);
static void LightingCB(FL_OBJECT *ob, long data);
static void ModeCB(FL_OBJECT *ob, long data);
static void SetColorCB(FL_OBJECT *ob, long data);

/*
** Default rotation and translation values, set in initialize()
*/
static GLint rotationValue;
static GLint translationValue;

/*
** Global state variables
*/
char *progname;
GLboolean show_axes = GL_FALSE;

GLfloat currentFgColor[4];
GLfloat currentBgColor[4];
static GLint currentT[3];
static GLint currentR[3];

/*
** Display list ids
*/
GLuint axes_id;
GLuint box_id;
GLuint top_id;

/*
** Model geometry parameters
*/
GLfloat model_offset[] = {60.0, 10.0, 70.0}; /* Model offset from origin */
GLfloat centroid[] = {15.0, 55.0, 15.0}; /* Relative to offset */

/*
** Current render mode
*/
typedef enum {
SOLID = 1, WIREFRAME, POINTS
} DISPLAY_MODE_E;

DISPLAY_MODE_E display_mode;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
** Called on Keypress event
*/
static int keyboard(FL_OBJECT *ob, Window win, int w, int h,
XEvent *xev, void *udata)
{
int i;
char key[10];
KeySym keysym;


XLookupString((XKeyEvent *) xev, key, sizeof(key), &keysym, NULL);

switch (keysym) {

/*
** Q to quit
*/
case 'Q':
fl_finish();
exit(0);
break;

/*
** Translations
*/

case '^':
doTranslate(translationValue, "y");
display();
break;

case 'V':
doTranslate(-translationValue, "y");
display();
break;

/*
** Rotations
*/

case 'r':
for (i = 1; i <= 6; i++) {
doRotate(rotationValue, "y");
display();
}
break;

case 'R':
for (i = 1; i <= 6; i++) {
doRotate(-rotationValue, "y");
display();
}
break;

/*
** Added options
*/

case 'h':
usage();
break;

default: break;

} /* endswitch */

return(0);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
** Called on Expose event
*/
static int expose(FL_OBJECT *ob, Window win, int w, int h,
XEvent *xev, void *udata)
{
glViewport(0, 0, (GLint) w, (GLint) h);

display();

return(0);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
** Called on ButtonPress event in canvas
*/
static int buttonpress(FL_OBJECT *ob, Window win, int w, int h,
XEvent *xev, void *udata)
{
GLint i;
GLuint numRotations = 36;

/*
** LEFT mouse button press event only
*/
if ((xev->type == ButtonPress) && (xev->xbutton.button == 1)) {

for (i = 0; i < numRotations; i++) {
doTranslate(5.0, "y");
doRotate(-5.0, "y");
display();
}

for (i = 0; i < numRotations; i++) {
doTranslate(-5.0, "y");
doRotate(-5.0, "y");
display();
}

}


return 0;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
** A set of axes
*/
static void draw_axes(void)
{
const GLint maxAxisExtent = 500;

glPushAttrib(GL_CURRENT_BIT | GL_LIGHTING_BIT);

/*
** Specify GL_EMISSION so that the axes appear to emit
** their own light, and hence are always visible
*/

glColor4fv(red);
glMaterialfv(GL_FRONT, GL_EMISSION, red);
glBegin(GL_LINES);
glVertex3i(0, 0, 0);
glVertex3i(maxAxisExtent, 0, 0);
glEnd();

glColor4fv(green);
glMaterialfv(GL_FRONT, GL_EMISSION, green);
glBegin(GL_LINES);
glVertex3i(0, 0, 0);
glVertex3i(0, maxAxisExtent, 0);
glEnd();

glColor4fv(blue);
glMaterialfv(GL_FRONT, GL_EMISSION, blue);
glBegin(GL_LINES);
glVertex3i(0, 0, 0);
glVertex3i(0, 0, maxAxisExtent);
glEnd();

glPopAttrib();

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
** Generic building block for the model: cube of size 1 unit
*/
static void draw_box(void)
{
GLint i;

/*
** Six faces of a unit cube
*/
GLint faces[6][12] = {
{0,0,0, 0,1,0, 1,1,0, 1,0,0}, /* back */
{0,0,1, 1,0,1, 1,1,1, 0,1,1}, /* front */
{0,0,0, 1,0,0, 1,0,1, 0,0,1}, /* bottom */
{0,1,0, 0,1,1, 1,1,1, 1,1,0}, /* top */
{0,0,0, 0,0,1, 0,1,1, 0,1,0}, /* left */
{1,0,0, 1,1,0, 1,1,1, 1,0,1}, /* right */
};

/*
** Cube normals
*/
GLint n[6][3] = {
{ 0, 0, -1},
{ 0, 0, 1},
{ 0, -1, 0},
{ 0, 1, 0},
{-1, 0, 0},
{ 1, 0, 0},
};

for (i = 0; i < 6; i++) {

glBegin(GL_QUADS);

glNormal3i(n[i][0], n[i][1], n[i][2]);

glVertex3i(faces[i][0], faces[i][1], faces[i][2]);
glVertex3i(faces[i][3], faces[i][4], faces[i][5]);
glVertex3i(faces[i][6], faces[i][7], faces[i][8]);
glVertex3i(faces[i][9], faces[i][10], faces[i][11]);

glEnd();

}

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void draw_top(void)
{
GLUquadricObj *quadObj;

/*
** Build model at the origin; translate to desired location
** after building. The hierarchial model is built from two primitive
** components: a cube and a cylinder.
*/

glPushMatrix();

/*
** Translate to final model position
*/
glTranslatef(model_offset[0], model_offset[1], model_offset[2]);

/*
** Base
*/
/*
glPushMatrix();
glScalef(30.0, 90.0, 30.0);
glCallList(box_id);
glPopMatrix();
*/
glPushMatrix();
quadObj = gluNewQuadric();;
glTranslatef(centroid[0], 90.0, centroid[2]);
glRotatef(90.0, 1.0, 0.0, 0.0);
gluCylinder(quadObj, 15.0, 15.0, 90.0, 20, 8);
glPopMatrix();

/*
** Top
*/
glPushMatrix();
glTranslatef(-50.0, 90.0, 0.0);
glScalef(130.0, 20.0, 30.0);
glCallList(box_id);
glPopMatrix();

/*
** Propellers: left, right
*/
glPushMatrix();
glTranslatef(-45.0, 95.0, 30.0);
glScalef(10.0, 10.0, 40.0);
glCallList(box_id);
glPopMatrix();

glPushMatrix();
glTranslatef(60.0, 95.0, -40.0);
glScalef(10.0, 10.0, 40.0);
glCallList(box_id);
glPopMatrix();

glPopMatrix();

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
** Builds the GUI
*/
static FORM_S *build_form(void)
{
FL_OBJECT *obj;
FORM_S *aForm = (FORM_S *) fl_calloc(1, sizeof(*aForm));

const GLint button_w = 100;
const GLint button_h = 25;
const GLint canvas_w = 400;
const GLint canvas_h = 450;

if (aForm == NULL) {
perror("build_form");
exit(1);
}


aForm->form = fl_bgn_form(FL_NO_BOX,
40 + canvas_w + button_w, 20 + canvas_h);

obj = fl_add_box(FL_UP_BOX,
0, 0, 40 + canvas_w + button_w, 20 + canvas_h, "");

aForm->canvas = obj = fl_add_glcanvas(FL_NORMAL_CANVAS,
30 + button_w, 10, canvas_w, canvas_h, "");

obj = fl_add_frame(FL_EMBOSSED_FRAME,
10, 10, button_w + 10, canvas_h, "");

aForm->quit = obj = fl_add_button(FL_NORMAL_BUTTON,
15, 15, button_w, button_h, "Quit");
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_object_lsize(obj, FL_NORMAL_SIZE);

obj = fl_add_button(FL_NORMAL_BUTTON,
15, 55, button_w, button_h, "Show Axes");
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_object_lsize(obj, FL_NORMAL_SIZE);
fl_set_object_callback(obj, AxesCB, 0);

obj = fl_add_button(FL_NORMAL_BUTTON,
15, 85, button_w, button_h, "Disable Lighting");
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_object_lsize(obj, FL_NORMAL_SIZE);
fl_set_object_callback(obj, LightingCB, 0);
fl_set_button(obj, 0);

obj = fl_add_text(FL_NORMAL_TEXT,
15, 125, button_w, button_h, "Background");
fl_set_object_lstyle(obj, FL_BOLDITALIC_STYLE);
fl_set_object_lalign(obj, FL_ALIGN_CENTER);

obj = fl_add_choice(FL_NORMAL_CHOICE,
15, 145, button_w, button_h, "");
fl_set_object_boxtype(obj, FL_UP_BOX);
fl_set_choice_fontsize(obj, FL_NORMAL_SIZE);
fl_set_choice_fontstyle(obj, FL_BOLD_STYLE);
fl_addto_choice(obj, "White|Red|Green|Blue|Yellow|Cyan|Violet|Black");
fl_set_object_callback(obj, SetColorCB, 0);
fl_set_choice(obj, 8);


obj = fl_add_text(FL_NORMAL_TEXT,
15, 175, button_w, button_h, "Object Color");
fl_set_object_lstyle(obj, FL_BOLDITALIC_STYLE);
fl_set_object_lalign(obj, FL_ALIGN_CENTER);

obj = fl_add_choice(FL_NORMAL_CHOICE,
15, 195, button_w, button_h, "");
fl_set_object_boxtype(obj, FL_UP_BOX);
fl_set_choice_fontsize(obj, FL_NORMAL_SIZE);
fl_set_choice_fontstyle(obj, FL_BOLD_STYLE);
fl_addto_choice(obj, "White|Red|Green|Blue|Yellow|Cyan|Violet|Black");
fl_set_object_callback(obj, SetColorCB, 1);
fl_set_choice(obj, 4);

obj = fl_add_text(FL_NORMAL_TEXT,
15, 225, button_w, button_h, "Render Mode");
fl_set_object_lstyle(obj, FL_BOLDITALIC_STYLE);
fl_set_object_lalign(obj, FL_ALIGN_CENTER);

obj = fl_add_choice(FL_NORMAL_CHOICE,
15, 245, button_w, button_h, "");
fl_set_object_boxtype(obj, FL_UP_BOX);
fl_set_choice_fontsize(obj, FL_NORMAL_SIZE);
fl_set_choice_fontstyle(obj, FL_BOLD_STYLE);
fl_addto_choice(obj, "Solid|Wireframe|Vertices");
fl_set_object_callback(obj, ModeCB, 0);

fl_end_form();

return(aForm);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void initialize(void)
{

GLfloat m[] = { 1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
-0.5, -1.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0};

GLfloat light0_position[] = {150.0, 150.0, 150.0, 0.0};

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

/*
** Set view volume
*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

/*
** Oblique orthographic parallel projection: need to shear view volume
*/
glOrtho(-200, 200, -200, 200, -5000, 5000);
glMultMatrixf(m);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

gluLookAt(75.0, 150.0, 150.0, /* viewpoint */
75.0, 150.0, 0.0, /* look at */
0.0, 1.0, 0.0); /* up vector */

/*
** A single OpenGL light
*/
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);

/*
** Normalize transformed normal vectors
*/
glEnable(GL_NORMALIZE);

/*
** Cause material property to track current color at all times
*/
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);

/*
** Cull non-visible faces, and use depth buffering for hidden
** surface elimination
*/
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);

/*
** Set initial colors and display mode
*/
setBgColor(black);
setFgColor(blue);
display_mode = SOLID;

/*
** Build hierarchical model
*/
if ((axes_id = glGenLists(1)) == 0) {
fprintf(stderr, "%s: could not generate display list id\n", progname);
exit(1);
}
glNewList(axes_id, GL_COMPILE);
draw_axes();
glEndList();

if ((box_id = glGenLists(1)) == 0) {
fprintf(stderr, "%s: could not generate display list id\n", progname);
exit(1);
}
glNewList(box_id, GL_COMPILE);
draw_box();
glEndList();

if ((top_id = glGenLists(1)) == 0) {
fprintf(stderr, "%s: could not generate display list id\n", progname);
exit(1);
}
glNewList(top_id, GL_COMPILE);
draw_top();
glEndList();

/*
** Transformation parameters
*/
rotationValue = 5;
translationValue = 10;

currentT[0] = 0; currentT[1] = 0; currentT[2] = 0;
currentR[0] = 0; currentR[1] = 0; currentR[2] = 0;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main(int argc, char **argv)
{
const char *title = "CS 645: Project 2";
GLint i;

FL_IOPT control;
FL_OBJECT *ob;

int test_str_width, test_str_height;
double scaleFactor[2];
const int dpi75_width = 89;
const int dpi75_height = 14;

progname = (char *) malloc (strlen(argv[0]) + 1);
if (progname == NULL) {
perror(argv[0]);
exit(1);
}
strcpy(progname, argv[0]);

/*
** Print the help on startup
*/
usage();

/*
** Set some defaults and initialize the xforms library
*/
control.buttonFontSize = 12;
control.labelFontSize = 12;
control.menuFontSize = 12;
control.borderWidth = -2;

fl_set_defaults(FL_PDButtonFontSize|
FL_PDLabelFontSize|
FL_PDMenuFontSize|
FL_PDBorderWidth,
&control);

fl_initialize(&argc, argv, "", 0, 0);

/* Get a test string dimension; main form is scaled based on a
** "normal" size computed from a 75dpi font
*/
fl_get_string_dimension(FL_BOLD_STYLE, FL_NORMAL_SIZE, "TEST_STRING",
strlen("TEST_STRING"), &test_str_width, &test_str_height);

scaleFactor[0] = (double) test_str_width / dpi75_width;
scaleFactor[1] = (double) test_str_height / dpi75_height;

/*
** Build the user interface
*/
theForm = build_form();

/*
** Attach event handlers
*/
fl_add_canvas_handler(theForm->canvas, Expose, expose, 0);
fl_add_canvas_handler(theForm->canvas, ButtonPress, buttonpress, 0);
fl_add_canvas_handler(theForm->canvas, KeyPress, keyboard, 0);

/*
** Scale form based on current font, and map to screen
*/
fl_scale_form(theForm->form, scaleFactor[0], scaleFactor[1]);
fl_show_form(theForm->form, FL_PLACE_CENTERFREE, FL_FULLBORDER, title);

/*
** Initialize parameters
*/
initialize();

/*
** Start event loop
*/
while ((ob = fl_do_forms()) != theForm->quit);


fl_finish();
return(0);

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void display(void)
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

switch (display_mode) {

case SOLID: glPolygonMode(GL_FRONT, GL_FILL); break;
case WIREFRAME: glPolygonMode(GL_FRONT, GL_LINE); break;
case POINTS: glPolygonMode(GL_FRONT, GL_POINT); break;

default: printf("Internal error: display: Invalid display_mode\n");
display_mode = SOLID;
break;
}

/*
** TRANSFORMATIONS
**
** We want to rotate about the object's centroid, so perform the
** following transformations:
**
** 1. Translate object to origin. Since the model was constructed
** relative to the bottom corner vertex of the base, a second
** translation is required so that the center of the model is
** at the origin prior to the initiation of the rotations. The
** values required for this translation are stored in model_offset[3]
**
** 2. Apply rotations. Order of rotations is irrelevant, since
** we only specify a single rotation about one of the three principal
** axes (WORLD x, y, z) for each pass through this portion of code.
** There are no rotations about arbitrary axes.
**
** 3. Translate the object back to its original position.
**
** 4. Apply user-specified translations.
**
** These transformations must appear in the code in reverse order.
*/

glPushAttrib(GL_CURRENT_BIT);
glPushMatrix();

glColor4fv(currentFgColor);

glTranslatef(currentT[0], currentT[1], currentT[2]);

glTranslatef(model_offset[0], model_offset[1], model_offset[2]);
glTranslatef(centroid[0], centroid[1], centroid[2]);

glRotatef(currentR[0], 1.0, 0.0, 0.0);
glRotatef(currentR[1], 0.0, 1.0, 0.0);
glRotatef(currentR[2], 0.0, 0.0, 1.0);

glTranslatef(-centroid[0], -centroid[1], -centroid[2]);
glTranslatef(-model_offset[0], -model_offset[1], -model_offset[2]);

glCallList(top_id);

glPopMatrix();
glPopAttrib();

if (show_axes)
glCallList(axes_id);

glXSwapBuffers(fl_display, fl_get_canvas_id(theForm->canvas));

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void doRotate(GLint angle, const char *axis)
{

if ((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0))
currentR[0] = (currentR[0] + angle) % 360;

if ((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0))
currentR[1] = (currentR[1] + angle) % 360;

if ((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0))
currentR[2] = (currentR[2] + angle) % 360;

}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void doTranslate(GLint value, const char *axis)
{
if ((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0))
currentT[0] += value;

if ((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0))
currentT[1] += value;

if ((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0))
currentT[2] += value;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void setFgColor(const GLfloat color[4])
{
GLint i;


for (i = 0; i < 4; i++)
currentFgColor[i] = color[i];

}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void setBgColor(const GLfloat color[4])
{
GLint i;


for (i = 0; i < 4; i++)
currentBgColor[i] = color[i];

glClearColor(currentBgColor[0], currentBgColor[1],
currentBgColor[2], currentBgColor[3]);

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void usage(void)
{

const char *help =

"\nDefault key and mouse bindings\n\n"

"\tV (^)\t\tTranslate -10 (+10) units along y-axis\n"
"\tR (r)\t\tRotate smoothly -30 (+30) degrees around y-axis\n"
"\th\t\tPrint help\n"
"\tLeft Mouse\tInitiate animation\n"

"\tQ\t\tQuit\n";

printf("%s\n", help);

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void AxesCB(FL_OBJECT *ob, long data)
{
if (show_axes) {
show_axes = GL_FALSE;
fl_set_object_label(ob, "Show Axes");
}
else {
show_axes = GL_TRUE;
fl_set_object_label(ob, "Hide Axes");
}


display();
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void LightingCB(FL_OBJECT *ob, long data)
{
if (glIsEnabled(GL_LIGHTING)) {
glDisable(GL_LIGHTING);
fl_set_object_label(ob, "Enable Lighting");
}
else {
glEnable(GL_LIGHTING);
fl_set_object_label(ob, "Disable Lighting");
}

display();
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void ModeCB(FL_OBJECT *ob, long data)
{
display_mode = fl_get_choice(ob);

display();

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void SetColorCB(FL_OBJECT *ob, long data)
{
GLint item;


item = fl_get_choice(ob);

switch (data) {

case 0: /* Background color */
switch (item) {
case 1: setBgColor(white); break;
case 2: setBgColor(red); break;
case 3: setBgColor(green); break;
case 4: setBgColor(blue); break;
case 5: setBgColor(yellow); break;
case 6: setBgColor(cyan); break;
case 7: setBgColor(violet); break;
case 8: setBgColor(black); break;
}
break;

case 1: /* Foreground color */
switch (item) {
case 1: setFgColor(white); break;
case 2: setFgColor(red); break;
case 3: setFgColor(green); break;
case 4: setFgColor(blue); break;
case 5: setFgColor(yellow); break;
case 6: setFgColor(cyan); break;
case 7: setFgColor(violet); break;
case 8: setFgColor(black); break;
}
break;
}

display();

}

--Robert S. Mallozzi
http://cspar.uah.edu/~mallozzir/

_________________________________________________
To unsubscribe, send the message "unsubscribe" to
xforms-request@bob.usuf2.usuhs.mil or see
http://bob.usuf2.usuhs.mil/mailserv/xforms.html
XForms Home Page: http://bragg.phys.uwm.edu/xforms
List Archive: http://bob.usuf2.usuhs.mil/mailserv/list-archives/