/* * This program illustrates how to generate effective and comfortable * stereoscopic images using the Silicon Graphics GL graphics library. * This program illustrates: * * Testing whether the SGI machine being used is stereo-ready * * Switching system to stereo display mode * * Setting up for full-screen stereoscopic graphics * * Stereoscopic offset projections * * Stereoscopic viewporting * * Automatic adjustment of stereoscopic separation * * Restoring system to non-stereo display mode * * This program will work on stereo-ready SGI computer systems which * normally run at 1280 x 1024 display resolution. * * The program's code is entirely contained in this file. * * To compile this program: * cc star.c -o star -lgl_s -lm */ #include #include #include #include #define YSTEREO 491 #define YOFFSET_LEFT 532 #define ROT_SPEED 6 #define MOVE_SPEED 0.04 #define MAX_DISTANCE 25.0 #define LEFT_EYE -1 #define RIGHT_EYE 1 #define PI 3.14159 /* function prototypes */ int main (void); void redraw (float distance, int rotation, float fovy_degrees, float dim_ratio); void draw_star (void); void stereoperspective (float fovy_degrees, float distance, int which_eye, float znear, float zfar, float aspect); float determine_stereo_separation (float distance, float tan_of_half_fovx); /* global variables: */ long xres, yres; int main (void) { int rotation = 0; short value, mode, monitor; long dev_id; float dim_ratio, move_speed, init_position, position; /* initialize variables */ xres = getgdesc (GD_XPMAX); yres = getgdesc (GD_YPMAX); dim_ratio = (float) xres / (float) yres; move_speed = -MOVE_SPEED; position = init_position = MAX_DISTANCE; /* open full screen window */ prefposition (0, xres, 0, yres); winopen ("Star"); /* check to see if system is stereo-ready */ if (getgdesc (GD_STEREO) == 0L) { printf ("System is not stereo-ready\n"); exit (0); } /* save original display mode and switch to stereo */ monitor = (short) getmonitor (); setmonitor (STR_RECT); /* limit cursor range to one eye's subfield */ setvaluator (MOUSEY, YSTEREO / 2, 0, YSTEREO); /* save original matrix mode */ mode = (short) getmmode (); mmode (MPROJECTION); /* allow color specification, activate doublebuffering */ RGBmode (); doublebuffer (); gconfig (); /* watch for these 'quit' events */ qdevice (ESCKEY); qdevice (WINQUIT); /* clear the screen in both buffers */ frontbuffer (TRUE); cpack (0L); clear (); frontbuffer (FALSE); /* take user input and drive image until done */ while (TRUE) { if (qtest ()) { dev_id = qread (&value); if (dev_id == ESCKEY || dev_id == WINQUIT) break; } redraw (position, rotation--, 45.0, dim_ratio); if (rotation < 0) rotation = 3600 / ROT_SPEED; position += move_speed; if (position < 7 || position > MAX_DISTANCE) move_speed = -move_speed; } /* restore to original display, cursor range, matrix mode */ setmonitor (monitor); setvaluator (MOUSEY, (short) yres / 2, 0, (short) yres); mmode (mode); exit (0); } /* end of main() */ void redraw (float distance, int rotation, float fovy_degrees, float dim_ratio) /* called by: main */ { /* draw left eye subfield */ viewport (0, xres, YOFFSET_LEFT, yres); cpack (0x00111111); clear (); stereoperspective (fovy_degrees, distance, LEFT_EYE, 6.0, -6.0, dim_ratio); rotate (rotation * ROT_SPEED, 'y'); rotate (-100, 'x'); draw_star (); /* draw right eye subfield */ viewport (0, xres, 0, YSTEREO); cpack (0x00111111); clear (); stereoperspective (fovy_degrees, distance, RIGHT_EYE, 6.0, -6.0, dim_ratio); rotate (rotation * ROT_SPEED, 'y'); rotate (-100, 'x'); draw_star (); /* display the completed stereo frame */ swapbuffers (); } /* end of redraw() */ void draw_star (void) /* called by: redraw */ { static float vertex[26][3] = { {-4.0, 0.0, 4.0}, { 4.0, 0.0, 4.0}, { 4.0, 0.0, -4.0}, {-4.0, 0.0, -4.0}, {-4.0, 4.0, 0.0}, { 4.0, 4.0, 0.0}, { 4.0, -4.0, 0.0}, {-4.0, -4.0, 0.0}, { 0.0, 4.0, 4.0}, { 0.0, 4.0, -4.0}, { 0.0, -4.0, -4.0}, { 0.0, -4.0, 4.0}, { 0.0, 0.0, 4.0}, { 4.0, 0.0, 0.0}, { 0.0, 0.0, -4.0}, {-4.0, 0.0, 0.0}, { 0.0, -4.0, 0.0}, { 0.0, 4.0, 0.0}, {-2.0, 2.0, 2.0}, {-2.0, -2.0, 2.0}, { 2.0, 2.0, 2.0}, { 2.0, -2.0, 2.0}, { 2.0, 2.0, -2.0}, { 2.0, -2.0, -2.0}, {-2.0, 2.0, -2.0}, {-2.0, -2.0, -2.0} }; cpack (0x00b030ff); bgnclosedline (); v3f (vertex[ 0]); v3f (vertex[12]); v3f (vertex[18]); v3f (vertex[17]); v3f (vertex[20]); v3f (vertex[13]); v3f (vertex[21]); v3f (vertex[ 1]); v3f (vertex[12]); v3f (vertex[19]); v3f (vertex[15]); v3f (vertex[18]); v3f (vertex[ 0]); v3f (vertex[15]); v3f (vertex[24]); v3f (vertex[17]); v3f (vertex[22]); v3f (vertex[ 2]); v3f (vertex[13]); v3f (vertex[ 1]); v3f (vertex[20]); v3f (vertex[ 5]); v3f (vertex[13]); v3f (vertex[22]); v3f (vertex[ 5]); v3f (vertex[17]); v3f (vertex[ 9]); v3f (vertex[14]); v3f (vertex[ 2]); v3f (vertex[23]); v3f (vertex[ 6]); v3f (vertex[13]); v3f (vertex[23]); v3f (vertex[16]); v3f (vertex[19]); v3f (vertex[11]); v3f (vertex[12]); v3f (vertex[20]); v3f (vertex[ 8]); v3f (vertex[12]); v3f (vertex[21]); v3f (vertex[ 6]); v3f (vertex[16]); v3f (vertex[ 7]); v3f (vertex[15]); v3f (vertex[25]); v3f (vertex[16]); v3f (vertex[21]); v3f (vertex[11]); v3f (vertex[16]); v3f (vertex[10]); v3f (vertex[14]); v3f (vertex[22]); v3f (vertex[ 9]); v3f (vertex[24]); v3f (vertex[14]); v3f (vertex[23]); v3f (vertex[10]); v3f (vertex[25]); v3f (vertex[14]); v3f (vertex[ 3]); v3f (vertex[15]); v3f (vertex[ 4]); v3f (vertex[17]); v3f (vertex[ 8]); v3f (vertex[18]); v3f (vertex[ 4]); v3f (vertex[24]); v3f (vertex[ 3]); v3f (vertex[25]); v3f (vertex[ 7]); v3f (vertex[19]); endclosedline (); } /* end of draw_star() */ void stereoperspective (float fovy_degrees, float distance, int which_eye, float znear, float zfar, float aspect) /* * This routine does a stereoscopic offset perspective projection for * one eye's view. The "center of interest" of the scene, which will be * rendered at a zero parallax setting, is assumed to be at the coordinate * system origin (0.0, 0.0, 0.0). * * Parameters: * fovy_degrees = field of view angle in vertical dimension, specified * in degrees * distance = the distance from the virtual cameras to the "center of * interest" of the scene * which_eye = LEFT_EYE or RIGHT_EYE * znear, zfar = the near and far clipping plane, relative to the * "center of interest" of the scene * aspect = the aspect ratio of the frustrum that will be set up * appropriate to the dimensions of the viewport * * called by redraw() */ { float left, right, top, bottom, clip_near, clip_far, camera_separation, eyeview, horz_tan, vert_tan, fovy_radians, perspective_offset; clip_near = distance - znear; clip_far = distance - zfar; fovy_radians = fovy_degrees * PI / 180.0; horz_tan = tanf (fovy_radians * aspect / 2.0); vert_tan = tanf (fovy_radians / 2.0); camera_separation = determine_stereo_separation (distance, horz_tan); eyeview = camera_separation / 2.0; if (which_eye == LEFT_EYE) eyeview = -eyeview; top = vert_tan * clip_near; bottom = -top; right = horz_tan * clip_near; left = -right; perspective_offset = eyeview * (clip_near / distance); right -= perspective_offset; left -= perspective_offset; window (left, right, bottom, top, clip_near, clip_far); translate (-eyeview, 0.0, -distance); } /* end of stereoperspective() */ float determine_stereo_separation (float distance, float tan_of_half_fovx) /* * This routine estimates an appropriate stereo "virtual camera" * separation. The wider angle the field of view, and/or the greater the * distance to the "center of interest" in the 3D scene, the greater the * camera separation should be for effective and comfortable stereo. * * called by stereoperspective() */ { return (distance * tan_of_half_fovx / 10.0); } /* end of determine_stereo_separation() */