This is the text version of the PDF file http://www.stereographics.com/support/developers/ce_sdk.pdf G o o g l e automatically generates text versions of PDF documents as we crawl the web.

Google is not affiliated with the authors of this page nor responsible for its content.

CrystalEyes TM Software Development Kit
            A StereoGraphics ® Product
                          Updated: December 1, 1997



THE INFORMATION IN THIS MANUAL IS SUBJECT TO CHANGE WITHOUT NOTICE AND IS DISTRIBUTED ON AN
"AS IS" BASIS, WITHOUT WARRANTY. WHILE EVERY PRECAUTION HAS BEEN TAKEN IN THE PREPARATION
OF THIS MANUAL, NEITHER THE AUTHORS NOR STEREOGRAPHICS CORPORATION SHALL HAVE ANY
LIABILITY, LOSS, OR DAMAGE CAUSED OR ALLEGED TO BE CAUSED DIRECTLY OR INDIRECTLY BY THE
INFORMATION CONTAINED HEREIN.


Acknowledgments

StereoGraphics would like to acknowledge the following people for their contributions to this document: Harvey Ziegler and
John Stevens at Hewlett-Packard, Michael Adams at Digital Equipment Corporation, Craig Winter and Maggie Bourget at
EDS Unigraphics, John Schimpf at Silicon Graphics, Dave Milici and Lenny Lipton at StereoGraphics, Bob Akka at Chasm
Graphics, Andy Woolf and Carsten R. at Diamond Multimedia Systems, and Geoff Hennessey at PCI Incorporated.


Copyright Notice

This manual is copyrighted by StereoGraphics Corporation. Copyright © 1997 StereoGraphics Corporation. All rights
reserved. Printed in the United States of America.


Limited Warranty

THIS DOCUMENT AND ASSOCIATED PROGRAMS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND
EITHER EXPRESSED OR IMPLIED. THE ENTIRE RISK AS TO THE RESULTS AND PERFORMANCE OF THE
SOFTWARE IS ASSUMED BY YOU. STEREOGRAPHICS DOES NOT WARRANT THAT THE FUNCTION OF THE
SOFTWARE WILL MEET WITH YOUR REQUIREMENTS OR THAT THE SOFTWARE WILL FUNCTION
UNINTERRUPTED AND ERROR FREE.

