This appendix contains an example program that uses Xt, IRIS IM, and the IRIS IM version of the Silicon Graphics widget. The program displays a planet with a moon, orbiting a sun, and uses a WorkProc for the animation.
/* opensolar.c
* opensolar displays a planet with a moon, orbiting a sun.
* To compile:
* cc -O -o opensolar opensolar.c -lXm -lGLw -lm -lGLU -lGL
*/
#include <Xm/Xm.h>
#include <Xm/Frame.h>
#include <Xm/Form.h>
#include <X11/keysym.h>
#include <X11/StringDefs.h>
#include <GL/GLwMDrawA.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "malloc.h"
typedef struct _spin {
short year;
} SPINDATA, *SPINPTR;
/* function prototypes */
void main(int argc, char **argv);
void initCB (Widget w, XtPointer client_data,
XtPointer call_data);
void exposeCB (Widget w, XtPointer spin,
XtPointer call_data);
void resizeCB (Widget w, XtPointer spin,
XtPointer call_data);
void inputCB (Widget w, XtPointer client_data,
XtPointer call_data);
Boolean drawWP (XtPointer spin);
void drawscene(SPINPTR spin);
void setbeachball(int stripes);
void beachball(unsigned long color1, unsigned long color2);
XtAppContext app_context;
XtWorkProcId workprocid = NULL;
GLXContext glx_context;
Display * global_display;
Window global_window;
/* main
* This program shows a solar system, with a sun, planet, and
* moon (in OpenGL). The user can exit with the ESCape key
* or through the window manager menu.
*/
void main(int argc, char **argv)
{
Arg wargs[15];
int n;
Widget glw, toplevel, frame, form;
SPINPTR spin;
static String fallback_resources[] = {
"*frame*shadowType: SHADOW_IN", "*glwidget*width: 750",
"*glwidget*height: 600", "*glwidget*rgba: TRUE",
"*glwidget*doublebuffer: TRUE",
"*glwidget*allocateBackground: TRUE", NULL
};
/* create main data structure, spin pointer */
spin = (SPINPTR) malloc (sizeof (SPINDATA));
spin->year = 0;
toplevel = XtAppInitialize(
&app_context, /* Application context */
"Opensolar", /* Application class */
NULL, 0, /* command line option list */
&argc, argv, /* command line args */
fallback_resources,
NULL, /* argument list */
0); /* number of arguments */
n = 0;
form = XmCreateForm(toplevel, "form", wargs, n);
XtManageChild(form);
n = 0;
XtSetArg(wargs[n], XtNx, 30);
n++;
XtSetArg(wargs[n], XtNy, 30);
n++;
XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM);
n++;
XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM);
n++;
XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM);
n++;
XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM);
n++;
XtSetArg(wargs[n], XmNleftOffset, 30);
n++;
XtSetArg(wargs[n], XmNbottomOffset, 30);
n++;
XtSetArg(wargs[n], XmNrightOffset, 30);
n++;
XtSetArg(wargs[n], XmNtopOffset, 30);
n++;
frame = XmCreateFrame (form, "frame", wargs, n);
XtManageChild (frame);
n = 0;
glw = GLwCreateMDrawingArea(frame, "glwidget", wargs, n);
XtManageChild (glw);
XtAddCallback(glw, GLwNginitCallback, initCB,
(XtPointer) NULL);
XtAddCallback(glw, GLwNexposeCallback, exposeCB,
(XtPointer) spin);
XtAddCallback(glw, GLwNresizeCallback, resizeCB,
(XtPointer) spin);
XtAddCallback(glw, GLwNinputCallback, inputCB,
(XtPointer) NULL);
XtRealizeWidget(toplevel); /* instantiate it now */
XtAppMainLoop(app_context); /* loop for events */
} /* end main() */
/* initCB
* The initCB subroutine initializes graphics modes and
* transformation matrices.
*/
void initCB (Widget w, XtPointer client_data,
XtPointer call_data)
{
Arg args[1];
XVisualInfo *vi;
XtSetArg(args[0], GLwNvisualInfo, &vi);
XtGetValues(w, args, 1);
global_display = XtDisplay(w);
global_window = XtWindow(w);
glx_context = glXCreateContext(global_display, vi, 0,
GL_FALSE);
} /* end initCB() */
/* exposeCB() and resizeCB() are called when the window
* is uncovered, moved, or resized.
*/
void exposeCB (Widget w, XtPointer ptr, XtPointer call_data)
{
SPINPTR spin;
static char firstTime = 0x1;
GLwDrawingAreaCallbackStruct *call_ptr;
call_ptr = (GLwDrawingAreaCallbackStruct *) call_data;
GLwDrawingAreaMakeCurrent(w, glx_context);
if (firstTime) {
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
gluPerspective(45.0, (GLfloat)(call_ptr->width)
/(GLfloat)(call_ptr->height), 1.0, 25.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glTranslatef(0.0, 0.0, -12.0);
workprocid = XtAppAddWorkProc(app_context, drawWP, ptr);
/* ptr is spin */
firstTime = 0;
}
spin = (SPINPTR) ptr;
drawscene(spin);
}
void resizeCB (Widget w, XtPointer ptr, XtPointer call_data)
{
GLwDrawingAreaCallbackStruct *call_ptr;
SPINPTR spin;
spin = (SPINPTR) ptr;
call_ptr = (GLwDrawingAreaCallbackStruct *) call_data;
GLwDrawingAreaMakeCurrent(w, glx_context);
glViewport (0, 0, (GLsizei) (call_ptr->width-1),
(GLsizei) (call_ptr->height-1));
glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
gluPerspective(45.0, (GLfloat)(call_ptr->width) /
(GLfloat)(call_ptr->height), 1.0, 25.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glTranslatef(0.0, 0.0, -12.0);
drawscene(spin);
}
/* inputCB() handles all types of input from the GL widget.
* The KeyRelease handles the ESCape key, so that it exits
* the program.
*/
void inputCB (Widget w, XtPointer client_data,
XtPointer call_data)
{
char buffer[1];
KeySym keysym;
GLwDrawingAreaCallbackStruct *call_ptr;
XKeyEvent *kevent;
call_ptr = (GLwDrawingAreaCallbackStruct *) call_data;
kevent = (XKeyEvent *) (call_ptr->event);
switch(call_ptr->event->type) {
case KeyRelease:
/* Must convert the keycode to a keysym before
* checking if it is an escape
*/
if (XLookupString(kevent,buffer,1,&keysym,NULL) == 1
&& keysym == (KeySym)XK_Escape)
exit(0);
break;
default:
break;
}
}
/* drawWP() is called by the WorkProc. When the scene
* is in automatic motion, the WorkProc calls this routine,
* which adds 1 degree (10 tenths) to the cumulative amount
* of rotation. drawscene() is called, so the image is
* redrawn. It returns(FALSE) so the WorkProc does not
* discontinue operation.
*/
Boolean drawWP (XtPointer ptr)
{
SPINPTR spin;
spin = (SPINPTR) ptr;
spin->year = (spin->year + 10) % 3600;
drawscene (spin);
return (FALSE);
}
/* drawscene
* drawscene calculates angles relative to the spin->year
* and then draws sun, planet, and moon.
*/
void drawscene(SPINPTR spin)
{
short sunangle;
/* actual dist is 1.5e8 km; mult by 3.0e-8 fudgefactor */
float earthdist = 4.5;
short dayangle;
float earthscale = 0.5;
short monthangle;
float moondist = 0.9;
float moonscale = 0.2;
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(10.0, 1.0, 0.0, 0.0); /* tilt entire scene */
glPushMatrix();
sunangle = (spin->year*365/25) % 3600;
/* sun rotates on axis every 25 days */
glRotatef(.1*(sunangle), 0.0, 1.0, 0.0);
/* cpack format color1, color2 */
/* swapped by hand: was beachball(0x20C0FF, 0x200FFFF); */
beachball(0xFFC02000, 0xFFFF0020);
glPopMatrix();
glPushMatrix();
glRotatef(.1*(spin->year), 0.0, 1.0, 0.0);
glTranslatef(earthdist, 0.0, 0.0);
glPushMatrix();
dayangle = (spin->year*50) % 3600;
/* dayangle fudged so earth rotation can be seen */
glRotatef(.1*(dayangle), 0.0, 1.0, 0.0);
glScalef(earthscale, earthscale, earthscale);
glColor3f(0.0, 0.0, 1.0);
/* swap by hand; was beachball(0xFF0000, 0xC02000);*/
beachball(0x0000FF00, 0x0020C000); /* earth */
glPopMatrix();
monthangle = (spin->year*365/28) % 3600;
glRotatef(.1*(monthangle), 0.0, 1.0, 0.0);
glTranslatef(moondist, 0.0, 0.0);
glScalef(moonscale, moonscale, moonscale);
glColor3f(1.0, 1.0, 1.0);
/* swap by hand; was beachball(0xFFFFFF, 0xC0C0C0); */
beachball(0xFFFFFF00, 0xC0C0C000); /* moon */
glPopMatrix();
glPopMatrix();
glXSwapBuffers(global_display, global_window);
} /* end drawscene() */
/*
* BEACHBALL
*/
/* three dimensional vector */
typedef float vector[3];
vector front = { 0.0, 0.0, 1.0 };
vector back = { 0.0, 0.0, -1.0 };
vector top = { 0.0, 1.0, 0.0 };
vector bottom = { 0.0, -1.0, 0.0 };
vector right = { 1.0, 0.0, 0.0 };
vector left = { -1.0, 0.0, 0.0 };
vector center = { 0.0, 0.0, 0.0 };
/* Number of colored stripes. Should be even to look right */
#define BEACHBALL_STRIPES 12
/* Default number of polygons making up a stripe. Should */
/* be even */
#define BEACHBALL_POLYS 16
/* array of vertices making up a stripe */
vector stripe_point[BEACHBALL_POLYS + 3];
/* has the beachball been initialized */
Boolean beachball_initialized = FALSE;
/* Number of polygons making up a stripe */
int beachball_stripes;
/* Number of vertices making up a stripe */
int stripe_vertices;
/* Initializes beachball_point array to a stripe of unit */
/* radius. */
void setbeachball(int stripes)
{
int i,j;
float x,y,z; /* vertex points */
float theta,delta_theta; /* angle from top pole to bottom*/
float offset; /* offset from center of stripe to vertex */
/* radius of cross-section at current latitude */
float cross_radius;
float cross_theta; /* angle occupied by a stripe */
beachball_stripes = stripes;
/* polys distributed by even angles from top to bottom */
delta_theta = M_PI/((float)BEACHBALL_POLYS/2.0);
theta = delta_theta;
cross_theta = 2.0*M_PI/(float)beachball_stripes;
j = 0;
stripe_point[j][0] = top[0];
stripe_point[j][1] = top[1];
stripe_point[j][2] = top[2];
j++;
for (i = 0; i < BEACHBALL_POLYS; i += 2) {
cross_radius = fsin(theta);
offset = cross_radius * ftan(cross_theta/2.0);
stripe_point[j][0] = - offset;
stripe_point[j][1] = fcos(theta);
stripe_point[j][2] = cross_radius;
j++;
stripe_point[j][0] = offset;
stripe_point[j][1] = stripe_point[j-1][1];
stripe_point[j][2] = stripe_point[j-1][2];
j++;
theta += delta_theta;
} /* end for */
stripe_point[j][0] = bottom[0];
stripe_point[j][1] = bottom[1];
stripe_point[j][2] = bottom[2];
stripe_vertices = j + 1;
beachball_initialized = TRUE;
}
/* Draws a canonical beachball. The colors are cpack values
* when in RGBmode.
*/
void beachball(unsigned long c1, unsigned long c2)
{
float angle, delta_angle;
int i, j;
if (! beachball_initialized)
setbeachball(BEACHBALL_STRIPES);
angle = 0.0;
delta_angle = 360.0/(float)beachball_stripes;
for (i = 0; i < beachball_stripes; i++) {
if ( i%2 == 0)
glColor4ubv((GLubyte *)(&c1));
else
glColor4ubv((GLubyte *)(&c2));
glPushMatrix();
glRotatef(angle, 0.0, 1.0, 0.0);
angle += delta_angle;
glBegin(GL_TRIANGLE_STRIP);
for (j = 0; j < stripe_vertices; j++)
glVertex3fv(stripe_point[j]);
glEnd();
glPopMatrix();
}
}
|