home *** CD-ROM | disk | FTP | other *** search
/ More Insanity: Totally Insane 2 / totally_insane_ii.iso / src / BackingStore / backingstore.c next >
Encoding:
C/C++ Source or Header  |  1997-05-29  |  11.0 KB  |  454 lines

  1. /****************************************************************************
  2. Copyright 1995 by Silicon Graphics Incorporated, Mountain View, California.
  3.  
  4.                         All Rights Reserved
  5.  
  6. Permission to use, copy, modify, and distribute this software and its 
  7. documentation for any purpose and without fee is hereby granted, 
  8. provided that the above copyright notice appear in all copies and that
  9. both that copyright notice and this permission notice appear in 
  10. supporting documentation, and that the name of Silicon Graphics not be
  11. used in advertising or publicity pertaining to distribution of the
  12. software without specific, written prior permission.  
  13.  
  14. SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17. CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  18. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19. OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20. PERFORMANCE OF THIS SOFTWARE.
  21.  
  22. ****************************************************************************/
  23.  
  24. /*
  25.  *  Roger Corron
  26.  *  May 1997
  27.  *
  28.  *      Use a pbuffer to provide backing store. This requires the following
  29.  *    extensions:
  30.  *
  31.  *    SGI_make_current_read
  32.  *    SGIX_fbconfig
  33.  *    SGIX_pbuffer
  34.  *
  35.  *    This example draws cubes with hidden lines removed. An optional delay
  36.  *    of one clock clock tick per cube face make the difference between
  37.  *    normal drawing and pbuffer exposure handling more obvious.
  38.  *
  39.  *      Depress the 'd' key to toggle drawing delay. It is initially on.
  40.  *    Depress the 'h' keyy to toggle hidden line removal. It is initially
  41.  *    off.
  42.  *    Depress the escape key to exit.
  43.  */
  44.  
  45. #include <GL/gl.h>
  46. #include <GL/glu.h>
  47. #include <GL/glx.h>
  48. #include <X11/keysym.h>
  49. #include <stdlib.h>
  50. #include <stdio.h>
  51. #include <string.h>
  52.  
  53. #define MAXQUAD 6
  54.  
  55. typedef GLfloat Vertex[4];
  56. typedef Vertex Quad[4];
  57.  
  58. /* data to define the six faces of a cube */
  59. static Quad quads[MAXQUAD] = {
  60.     0,0,0,1, 1,0,0,1, 1,1,0,1, 0,1,0,1,
  61.     0,0,1,1, 1,0,1,1, 1,1,1,1, 0,1,1,1,
  62.     0,0,0,1, 1,0,0,1, 1,0,1,1, 0,0,1,1,
  63.     0,1,0,1, 1,1,0,1, 1,1,1,1, 0,1,1,1,
  64.     0,0,0,1, 0,0,1,1, 0,1,1,1, 0,1,0,1,
  65.     1,0,0,1, 1,0,1,1, 1,1,1,1, 1,1,0,1
  66. };
  67.  
  68. static void fill(Quad quad);
  69. static void outline(Quad quad);
  70. static void drawhidden(Quad quad);
  71. static void process_input(Display *dpy, Window win);
  72.  
  73. static int dimension = 5;
  74. static GLboolean offset = GL_TRUE;
  75. static GLboolean hidden = GL_FALSE;
  76.  
  77. static int attributeList[] = { GLX_RGBA,
  78.                    GLX_DEPTH_SIZE, 1,
  79.                    GLX_RED_SIZE, 1,
  80.                    GLX_GREEN_SIZE, 1,
  81.                    GLX_BLUE_SIZE, 1,
  82.                    None };
  83.  
  84. static int pbuffer_fb_attributes[] =  
  85. { GLX_DRAWABLE_TYPE_SGIX, GLX_PBUFFER_BIT_SGIX | GLX_WINDOW_BIT_SGIX,
  86.   GLX_RENDER_TYPE_SGIX,      GLX_RGBA_BIT_SGIX,
  87.   GLX_DOUBLEBUFFER,       False,
  88.   GLX_RED_SIZE,          1,
  89.   GLX_GREEN_SIZE,      1,
  90.   GLX_BLUE_SIZE,      1,
  91.   GLX_DEPTH_SIZE,      1,
  92.   GLX_X_VISUAL_TYPE_EXT,  GLX_TRUE_COLOR_EXT,
  93.   None };
  94.  
  95. static int pbuffer_attributes[] =
  96. {GLX_PRESERVED_CONTENTS_SGIX, True,
  97.  None };
  98.  
  99. static GLXContext cx, win_cx;
  100. static GLXPbufferSGIX pbuffer;
  101. static Display *dpy;
  102. static Window win;
  103. static int width = 500 , height = 500;
  104. static Bool delay = True;
  105.  
  106. int main(int argc, char** argv) {
  107.     XVisualInfo *vi;
  108.     XSetWindowAttributes swa;
  109.     int list_length;
  110.     int visual_red_size, FBconfig_red_size;
  111.     GLXFBConfigSGIX *configs, pbuffer_cfg;
  112.     int i;
  113.     Bool status;
  114.  
  115.     dpy = XOpenDisplay(0);
  116.  
  117.     if (!(vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList))) {
  118.     fprintf(stderr, "backingstore: no suitable RGB visual available\n");
  119.     exit(EXIT_FAILURE);
  120.     }
  121.  
  122.     win_cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
  123.  
  124.     swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
  125.                                    vi->visual, AllocNone);
  126.  
  127.     swa.border_pixel = 0;
  128.     swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
  129.     ButtonPressMask | ButtonReleaseMask | ButtonMotionMask ;
  130.     win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, width, height,
  131.             0, vi->depth, InputOutput, vi->visual,
  132.             CWBorderPixel|CWColormap|CWEventMask, &swa);
  133.     XStoreName(dpy, win, "Backing Store");
  134.     XMapWindow(dpy, win);
  135.  
  136.     glXMakeCurrent(dpy, win, win_cx);
  137.  
  138.     /* check for required capabilities. We need pbuffers, fbconfig, and
  139.        make_current_read for backing store, and polygon offset for hidden
  140.        line removal.
  141.     */
  142.  
  143.     if (!strstr(glGetString(GL_EXTENSIONS), "polygon_offset")) {
  144.     fprintf(stderr,
  145.         "backingstore: PolygonOffset extension not available.  Abort\n");
  146.     exit(EXIT_FAILURE);
  147.     }
  148.  
  149.     if (!strstr(glXQueryExtensionsString(dpy,DefaultScreen(dpy)), "pbuffer")) {
  150.     fprintf(stderr,
  151.         "backingstore: Pbuffer extension not available.  Abort\n");
  152.     exit(EXIT_FAILURE);
  153.     }
  154.  
  155.     if (!strstr(glXQueryExtensionsString(dpy,DefaultScreen(dpy)), "fbconfig")) {
  156.     fprintf(stderr,
  157.         "backingstore: FBconfig extension not available.  Abort\n");
  158.     exit(EXIT_FAILURE);
  159.     }
  160.  
  161.     if (!strstr(glXQueryExtensionsString(dpy,DefaultScreen(dpy)), "make_current_read")) {
  162.     fprintf(stderr,
  163.         "backingstore: make_current_read extension not available.  Abort\n");
  164.     exit(EXIT_FAILURE);
  165.     }
  166.  
  167.     /*  In the window context:
  168.   
  169.       1. Set the appropriate orthographic projection for easy specification
  170.          of the raster position.
  171.       2. Turn off dithering so images will not be dithered twice.
  172.       3. Set the read buffer to GL_FRONT.
  173.       4. Set the draw buffer to GL_FRONT.
  174.  
  175.     */
  176.  
  177.     glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
  178.     glDisable(GL_DITHER);
  179.     glReadBuffer(GL_FRONT);
  180.     glDrawBuffer(GL_FRONT);
  181.  
  182.     /* Set up the pbuffer */
  183.  
  184.     /* get the available frame buffer configurations    */
  185.  
  186.     configs = glXChooseFBConfigSGIX(dpy,
  187.                     DefaultScreen(dpy),
  188.                     pbuffer_fb_attributes,
  189.                     &list_length);
  190.     if (configs == NULL) {
  191.       fprintf(stderr,
  192.           "backingstore: There are no suitable frame buffer configurations. Abort.\n");
  193.       exit(EXIT_FAILURE);
  194.     }
  195.  
  196.     /*  Now that we have a list of configs that meet minimum requirements,
  197.     select one that matches the color depth of the window's visual.
  198.     We check the red size only.
  199.     */
  200.  
  201.     (void) glXGetConfig(dpy,
  202.             vi,
  203.             GLX_RED_SIZE,
  204.             &visual_red_size);
  205.  
  206.     for ( i = 0 ; i < list_length; i++) {
  207.       (void) glXGetFBConfigAttribSGIX(dpy,
  208.                       configs[i],
  209.                       GLX_RED_SIZE,
  210.                       &FBconfig_red_size);
  211.  
  212.       if (FBconfig_red_size == visual_red_size) {
  213.     break;
  214.       }
  215.  
  216.     }
  217.     if (i < list_length) {
  218.       pbuffer_cfg = configs[i];
  219.       XFree(configs);
  220.     }
  221.     else {
  222.       fprintf(stderr,
  223.          "backingstore: could not find a FBconfig that matches the window visual. Abort.\n");
  224.       exit(EXIT_FAILURE);
  225.     }
  226.  
  227.     /* create the pbuffer */
  228.     pbuffer = glXCreateGLXPbufferSGIX(dpy,
  229.                       pbuffer_cfg,
  230.                       width,
  231.                       height,
  232.                       pbuffer_attributes);
  233.  
  234.     if (pbuffer == None) {
  235.       fprintf(stderr, "backingstore: couldn't create pbuffer. Abort.\n");
  236.       exit(EXIT_FAILURE);
  237.     }
  238.  
  239.     cx = glXCreateContextWithConfigSGIX(dpy,
  240.                     pbuffer_cfg,
  241.                     GLX_RGBA_TYPE_SGIX,
  242.                     NULL,
  243.                     GL_TRUE);
  244.  
  245.     if (cx == NULL) {
  246.       fprintf(stderr,
  247.           "backingstore: could not create an OpenGL context for the pbuffer\n");
  248.       exit(EXIT_FAILURE);
  249.     }  
  250.     
  251.     /* In the pbuffer context: */
  252.  
  253.     status = glXMakeCurrent (dpy, pbuffer, cx);
  254.  
  255.     /* initialize graphics */
  256.  
  257.     glMatrixMode(GL_PROJECTION);
  258.     glLoadIdentity();
  259.     gluPerspective(90.0, 1.0, 0.5, 5.0);
  260.     glMatrixMode(GL_MODELVIEW);
  261.     glLoadIdentity();
  262.     glTranslatef(0.0, 0.0, -1.5);
  263.     glClearColor(0.0, 0.0, 0.0, 0.0);
  264.  
  265.     glEnable(GL_DEPTH_TEST);
  266.     glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
  267.     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  268.  
  269.     /* Enable polygon offset by default */
  270.  
  271.     glPolygonOffsetEXT(1.0, 0.0);
  272.     glEnable(GL_POLYGON_OFFSET_EXT);
  273.  
  274.     /* read arguments */
  275.     if (argc > 1)
  276.     dimension = atoi(argv[1]);
  277.     printf("dimension = %d\n", dimension);
  278.  
  279.     /* loop drawing the cube */
  280.  
  281.     process_input(dpy, win);
  282. }
  283. static void flush()
  284. {
  285.     glFlush();
  286.     glXMakeCurrentReadSGI(dpy,
  287.               win,
  288.               pbuffer,
  289.               win_cx);
  290.  
  291.     glRasterPos2i(-1, -1);
  292.  
  293.     glCopyPixels(0,
  294.          0, 
  295.          width,
  296.          height,
  297.          GL_COLOR);
  298.  
  299.     glXMakeCurrent(dpy, pbuffer, cx);
  300. }
  301. static void draw_scene(int mx, int my)
  302. {
  303.     int x, y, z, i;
  304.  
  305.     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  306.  
  307.     glPushMatrix();
  308.  
  309.     /* track the mouse */
  310.     glRotatef(0.5 * mx, 0.0, 1.0, 0.0);
  311.     glRotatef(0.5 * my, 0.0, 0.0, 1.0);
  312.     glTranslatef(-0.5,-0.5,-0.5);
  313.     glScalef(1.0/dimension,1.0/dimension,1.0/dimension);
  314.  
  315.     /* draw the lines as hidden polygons */
  316.     for (z=0; z < dimension; z++) {
  317.     for (y=0; y < dimension; y++) {
  318.         for (x=0; x < dimension; x++) {
  319.         glPushMatrix();
  320.         glTranslatef(x, y, z);
  321.         glScalef(0.8, 0.8, 0.8);
  322.         for (i=0; i<MAXQUAD; i++)
  323.             drawhidden(quads[i]);
  324.             flush();
  325.         glPopMatrix();
  326.         }
  327.     }
  328.     }
  329.  
  330.     glPopMatrix();
  331.     flush();
  332. }
  333.  
  334. static void fill(Quad quad)
  335. {
  336.     /* fill the polygon */
  337.     glBegin(GL_QUADS);
  338.     glVertex3fv(quad[0]);
  339.     glVertex3fv(quad[1]);
  340.     glVertex3fv(quad[2]);
  341.     glVertex3fv(quad[3]);
  342.     glEnd();
  343. }
  344.  
  345. static void outline(Quad quad) 
  346. {
  347.     /* outline the polygon */
  348.     glBegin(GL_LINE_LOOP);
  349.     glVertex3fv(quad[0]);
  350.     glVertex3fv(quad[1]);
  351.     glVertex3fv(quad[2]);
  352.     glVertex3fv(quad[3]);
  353.     glEnd();
  354. }
  355.  
  356. static void drawhidden(Quad quad)
  357. {
  358.     static GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
  359.     static GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
  360.  
  361.     if (delay)
  362.       sginap(1);
  363.     glColor4fv(white);
  364.     outline(quad);
  365.  
  366.     if (hidden) {
  367.     glColor4fv(black);
  368.     fill(quad);
  369.     }
  370. }
  371.  
  372. static void process_input(Display *dpy, Window win)
  373. {
  374.     XEvent event;
  375.     int mx = 0, my = 0;
  376.     GLboolean update;
  377.     static int first_time = True;
  378.  
  379.     while (1) {
  380.     char buf[31];
  381.     KeySym keysym;
  382.  
  383.     update = False;
  384.  
  385.     XNextEvent(dpy, &event);
  386.     switch(event.type) {
  387.  
  388.     case Expose:
  389.       if (first_time) {
  390.         update = True;
  391.         first_time = False;
  392.       }
  393.       else {
  394.        flush();
  395.       }
  396.       break;
  397.  
  398.     case ConfigureNotify:
  399.       if (event.xconfigure.width == width && 
  400.           event.xconfigure.height == height) break;
  401.       glViewport(0, 0, event.xconfigure.width, event.xconfigure.height);
  402.       update = True;
  403.       break;
  404.  
  405.     case KeyPress:
  406.       (void) XLookupString(&event.xkey, buf, sizeof(buf), &keysym, NULL);
  407.       switch (keysym) {
  408.       case XK_h:
  409.         hidden = !hidden;
  410.         update = GL_TRUE;
  411.         break;
  412.       case XK_d:
  413.         delay = !delay;
  414.         break;
  415.       case XK_Escape:
  416.         exit(EXIT_SUCCESS);
  417.       default:
  418.         break;
  419.       }
  420.       break;
  421.       
  422.     case ButtonRelease:
  423.       mx = event.xbutton.x;
  424.       my = event.xbutton.y;
  425.       update = True;
  426.       break;
  427.  
  428.     case MotionNotify:
  429.       /* Grab all pending motion events! */
  430.       while (XPending(dpy)) {
  431.         XEvent peek;
  432.         XPeekEvent(dpy, &peek);
  433.         if (peek.type == MotionNotify &&
  434.         peek.xany.window == event.xany.window)
  435.           XNextEvent(dpy, &event);
  436.         else
  437.           break;
  438.       }
  439.       mx = event.xbutton.x;
  440.       my = event.xbutton.y;
  441.  
  442.       update = True;
  443.       break;
  444.  
  445.     default:
  446.       break;
  447.     }
  448.  
  449.     if (update) {
  450.       draw_scene(mx, my);
  451.     }
  452.     }
  453. }
  454.