StereoGraphics is a registered trademark of StereoGraphics Corporation; CrystaEyes is a trademark of StereoGraphics
Corporation. All product and brand names mentioned in this document are trademarks or registered trademarks of their
respective holders.







                                               StereoGraphics Corporation
                                             2171 East Francisco Boulevard
                                                      San Rafael, CA 94901
                                                         (415) 459-4500

                                             Email: develop@crystaleye.com
                                              Web: www.stereographics.com

                        Soft copies of this document are available on the accompanying disk
                            (non web/ftp site version), or via the StereoGraphics web site

                                 Updated versions of this document are available at:
                                               www.  stereographics.com





  StereoGraphics CrystalEyes Software Development Kit                                                              Page 2



                                     CrystalEyes Software Development Kit
                                                                 Table of Contents

    TABLE OF CONTENTS - CRYSTALEYES SOFTWARE DEVELOPMENT KIT                          3

    PREFACE - STEREOSCOPIC DISPLAY SUPPORT IN OPEN GL                                 5

    CHAPTER 1                                                                         7

       SGI GL Development                                                             7
         Introduction                                                                 7
         Checking Stereoscopic Hardware                                               8
         Four Different SGI Modes                                                     9
         Switching To and From Stereo Display Mode                                10
         Opening a Window for Stereoscopic Display                                12
         Stereoscopic Viewporting and Buffering                                   13
         Stereoscopic Projections                                                 15
         Cursor and Interface Issues                                              17
         Sample GL Application                                                    18

    CHAPTER 2                                                                    23

       SGI OpenGL Development                                                     23
         Stereo Support Under OpenGL                                              23
         Sample OpenGL Application                                                24

    CHAPTER 3                                                                    33

       SUN XGL Development                                                        33
         Introduction                                                             33
         Checking Stereoscopic Hardware                                           34
         Configuring the Frame Buffer for Stereo Display Mode                     35
         Rendering the Left and Right Eyes                                        36
         Two Dimensional Rendering                                                37
         Stereoscopic Projections                                                 38
         Sample XGL Application                                                   39

    CHAPTER 4                                                                    49

       DEC OpenGL Development                                                     49
         Introduction                                                             49
         Stereo Support                                                           50
         Enabling Stereo from an Application                                      51
         Supported Screen Resolutions and Refresh Rates                           52
         Supported Hardware                                                       56
         Supported Visuals                                                        57
         Backing Store                                                            58



       DEC OpenGL Development (cont.)
  StereoGraphics CrystalEyes Software Development Kit                         Page 3



         Performance                                                                                        59
         Left and Right Construction Planes                                                                 60
         Sample OpenGL Application                                                                          61

     CHAPTER 5                                                                                             65

       PC Development                                                                                       65
         Introduction                                                                                       65
         Sample Windows NT OpenGL Application                                                               66
         OpenGL Stereo Quad Buffering Under Windows NT                                                      69
         Sample OpenGL Application for Diamond Multimedia Systems' FireGL 4000 Graphics Board               71
         Creating Stereoscopic Renderings Using Kinetix 3D Studio Products and Autodesk Animator Pro        74

     CHAPTER 6                                                                                             81

       HP Open GL Development                                                                               81
         Introduction                                                                                       81
         Supported Graphics Cards                                                                           82
         Supported Monitors                                                                                 83
         Enabling Stereo Support                                                                            84



































  StereoGraphics CrystalEyes Software Development Kit                                                   Page 4



                                                                                              Preface
                                            Stereoscopic Display Support in Open GL

     With the release of OpenGL version 1.1 specification, stereoscopic display support is readily
     programmable through APIs common to all graphics workstations. The same OpenGL APIs which support
     double buffering for real-time 3D rendering also support stereo quad buffering on stereo-ready systems.
     Identification of stereo-capable display modes is queried via glGetBooleanv() with GL_STEREO
     parameter.

     Whereas double buffering assigns a visible front buffer and a non-visible back buffer, stereo quad
     buffering additionally assigns left and right buffer components. Instead of referring to the double buffers
     as GL_FRONT and GL_BACK, the stereo buffers are individually identified as GL_FRONT_LEFT and
     GL_FRONT_RIGHT, GL_BACK_LEFT, and GL_BACK_RIGHT.  The underlying graphics hardware
     automatically alternates between the left and right front buffer displays. Typically the programmer selects
     only the left and right back buffers for drawing with glDrawBuffer(), and then updates the complete stereo
     pair with a system swap function, such as glXSwapBuffers() or glutSwapBuffers().

     While OpenGL specifies system-independent functions for primitive 3D rendering operations, system-
     specific functions like setting the display modes are deferred into separate libraries, like GLX for X-
     Windows, or GLUT for any compatible system. In GLX, a stereo display mode is requested by adding
     GLX_STEREO flag for glXChooseVisual(), which is then enabled by subsequent calls to
     glXCreateContext() and glXMakeCurrent(). In GLUT, the equivalent sequence of calls is handled by
     passing GLUT_STEREO flag to glutInitDisplayMode().

     Under Microsoft Windows NT/9x, an equivalent set of WIN32 system APIs are available as counterparts
     to the GLX APIs: ChoosePixelFormat(), wglCreateContext(), and wglMakeCurrent(). A stereo display
     mode is requested by adding the PFD_STEREO flag to the OpenGL-specified Pixel Format Descriptor
     used in ChoosePixelFormat(). OpenGL graphics boards with mini client drivers for intercepting OpenGL
     calls with hardware support will be able to enable GL_STEREO quad buffering modes in the same
     manner.

     For further information about OpenGL, the following reference textbooks are currently available from the
     OpenGL Architecture Review Board, published by Addison Wesley.

     * OpenGL Reference Manual, by the OpenGL Architecture Review Board, Renate Kempf and Chris
         Frazier, Editors.

     * OpenGL Programming Guide, by Jackie Neider, Tom Davis, and Mason Woo.

     * OpenGL Programming for the X-Windows System, by Mark J. Kilgard.

     For information about OpenGL on Microsoft Windows NT/9x, refer to the WIN32 SDK included with all
     commercial C compilers supporting MS Windows platforms, and the OpenGL SDK available from the
     Microsoft Developer Network, MSDN.




  StereoGraphics CrystalEyes Software Development Kit                                                           Page 5



  StereoGraphics CrystalEyes Software Development Kit    Page 6



                                                                                         Chapter 1
                                                                                                   SGI GL

     1.  Introduction
     Nearly all SGI hardware systems built in the last five years (including all systems currently being shipped)
     include built-in support for StereoGraphics CrystalEyes  compatible stereoscopy, the most notable
     exceptions being some of the early Indigo models that operate at resolutions lower than 1280 x 1024.
     Furthermore, such stereo-ready Silicon Graphics computer systems have also been shipped with monitors
     that are designed to handle the higher vertical frequency that CrystalEyes requires.  This nearly universal
     support for stereoscopic graphics makes SGI a very attractive platform for developing stereoscopic
     applications.

     This document discusses methods for developing stereoscopic software on SGI systems using GL,
     including:

               *  How to check whether the hardware supports stereo
               *  Converting to and from stereo display mode
               *  Opening a window for stereoscopic display
               *  Viewporting for left and right eyes
               *  Stereoscopic perspective projections
               *  Interface issues
               *  Sample GL Application

     Many of the concepts discussed in this document are illustrated in a short example program, whose source
     code should accompany this document.



















  StereoGraphics CrystalEyes Software Development Kit                                                      Page 7



     2.  Checking Stereoscopic Hardware
     This section discusses how an application ought to check the stereoscopic compatibility of a user's
     computer system.  If you would like to test your own computer's stereo compatibility, attempt to switch in
     and out of stereo mode using setmon (see section 4); if the system is not stereo-ready, you will most
     likely see no change.

     Nearly all SGI computers that are currently in use include system support for stereoscopic display.  Some
     older models, and a few lower priced recent models, do not support stereo.  Application software should
     check whether the system is stereo-ready before attempting to display stereoscopic graphics.  Here's how:

               testval = (int) getgdesc (GD_STEREO);

     If the return value equals 1 (TRUE ), then the computer system is stereo-ready.  If the return value equals 0
     (FALSE ), then it is not stereo-ready, and your application should not attempt to switch to a stereoscopic
     display mode.

     Certain high-end SGI computer systems (some Crimson, VTX, Onyx models) include support for
     windowed square-pixel stereoscopy.  To check whether this higher level of stereo support is available, use:

               testval = (int) getgdesc (GD_STEREO_IN_WINDOW);

























  StereoGraphics CrystalEyes Software Development Kit                                                       Page 8



     3.  Four Different SGI Stereo Modes
     SGI has not one, but four different stereoscopic display modes.  Three of these are available on most SGI
     computer systems, and all four are available on certain high-end models.

     STR_RECT:
     The most common SGI stereo mode is the one that has been available the longest, STR_RECT.  In this
     stereo mode, the vertical sync rate of the monitor is doubled from its normal display rate, and:

       *  Everything that is drawn to the top half (actually, the upper 492 out of 1024 pixel rows, a little less
             than half) of the normal display will appear to fill the screen for the left eye only.
       *  Everything that is drawn to the bottom half (actually, the lower 492 out of 1024 pixel rows) of the
             normal display will appear to fill the screen for the right eye only.
       *  The middle 40 pixel rows disappear into the display blanking interval.

     STR_TOP:
     This newer stereo mode allows stereoscopic windowing.  In this stereo mode:

       *  Everything that is drawn to the top half (the upper 492 out of 1024 pixel rows) of the normal display
             will appear to fill the screen for both eyes, unless the contents of windows have been programmed
             to have both left- and right-eye buffers, in which case the left- and right-eye buffers will each be
             displayed to the appropriate eye.

     Programming for STR_TOP display mode requires using SGI extensions to OpenGL.

     STR_BOT:
     This stereo mode is just like STR_TOP, except that the bottom half (492 pixel rows) of the normal
     display, rather than the top half, fill the screen for both eyes.

     Programming for STR_BOT display mode requires using SGI extensions to OpenGL.

     Square-pixel stereo:
     Some high-end SGI models (those for which getgdesc (GD_STEREO_IN_WINDOW) returns TRUE)
     offer a fully double-buffered stereo windowing mode, though at somewhat lower than normal stereoscopic
     resolution.












  StereoGraphics CrystalEyes Software Development Kit                                                         Page 9



     4.  Switching To and From Stereo Display Mode
     Switching to and from stereoscopic display mode may be done by the application, or by the user from the
     command line.

     To manually switch to stereo mode, type one of the following at the command line (see the above section
     about the difference between these stereo modes):

                 /usr/gfx/setmon STR_RECT
                 /usr/gfx/setmon STR_TOP
                 /usr/gfx/setmon STR_BOT

     Before doing this, be sure that you will have a convenient command prompt to switch back out of stereo
     mode.  For example, if switching to STR_TOP stereo mode, make sure that you will have a command
     prompt available on the top half of the display.

     You would also use /usr/gfx/setmon to manually switch to square-pixel stereo, on those SGI models
     that support it.  Consult SGI documentation, including man setmon and man stereo, for further
     details.

     To manually switch out of stereo mode, type one of the following at the command line:

                 /usr/gfx/setmon 60HZ
                 /usr/gfx/setmon 72HZ

     If you are not sure whether your system normally uses a 72 Hz vertical frequency, use 60HZ.


     It is generally far more elegant for your application to switch to and from stereo mode on its own, without
     requiring the user to shell out and use setmon.  To switch display modes using GL, simply use the
     setmonitor() function:

                 setmonitor (STR_RECT);
                 setmonitor (STR_TOP);
                 setmonitor (STR_BOT);

     setmonitor() does not work for switching to square-pixel stereo.  For systems that support square-
     pixel stereo, your code can call /usr/gfx/setmon using the system() function.

     Before switching to stereo mode using setmonitor(), use getmonitor() to find out the previous
     monitor mode:

                 prev_monitor = (short) getmonitor ();

     To switch out of stereo mode, simply setmonitor() to the previous monitor mode:

                 setmonitor (prev_monitor);

  StereoGraphics CrystalEyes Software Development Kit                                                    Page 10



     If the previous mode is unknown, or to switch to normal monoscopic display mode regardless of the
     previous mode, use:

               setmonitor (HZ60);

     Note again that GL does not provide programming support for STR_TOP or STR_BOT stereo display
     modes.  Programming for these display mode requires using SGI extensions to OpenGL.







































  StereoGraphics CrystalEyes Software Development Kit                                                Page 11



     5.  Opening a Window for Stereoscopic Display
     You may create a window for doing stereo using the same methods that you normally do.  The differences
     that are specific to stereo are:

       *  STR_RECT display mode:  The display window needs to be full-screen, since anything else on the
             display will not view properly while the display is in this mode.
       *  STR_TOP display mode:  The display window should either fill or be entirely contained within the
             upper half (492 pixel rows) of the normal display, since the remainder of the normal display does
             not appear in stereo mode.  Stereo buffering requires SGI extensions to OpenGL.
       *  STR_BOT display mode:  The display window should either fill or be entirely contained within the
             lower half (492 pixel rows) of the normal display. Stereo buffering requires SGI extensions to
             OpenGL.
       * Square-pixel stereo  display mode (if supported):  No restrictions compared to non-stereo display.

     To set up a full-screen display window that does not have window borders, using GL:

               prefposition (0, getgdesc (GD_XPMAX), 0, getgdesc (GD_YPMAX));
               winopen ("");



























  StereoGraphics CrystalEyes Software Development Kit                                                   Page 12



     6.  Stereoscopic Viewporting and Buffering
     STR_RECT stereo mode:

     In the STR_RECT stereo mode, the program should have a full-screen application window (see the section
     above).  The left-eye viewport should then be placed at the top half (the upper 492 out of 1024 pixel rows,
     which is slightly less than half) of the normal display, and the right-eye viewport should be placed at the
     bottom half (the lower 492 out of 1024 pixel rows) of the normal display.  GL's viewport() function
     enables this.  Assuming a full-screen application window, the following specifies a viewport for the left-
     eye view:

               viewport (0, 1279, 532, 1023);

     and the following specifies a viewport for the right-eye view:

               viewport (0, 1279, 0, 491);


     STR_TOP and  STR_BOT stereo modes:

     GL's stereo buffering functions do not work with STR_TOP or STR_BOT stereo modes.  Buffering for
     these stereo modes requires SGI extensions to OpenGL.


     Square-pixel stereo:

     GL provides stereoscopic buffering functions that work with the square-pixel stereo mode that is
     supported by certain high-end SGI computer systems.  These stereo buffering functions work similarly to
     (and can be used together with) GL's double-buffering functions which enable smooth graphics animation.

     To initialize stereoscopic buffering for an existing graphics window, use the GL function
     stereobuffer().  Like the commonly used doublebuffer() function, this will not take effect
     until gconfig() is called:

               stereobuffer ();
               gconfig ();

     To disable stereo buffering in a graphics window, call monobuffer() followed by gconfig().

     Use GL's leftbuffer() and rightbuffer() functions to draw to the left-eye and/or the right-eye
     buffer.  To draw to the left-eye buffer only (this is the initial default):

               leftbuffer (TRUE);
               rightbuffer (FALSE);




  StereoGraphics CrystalEyes Software Development Kit                                                      Page 13



     To draw to the right-eye buffer only:

               leftbuffer (FALSE);
               rightbuffer (TRUE);

     To draw to both eye's buffers at the same time:

               leftbuffer (TRUE);
               rightbuffer (TRUE);





































  StereoGraphics CrystalEyes Software Development Kit    Page 14



     7.  Stereoscopic Projections

     To produce stereoscopic graphics that both appear natural and are mathematically correct, render your
     stereo pairs using two asymmetrical-frustum perspective (also called offset perspective) projections whose
     projection axes are parallel to each other.

     This involves projecting from two slightly different viewpoints in the scene.  Naturally, the left eye's
     viewpoint should be offset somewhat to the left of the right eye's viewpoint.  Since GL's perspective
     projection functions are based on the center of projection (the viewpoint) residing at the coordinate origin,
     this viewpoint offset is simulated by translating the scene elements in the opposite direction. Thus, you
     want to translate the scene to the right for the left-eye projection, and to the left for the right-eye
     projection.  This pre-projection translation is accomplished by using GL's translate() function just
     after the function that performs the perspective projection.

     How much separation should there be between the stereoscopic viewpoints?  For stereoscopic graphics
     that are both compelling and comfortable, it is important to have enough stereoscopic interaxial
     separation, but not too much.  Generally, you want to have negative parallax (projected display offset that
     causes something to appear to pop out of the screen) ranging from 0%  to 3%  of the width of the display
     window, and you want to have positive parallax (projected display offset that causes something to appear
     to sink into the screen) ranging from 0%  to 3%  of the width of the display window.  This can usually be
     achieved using a moderately wide angle field of view, and a camera separation that is about 5%  of the
     distance from the viewpoints to the center of interest in the scene being rendered.  Consult other
     StereoGraphics documentation for more information about stereoscopic aesthetic issues.

     It is extremely important to use asymmetrical-frustum projections for generating stereo pairs.  If you use
     parallel perspective projections without asymmetrical frustums, the result will be uncomfortable graphics
     that reside entirely in negative parallax viewing space (everything coming out of the screen).  GL provides
     two functions for implementing perspective projections, perspective() and window().  Of these,
     only window() permits asymmetrical-frustum projections (you may also implement projections by
     defining transformation matrices; see other StereoGraphics documentation for more about the appropriate
     transformation matrices for stereoscopic asymmetrical-frustum projections).

     The frustum of the left-eye perspective projection should take in a slightly wider angle to the right of its
     projection axis than to the left of it, and the frustum of the right-eye projection should take in a slightly
     wider angle to the left of its projection axis than to the right.  Scene elements that reside in plane at which
     the two frustums intersect will be rendered at zero parallax.  Scene elements at zero parallax will appear to
     reside at the display surface, neither popping out of the screen nor sinking into it.  Ideally, scene elements
     close to the center of interest in the scene should be rendered at or near zero parallax.

     Putting all of the above, the viewpoint translation and the asymmetrical-frustum projection, into GL code:







  StereoGraphics CrystalEyes Software Development Kit                                                           Page 15



     Left eye view:
       window (-top * aspect + (half_sep * clip_near / distance), top *
               aspect + (half_sep * clip_near / distance), -top, top, clip_near,
               clip_far);
       translate (half_sep, 0.0, 0.0);

     Right eye view:
       window (-top * aspect - (half_sep * clip_near / distance), top *
               aspect - (half_sep * clip_near / distance), -top, top, clip_near,
               clip_far);
       translate (-half_sep, 0.0, 0.0);

     Where:
       top = half of the vertical frustum dimension as measured at the frustum's intersection with the near
               clipping plane
       aspect = the ratio between overall display width and overall display height (full-screen STR_RECT
               stereo), or the ratio between window width and window height (square pixel stereo)
       half_sep = half of the interaxial separation
       clip_near = the distance from the viewpoint to the near clipping plane
       distance = the distance from the viewpoint to the center of interest in the scene
       clip_far = the distance from the viewpoint to the far clipping plane


     Note that, except with square-pixel stereo, stereo projections should be rendered at a vertically squashed
     aspect ratio of about 0.48 (=1024 / 492), since the stereo display mode expands the display vertically by
     about a factor of two.  The code examples above have already taken aspect ratio into consideration.

     Many stereoscopic implementations use a rotation method instead of parallel asymmetrical-frustum
     projections.  With the rotation method, the two viewpoints are offset as they are above.  However, rather
     than using two asymmetrical-frustum projections with parallel projection axes, standard (symmetrical-
     frustum) projections are done, with projection axes that are angled inward.  Typically, the projection axes
     intersect at or near the center of interest in the scene.  The rotation method has the advantage of being
     easier for most people to conceptualize.  In addition, the rotation method is able to render into both
     positive and negative parallax, without requiring an asymmetrical-frustum projection.  However,
     compared to the methods described in this section, the rotation method has two significant disadvantages:
     It is not mathematically correct, and the results will not look as good.   The rotation method introduces
     distortion and vertical misalignment. As SGI software libraries and hardware acceleration fully support
     asymmetrical-frustum perspective projections, there is no good reason to use the rotation method .












  StereoGraphics CrystalEyes Software Development Kit                                                          Page 16



     8.  Cursor and Interface Issues
     When using the STR_RECT stereoscopic display mode, it is a good idea to limit the cursor to one eye's
     viewport of the display.  For reasons having to do with pop-up menus, it is generally best to lock the
     cursor in the right-eye viewport:

               setvaluator (MOUSEY, 492 / 2, 0, 492);

     To restore the cursor range:

               setvaluator (MOUSEY, 1024 / 2, 0, 1024);


     With STR_RECT stereo mode, menus, buttons, dialog boxes, scroll bars, text, and anything else that you
     wish to appear for both eyes, must be separately drawn to both eyes' viewports. All such interface
     elements will appear vertically stretched compared to how they are drawn, due to the aspect ratio
     difference between the viewport and the display.





























  StereoGraphics CrystalEyes Software Development Kit                                                      Page 17



     9.  Sample GL Application

     *       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 <gl.h>
     #include <device.h>
     #include <get.h>
     #include <math.h>

     #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;

  StereoGraphics CrystalEyes Software Development Kit                               Page 18



                /* 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   */
     {

  StereoGraphics CrystalEyes Software Development Kit                           Page 19



                /* 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() */
  StereoGraphics CrystalEyes Software Development Kit                             Page 20



     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() */

  StereoGraphics CrystalEyes Software Development Kit                                Page 21



                                                                                              Chapter 2
                                                                                               SGI OpenGL


     1.  Stereo Support Under OpenGL
     Writing stereoscopic applications for SGI using OpenGL requires using functions in an SGI extension to
     OpenGL.  These special OpenGL extension functions can be used to develop stereoscopic applications that
     are windowed using the STR_TOP or STR_BOT stereoscopic display modes. The SGI OpenGL extension
     functions allow you to check whether the display hardware is stereo-ready, switch in and out of
     stereoscopic display mode, and draw to either or both of the two eyes' buffers.  Detailed information
     relating to the SGI OpenGL extensions is beyond the scope of this document.

     Asymmetrical-frustum perspective projections may be done in OpenGL using the standard OpenGL
     functions glFrustum() and glTranslate(), instead of the similar GL functions window() and
     translate().

     OpenGL supports stereo via quad buffering. The programmer needs to choose a visual that supports
     stereo. Then they draw to the left front/back buffer (you designate left buffer using glDrawBuffer and
     then set the xform appropriately before drawing the left-eye view) and to the right front/back buffer. If
     drawing to back buffers then glXSwapBuffers must be called after rendering.

     In RealityEngine and InfiniteReality, stereo is supported in a window, so the programmer can simply
     find a visual that supports stereo and then create a window with that visual. On Impact you need to call
     setmon in order to put the gfx in a state where it can support stereo. (If you don't call setmon then you
     won't be able to find any visuals that support stereo). On EXPRESS machines (XZ, EXTREME, XL,
     Elan) you need to call setmon and then restart the X server.

















  StereoGraphics CrystalEyes Software Development Kit                                                      Page 22



     2.  Sample OpenGL Application
     /*
     ** A simple OpenGL stereo application.  Uses the GLw Motif DrawingArea
     ** widget with a popup menu.  Includes a simple API for controlling
     ** stereo.
     **
     ** cc -o glwstereo glwstereo.c -lGLw -lXm -lXt -lGL -lXext -lX11 -lm
     */
     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include <math.h>
     #include <sys/time.h>
     #include <X11/Xlib.h>
     #include <X11/Xutil.h>
     #include <X11/StringDefs.h>
     #include <Xm/Xm.h>
     #include <Xm/Form.h>
     #include <Xm/RowColumn.h>
     #include <Xm/PushBG.h>
     #include <Xm/SeparatoG.h>
     #include <X11/GLw/GLwMDrawA.h>

     /********************************************************************/

     #include <X11/extensions/SGIStereo.h>

     static struct stereoStateRec {
         Bool        useSGIStereo;
         Display     *currentDisplay;
         Window      currentWindow;
         GLXContext  currentContext;
         GLenum      currentDrawBuffer;
         int         currentStereoBuffer;
         Bool        enabled;
         char        *stereoCommand;
         char        *restoreCommand;
     } stereo;

     /* call instead of glDrawBuffer */
     void
     stereoDrawBuffer(GLenum mode)
     {    if (stereo.useSGIStereo) {
             stereo.currentDrawBuffer = mode;
             switch (mode) {
               case GL_FRONT:
               case GL_BACK:
               case GL_FRONT_AND_BACK:
                 /*
                 ** Simultaneous drawing to both left and right                              **
       buffers isn't really possible if we don't have a                       ** stereo
     capable visual. For now just fall through                        and use the left buffer.
                 */
               case GL_LEFT:
               case GL_FRONT_LEFT:
               case GL_BACK_LEFT:
                 stereo.currentStereoBuffer = STEREO_BUFFER_LEFT;
                 break;
               case GL_RIGHT:
               case GL_FRONT_RIGHT:
                 stereo.currentStereoBuffer = STEREO_BUFFER_RIGHT;
                 mode = GL_FRONT;
  StereoGraphics CrystalEyes Software Development Kit                                      Page 23



                 break;
               case GL_BACK_RIGHT:
                 stereo.currentStereoBuffer = STEREO_BUFFER_RIGHT;
                 mode = GL_BACK;
                 break;
               default:
                 break;
             }
             if (stereo.currentDisplay && stereo.currentWindow) {
                 glXWaitGL();  /* sync with GL command stream before calling X */
                 XSGISetStereoBuffer(stereo.currentDisplay,
                                     stereo.currentWindow,
                                     stereo.currentStereoBuffer);
                 glXWaitX();   /* sync with X command stream before calling GL */
             }
         }
         glDrawBuffer(mode);
     }

     /* call instead of glClear */
     void
     stereoClear(GLbitfield mask)
     {    if (stereo.useSGIStereo) {
             GLenum drawBuffer = stereo.currentDrawBuffer;
             switch (drawBuffer) {
               case GL_FRONT:
                 stereoDrawBuffer(GL_FRONT_RIGHT);
                 glClear(mask);
                 stereoDrawBuffer(drawBuffer);
                 break;
               case GL_BACK:
                 stereoDrawBuffer(GL_BACK_RIGHT);
                 glClear(mask);
                 stereoDrawBuffer(drawBuffer);
                 break;
               case GL_FRONT_AND_BACK:
                 stereoDrawBuffer(GL_RIGHT);
                 glClear(mask);
                 stereoDrawBuffer(drawBuffer);
                 break;
               case GL_LEFT:
               case GL_FRONT_LEFT:
               case GL_BACK_LEFT:
               case GL_RIGHT:
               case GL_FRONT_RIGHT:
               case GL_BACK_RIGHT:
               default:
                 break;
             }
         }
         glClear(mask);
     }

     /* call after glXMakeCurrent */
     void
     stereoMakeCurrent(Display *dpy, Window win, GLXContext ctx)
     {    if (stereo.useSGIStereo) {
             if (dpy && (dpy != stereo.currentDisplay)) {
                 int event, error;
                 /* Make sure new Display supports SGIStereo */
                 if (XSGIStereoQueryExtension(dpy, &event, &error) == False)
     {                dpy = NULL;
                 }
             }
  StereoGraphics CrystalEyes Software Development Kit                                Page 24



             if (dpy && win && (win != stereo.currentWindow)) {
                 /* Make sure new Window supports SGIStereo */
                 if (XSGIQueryStereoMode(dpy, win) == X_STEREO_UNSUPPORTED) {
                     win = None;
                 }
             }
             if (ctx && (ctx != stereo.currentContext)) {
                 GLint drawBuffer;
                 glGetIntegerv(GL_DRAW_BUFFER, &drawBuffer);
                 stereoDrawBuffer((GLenum) drawBuffer);
             }
             stereo.currentDisplay = dpy;
             stereo.currentWindow = win;
             stereo.currentContext = ctx;
         }
     }

     /* call to turn on stereo viewing */
     void
     stereoEnable(void)
     {    if (!stereo.enabled && stereo.stereoCommand) {
             system(stereo.stereoCommand);
         }
         stereo.enabled = True;
     }

     /* call to turn off stereo viewing */
     void
     stereoDisable(void)
     {    if (stereo.enabled && stereo.restoreCommand) {
             system(stereo.restoreCommand);
         }
         stereo.enabled = False;
     }

     /* call before using stereo */
     void
     stereoInit(GLboolean usingStereoVisual, char *stereoCmd, char
     *restoreCmd)
     {    stereo.useSGIStereo = !usingStereoVisual;
         stereo.currentDisplay = NULL;
         stereo.currentWindow = None;
         stereo.currentContext = NULL;
         stereo.currentDrawBuffer = GL_NONE;
         stereo.currentStereoBuffer = STEREO_BUFFER_NONE;
         stereo.enabled = False;
         if (stereo.stereoCommand) {
             free(stereo.stereoCommand);
         }
         stereo.stereoCommand = stereoCmd ? strdup(stereoCmd) : NULL;
         if (stereo.restoreCommand) {
             free(stereo.restoreCommand);
         }
         stereo.restoreCommand = restoreCmd ? strdup(restoreCmd) : NULL;
     }

     /* call when done using stereo */
     void
     stereoDone(void)
     {    stereoDisable();
         stereoInit(True, NULL, NULL);
     }

  StereoGraphics CrystalEyes Software Development Kit                            Page 25



     /************************************************************************/

     #define APP_CLASS "GLWApp"

     String fallbackResources[] = {
         /*
         ** Widget resources
         */
         "*sgiMode: True",
         "*useSchemes: all",
         "*title: Simple OpenGL Stereo Demo",
         "*form.width: 300",
         "*form.height: 300",
         /*
         ** Non-Widget (application) resources
         */
         "*stereoCommand: /usr/gfx/setmon -n 640x512_120s",
         "*restoreCommand: /usr/gfx/setmon -n 72HZ",
         "*SGIStereoCommand: /usr/gfx/setmon -n STR_BOT",
         "*SGIRestoreCommand: /usr/gfx/setmon -n 60HZ",
         NULL,
     };

     struct appResourceRec {
         _XtString stereoCommand;
         _XtString restoreCommand;
         _XtString SGIStereoCommand;
         _XtString SGIRestoreCommand;
     } appResources;

     XtResource appResourceList[] = {
         { "stereoCommand",
           XtCString, XtRString, sizeof (_XtString),
           XtOffsetOf(struct appResourceRec, stereoCommand),
           XtRImmediate, (XtPointer) NULL },
         { "restoreCommand",
           XtCString, XtRString, sizeof (_XtString),
           XtOffsetOf(struct appResourceRec, restoreCommand),
           XtRImmediate, (XtPointer) NULL },
         { "SGIStereoCommand",
           XtCString, XtRString, sizeof (_XtString),
           XtOffsetOf(struct appResourceRec, SGIStereoCommand),
           XtRImmediate, (XtPointer) NULL },
         { "SGIRestoreCommand",
           XtCString, XtRString, sizeof (_XtString),
           XtOffsetOf(struct appResourceRec, SGIRestoreCommand),
           XtRImmediate, (XtPointer) NULL },
     };

     XtAppContext appContext;
     XtWorkProcId appWorkProcId;
     Widget topLevel, form, glw, popup;
     GLXContext ctx;
     GLboolean animationEnabled = GL_FALSE;
     GLboolean stereoEnabled = GL_FALSE;
     double lastTime = 0.0;
     double rotationRate = 360.0 / 8.0;
     double rotation = 0.0;

     static void
     drawCylinder(void)
     {    int numSides = 20;
         double radius = 0.7;
         double stepSize = 2.0*M_PI / numSides;
         int i;

  StereoGraphics CrystalEyes Software Development Kit                              Page 26



         glBegin(GL_TRIANGLE_STRIP);
         for (i=0; i<=numSides; ++i) {
             double a = i * stepSize;
             GLfloat x = cos(a);
             GLfloat y = sin(a);

             glNormal3f(x, y, 0.0);
             glVertex3f(x * radius, y * radius, 0.7);
             glNormal3f(x, y, 0.0);
             glVertex3f(x * radius, y * radius, -0.7);
         }
         glEnd();
     }

     static void
     initialize(void)
     {    GLfloat lightAmb[4] = { 0.2, 0.2, 0.2, 1.0 };
         GLfloat lightPos[4] = { 1.5, 1.5, 1.5, 1.0 };
         GLfloat matAmbDiff[4] = { 0.30, 0.40, 0.80, 1.0 };

         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
         glTranslatef(0, 0, -2);

         glEnable(GL_DEPTH_TEST);
         glEnable(GL_LIGHTING);
         glEnable(GL_LIGHT0);
         glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb);
         glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matAmbDiff);
         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
     }

     void
     stereoFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top,
                   GLfloat near, GLfloat far, GLfloat eyeDist, GLfloat
     eyeOffset)
     {    GLfloat eyeShift = (eyeDist - near) * (eyeOffset / eyeDist);
         glFrustum(left+eyeShift, right+eyeShift, bottom, top, near, far);
         glTranslatef(-eyeShift, 0.0, 0.0);
     }

     static void
     redraw(void)
     {    GLfloat eyeDist = 2.0;
         GLfloat eyeOffset = 0.05;

         glPushMatrix();
         glRotated(rotation, 0, 1, 0);

         if (stereoEnabled) {
             /*
             ** Draw right-eye view.
             */
             glMatrixMode(GL_PROJECTION);
             glLoadIdentity();
             stereoFrustum(-1, 1, -1, 1, 1, 3, eyeDist, eyeOffset);
             glMatrixMode(GL_MODELVIEW);

             stereoDrawBuffer(GL_BACK_RIGHT);
             stereoClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
             drawCylinder();
  StereoGraphics CrystalEyes Software Development Kit                            Page 27



         } else {
             eyeOffset = 0.0;
         }

         /*
         ** Draw left-eye view.
         */
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         stereoFrustum(-1, 1, -1, 1, 1, 3, eyeDist, -eyeOffset);
         glMatrixMode(GL_MODELVIEW);

         stereoDrawBuffer(GL_BACK_LEFT);
         stereoClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         drawCylinder();

         glPopMatrix();
         GLwDrawingAreaSwapBuffers(glw);
     }

     double
     getTime(void)
     {    struct timeval time;
         gettimeofday(&time);
         return ((double) time.tv_sec + (double) time.tv_usec * 1E-6);
     }

     static Boolean
     animateWP(XtPointer clientData)
     {    double currentTime = getTime();
         double elapsed = currentTime - lastTime;

         lastTime = currentTime;

         rotation += rotationRate * ((elapsed <= 1.0) ? elapsed : 1.0);
         if (rotation >= 360) rotation -= 360;

         redraw();
         return False;
     }

     static void
     popupCB(Widget w, XtPointer clientData, XtPointer callData)
     {    int button = (int) clientData;
         Bool needsRedraw = False;

         switch (button) {
           case 0:
             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
             needsRedraw = True;
             break;
           case 1:
             glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
             needsRedraw = True;
             break;
           case 2:
             animationEnabled = !animationEnabled;
             if (animationEnabled) {
                 lastTime = getTime();
                 appWorkProcId = XtAppAddWorkProc(appContext, animateWP,
     NULL);
             } else {
                 XtRemoveWorkProc(appWorkProcId);
             }
  StereoGraphics CrystalEyes Software Development Kit                       Page 28



             break;
           case 3:
             stereoEnabled = !stereoEnabled;
             if (stereoEnabled) {
                 stereoEnable();
             } else {
                 stereoDisable();
             }
             needsRedraw = True;
             break;
           case 4:
             stereoDone();
             exit(EXIT_SUCCESS);
             break;
           default:
             break;
         }

         if (needsRedraw) {
             redraw();
         }
     }

     static void
     popupEH(Widget w, XtPointer clientData, XEvent *event, Boolean *cont)
     {    Widget popup = *((Widget *) clientData);
         if ((event->type == ButtonPress) && (event->xbutton.button ==
     Button3)) {
             XmMenuPosition(popup, &event->xbutton);
             XtManageChild(popup);
         }
     }

     static void
     exposeCB(Widget w, XtPointer clientData, XtPointer callData)
     {    redraw();
     }

     static void
     resizeCB(Widget w, XtPointer clientData, XtPointer callData)
     {    GLwDrawingAreaCallbackStruct *glwcallData =
             (GLwDrawingAreaCallbackStruct *) callData;

         glViewport(0, 0, glwcallData->width, glwcallData->height);
         redraw();
     }

     int
     main(int argc, char **argv)
     {    int stereoAttrs[] = {
             GLX_STEREO,
             GLX_RGBA,
             GLX_DOUBLEBUFFER,
             GLX_RED_SIZE, 1,
             GLX_DEPTH_SIZE, 1,
             None,
         };
         int visualAttrs[] = {
             GLX_RGBA,
             GLX_DOUBLEBUFFER,
             GLX_RED_SIZE, 1,
             GLX_DEPTH_SIZE, 1,
  StereoGraphics CrystalEyes Software Development Kit                         Page 29



             None,
         };
         Display *dpy;
         int scrn;
         XVisualInfo *vis;
         Arg args[10];
         int n;

         topLevel = XtOpenApplication(&appContext, APP_CLASS, NULL, 0,
                                      &argc, argv, fallbackResources,
                                      applicationShellWidgetClass, NULL, 0);

         XtGetApplicationResources(topLevel, &appResources, appResourceList,
                                   XtNumber(appResourceList), NULL, 0);

         dpy = XtDisplay(topLevel);
         scrn = XScreenNumberOfScreen(XtScreen(topLevel));

         if ((vis = glXChooseVisual(dpy, scrn, stereoAttrs)) != NULL) {
             /* initialize for use with a stereo capable visual */
             stereoInit(True,
                        appResources.stereoCommand,
                        appResources.restoreCommand);

         } else if ((vis = glXChooseVisual(dpy, scrn, visualAttrs)) != NULL)
     {        /* initialize for use without a stereo capable visual */
             stereoInit(False,
                        appResources.SGIStereoCommand,
                        appResources.SGIRestoreCommand);

             /* Force the topLevel widget to maintain a 2:1 aspect ratio */
             n = 0;
             XtSetArg(args[n], XmNminAspectX, 2); n++;
             XtSetArg(args[n], XmNminAspectY, 1); n++;
             XtSetArg(args[n], XmNmaxAspectX, 2); n++;
             XtSetArg(args[n], XmNmaxAspectY, 1); n++;
             XtSetValues(topLevel, args, n);

         } else {
             fprintf(stderr, "can't find appropriate visual\n");
             exit(EXIT_FAILURE);
         }

         if ((ctx = glXCreateContext(dpy, vis, 0, True)) == NULL) {
             fprintf(stderr, "can't create rendering context\n");
             exit(EXIT_FAILURE);
         }

         form = XtCreateManagedWidget("form", xmFormWidgetClass, topLevel,
     NULL, 0);

         n = 0;
         XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
         XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
         XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
         XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
         XtSetArg(args[n], GLwNvisualInfo, vis); n++;
         glw = XtCreateManagedWidget("glw", glwMDrawingAreaWidgetClass,
                                     form, args, n);
         XtAddCallback(glw, GLwNexposeCallback, exposeCB, 0);
         XtAddCallback(glw, GLwNresizeCallback, resizeCB, 0);

         {
             XmButtonType buttonTypes[] = {
                 XmPUSHBUTTON, XmPUSHBUTTON, XmSEPARATOR, XmPUSHBUTTON,
                 XmSEPARATOR, XmPUSHBUTTON, XmSEPARATOR, XmPUSHBUTTON,
  StereoGraphics CrystalEyes Software Development Kit                           Page 30



             };
             XmString buttonLabels[XtNumber(buttonTypes)];

             buttonLabels[0] = XmStringCreateLocalized("draw filled");
             buttonLabels[1] = XmStringCreateLocalized("draw lines");
             buttonLabels[2] = NULL;
             buttonLabels[3] = XmStringCreateLocalized("toggle animation");
             buttonLabels[4] = NULL;
             buttonLabels[5] = XmStringCreateLocalized("toggle stereo mode");
             buttonLabels[6] = NULL;
             buttonLabels[7] = XmStringCreateLocalized("quit");

             n = 0;
             XtSetArg(args[n], XmNbuttonCount, XtNumber(buttonTypes)); n++;
             XtSetArg(args[n], XmNbuttonType, buttonTypes); n++;
             XtSetArg(args[n], XmNbuttons, buttonLabels); n++;
             XtSetArg(args[n], XmNsimpleCallback, popupCB); n++;
             popup = XmCreateSimplePopupMenu(form, "popup", args, n);
             XtAddEventHandler(form, ButtonPressMask, False, popupEH,
     &popup);

             XmStringFree(buttonLabels[0]);
             XmStringFree(buttonLabels[1]);
             XmStringFree(buttonLabels[3]);
             XmStringFree(buttonLabels[5]);
             XmStringFree(buttonLabels[7]);
         }

         XtRealizeWidget(topLevel);

         GLwDrawingAreaMakeCurrent(glw, ctx);
         stereoMakeCurrent(dpy, XtWindow(glw), ctx);
         initialize();

         XtAppMainLoop(appContext);


























  StereoGraphics CrystalEyes Software Development Kit                            Page 31



                                                                                          Chapter 3
                                                                                                          SUN

     1.  Introduction
     All Creator3D and ZX graphics devices include built-in support for StereoGraphics CrystalEyes (R)
     compatible stereoscopy.  All monitors shipped with these graphics devices are multi-scan units designed to
     handle the higher vertical frequency that CrystalEyes requires.

     This document discusses methods for developing stereoscopic software on Sun systems using XGL,
     including:

     * Checking Stereoscopic Hardware
     * Configuring the Frame Buffer for Stereo Display Mode
     * Rendering to the Left and Right Eyes
     * Two Dimensional Rendering
     * Stereoscopic Projections
     * Sample XGL Application

























  StereoGraphics CrystalEyes Software Development Kit                                                  Page 32



     2.  Checking Stereoscopic Hardware
     This section discusses how an application should check the stereoscopic compatibility of a user's
     computer system. All Sun Creator3D and ZX graphics devices with multi-scan monitors are Stereo
     capable.  The graphics devices that do not support Stereo are the GX series, the SX, and the GS.  If you
     would like to test your own computer's stereo compatibility, the xgl_inquire call (see section 4) may
     be used within the program to determine if the graphics window has hardware support for Stereo.  This
     should be taken into consideration if the application enables Stereo via the user interface. If there is no
     hardware support for Stereo, the application should not allow XGL_WIN_RAS_STEREO_MODE to be set
     to anything but XGL_STEREO_NONE.


































  StereoGraphics CrystalEyes Software Development Kit                                                       Page 33



     3. Configuring the Frame Buffer for Stereo Display Mode

     The frame buffer must be reconfigured to support stereoscopic display. This is done with the ffbconfig
     command on the Creator3D and the leoconfig command on the ZX.  Only root may run these commands
     and it must be done outside of the windowing system.  In CDE, choose "Command Line Login" from the
     "Options" option menu on the login screen.

     To configure the Creator3D for stereo, issue the following command:

             ffbconfig -res 960x680x108s
     or:
             ffbconfig -res 960x680x112s


     To configure the ZX for stereo, issue the following command:

            leoconfig -M stereo108
     or:
            leoconfig -M stereo114

     After the reconfiguration of the Frame Buffer is complete, the user may login.  All windows will now
     appear larger due to the decreased resolution of the screen.  This will not affect the functionality of the
     window manager and the screen may be viewed with or without the CrystalEyes glasses with no adverse
     effects.

     To return the Creator3D frame buffer to the standard default, use:

          ffbconfig -res 1280x1024x76



     To return the ZX frame buffer to the standard default, use:

      leoconfig -M 1280_76


     See the man pages for ffbconfig and leoconfig for more detail.










  StereoGraphics CrystalEyes Software Development Kit                                                       Page 34



     4. Rendering the Left and Right Eyes
     To render the left eye view in a stereo window in XGL, the following attribute is specified in an
     xgl_object_set call:

        xgl_object_set (ras,
                       XGL_WIN_RAS_STEREO_MODE, XGL_STEREO_LEFT,
                        NULL);

     For the right eye, it would be:

    xgl_object_set (ras,
                XGL_WIN_RAS_STEREO_MODE, XGL_STEREO_RIGHT,
                        NULL);

     And to turn stereo off:

    xgl_object_set (ras,
                XGL_WIN_RAS_STEREO_MODE, XGL_STEREO_NONE,
                        NULL);

     These calls must be made before any rendering takes place in the window. For stereo viewing, the image is
     shifted to one side and then rendered for the left eye, then shifted in the opposite direction and rendered
     again for the right eye.  When stereo is off, the image is rendered only once with no extra shifting taking
     place.

     Since the Frame Buffer is configured for Stereo, there is no special window  to create to enable Stereo.
     All rendering is done in a standard graphics window.



















  StereoGraphics CrystalEyes Software Development Kit                                                      Page 35



     5. Two Dimensional Rendering

     Any two dimensional primitives that are to be rendered in the graphics window should be drawn either
     before or after the left and right eye renderings have taken place and stereo has been turned off.








































  StereoGraphics CrystalEyes Software Development Kit                                                      Page 36



     6.  Stereoscopic Projections

     XGL does not have an API function to control asymmetric frustum projections.

     The programmer must implement appropriate image re-positioning when using default symmetric frustum
     projections to render stereo image pairs.

     Refer to Chapter 6 of the "StereoGraphics Developer's Handbook" for mathematical description of
     creating stereoscopic projections.




































  StereoGraphics CrystalEyes Software Development Kit                                                   Page 37



     7. Sample XGL Application

     This program allows stereo image pairs to be viewed on the ZX using the Crystal Eyes glasses.  The
     program is written in "C" and uses XGL for the stereo and imaging and xview for the windows.

     The syntax for the program is:

     stereo lefteyefile  righteyefile

     ex:  stereo left.ras right.ras

     Included is the source (stereo.c) and makefile (make stereo). A pair of sample stereo images (left.ras,
     right.ras) are available from the StereoGraphics website at www.stereographics.com.
     The source draws some of  the code from leotool.  The sample images were created by doing raster saves
     from leotool.

     /*
      ***********************************************************************
      *
      * stereo.c
      *
      *  Program to load in stereo image pairs on the ZX and display them
      * in stereo using the crystal eyes glasses.
      *
      ***********************************************************************
      */

     #include <math.h>
     #include <X11/Xlib.h>
     #include <X11/Xutil.h>
     #include <xview/xview.h>
     #include <xview/canvas.h>
     #include <xview/xv_xrect.h>
     #include <stdio.h>
     #include <xgl/xgl.h>

     /* not sure what these are - they were in leotool so I'll keep them */

     #define V_STEREO_WIDTH_IN_PIXELS                    960.0
     #define V_STEREO_HEIGHT_IN_PIXELS                   680.0
     #define V_STEREO_WIDTH_IN_CM                        36.5
     #define V_STEREO_HEIGHT_IN_CM                       25.8
     #define V_EYE_POS_X                       (V_STEREO_WIDTH_IN_CM / 2.0)

     /*
      * Definitions from rasterfile.h
      */

     struct rasterfile {
       int     ras_magic;                /* magic number */
       int     ras_width;                /* width (pixels) of image */
       int     ras_height;               /* height (pixels) of image */
       int     ras_depth;                /* depth (1, 8, or 24 bits) of pixel */
       int     ras_length;               /* length (bytes) of image */
       int     ras_type;                 /* type of file; see RT_* below */
       int     ras_maptype;                    /* type of colormap; see RMT_* below */
       int     ras_maplength;                  /* length (bytes) of following map */
  StereoGraphics CrystalEyes Software Development Kit                                                     Page 38



       /* color map follows for ras_maplength bytes, followed by image */
     };
     #define RAS_MAGIC        0x59a66a95

       /* Sun supported ras_type's */
     #define RT_OLD                     0       /* Raw pixrect image in 68000 byte order */
     #define RT_STANDARD 1              /* Raw pixrect image in 68000 byte order */
     #define RT_BYTE_ENCODED            2       /* Run-length compression of bytes */
     #define RT_FORMAT_RGB              3       /* XRGB or RGB instead of XBGR or BGR */
     #define RT_FORMAT_TIFF             4       /* tiff <-> standard rasterfile */
     #define RT_FORMAT_IFF              5       /* iff (TAAC format) <-> standard rasterfile */
     #define RT_EXPERIMENTAL 0xffff /* Reserved for testing */
     #define RMT_RAW                    2       /* Sun supported ras_maptype's */
     #define RMT_NONE         0         /* ras_maplength is expected to be 0 */
     #define RMT_EQUAL_RGB              1       /* red[ras_maplength/3],green[],blue[] */

     static Xgl_3d_ctx                  ctx;
     static Xgl_ras                             ras = NULL; /* Xgl window raster */
     static Xgl_win_ras                 win_ras = NULL;        /* Xgl window raster */
     static Xgl_boolean                 raster_bug_fixed;
     static Xgl_sys_state                       sys_st;              /* XGL System State object */

     typedef struct xg_raster_type xg_raster_type;

     /* Raster values */
     struct xg_raster_type {
       /* Offset into original image */
       int                    left_offset;
       int                    top_offset;
       /* Size taken from original image */
       int                    width;
       int                    height;
       /* Where to draw it in the window */
       int                    x_origin;
       int                    y_origin;
       /* Specifications for the stored image */
       unsigned *             image_data;
       int                    image_width;
       int                    image_height;
     };xg_raster_type                   xg_raster;

     char            re_name[50],le_name[50];
     static void   image_proc();

     main (argc, argv)
         int                  argc;
         char                *argv[];
     {    Xgl_X_window xgl_x_win; /* XGL-X data structure */
         Xgl_obj_desc         win_desc;         /* XGL window raster structure */

         Frame                frame;                     /* XView frame around this window */
         Canvas               canvas;                    /* XView canvas inside frame */

         Xv_Window            pw;                        /* XView paint window */
         Window               frame_window;                    /* XID of frame */
         Window               canvas_window;                   /* XID of canvas */

         Display              *display;                  /* pointer to X display */
         int                  screen;                          /* X screen number */

         void                 event_proc ();                   /* XView event procedure */
         void                 repaint_proc (); /* XView repaint procedure */
         Notify_value         quit_proc ();                    /* XView quit procedure */
  StereoGraphics CrystalEyes Software Development Kit                                                 Page 39



     /* this is a leotool thing - not sure what it involves, but if
     there is ever a fix, we can turn off the kludge */

         if (getenv("LEOTOOL_RASTER_BUG_FIXED")) {
       raster_bug_fixed = TRUE;
         }

          if(argc<3) {
            printf("usage: stereo lefteyefile  righteyefile\n");
            exit(0);
            }
            else {
             strcpy(re_name,argv[1]);
             strcpy(le_name,argv[2]);
            }

         xv_init (XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);

         /* create a XView simple window frame      */

         frame = xv_create (NULL, FRAME,
                       FRAME_LABEL,                      "Stereo Image Viewer",
                       WIN_DYNAMIC_VISUAL,               TRUE,
                       OPENWIN_AUTO_CLEAR,               FALSE,
                       CANVAS_RETAINED,                  FALSE,
                       CANVAS_FIXED_IMAGE,               FALSE,
                              WIN_DEPTH,                 24,
                              XV_VISUAL_CLASS,                     TrueColor,
                       NULL);

         /*  create a XView canvas. set event and repaint procedures */

         canvas = xv_create (frame, CANVAS,
                       WIN_DYNAMIC_VISUAL,               TRUE,
                       OPENWIN_AUTO_CLEAR,               FALSE,
                       CANVAS_RETAINED, FALSE,
                       WIN_EVENT_PROC,                   event_proc,
                       CANVAS_REPAINT_PROC,              repaint_proc,
                               WIN_DEPTH,                          24,
                               XV_VISUAL_CLASS,                    TrueColor,
                       NULL);

         /* get X stuff */
         display = (Display *) xv_get (frame, XV_DISPLAY);
         pw = (Xv_Window) canvas_paint_window (canvas);
         canvas_window = (Window) xv_get (pw, XV_XID);
         frame_window  = (Window) xv_get (frame, XV_XID);

         /* put X stuff into XGL data structure */
         xgl_x_win.X_display = (void *) XV_DISPLAY_FROM_WINDOW (pw);
         xgl_x_win.X_window  = (Xgl_usgn32) canvas_window;
         xgl_x_win.X_screen  = (int) DefaultScreen (display);

         /* wait for the window */
         sleep (2);

         /* create XGL System State object */
         sys_st = xgl_open (NULL);

         /* create Window Raster Device using XView canvas */
         win_desc.win_ras.type = XGL_WIN_X | XGL_WIN_X_PROTO_DEFAULT;
         win_desc.win_ras.desc = &xgl_x_win;

         win_ras = (Xgl_win_ras) xgl_object_create(sys_st,
       XGL_WIN_RAS,                           &win_desc,
  StereoGraphics CrystalEyes Software Development Kit                              Page 40



          XGL_DEV_COLOR_TYPE,                 XGL_COLOR_RGB,
          XGL_WIN_RAS_STEREO_MODE,            XGL_STEREO_NONE,
          NULL);

         ras = (Xgl_ras) xgl_object_create(sys_st,
          XGL_MEM_RAS,                        NULL,
          XGL_RAS_DEPTH,                      32,
          XGL_RAS_WIDTH,                      5,         /* It WILL change */
          XGL_RAS_HEIGHT,                     5,
          NULL);

         /* create XGL graphics Context object using the Window Raster object */
         ctx = xgl_object_create (sys_st, XGL_3D_CTX, NULL,
                               XGL_CTX_DEVICE, win_ras,
                               XGL_CTX_DEFERRAL_MODE, XGL_DEFER_ASAP,
                               NULL);

         /* set quit procedure where xgl_close is called */
         notify_interpose_destroy_func (frame, quit_proc);

          image_proc();

         /* go into XView loop */
         window_main_loop (frame);

         exit (0);
     }

     /*
      *   Load up the left and right eye in this function.
      */
     static
     void
     image_proc ()
     {    Xgl_bounds_i2d rect;                /* Size of rectangle to be drawn */
         Xgl_pt_i2d pos;                      /* Position on screen */
         int read_succeeded;                             /* True if object read worked */

         /* clear canvas area (both eyes) to default background color of black */
         xgl_object_set(win_ras,
          XGL_WIN_RAS_STEREO_MODE, XGL_STEREO_NONE,
          NULL);
         xgl_context_new_frame (ctx);

         rect.xmin = xg_raster.left_offset;
         rect.xmax = xg_raster.left_offset + xg_raster.width;
         rect.ymin = xg_raster.top_offset;
         rect.ymax = xg_raster.top_offset + xg_raster.height;

         pos.x = xg_raster.x_origin - (xg_raster.width / 2);
         pos.y = xg_raster.y_origin - (xg_raster.height / 2);

         if (!raster_bug_fixed) {
          if (pos.x < 0) {
              rect.xmin -= pos.x;
              pos.x = 0;
          }rect.xmin *= 4;                    /* Correct for Leo XGL bug */
          if (pos.y < 0) {
              rect.ymin -= pos.y;
              pos.y = 0;
          }
         }
  StereoGraphics CrystalEyes Software Development Kit                                        Page 41



            /* Draw the left eye view */

          xgl_object_set(win_ras,
              XGL_WIN_RAS_STEREO_MODE, XGL_STEREO_LEFT,
              NULL);

             read_succeeded = load_raster_file(le_name);
             xgl_context_copy_buffer(ctx, &rect, &pos, ras);

            /* Draw the right eye view */

          xgl_object_set(win_ras,
              XGL_WIN_RAS_STEREO_MODE, XGL_STEREO_RIGHT,
              NULL);

           read_succeeded = load_raster_file(re_name);
           xgl_context_copy_buffer(ctx, &rect, &pos, ras);

     }

     static
     void
     event_proc (window, event, arg)
         Xv_Window            window;
         Event               *event;
         Notify_arg           arg;
     {    switch (event_action (event)) {
          /*
           * not anything to do here but mouse and keyboard events should be
           * tracked in this procedure
           */
         default:
          break;
         }
     }

     /*
      * Xview repaint procedure.  Load up the left and right eye in this function.
      */
     static
     void
     repaint_proc (local_canvas, local_pw, dpy, xwin, xrects)
         Canvas               local_canvas;
         Xv_Window            local_pw;
         Display              *dpy;
         Window               xwin;
         Xv_xrectlist         *xrects;
     {     image_proc();
     }

     static
     Notify_value
     quit_proc (fr, status)
         Frame                fr;
         Destroy_status status;
     {    if (status == DESTROY_CHECKING) {
          xgl_close (sys_st);
         }
         return (notify_next_destroy_func (fr, status));
     }

     /*
  StereoGraphics CrystalEyes Software Development Kit                                 Page 42



      * load_raster_file
      *
      *        Load in a Sun Rasterfile.
      *
      *        Note that this code is designed to be extended so that
      *        color maps can be handled better.  If the need arises,
      *        we just have to update the color map code, not anything else.
      */

     int
     load_raster_file(char filename[])
     {    FILE * input;                       /* The input file */
         struct rasterfile rf;                /* File header */
         unsigned char red[256];                         /* For the CLUT, if present */
         unsigned char green[256];
         unsigned char blue[256];
         int x, y;                            /* Index into frame buffer array */
         unsigned * p;                        /* Pointer to pixel array */
         unsigned char * bptr;                /* Pointer TO image input buffer */
         unsigned char * iptr;                /* Pointer INTO image input buffer */
         unsigned char r, g, b;                          /* To build a 32-bit word */
         unsigned c;                                     /* The finished color value */
         int i;                               /* Iterative counter */

         input = fopen(filename, "r");
         if (input == NULL) {
       fprintf(stderr, "Error opening file...\n");
       perror(filename);
       return (FALSE);
         }

         /* Read in the header and check for any possible error */

         if (fread(&rf, sizeof(struct rasterfile), 1, input) != 1) {
       fprintf(stderr, "Unable to read rasterfile header\n");
       close(input);
       return (FALSE);
         }

         if (rf.ras_magic != RAS_MAGIC) {
       fprintf(stderr, "Invalid magic number: 0x%.8X\n", rf.ras_magic);
       close(input);
       return (FALSE);
         }

         if ((rf.ras_depth != 8) && (rf.ras_depth != 24) && (rf.ras_depth != 32)) {
       fprintf(stderr, "We don't do depths of %d\n", rf.ras_depth);
       close(input);
       return (FALSE);
         }

         if ((rf.ras_width > 4096) || (rf.ras_height > 4096)) {
       fprintf(stderr, "Image of %d x %d is too big\n", rf.ras_width,
           rf.ras_height);
       close(input);
       return (FALSE);
         }

         if ((rf.ras_type != RT_STANDARD) && (rf.ras_type != RT_FORMAT_RGB)) {
       fprintf(stderr, "Unsupported ras_type: %d\n", rf.ras_type);
       close(input);
       return (FALSE);
         }

         /* Get any color lookup table */

  StereoGraphics CrystalEyes Software Development Kit                                      Page 43



         for (i = 0; i < 256; i++) {                     /* First initialize the CLUT */
       red[i] = i;
       green[i] = i;
       blue[i] = i;
         }

         if (rf.ras_maplength != 0) {
       if ((fread(red, rf.ras_maplength / 3, 1, input) != 1) ||
                 (fread(green, rf.ras_maplength / 3, 1, input) != 1) ||
                 (fread(blue, rf.ras_maplength / 3, 1, input) != 1)) {
           fprintf(stderr, "Unable to read CLUT\n");
           close(input);
           return (FALSE);
       }

       /* Undo gamma for 8-bit images... */
       if (rf.ras_depth == 8)
           for (i = 0; i < 256; i++) {
                 red[i] = (int) (255.0 * pow((double) red[i] / 255.0, 2.22));
                 green[i] = (int) (255.0 * pow((double) green[i] / 255.0, 2.22));
                 blue[i] = (int) (255.0 * pow((double) blue[i] / 255.0, 2.22));
           }
         } /* End of CLUT loading */

         /* Initialize data storage area */

         xg_raster.left_offset = 0;
         xg_raster.top_offset = 0;
         xg_raster.image_width = rf.ras_width;
         xg_raster.image_height = rf.ras_height;
         xg_raster.width = xg_raster.image_width;
         xg_raster.height = xg_raster.image_height;
         xg_raster.x_origin = xg_raster.image_width / 2;
         xg_raster.y_origin = xg_raster.image_height / 2;

         xgl_object_set(ras,
       XGL_RAS_WIDTH,                         xg_raster.image_width,
       XGL_RAS_HEIGHT,                        xg_raster.image_height,
       NULL);

         xgl_object_get(ras, XGL_MEM_RAS_IMAGE_BUFFER_ADDR,
       (unsigned **) &xg_raster.image_data);

         /* Now go read the image */

         if (rf.ras_length == (rf.ras_width * rf.ras_height))
       /* Correct for certain screwed up files */
       rf.ras_length = rf.ras_width * rf.ras_height * (rf.ras_depth / 8) +
           (rf.ras_width & 1 ? rf.ras_width : 0);



     /* Get room for the full image and read it */
         bptr = (unsigned char *) malloc(rf.ras_length);
         if (fread(bptr, rf.ras_length, 1, input) != 1) {
       fprintf(stderr, "Unable to read full image file\n");
       close(input);
       return (FALSE);
         }

         p = xg_raster.image_data;                       /* Point into pixel array */
         iptr = bptr;
         if (rf.ras_depth == 8) {
       for (y = 0; y < rf.ras_height; y++) {
           for (x = 0; x < rf.ras_width; x++) {
                 c = *iptr++;
  StereoGraphics CrystalEyes Software Development Kit                                       Page 44



                r = red[c];
                g = green[c];
                b = blue[c];
                c = r | (g << 8) | (b << 16);
                *p++ = c;
           }
           if (rf.ras_width & 1)
                iptr++;                       /* Make up for rasterfile kludge */
       }
         } /* End of 8-bit rasterfile */
         else if (rf.ras_depth == 24) {
       for (y = 0; y < rf.ras_height; y++) {
           for (x = 0; x < rf.ras_width; x++) {
                if (rf.ras_type == RT_FORMAT_RGB) {
                    r = red[*iptr++];
                    g = green[*iptr++];
                    b = blue[*iptr++];
                }else {
                    b = blue[*iptr++];
                    g = green[*iptr++];
                    r = red[*iptr++];
                }c = r | (g << 8) | (b << 16);
                *p++ = c;
           }
           if (rf.ras_width & 1)
                iptr++;                       /* Make up for rasterfile kludge */
       }
         } /* End of 24-bit rasterfile */
         else if (rf.ras_depth == 32) {
       for (y = 0; y < rf.ras_height; y++) {
           for (x = 0; x < rf.ras_width; x++) {
                iptr++;                       /* Bypass the spare byte */
                if (rf.ras_type == RT_FORMAT_RGB) {
                    r = red[*iptr++];
                    g = green[*iptr++];
                    b = blue[*iptr++];
                }else {
                    b = blue[*iptr++];
                    g = green[*iptr++];
                    r = red[*iptr++];
                }c = r | (g << 8) | (b << 16);
                *p++ = c;
           }
       }
         } /* End of 32-bit rasterfile */

         free(bptr);
         close(input);
         return (TRUE);
     } /* End of load_raster_file */











  StereoGraphics CrystalEyes Software Development Kit                                Page 45



     ## @(#)Makefile 1.4 93/02/18
     ## Copyright (c) 1993 by Sun Microsystems, Inc.

     all:  stereo

     OS:sh        =       /bin/expr  uname -r  : '\(.\)'

     CC_5 = cc
     CC = $(CC_$(OS))

     BUILD=

     UG_DEBUG_5-g = -g
     UG_DEBUG = $(UG_DEBUG_$(OS)$(BUILD))

     COMPILE_FLAGS_5 = -c $(UG_DEBUG) -D__SVR4__ -DDEBUG -Dsun -Dsun2 \
     -I. -I$(XGLHOME)/include  \
     -I$(OPENWINHOME)/include

     COMPILE_FLAGS = $(COMPILE_FLAGS_$(OS))

     .SUFFIXES: .c .o

     OTHER_SYSLIBS_5 = -L$(XGLHOME)/lib -lxgl  -L/usr/ucblib \
       -L$(OPENWINHOME)/lib -lX11 -lXt -ldga -ldl -lintl -lnsl -lsocket \
       -lxview -lolgx -lw -lm -lelf
     OTHER_SYSLIBS = $(OTHER_SYSLIBS_$(OS))

     obj_$(OS)$(BUILD)/%.o: %.c
       $(CC) $(COMPILE_FLAGS) -o $@ $<

     PWX_SOURCE= \
     stereo.c

     PWX_OBJECTS_5-g = $(PWX_SOURCE:%.c=obj_5-g/%.o)
     PWX_OBJECTS  = $(PWX_OBJECTS_$(OS)$(BUILD))

     LINK_5_-g =
     LINK = $(LINK_$(OS)$(BUILD))

     stereo: obj_$(OS)$(BUILD)/stereo.o $(PWX_OBJECTS)
       $(CC) $(UG_DEBUG) -o stereo$(BUILD) \
       obj_$(OS)$(BUILD)/stereo.o $(PWX_OBJECTS) \
       $(LINK) $(OTHER_SYSLIBS)

     stereo-g:
       make "BUILD=-g" stereo










  StereoGraphics CrystalEyes Software Development Kit                        Page 46



  StereoGraphics CrystalEyes Software Development Kit    Page 47



                                                                                                                                                                            Chapter 4
                                                                                                                                                                                                      DEC


     1.  Introduction

     This document is intended to give a brief overview of the stereo implementation that is available for the PowerStorm 4DT
     family of graphics adapters.

     In some cases, information in a section of this document may apply only to OpenGL implementations layered on a
     particular operating system (Digital Unix or Windows NT). In such cases, the text is preceded by a bracketed
     [ ] disclaimer. OpenGL stereo as described in this document is currently only supported on Digital Unix.

     This document does not discuss algorithms for generating stereo views from a 3D scene, and it does not discuss how to
     write a stereo application using OpenGL. (Although an example of a simple stereo application is given at the end of this
     document). The OpenGL stereo implementation for the PowerStorm 4DT family was intended to be as transparent as
     possible, and thus take advantage of pre-existing (and well-documented) API's.
     This document is intended to provide developers with preliminary information about unreleased Digital products. As such, it is intended to be as accurate as possible, but may be subject to change without
     notice, and should not be construed as a commitment by Digital Equipment Corporation.

     This document discusses methods for developing stereoscopic software on DEC systems, including:

     * Stereo Support
     * Enabling Stereo From an Application
     * Supported Screen Resolutions and Refresh Rates
     * Supported Hardware
     * Supported Visuals
     * Backing Store
     * Performance
     * Left and Right Construction Planes
     * Example OpenGL Application















  StereoGraphics CrystalEyes Software Development Kit                                                                                                                                                Page 48



     2. Stereo Support
     Stereo support for the Powerstorm 4DT family of graphics adapters conforms to the model defined by the OpenGL
     standard. An application can render a stereoscopic scene by simply drawing to the appropriate left or right buffers. The
     hardware mechanics of rendering in stereo mode are completely transparent to the applications developer.

     The form of stereo rendering that has been implemented is commonly referred to as 'stereo-in-a-window'. A stereo scene
     can be rendered into a normal window on the screen. Pixels that are displayed in a stereo window will have a normal
     aspect ratio.

     Other monoscopic applications can displayed on the same screen, and will appear normal. Multiple stereo windows and
     monoscopic windows can be displayed simultaneously, can overlap and can be managed by a standard window manager.







































  StereoGraphics CrystalEyes Software Development Kit                                                                  Page 49



     3. Enabling Stereo from an Application
     To enable stereo rendering, an application must select a visual or pixel format that supports stereo.

     For an OpenGL implementation layered on the X Window System, simply use glXChooseVisual() to select an
     appropriate stereo visual. Use glXCreateContext() to create a new GLX rendering context using the visual that was
     selected. When the application calls glXMakeCurrent() with this context, the screen will be switched into stereo mode,
     and rendering can proceed as normal.

     The same effect can be achieved using a GL toolkit that supports stereo. For example, when using the OpenGL Utility
     Toolkit (GLUT), simply OR in the GLUT_STEREO bit to the mode argument when calling glutInitDisplayMode().

     Selecting the left or right stereo buffer is accomplished through the standard call to glDrawBuffer(). When the context or
     window used for stereo rendering is destroyed, the screen is switched back out of stereo mode. If multiple contexts are
     being used for stereo rendering, the screen is not switched out of stereo mode until the last of these contexts is destroyed.

     An application can determine if a particular display is stereo- capable by calling glXGetConfig() with the requested
     attribute set to GLX_STEREO.


































  StereoGraphics CrystalEyes Software Development Kit                                                                    Page 50



     4. Supported Screen Resolutions and Refresh Rates
     In order to support normal aspect ratio pixels in stereo mode, the frame buffer is divided into two full height left and right
     buffers.

     Because of the increased memory requirements associated with maintaining separate left and right buffers, the maximum
     screen resolution for each graphics adapter will be slightly smaller than in non-stereo mode.

                                                     Maximum Stereo Resolutions

      PowerStorm Model                                         Planes Per Pixel                 Max Resolution
      4D60T                                                    102                              1280x1024
                                                               128                              1152x900
      4D50T/4D40T                                              102                              800x600
                                                               128                              800x600

     [NOTE: the following information applies only to OpenGL implementations layered on the X Window System.]

     To select a particular screen resolution and vertical refresh rate, use the '-screen' and '-vsync' command line options in the
     X server configuration file.
     To select an additional vertical refresh rate to be used when the screen is in stereo mode, use the '-I -e3stereo ' command
     line arguments in the Xserver configuration file. Replace by one of the vertical refresh rates in the table below. Note that
     the maximum refresh rates indicated may not be supported by all hardware.

     If you omit the '-I -e3stereo ' arguments in the Xserver configuration file, the server will use continue use the same rate
     that it was using when the screen was in monoscopic mode.

     See your system administrator or refer to your documentation and release notes for more information on configuring the
     Xserver via the configuration file.

     The following table indicates the range of vertical refresh rates available at each of the above resolutions. Note that these
     refresh rates are per frame , so in stereo mode, divide by two to get the effective refresh rate per eye . In the comment
     column, 'Default' indicates the default refresh rate for monoscopic operation, 'StereoDefault' indicates the default refresh
     rate for stereo operation.

                                                        Supported Video Modes

                 Resolution (HxV)                     Refresh Rate (Hz)                            Comment
      1600x1280                              60
      1600x1280                              65
      1600x1280                              70                                      Default
      1600x1280                              75
      1600x1200                              60
      1600x1200                              65
      1600x1200                              70
                 Resolution (HxV)                     Refresh Rate (Hz)                            Comment
      1600x1200                              75                                      Default
      1600x1200                              80
      1600x1200                              85
      1280x1024                              60
      1280x1024                              65
      1280x1024                              66

  StereoGraphics CrystalEyes Software Development Kit                                                                     Page 51



      1280x1024                      70
      1280x1024                      72
      1280x1024                      75                          Default
      1280x1024                      80
      1280x1024                      85                          StereoDefault
      1152x900                       60
      1152x900                       65
      1152x900                       70
      1152x900                       75
      1152x900                       76                          Default
      1152x900                       80
      1152x900                       85
      1152x900                       90
      1152x900                       95
      1152x900                       100
      1152x900                       105
      1152x900                       110
      1024x768                       60
      1024x768                       65
      1024x768                       70
      1024x768                       75                          Default
      1024x768                       80
      1024x768                       85
      1024x768                       90
      1024x768                       95
      1024x768                       100
      1024x768                       105
      1024x768                       110                         StereoDefault
      1024x768                       115
      1024x864                       60                          Default
      1024x864                       65
      1024x864                       70
      1024x864                       75
      1024x864                       80
      1024x864                       85
             Resolution (HxV)               Refresh Rate (Hz)               Comment
      1024x864                       90
      1024x864                       95
      1024x864                       100
      1024x864                       105
      1024x864                       110
      1024x864                       115
      1024x864                       120
      1024x864                       125
      1024x864                       130
      1024x864                       135
      1024x864                       140
      800x600                        60
  StereoGraphics CrystalEyes Software Development Kit                                  Page 52



      800x600                        65
      800x600                        70
      800x600                        72
      800x600                        75                          Default
      800x600                        80
      800x600                        85
      800x600                        90
      800x600                        95
      800x600                        100
      800x600                        105
      800x600                        110
      800x600                        115
      800x600                        120
      800x600                        125
      800x600                        130
      800x600                        135
      800x600                        140                         StereoDefault
      640x480                        60
      640x480                        65
      640x480                        70
      640x480                        72
      640x480                        75                          Default
      640x480                        80
      640x480                        85
      640x480                        90
      640x480                        95
      640x480                        100
      640x480                        105
      640x480                        110
             Resolution (HxV)               Refresh Rate (Hz)               Comment
      640x480                        115
      640x480                        120
      640x480                        125
      640x480                        130
      640x480                        135
      640x480                        140
      640x480                        145
      640x480                        150                         StereoDefault











  StereoGraphics CrystalEyes Software Development Kit                                  Page 53



     5. Supported Hardware
     This stereo implementation requires a PowerStorm 4D40T, 4D50T, or 4D60T graphics adapter and compatible MultiSync
     monitor, such as Digital's VRC15, VRC17, or VRC21 series monitors.















































  StereoGraphics CrystalEyes Software Development Kit                                                        Page 54



     6. Supported Visuals
     [NOTE: the following information applies only to OpenGL implementations layered on the X Window System.]

     GL stereo is currently supported only on single and double buffered TrueColor-24 visuals. Future support will
     include PseudoColor and DirectColor visuals.














































  StereoGraphics CrystalEyes Software Development Kit                                                                 Page 55



     7. Backing Store
     [NOTE: the following information applies only to OpenGL implementations layered on the X Window System.]

     Backing store is currently not supported when rendering in stereo mode. Windows that have their backing store attribute
     set will have backing store turned off while the screen is in stereo mode and will receive exposure events.

     When the screen returns to monoscopic mode, these windows will have backing store re-enabled. Backing store for any obscured
     regions will have been lost, but will be available for subsequent window operations.











































  StereoGraphics CrystalEyes Software Development Kit                                                               Page 56



     8. Performance
     When the graphics adapter is in stereo mode, the rendering performance of monoscopic applications will be lower than
     normal. Because of this, it is recommended that when stereoscopic rendering is no longer required, the adapter be
     switched out of stereo mode.

     This reduction in performance is most apparent in applications that draw large, simple primitives. Large rectangle fills are
     the best example of this. Rendering complex three-dimensional scenes with many polygons or textured polygons should
     not suffer significant performance degradation.

     Switching between normal and stereo modes is fairly expensive, so switching back to normal mode is only required when it is
     unlikely that stereo rendering will be performed in the near future. An application that renders in both mono and stereo should
     remain in stereo mode for as long as stereo rendering is required.







































  StereoGraphics CrystalEyes Software Development Kit                                                                   Page 57



     9. Left and Right Construction Planes
     [NOTE: the following information applies only to OpenGL implementations layered on the X Window System.]

     As described above, in this stereo implementation, the frame buffer is divided into separate full-height left and right
     buffers. This means that when the screen is in stereo mode, the left and right buffers use separate portions of the frame
     buffer for the construction planes. (Depth buffer, alpha buffer, and stencil buffer).

     This does not cause problems in normal rendering, but it can cause unexpected results when an application reads and
     writes to these buffers. OpenGL implicitly assumes that there is only one of each of these construction buffers.

     In the case of an application that reads from these planes (via glReadPixels), data will always be fetched from the buffer
     associated with the left stereo buffer. When an application writes to these buffers (via DrawPixels) the data is replicated
     and sent to both  the left and right buffers.

     Note that having separate depth, stencil, and alpha buffers for the left and right stereo buffers will not cause problems for
     monoscopic applications that are running when the screen is in stereo mode. For these applications, the same information is
     rendered in both the left and right buffers, so both sets of construction planes will be identical.



































  StereoGraphics CrystalEyes Software Development Kit                                                                    Page 58



     10. Sample OpenGL Application

     Demonstration of a simple stereo application in OpenGL and GLUT. This application puts a crude stereo image of a
     paper airplane on the screen, rotating about its center.

     This program uses perspective depth, which draws things in the distance smaller. The only correct way to do this in gl is
     with the "window" subroutine made to perform asymmetric projection by the use of parallel cameras. It is incorrect to
     angle the cameras inward so that their lines of gaze intersect at a point in space.
     For orthographic display (no perspective -- things in the distance drawn the same size as things up close) it is correct to
     angle the cameras inward. The gl "perspective" may be used in this case if one wishes.

     The original version of the program before modification, was by Robert Akka published in The CrystalEyes Handbook,
     previously distributed by StereoGraphics.

     /*
      *
      *  plane.c  (OpenGL version)
      *  Draws rotating paper airplane in stereo.
      *
      *  Converted to use OpenGL Utility Toolkit
      *  Rick Hammerstone, Digital, December 1996.
      *
      *  Converted to OpenGL by Silicon Graphics Corp. 4Dgifts program toogl.
      *  Further modified by James S. Lipscomb and Keh-Shin Cheng, IBM Research,
      *  March 1995.  Uses Motif.
      *
      *  Original program in GL by Robert Akka
      *  StereoGraphics Corporation
      *  April 2, 1991
      *
      * Compile with:
      *    cc -o plane plane.c -lglut -lGLU -GL -lXmu -lXi -lXext -lX11 -lm
      *
      *  Hit escape to stop program.
      */

     #include stdio.h
     #include string.h
     #include math.h

     #include GL/glut.h

     /*
      * Speed of rotation in degrees per update.
      */
     #define VELOCITY -0.2

     float yAngle = 0;
     GLenum rgb, doubleBuffer;

     void Reshape(int width, int height)
     {    glViewport(0, 0, width, height);
     }

     void Key(unsigned char key, int x, int y)
     {    if (key == 27)
            exit(0);
     }

     void Init()
  StereoGraphics CrystalEyes Software Development Kit                                                                     Page 59



     {    glMatrixMode(GL_PROJECTION);
     }

     void DrawAirplane()
     {    static float airplane[9][3] = {
             { 0.0,  0.5, -4.5},
             { 3.0,  0.5, -4.5},
             { 3.0,  0.5, -3.5},
             { 0.0,  0.5,  0.5},
             { 0.0,  0.5,  3.25},
             { 0.0, -0.5,  5.5},
             {-3.0,  0.5, -3.5},
             {-3.0,  0.5, -4.5},
             { 0.0, -0.5, -4.5}
         };

         glColor3f(1.00, 0.19, 0.69); /* violet: r=1, g=.19, b=.69 */

         glBegin(GL_LINE_LOOP);
             glVertex3fv(airplane[6]);
             glVertex3fv(airplane[7]);
             glVertex3fv(airplane[1]);
             glVertex3fv(airplane[2]);
             glVertex3fv(airplane[4]);
         glEnd();

         glBegin(GL_LINE_LOOP);
             glVertex3fv(airplane[0]);
             glVertex3fv(airplane[4]);
             glVertex3fv(airplane[5]);
             glVertex3fv(airplane[8]);
         glEnd();

         glBegin(GL_LINE_LOOP);
             glVertex3fv(airplane[6]);
             glVertex3fv(airplane[3]);
             glVertex3fv(airplane[2]);
         glEnd();
     }

     void Plane(float yAngle)
     {    glRotatef(yAngle, 0, 1, 0);
         glRotatef(-10, 1, 0, 0);
         DrawAirplane();
     }

     void StereoProjection(float left,
                            float right,
                            float bottom,
                            float top,
                            float near,
                            float far,
                            float zero_plane,
                            float dist,
                            float eye)
     /* Perform the perspective projection for one eye's subfield.
        The projection is in the direction of the negative z axis.

        -6.0, 6.0, -4.8, 4.8,
        left, right, bottom, top = the coordinate range, in the plane of zero
             parallax setting, which will be displayed on the screen.  The
             ratio between (right-left) and (top-bottom) should equal the aspect
             ratio of the display.

  StereoGraphics CrystalEyes Software Development Kit                               Page 60



         6.0, -6.0,
         near, far = the z-coordinate values of the clipping planes.

         0.0,
         zero_plane = the z-coordinate of the plane of zero parallax setting.

         14.5,
         dist = the distance from the center of projection to the plane
             of zero parallax.

         -0.31
         eye = half the eye separation; positive for the right eye subfield,
             negative for the left eye subfield.
     */
     {    float xmid,
           ymid,
           clip_near,
           clip_far,
           topw,
           bottomw,
           leftw,
           rightw,
           dx,
           dy,
           n_over_d;

         dx = right - left;
         dy = top - bottom;

         xmid = (right + left) / 2.0;
         ymid = (top + bottom) / 2.0;

         clip_near = dist + zero_plane - near;
         clip_far  = dist + zero_plane - far;

         n_over_d = clip_near / dist;

         topw = n_over_d * dy / 2.0;
         bottomw = -topw;
         rightw = n_over_d * (dx / 2.0 - eye);
         leftw  = n_over_d *(-dx / 2.0 - eye);

         /* Need to be in projection mode for this. */
         glLoadIdentity();
         glFrustum(leftw,  rightw,  bottomw,  topw,  clip_near,  clip_far);

         glTranslatef(-xmid - eye,  -ymid,  -zero_plane - dist);
     }

     void DrawScene(void)
     {    glDrawBuffer(doubleBuffer ? GL_BACK : GL_FRONT);
         glClearColor(0.0, 0.0, 0.0, 0.0);
         glClear(GL_COLOR_BUFFER_BIT);

         glDrawBuffer(doubleBuffer ? GL_BACK_LEFT : GL_FRONT_LEFT);
         glPushMatrix();
         StereoProjection(-6.0, 6.0, -4.8, 4.8, 6.0, -6.0, 0.0, 14.5, -0.31);
         Plane(yAngle);
         glPopMatrix();

         glDrawBuffer(doubleBuffer ? GL_BACK_RIGHT : GL_FRONT_RIGHT);
         glPushMatrix();
         StereoProjection(-6.0, 6.0, -4.8, 4.8, 6.0, -6.0, 0.0, 14.5, 0.31);
         Plane(yAngle);
         glPopMatrix();
  StereoGraphics CrystalEyes Software Development Kit                            Page 61



         if (doubleBuffer)
           glutSwapBuffers();
         else
           glFlush();

         yAngle -= VELOCITY;
         if (yAngle < 0)
           yAngle = 360.0 + yAngle; /* degrees */
     }

     GLenum Args(int argc, char **argv)
     {    GLint i;
         rgb = GL_TRUE;
         doubleBuffer = GL_TRUE;

         for (i = 1; i < argc; i++) {
           if (strcmp(argv[i], "-ci") == 0) {
               rgb = GL_FALSE;
           } else if (strcmp(argv[i], "-rgb") == 0) {
               rgb = GL_TRUE;
           } else if (strcmp(argv[i], "-sb") == 0) {
               doubleBuffer = GL_FALSE;
           } else if (strcmp(argv[i], "-db") == 0) {
               doubleBuffer = GL_TRUE;
           } else {
               printf("%s (Bad option).\n", argv[i]);
               return GL_FALSE;
           }
         }
         return GL_TRUE;
     }

     main(int argc, char **argv)
     {    GLenum type;
         glutInit(&argc;, argv);
         Args(argc, argv);

         type = GLUT_STEREO;
         type |= (rgb) ? GLUT_RGB : GLUT_INDEX;
         type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE;

         glutInitDisplayMode(type);
         glutInitWindowSize(300, 300);
         glutCreateWindow("Airplane");

         Init();

         glutReshapeFunc(Reshape);
         glutKeyboardFunc(Key);
         glutIdleFunc(DrawScene);
         glutDisplayFunc(DrawScene);
         glutMainLoop();
     }




                                                                Chapter 5

  StereoGraphics CrystalEyes Software Development Kit                Page 62



                                                                                                                 PC

     1.  Introduction

     For this section, a brief overview of the above and below  format is warranted. The above-below method
     uses two subfields arranged above and below each other in a single standard field.  The images in these
     subfields are squeezed top to bottom by a factor of two.

     At the standard 60 fields per second it takes half the duration of an entire field, or 1/120th second, to scan
     a subfield.  When played back on a monitor operating at 120 fields per second, the subfields which had
     been juxtaposed spatially become juxtaposed temporally.  Therefore each eye of the beholder, when
     wearing the proper shuttering eyewear, will see 60 fields of image per second, out of phase with the other
     60 fields prepared for the other eye.  Thus it is possible to see a flicker-free stereoscopic image, because
     each eye is seeing a pattern of images of 1/120th second followed by 1/120th second of darkness.  When
     one eye is seeing an image, the other is not, and vice versa. (The field rate is typically 120, but anything
     somewhat slower or a great deal faster will work fine for many applications.)

     Today there are many models of high-end graphics monitors which will run at field rates of 120 or higher.
     Providing a synchronization pulse is added between the subfields in the subfield blanking area, such a
     monitor will properly display such images.  The monitor can unsqueeze the image in the vertical so the
     picture has the normal proportions and aspect ratio.

     StereoGraphics' synch doubling emitter, the model EPC, for the above-and-below format is available for
     PCs.  It adds the missing synchronization pulses to the vertical blanking for a proper video signal.  The
     EPC unit also displays SimulEyes white-line-code formatted images.  The shutters in the eyewear are
     triggered by the emitter's infra-red signal.

     If the image has high enough resolution to begin with, or - more to the point - enough raster lines, then
     the end result is pleasing.  Below 300 to 350 lines per field the image starts to look coarse on a good sized
     monitor viewed from two feet, and that's about the distance people sit from workstations or PC monitors
     - which sheds light on the basis for why this approach is obsolete for video.  NTSC has 480 active video
     lines.  It uses a two-fold interlace so each field has 240 lines.  Using the subfield technique, the result is
     four 120-line fields for one complete stereoscopic image.

     At the frequently used 1280x1024 resolution an above-and-below formatted image will wind up at about
     1280x500 pixels per eye (some lines are lost to blanking).  Even from the workstation viewing distance of
     two feet, most people would agree that this is good quality.

     Additional details about the above/below stereoscopic format can be found in Chapter 6 of the
     StereoGraphics Developers' Handbook.








  StereoGraphics CrystalEyes Software Development Kit                                                         Page 63



     2. Example Windows NT OpenGL Application

     The C code fragment below is adapted from an OpenGL example "TQUAD.c" provided in the WinNT
     SDK CD-ROM (from Microsoft Corp.). It demonstrates how to display a stereoscopic image pair using the
     above/below format. The complete "TQUAD.c" file is also available from the StereoGraphics web site, as
     well as on the floppy included with hard-copies of this document.

     Since the above/below format uses the available window client area, no special API extensions need to be
     called. This is because the display output is modified externally to the computer, by a device such as
     StereoGraphics' Sync-Doubling Emitter.

     So the application software renders the left and right stereoscopic views onto the single client area as two
     OpenGL viewports. The rendering generates the stereo views in pairs on the same window surface,
     regardless of single- or double-buffered hardware operations by the PC graphics controller.


     <<<<<<<<<<<<<<<<<<<<<<<

     #if STEREO
     #define EYE_OFFSET 0.200 // default viewpoint separation
     #define EYE_ADJUST -0.070 // default horizontal image shift adjustment

     int winWidth, winHeight; // client window
     int winAdjust=30;                // Y height adjustment to "above" viewport

     GLfloat eyeDist=4.5;                     // Z distance for zero parallax setting
     GLfloat eyeOffset=EYE_OFFSET;            // X offset for left/right viewpoint separation
     GLfloat eyeAdjust=EYE_ADJUST;            // X adjustment for horizontal image shift
     #endif

     static void CALLBACK Reshape(int width, int height)
     {#if STEREO
         winWidth = width;
         winHeight = height;

         // viewport and perspective matrixes must be updated every drawn frame
         // to render left and right views in above/below format onto same client window
     #else
         glViewport(0, 0, (GLint)width, (GLint)height);

         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         glFrustum(-1, 1, -1, 1, 1, 10);
         gluLookAt(2, 2, 2, 0, 0, 0, 0, 0, 1);
         glMatrixMode(GL_MODELVIEW);
     #endif
     }

     static void CALLBACK Draw(void)
     {#if STEREO
         // calculate delta-X translation for left or right perspective view
         GLfloat dx0 = eyeAdjust;             // asymmetrical viewing pyramid offset
         GLfloat dx1 = eyeOffset;             // viewpoint separation

         // set "above" viewport for left eye rendering

  StereoGraphics CrystalEyes Software Development Kit                                                     Page 64



         glViewport(0, (GLint)(winHeight/2 + winAdjust), (GLint)winWidth,
     (GLint)(winHeight/2 - winAdjust));

         // set left-eye perspective
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         glFrustum(-1-dx0, 1-dx0, -1, 1, 1, 10); // skew viewer symmetry leftward
         glTranslatef(0+dx1, 0, 0);                      // move rightward for left eye view
         glTranslatef(0, 0, -3);                               // pull back to look at
         glMatrixMode(GL_MODELVIEW);
     #endif // STEREO

         glLoadIdentity();
         glRotatef(xRotation, 1, 0, 0);
         glRotatef(yRotation, 0, 1, 0);
         glRotatef(zRotation, 0, 0, 1);

         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

         glColor3f(1.0, 1.0, 1.0);
         switch (whichQuadric) {
           case 0:
         glTranslatef(0, 0, -height/20.0);
         gluCylinder(quadObj, radius1/10.0, radius2/10.0, height/10.0,
                 slices, stacks);
         break;
           case 1:
         gluSphere(quadObj, radius1/10.0, slices, stacks);
         break;
           case 2:
         gluPartialDisk(quadObj, radius2/10.0, radius1/10.0, slices,
                    stacks, angle1, angle2);
         break;
           case 3:

         gluDisk(quadObj, radius2/10.0, radius1/10.0, slices, stacks);
         break;
         }

     # if STEREO
         // set "below" viewport for right eye rendering
         glViewport(0, 0, (GLint)winWidth, (GLint)(winHeight/2 - winAdjust));

         // set right-eye perspective
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         glFrustum(-1+dx0, 1+dx0, -1, 1, 1, 10); // skew viewer symmetry rightward
         glTranslatef(0-dx1, 0, 0);                      // move leftward for right eye view
         glTranslatef(0, 0, -3);                               // pull back to look at
         glMatrixMode(GL_MODELVIEW);

         // render scene again for right-eye view
         glLoadIdentity();
         glRotatef(xRotation, 1, 0, 0);
         glRotatef(yRotation, 0, 1, 0);
         glRotatef(zRotation, 0, 0, 1);

         glColor3f(1.0, 1.0, 1.0);
         switch (whichQuadric) {
           case 0:
         glTranslatef(0, 0, -height/20.0);
         gluCylinder(quadObj, radius1/10.0, radius2/10.0, height/10.0,
                 slices, stacks);
         break;
           case 1:
  StereoGraphics CrystalEyes Software Development Kit                                           Page 65



         gluSphere(quadObj, radius1/10.0, slices, stacks);
         break;
           case 2:

         gluPartialDisk(quadObj, radius2/10.0, radius1/10.0, slices,
                    stacks, angle1, angle2);
         break;
           case 3:
         gluDisk(quadObj, radius2/10.0, radius1/10.0, slices, stacks);
         break;
         }
     #endif // STEREO

         glFlush();

         if (doubleBuffer) {
         auxSwapBuffers();
         }








































  StereoGraphics CrystalEyes Software Development Kit                     Page 66



     3. OpenGL Stereo Quad Buffering Under Windows NT
     With Windows NT 4.0 and Windows 95 service release 2, Microsoft has provided a software-only version
     of OpenGL with many common rendering functions. 3D graphics accelerator boards include a type of
     extension driver (called a mini client driver, MCD, or installable client driver, ICD) which intercepts the
     OpenGL API calls, and redirects them to the equivalent hardware functions.

     The WIN32 API ChoosePixelFormat() passes a Pixel Format Descriptor for specifying an OpenGL
     rendering context via PDF_ALLOW_OPENGL flag. PDF_STEREO flag may be added to
     PDF_DOUBLEBUFFER to specify that stereo quad buffering is requested. Subsequent calls to WIN32
     APIs wglCreateContext() and wglMakeCurrent() set the stereo display mode, and make GL_STEREO
     quad buffers available for drawing via OpenGL APIs.

     In the OpenGL SDK for Windows NT, Microsoft provides their own toolkit library, GLAUX, which is
     comparable to the GLUT toolkit for X-Windows systems. The GLAUX library source is provided for
     compilation in the \OPENGL\GLAUX subdirectory, and ultimately produces GLAUX.LIB for linking
     with OpenGL example applications. GLAUX provides the system buffer swap function,
     auxSwapBuffers(), which will update stereo pairs if GL_STEREO quad buffering is effective.

     GLAUX also provides a high-level initialization API, auxInitDisplayMode(), for making the above
     sequence of system calls to ChoosePixelFormat(), etc, for a Windows display context. Since Microsoft did
     not include stereo support in NT 4.0's software-only OpenGL library, an AUX_STEREO flag needs to be
     assigned to complement AUX_DOUBLEBUFFER. This is done in the modified TK.C toolkit source for
     compiling GLAUX.LIB, and utilized in the modified TQUAD.C example.

     The modified TQUAD.C example may be used for either above/below format stereo on any graphics card,
     or GL_STEREO quad buffering on stereo-ready graphics cards. Below are code fragments for highlighting
     stereo quad buffer support. The complete listing of the modified TQUAD.C example file is posted at:
     ftp.stereographics.com/developers/tquad.zip
     You must have installed the Microsoft OpenGL SDK for Windows NT in order to use these modified files
     to build this example.

    // at initialization:

    // specify a display format to be passed to GLAUX toolkit library
    type = AUX_DEPTH16;
    type |= (rgb) ? AUX_RGB : AUX_INDEX;
    type |= (doubleBuffer) ? AUX_DOUBLE : AUX_SINGLE;

    // pass additional STEREO flag to GLAUX toolkit
    if (stereoQuadBuffer)
        type |= AUX_STEREO;

    // enable stereo quad-buffer display modes through GLAUX
    auxInitDisplayMode(type);

    auxInitWindow("Stereoscopic Viewport Test");
    //...

    // in callback routine for main event loop:

    // calculate delta-X translation for left or right perspective view
    GLfloat dx0 = eyeAdjust; // asymmetrical viewing pyramid offset
    GLfloat dx1 = eyeOffset; // viewpoint separation

    // set back buffer for left eye rendering
  StereoGraphics CrystalEyes Software Development Kit                                                     Page 67



    glDrawBuffer(GL_BACK_LEFT);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // set left-eye perspective
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1-dx0, 1-dx0, -1, 1, 1, 10);                    // skew viewer symmetry leftward
    glTranslatef(0+dx1, 0, 0);                           // move rightward for left eye view

    // render objects in scene for left-eye view
    glMatrixMode(GL_MODELVIEW);
    // ...
    glFlush();

    // set back buffer for right eye rendering
    glDrawBuffer(GL_BACK_RIGHT);
    // clear separate draw buffer for right eye rendering
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // set right-eye perspective
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1+dx0, 1+dx0, -1, 1, 1, 10);                    // skew viewer symmetry rightward
    glTranslatef(0-dx1, 0, 0);                           // move leftward for right eye view

    // render scene again for right-eye view
    glMatrixMode(GL_MODELVIEW);
    // ...
    glFlush();

    // update stereo pair just rendered
    auxSwapBuffers();





























  StereoGraphics CrystalEyes Software Development Kit                                               Page 68



     4. Example OpenGL Application for Diamond Multimedia
         Systems' FireGL 4000 Graphics Board

     The FireGL 4000 3D graphics board from Diamond Multimedia Systems is equipped with internal sync
     doubling circuitry. This provides a convenient technique for supporting stereoscopic applications which
     already use the popular "above/below" display format.

     Since the sync-doubler is already built-in, no additional accessories are necessary to plug in-between the
     graphics board and the monitor connector.

     Stereoscopic eyewear plug directly in to the mini-DIN3 stereo sync connector, which has been proposed as
     VESA standard. The user has the choice of plugging in the IR emitter for wireless CrystalEyes eyewear, or
     the direct-drive wired SimulEyes eyewear.

     Additionally, the function of toggling sync-doubled stereoscopic display on and off is under control of
     software. Unlike the external sync-doubling emitter accessory, the user does not need to press a manual
     button to enable or disable the sync-doubled stereoscopic display. Instead the application can make the
     equivalent driver function calls to enable or disable stereoscopic display according to the appropriate
     stereoscopic or monoscopic display context.

     In order to make such hardware-specific function calls to the stereo-ready FireGL 4000, the application
     makes use of the OpenGL QueryExtension API mechanism for searching for extension APIs. The same
     scheme is initially used to detect and identify that a FireGL 4000 is installed in the system, so that the
     application can make use of the stereoscopic hardware capabilities.

     Listed below is a C code fragment utilizing the FireGL 4000's stereoscopic extension APIs for the
     preceding OpenGL example "TQUAD.C". The complete example which has been modified and provided
     by Diamond Multimedia Systems is also included on the CrystalEyes SDK disk or via the StereoGraphics'
     web site.

     /************************************************************************
      *      Copyright (C) 1997               Diamond Multimedia Systems, Inc.        *
      ************************************************************************/

     #define DIMD_STEREO_EXTENSION                       "GL_EXT_dimd_stereo"
     #define GLQUERYSTEREOEXTPROC                        "glQueryStereoEXT"
     #define GLSETSTEREOMODEEXTPROC                      "glSetStereoModeEXT"
     #define GLENABLESTEREOEXTPROC                       "glEnableStereoEXT"
     #define GLDISABLESTEREOEXTPROC                      "glDisableStereoEXT"
     #define GLDISPLAYSTEREOSUPPORTEXTPROC "glDisplayStereoSupportEXT"

     #define STEREO_QUAD_BUFFER                          1     //    Currently not supported
     #define STEREO_ABOVE_BELOW                          2     //    Currently supported by FIRE 4000,
                                              //         1280x1024 True Colour 60Hz

     typedef struct tagStereoDisplayContext {
       GLuint uiSize;                 // Must be set to sizeof(STEREODISPLAYCONTEXT).
       GLuint uiWinWidth;             // Width of window (== width of screen) in pixel is returned.
       GLuint uiWinHeight;            // Height of window (== height of screen) in pixel is returned.
       GLuint uiWinAdjust;            // Window adjustment between "above" and "below" is returned.
     } STEREODISPLAYCONTEXT, *PSTEREODISPLAYCONTEXT;

     // Note: All functions return GL_TRUE in case of success.

  StereoGraphics CrystalEyes Software Development Kit                                                       Page 69



     typedef GLboolean (APIENTRY * PFNGLQUERYSTEREOEXTPROC)(GLenum stereoCap);
     typedef GLboolean (APIENTRY * PFNGLSETSTEREOMODEEXTPROC)(GLenum stereoMode,
     PSTEREODISPLAYCONTEXT stereoDisplayContext);
     typedef GLboolean (APIENTRY * PFNGLENABLESTEREOEXTPROC)(void);
     typedef GLboolean (APIENTRY * PFNGLDISABLESTEREOEXTPROC)(void);
     typedef GLboolean (APIENTRY * PFNGLDISPLAYSTEREOSUPPORTEXTPROC)(GLuint uiWidth, GLuint
     uiHeight, GLuint uiBitsPerPixel, GLuint uiVFrequency);

     // Example:
     //
     //        ...
     //        "Create full-screen window without border"
     //        ...

       // Try to enable stereo mode
       LPCSTR lpszExtentions = glGetString(GL_EXTENSIONS);
       if (strstr(glGetString(GL_EXTENSIONS), DIMD_STEREO_EXTENSION)) {
               PFNGLQUERYSTEREOEXTPROC pfnStereoQuery =
     (PFNGLQUERYSTEREOEXTPROC)wglGetProcAddress(GLQUERYSTEREOEXTPROC);
               PFNGLSETSTEREOMODEEXTPROC pfnStereoSet =
     (PFNGLSETSTEREOMODEEXTPROC)wglGetProcAddress(GLSETSTEREOMODEEXTPROC);
               PFNGLENABLESTEREOEXTPROC  pfnStereoEnable =
     (PFNGLENABLESTEREOEXTPROC)wglGetProcAddress(GLENABLESTEREOEXTPROC);
               if (pfnStereoQuery && pfnStereoSet && pfnStereoEnable) {
                       if ((* pfnStereoQuery)(STEREO_ABOVE_BELOW) == GL_TRUE) {
                              STEREODISPLAYCONTEXT context;
                              context.uiSize = sizeof(STEREODISPLAYCONTEXT);
                              if ((* pfnStereoSet)(STEREO_ABOVE_BELOW, &context)) {
                                      winWidth = context.uiWinWidth;
                                      winHeight = context.uiWinHeight;
                                      winAdjust = context.uiWinAdjust;
                                      if ((* pfnStereoEnable)())
                                              stereoEnabled = TRUE;
                              }
                       }if (!stereoEnabled) { // Find out on which videomode(s) stereo is
     supported.
                              PFNGLDISPLAYSTEREOSUPPORTEXTPROC pfnDisplayStereoSupport =
     (PFNGLDISPLAYSTEREOSUPPORTEXTPROC)wglGetProcAddress(GLDISPLAYSTEREOSUPPORTEXTPROC);
                              if (pfnDisplayStereoSupport) {
                                      DWORD dwMode = 0;
                                      CHAR szMsg[2048];

                                      lstrcpy(szMsg, "Stereo is only supported in the following
     videomode(s):\n");
                                      while (TRUE) {
                                              if (EnumDisplaySettings(NULL, dwMode++, &devMode) == FALSE)
                                                         break;
                                              if ((* pfnDisplayStereoSupport)(
                                                                   devMode.dmPelsWidth,
                                                                   devMode.dmPelsHeight,
                                                                   devMode.dmBitsPerPel,
                                                                   devMode.dmDisplayFrequency)) {
                                                         wsprintf(
                                                                   szMsg + lstrlen(szMsg),
                                                                   "\t%4dx%4dx%2d, %3d Hz\n",
                                                                   devMode.dmPelsWidth,
                                                                   devMode.dmPelsHeight,
                                                                   devMode.dmBitsPerPel,
                                                                   devMode.dmDisplayFrequency
                                                         );
                                              }
                                      }MessageBox(hWnd, szMsg, "TQUAD", MB_OK | MB_ICONEXCLAMATION);
                                      DestroyWindow(hWnd);
                                      return 1;
                              }
  StereoGraphics CrystalEyes Software Development Kit                                                Page 70



                       }}
       }
               if (!stereoEnabled) {          // No stereo support at all.
               MessageBox(NULL, "Stereo not supported", "TQUAD", MB_OK | MB_ICONEXCLAMATION);
               DestroyWindow(hWnd);
               return 1;
       }

       ...
       // set "above" viewport for left eye rendering
       glViewport(0, winHeight / 2 + winAdjust, winWidth, winHeight / 2 - winAdjust);

       ...

       // set "below" viewport for right eye rendering
       glViewport(0, 0, winWidth, winHeight / 2 - winAdjust);

       ...

       // Disable stereo mode
       if (stereoEnabled) {
               PFNGLENABLESTEREOEXTPROC pfnStereoDisable =
     (PFNGLDISABLESTEREOEXTPROC)wglGetProcAddress(GLDISABLESTEREOEXTPROC);
               if (pfnStereoDisable) {
                       if ((* pfnStereoDisable)())
                              stereoEnabled = FALSE;
               }
       }

       ...






























  StereoGraphics CrystalEyes Software Development Kit                                 Page 71



     5. Creating Stereoscopic Renderings Using Kinetix 3D Studio
         Products and Autodesk Animator Pro

     INTRODUCTION

     Kinetix 3D Studio products, with Autodesk Animator Pro (any version), can be used to render
     stereoscopic 3D images and animations.  Unlike conventional planar renderings, stereoscopic 3D images
     convey a natural sense of depth.  This sense of true depth can be used to better captivate the viewer in a
     presentation setting, or to enhance the viewer's ability to perceive 3D information in an analytical setting.

     Creating a stereoscopic image, that is compatible with StereoGraphics CrystalEyes stereo viewing
     hardware, requires two steps:

         1)  The creation of a geometrically correct "stereo pair," consisting of a rendering for the left eye, and
       a rendering for the right eye; and,

         2)  A combining of these elements into a single image, viewported according to the requirements of the
       StereoGraphics "above/below" stereo format.

     In this two-step process, 3D Studio performs the first step of creating the stereo pair, and Animator Pro
     does the second step of merging the stereo components.
























  StereoGraphics CrystalEyes Software Development Kit                                                         Page 72



     CRYSTALEYES STEREO: HOW IT WORKS

     StereoGraphics CrystalEyes liquid crystal eyewear works by shuttering the left and right eye lenses very
     rapidly (60 to 72 times per second per eye), so fast that there is no perceptible "flicker."  The glasses are
     synchronized by an infrared signal, sent by an infrared emitter that is plugged into a StereoGraphics
     controller (PC SDE or GDC-3) or a stereo-ready graphics board.

     The StereoGraphics controller works by driving the stereo-ready display at double the normal vertical
     synchronization rate. It feeds off of the graphics board's sync signal, to drive both the display and the
     glasses.  Here is the effect of this double sync pulse, as coordinated by StereoGraphics hardware:
     Whatever the graphics board sends to the top half of the display will be seen, full-screen, by the left eye;
     whatever the graphics board sends to the bottom half of the display will appear, full-screen, by the right
     eye.

     There is one additional detail.  These two "halves" of the display must be separated by a black "blank
     interval," of about 40 to 44 pixel rows.  This blank interval allows the display's electron beam time to
     return to the top of the display.

     Thus, to be compatible with StereoGraphics PC hardware, a computer graphics image or animation must
     draw a left eye component to the top half of the display, and a right eye component to the bottom half of
     the display.  Of course, how the result looks depends on what kind of image you send to each eye.


























  StereoGraphics CrystalEyes Software Development Kit                                                        Page 73



     STEP 1: MAKING A STEREO PAIR

     Before creating stereo pairs of a still picture or an animation, you must produce a high quality "non-stereo"
     rendered image or animation.  Feel free to use all available tools and techniques that would apply if the
     non-stereo rendering was your final goal, with the following exceptions:

         *  In general, unless you are rendering 24-bit images, avoid gradient backgrounds, spot lighting, and
     other effects that might create unequal gradient bands between left and right eye stereo pair components.
     The "Dither 256" system option can eliminate mismatched banding, though this will greatly cut animation
     performance.

         *  Generally, stereo images look best if a relatively wide field of view angle, such as 50 degrees, is used.
     Other field of view angles can be used, however.

         *  Camera Roll complicates matters.  Keep your Roll adjustment at 0, if you can.

     Once you have a rendering that you are happy with, you must clone the camera that the rendering was
     based on.  Before doing this, enter the 3D Editor, and examine the camera-target vector. Normally, the
     length of the camera-target vector does not matter; only its 3D direction (and the camera's 3D position)
     matters. Now, we want to position the target at a particular distance, such that objects close to the target
     point will appear, stereoscopically, to rest at the surface of the display.  This may involve repositioning the
     target point either closer or farther from the camera point.  You want the target point to rest near the
     "center of interest" of the 3D scene.

     There is one more thing that also should be done before cloning the camera.  Because the stereo pair
     elements will need extra width to facilitate alignment, use Camera/Adjust to widen the field of view angle
     by about 20%, for example, from 50* to about 60*.

     Now that the camera-target distance is meaningful, measure it.  To do this, select the camera view as the
     active viewport. Then, without touching the mouse, press the 'U' key, immediately followed by the
     <Enter> key.  Click the Camera menu item to show the camera and target, if it is not already shown.  The
     active viewport is now a User viewport, and you are looking straight down the camera-target vector.  Next,
     rotate the viewport 90*, by pressing the <up-arrow> key nine times (you may want to be in block mode
     when you do this).  Change the extents of the viewport so that the entire camera-target vector is visible.
     You should now be looking at the camera-target vector from a direction perpendicular to that vector.  You
     can now measure it, using Display/Tape/Find and Display/Tape/Move.  Make a note of the distance.
     Multiply this distance by 0.06.  The resulting value is the interaxial separation, the desired separation
     between the camera-target vector corresponding to the left eye's view, and the camera-target vector
     corresponding to the right eye's view.

     Return to the User view down the camera-target vector, by pressing the <down-arrow> key nine times.
     You might want to zoom your viewport view now.  You are now ready to clone the camera-target vector
     into both a left and right camera-target vector. Use Display/Tape/Find and Display/Tape/Move to show
     half the interaxial separation value determined above.  While holding down both the <ctrl> and <shift>
     keys, select the Camera/Move menu item.  Use the <tab> key until the horizontal-lock icon shows. Click
     the camera, and create a cloned camera-target vector to the left of the originalcamera.  Then create another
     clone to the right of the original. These cameras should be named appropriately ("LeftCam" and
     "RightCam," for example).

  StereoGraphics CrystalEyes Software Development Kit                                                        Page 74



     If you are creating an animation in which the cameras move and/or if you are using a non-zero Camera
     Roll value, you will want to go into the Keyframe Animator, and create a Dummy Object, which is created
     while looking down the camera-target vector, and which is centered about the target of the original
     camera.  The Cameras and Targets of both the left and right cameras (but not the original camera) should
     be linked to this dummy object.  Now, the left and right cameras can be moved as though they were
     mounted to a solid bar.

     Unfortunately, you cannot link this Dummy Object as a child of the original camera.  Thus, in order for the
     Dummy Object, with its two cameras attached, to follow the path of the original camera, you must go to
     each frame with a Camera and/or Target Key, and move, and reorient, the Dummy Object until the stereo
     cameras' paths roughly agree with the original camera's path (there may be a simpler way to do this; let me
     know if you find one).  In all frames, the left and right cameras must remain horizontally level, relative to
     each other (unless non-zero Camera Roll is used, in which case, the cameras must remain at that Roll
     angle, relative to each other).  You may rotate the Dummy Object about its z axis to level the cameras
     properly.  The Dummy Object can also be scaled, along one or more axes at once, in order to change
     interaxial separation, and/or "Dolly" the cameras.

     It is almost time to render for the left and right camera views.  But first, we need to change the render
     configuration. In order to do this, we must think about how the stereo pair components will be viewported.
     The stereo image or animation must be full-screen, since the entire display must be run at a stereo sync
     rate.  The left eye component will be viewported to the top half of the display, and the right eye component
     will be viewported to the bottom half.  These two fields will be separated by a "blank interval" of 40
     (1024x768 and higher resolutions, typically) to 44 (640x480 resolution, typically) scan lines, which must
     be black.  Also recall that we are rendering for a 20% wider field of view than we intend to use. Thus, we
     want to render, to disk, at a horizontal resolution that is 1.2 times the horizontal resolution of the final
     image, and at a vertical resolution that is a bit less than half (you should calculate exactly using the
     numbers above) of the final resolution.  In addition, an aspect ratio of about 0.5 should be used.  This may
     change the camera view somewhat; use the Safe Frame option to check camera placement before
     rendering.

     Finally, render for both left and right cameras.  Render to files that are appropriately named, including a
     designation for which camera was used (i.e.: SceneL.gif and SceneR.gif).  If you are producing an
     animation, it would probably be wise to first render individual frames, particularly those with Keys
     involving the cameras and/or the Dummy Object holding the cameras.















  StereoGraphics CrystalEyes Software Development Kit                                                            Page 75



     STEP 2: PUTTING THE STEREO COMPONENTS TOGETHER

     We now have two stereo pair elements, one with a left eye view, the other with a right eye view.  Both of
     these elements are bitmap files, each with a vertically squashed aspect ratio, which is appropriate for
     putting together stereo images in the StereoGraphics "above/below" format.  Using Autodesk Animator
     Pro, we can combine these stereo pair elements.

     Upon starting Animator Pro, make sure that the resolution is set to agree with the resolution of the image
     or animation that you are about to create.  Then, open a new full-screen flic.  If you are creating an
     animation, set Total Frames to agree with the number of frames in the animation that you are about to
     make.

     To create a single frame image, you will load the two image files as Cels.  Load the left camera's rendering
     first.  As you load the Cel, the image will briefly flash on the display.  To position the Cel, you must Paste
     it (Cel/Paste).  Recall that we rendered a wider scene than we intend to use.  In the left camera rendering,
     we will want to chop off more of the left edge (about 15% of display resolution) than the right edge (about
     5%), and in the right camera rendering, we will want to chop off more of the right edge than the left edge.
     Thus, the left camera's Cel should be moved to the left by about 15% of the horizontal resolution, without
     any vertical displacement whatsoever.  Once this is fixed in place, load the right camera's rendering as a
     Cel, and Paste that to the lower half of the display.  At this point, it would be helpful to activate stereo
     display mode, so that you can interactively perfect the vertical and horizontal alignment.  The vertical
     alignment must be exact.  The horizontal alignment should be set such that some image elements appear to
     come out of the display ("negative parallax"), and other image elements appear to go into the display
     ("positive parallax"). Once the image looks good, store it as a single image file.

     To create a stereo animation from two rendered flics, use the Flic/Composite feature.  As with the single
     frame method described above, composite the left camera's rendering first. Select Overlay Opaque, in
     response to the Composite operation's first prompt.  Position the first frame appropriately, with no vertical
     displacement, and with a left-ward horizontal displacement equal to about 15% of the horizontal
     resolution. When prompted about palette, select "Use Incoming Colors."  Once this Composite operation
     is done, make sure that you are back at the first frame of the flic, and Composite the right camera's
     rendering to the bottom half of the display.  Activate the stereo display, and position the flic frame so that
     vertical alignment is perfect, and horizontal alignment looks good.  When prompted about palette, select
     "Combine Color Maps."  You can now save the combined animation as a single .FLC file.














  StereoGraphics CrystalEyes Software Development Kit                                                          Page 76



     REPEAT UNTIL SUCCESSFUL

     As with non-stereoscopic renderings and animations, stereo renderings and animations will rarely be
     perfect on the first try.  After your first effort, you will likely want to alter the camera positioning, the
     interaxial separation, the positive parallax / negative parallax balance, and probably several other things
     that are not particular to stereo.  With practice, you will become more proficient at the techniques of
     producing stereoscopic renderings.  In addition, you will develop a sense of stereo aesthetic.  With practice
     and experimentation, you will be able to produce stunning stereoscopic imagery, with true 3D depth.





































  StereoGraphics CrystalEyes Software Development Kit                                                          Page 77



  StereoGraphics CrystalEyes Software Development Kit    Page 78



                                                                                         Chapter 6
                                                                                                           HP

     1. Introduction
     This document describes the configuration necessary to support stereo display on a Hewlett-Packard
     workstation, including:

     *      Supported graphics cards
     *      Supported monitors
     *      Enabling stereo support


































  StereoGraphics CrystalEyes Software Development Kit                                                 Page 79



     2. Supported Graphics Cards
     Stereoscopic display is directly supported on Hewlett-Packard VISUALIZE fx4 and fx6 graphics boards.

     Stereoscopic display is also supported on VISUALIZE 48-XP graphics cards, though stereo support may
     have to be enabled via onboard jumpers. Likewise there are some older Visualize 8 and Visualize 24 cards
     that allow stereo, however, stereo display is no longer a supported configuration for these cards. Contact
     Hewlett-Packard for specific jumper specifications on these VISUALIZE series graphics boards.





































  StereoGraphics CrystalEyes Software Development Kit                                                    Page 80



     3. Supported Monitors
     All of the following HP workstation monitors support the vertical rates required for stereo operation, and
     will need cables as noted to support this.  Host controllers using the 15-pin D output connector must also
     be specially configured for stereo operation, which will usually require both selecting a sync-on-green
     stereo timing mode AND moving jumpers to enable the stereo sync output.

     Monitors not listed below cannot be used in stereo mode due to limited vertical frequency range.

      Monitor                           Use with EVC host                  Use with 15-pin D host

      A4032A/B                          Use 15-pin to BNC cable assy       Use EVC-to-15p stereo breakout,
      (17" Color)                       connect to RGB monitor inputs      then 15-pin adapter with to BNC
                                        ONLY; use H or V cable for         cable assembly.  Sep syncs may be
                                        external stereo hardware.          connected at monitor if desired.

      A4330A/B                          Select BNC inputs on monitor       Use EVC-to-15p adapter cable
      (17" color)                       and connect to RGB inputs via      w/stereo breakout.
                                        15-pin to BNC cable assy.,
                                        using H or V cable for stereo
                                        hardware.
      A4033A/B                          As for A4032A/B above.             As for A4032A/B above.
      (20" color)


      A4331A/B                          Use 15-pin to 15-pin cable with    Use EVC-to-15p adapter cable
      (20" color)                       H&V lines broken out. (avail.      w/stereo breakout.
                                        from StereoGraphics)
      A4332A/B                          No stereo solution available *     Use EVC-to-EVC video cable with
      (21" color)                                                          stereo breakout.






     * The A4332A/B is intended to support 1600 x 1200, and no graphics controllers with 15-pin D outputs support this
     mode.  The A4332A/B does support 1280 x 1024 and lower operation, and with proper adapters may be used with 15-pin
     D outputs, but there is no such adapter available with a stereo breakout line. The recommended monitor for stereo on
     these systems would be the current A4331A/B or the previous A4033A/B, used as described above.














  StereoGraphics CrystalEyes Software Development Kit                                                                Page 81



     4. Enabling Stereo Support
     There is a hardware jumper that must be set to enable stereo support.  Please refer to the graphics card installation and
     configuration guide for the exact location.

     The HP VISUALIZE fx4 and fx6 graphics boards support OpenGL, including the GL_STEREO quad
     buffering specification. The VISUALIZE 48 and earlier graphics boards only support HP's Starbase
     operating system. Stereoscopic display would only be enabled via system setmon command.

     The HP implementation of OpenGL includes GLX and GLUT libraries for X-Windows. The application programmer can
     request a stereoscopic display mode by adding GLUT_STEREO flag to glutInitDisplayMode(), or the equivalent
     sequence of calls with GLX_STEREO flag for glXChooseVisual().

     Refer to the GLUT example described in the DEC OpenGL implementation.





































  StereoGraphics CrystalEyes Software Development Kit                                                                    Page 82