/**************************************************************** * - viewing position controlled by mouse * - leftmouse: polar angles, rightmouse: distance from origin * - use z-buffering to correctly sort 3d objects * - use begin-vertex-end drawing routines * - use texture-mapping * * K. Perry, ICGL, Nov 1995 ***************************************************************/ #include #include #include #include #include #include #include #include #include #include /* GL window callbacks */ static void initCB(int window, pglCallbackInfo info); static void exposeCB(int window, pglCallbackInfo info); static void resizeCB(int window, pglCallbackInfo info); static void inputCB(int window, pglCallbackInfo info); static void menuCB(Widget w, XtPointer client, XtPointer call); /* subroutine to load an image file into memory */ static unsigned long* myImageRead(char *name, int *xsize, int *ysize); /* viewing parameters */ static float aspect = 1.0; static float radius = 500.0; static float Axy = 0.0; static float Ayz = 90.0; static float nearclip= 1.0; /* the image file to use as a texture map */ static char* imagefile = "/local/images/mandrill.sgi"; /* Coordinates of the vertices of a unit cube */ static int Cv[][3] = { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, }; /* fallback X11 resource strings, for initialization */ static String config[] = { "*pglWindow.geometry: 400x400", NULL }; /* identifiers for our display lists */ static enum { figure = 1, cube, axes } displayLists; /* identifiers for our menu items */ static enum { byebye, near1, near2 } menuValues; /* temporary variables, for motion callbacks */ static int xx; static int yy; main(int argc, char** argv) { Widget app; int winid; /* open a window */ app = pglInitialize("sample", config); winid = pglOpenWindow("My Sample Program", initCB, PGL_DOUBLE|PGL_RGBA); pglSetCallback(winid, PGL_EXPOSE, exposeCB); pglSetCallback(winid, PGL_RESIZE, resizeCB); pglSetCallback(winid, PGL_INPUT, inputCB); /* create a menu */ pglMakeMenu(winid, "Pick Something"); pglAddMenuItem(winid, "near=1", near1, menuCB); pglAddMenuItem(winid, "near=150", near2, menuCB); pglAddMenuItem(winid, "quit", byebye, menuCB); /* enter main control loop */ pglManageWindows(); pglMainLoop(); } /***********************/ /* PGL-STYLE CALLBACKS */ /***********************/ static void initCB(int window, pglCallbackInfo info) { int imagex, imagey; unsigned long* imagedata; /* build the texture map */ imagedata = myImageRead(imagefile, &imagex, &imagey); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); gluBuild2DMipmaps(GL_TEXTURE_2D, 4, imagex, imagey, GL_RGBA, GL_UNSIGNED_BYTE, imagedata); /* turn on Z-buffering, automatic re-normalization, and flat shading */ glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glShadeModel(GL_FLAT); /* The rest of this subroutine defines 3 Display Lists * (cube, figure, and axes), which hold the OpenGL * drawing commands we will use later to draw our picture */ /* define drawing commands to draw a unit cube: * 8 corners, 6 faces (right-handed) */ glNewList(cube, GL_COMPILE); glBegin(GL_QUADS); glColor3f(0, 1, 0); glNormal3f(0, -1, 0); glVertex3iv(Cv[0]); glVertex3iv(Cv[1]); glVertex3iv(Cv[5]); glVertex3iv(Cv[4]); glColor3f(0, 0, 1); glNormal3f(-1, 0, 0); glVertex3iv(Cv[0]); glVertex3iv(Cv[4]); glVertex3iv(Cv[7]); glVertex3iv(Cv[3]); glColor3f(1, 1, 0); glNormal3f(0, 1, 0); glVertex3iv(Cv[2]); glVertex3iv(Cv[3]); glVertex3iv(Cv[7]); glVertex3iv(Cv[6]); glColor3f(1, 0, 1); glNormal3f(1, 0, 0); glVertex3iv(Cv[2]); glVertex3iv(Cv[6]); glVertex3iv(Cv[5]); glVertex3iv(Cv[1]); glEnd(); /* These are the default filter & wrap values. * Un-comment and change the values, if you want different behavior * * * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); */ glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(1, 1, 1); glBegin(GL_QUADS); glNormal3f(0, 0, -1); glTexCoord2s(0, 0); glVertex3iv(Cv[0]); glTexCoord2s(0, 1); glVertex3iv(Cv[3]); glTexCoord2s(1, 1); glVertex3iv(Cv[2]); glTexCoord2s(1, 0); glVertex3iv(Cv[1]); glNormal3f(0, 0, 1); glTexCoord2s(0, 0); glVertex3iv(Cv[4]); glTexCoord2s(1, 0); glVertex3iv(Cv[5]); glTexCoord2s(1, 1); glVertex3iv(Cv[6]); glTexCoord2s(0, 1); glVertex3iv(Cv[7]); glEnd(); glDisable(GL_TEXTURE_2D); glEndList(); /* define drawing commands to draw our scene: * three cubes variously transformed */ glNewList(figure, GL_COMPILE); glPushMatrix(); /* cube centered at origin, scaled */ glScalef(100, 100, 100); glCallList(cube); glPopMatrix(); glPushMatrix(); /* cube translated, scaled, intersects first */ glTranslatef(100, 100, 100); glScalef(50, 50, 50); glRotatef(90, 0, 1, 0); glRotatef(90, 0, 0, 1); glTranslatef(-.5, -.5, -.5); glCallList(cube); glPopMatrix(); glPushMatrix(); /* another cube, distorted */ glTranslatef(-50.0, -150.0, -70.0); glScalef(30.0, 20.0, 50.0); glRotatef(30, 1, 0, 0); glCallList(cube); glPopMatrix(); glEndList(); /* define drawing commands to draw axes at the point of rotation */ glNewList(axes, GL_COMPILE); glBegin(GL_LINES); /* 3 axial lines, differently colored */ glColor3f(1, 0, 0); glVertex3i(0, 0, 0); glVertex3i(150, 0, 0); glColor3f(0, 1, 0); glVertex3i(0, 0, 0); glVertex3i(0, 150, 0); glColor3f(0, 0, 1); glVertex3i(0, 0, 0); glVertex3i(0, 0, 150); glEnd(); glEndList(); /* initialize the projection matrix, and draw the picture */ resizeCB(window, info); } static void exposeCB(int window, pglCallbackInfo info) { /* clear background to black; clear Z-buffer */ glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT); /* set up the viewing matrix */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0, 0, -radius); glRotatef(0, 0, 0, 1); glRotatef(-Ayz, 1, 0, 0); glRotatef(-Axy, 0, 0, 1); /* draw the coordinate axes by calling our * previously stored Display List */ glDisable(GL_LIGHTING); glCallList(axes); /* turn on lighting, then draw the scene by calling our * other previously stored Display List. */ glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glColorMaterial(GL_FRONT, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glCallList(figure); /* swap buffers */ pglSwapBuffers(window); } static void resizeCB(int window, pglCallbackInfo info) { /* resize, reshape */ aspect = info->width/(float)info->height; glViewport(0, 0, info->width, info->height); /* re-load the projection matrix, * in case aspect or nearclip have changed */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, nearclip, 750); /* re-draw the picture */ exposeCB(window, info); } static void inputCB(int window, pglCallbackInfo info) { XButtonEvent bev = info->event->xbutton; XMotionEvent mev = info->event->xmotion; static int which = -1; /* decide what type of event we got */ switch ( bev.type ) { case ButtonPress: /* mouse button pressed */ /* (note: RIGHTMOUSE pops up the menu, instead of calling inputCB() * so we don't have to worry about RIGHTMOUSE here */ which = bev.button; /* possible values: Button1, Button2, Button3 */ xx = bev.x; yy = bev.y; break; case MotionNotify: /* mouse motion */ switch ( which ) { case Button1: /* update the viewer's orientation */ Axy -= (mev.x - xx); Ayz += (mev.y - yy); xx = mev.x; yy = mev.y; break; case Button2: /* update the viewer's distance from the origin */ radius += (mev.y - yy); yy = mev.y; break; default: return; } break; /* some other possible event types you can check for */ case ButtonRelease: /* mouse button released */ case KeyPress: /* keyboard key pressed */ case KeyRelease: /* keyboard key released */ case EnterNotify: /* mouse entered window */ case LeaveNotify: /* mouse left window */ case FocusIn: /* application obtained keyboard focus */ case FocusOut: /* application lost keyboard focus */ default: return; } /* re-draw the picture */ exposeCB(window, info); } /***********************/ /* X11-STYLE CALLBACKS */ /***********************/ /* callback for GL window's popup menu */ static void menuCB(Widget w, XtPointer client, XtPointer call) { /* perform user-requested updates */ switch ( (int)client ) { case near1: nearclip = 1.0; break; case near2: nearclip = 150.0; break; case byebye: exit(0); } /* fix the projection matrix, in case nearclip has changed */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, nearclip, 750); } unsigned long * myImageRead(char *name, int *xsize, int *ysize) { unsigned long* image; unsigned long pixel; IMAGE* imgfile; int x,y,z; short* rbuf; short* gbuf; short* bbuf; short* abuf; static unsigned long dummy = 0xffffffff; imgfile = iopen(name, "r"); if ( imgfile == NULL ) { fprintf(stderr, "iopen: can't open input file: %s\n", name); *xsize = *ysize = 1; return(&dummy); } *xsize = imgfile->xsize; *ysize = imgfile->ysize; z = imgfile->zsize; /* Create memory for the packed image array */ image = (unsigned long *)malloc((*xsize)*(*ysize)*sizeof(unsigned long)); if ( image == NULL ) { fprintf(stderr,"malloc: trouble allocating space for image.\n"); *xsize = *ysize = 1; return(&dummy); } rbuf = (short*)malloc((*xsize)*sizeof(short)); gbuf = (short*)malloc((*xsize)*sizeof(short)); bbuf = (short*)malloc((*xsize)*sizeof(short)); abuf = (short*)malloc((*xsize)*sizeof(short)); for ( y = 0; y < *ysize; y++ ) { switch ( z ) { case 4: getrow(imgfile, abuf, y, 3); case 3: getrow(imgfile, bbuf, y, 2); case 2: getrow(imgfile, gbuf, y, 1); case 1: getrow(imgfile, rbuf, y, 0); break; default: fprintf(stderr, "myImageRead: unsupported image type; z=%d\n", z); break; } for ( x = 0; x < *xsize; x++ ) { /* Create unsigned long packed RGBA values, no matter what we read */ switch ( z ) { case 1: pixel = ((rbuf[x]&0xff)<<24) | ((rbuf[x]&0xff)<<16) | ((rbuf[x]&0xff)<<8) | 0xff; break; case 2: pixel = ((rbuf[x]&0xff)<<24) | ((rbuf[x]&0xff)<<16) | ((rbuf[x]&0xff)<<8) | (gbuf[x]&0xff); break; case 3: pixel = ((rbuf[x]&0xff)<<24) | ((gbuf[x]&0xff)<<16) | ((bbuf[x]&0xff)<<8) | 0xff; break; case 4: pixel = ((rbuf[x]&0xff)<<24) | ((gbuf[x]&0xff)<<16) | ((bbuf[x]&0xff)<<8) | (abuf[x]&0xff); break; } image[(y*(*xsize))+x] = pixel; } } iclose(imgfile); free(rbuf); free(gbuf); free(bbuf); free(abuf); return(image); }