home *** CD-ROM | disk | FTP | other *** search
/ Chestnut's Multimedia Mania / MM_MANIA.ISO / graphics / povsrc20 / xwindows.c < prev    next >
C/C++ Source or Header  |  1993-08-06  |  18KB  |  621 lines

  1. /****************************************************************************
  2. *                xwindows.c
  3. *
  4. *  This module implements X-windows specific routines.
  5. *
  6. *  from Persistence of Vision Raytracer
  7. *  Copyright 1993 Persistence of Vision Team
  8. *---------------------------------------------------------------------------
  9. *  NOTICE: This source code file is provided so that users may experiment
  10. *  with enhancements to POV-Ray and to port the software to platforms other 
  11. *  than those supported by the POV-Ray Team.  There are strict rules under
  12. *  which you are permitted to use this file.  The rules are in the file
  13. *  named POVLEGAL.DOC which should be distributed with this file. If 
  14. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  15. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  16. *  Forum.  The latest version of POV-Ray may be found there as well.
  17. *
  18. * This program is based on the popular DKB raytracer version 2.12.
  19. * DKBTrace was originally written by David K. Buck.
  20. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  21. *
  22. *****************************************************************************/
  23.  
  24.  
  25.  /*
  26.  * Here are some routines I wrote which implement +d option on unix computers
  27.  * running X-windows. For now, only black and white output is supported. If I
  28.  * get access to a computer with a color monitor, I'll probably add support
  29.  * for colors to my routines.
  30.  * 
  31.  * In future I'll probably add some more dithering methods. I have tested these
  32.  * routines on SUN 3 and SUN 4. I'm using the tvtwm window manager.
  33.  * 
  34.  * If you have some suggestions to my source code or if you change anything,
  35.  * please let me know. I can be reached at the following address: Marek
  36.  * Rzewuski, Avstikkeren 11, 1156 Oslo 11, Norway or marekr@ifi.uio.no on
  37.  * Internet.
  38.  */
  39.  
  40. /*
  41.  * 91-07-29 Allan H. Wax (Wax.OSBU_South@Xerox.COM) Hacked this module so it
  42.  * can be used with either a colour or B&W screen. Made all variables local
  43.  * to this routine (no need for more globals if no one ever uses them). Fixed
  44.  * bug in refresh routine. Use dither from colorx.c. Use xpov.icon instead of
  45.  * theIcon.
  46.  */
  47.  
  48. #include <stdio.h>
  49. #include <X11/Xlib.h>        /* some Xlib stuff */
  50. #include <X11/Xutil.h>
  51. #include <X11/Xos.h>
  52. #include <X11/Xatom.h>
  53. #include "xpov.icn"
  54. #include <math.h>
  55.  
  56. #include "frame.h"
  57. #include "povproto.h"
  58.  
  59. #define     BORDER_WIDTH    2
  60. #define    EV_MASK    (ButtonPressMask | \
  61.          KeyPressMask     | \
  62.          ExposureMask    | \
  63.          StructureNotifyMask)
  64.  
  65. static Display *theDisplay;
  66. static int      theScreen;
  67. static int      theDepth;
  68. static unsigned long theBlackPixel;
  69. static unsigned long theWhitePixel;
  70. static XEvent   theEvent;
  71. static Window   theWindow, openWindow();
  72. static GC       theGC;
  73. static unsigned char *bitmap;    /* pointer to our picture bitmap */
  74. static unsigned char *bitmapPos;/* position to the last drawn pixel in our
  75.                  * bitmap */
  76.  
  77.  
  78. static char    *display_name = 0;
  79. static int     disp_wide, disp_high;
  80. static XImage  *xi;
  81. static char    *data;
  82. static XGCValues gcvalues;
  83. static long     colorpixels[256];
  84. static Bool     iscolor;
  85. static int     screen_open = 0;
  86.  
  87. struct {
  88.     void            (*Init) ();
  89.     void            (*Close) ();
  90.     void            (*Finished) ();
  91.     void            (*Plot) ();
  92. }               display;
  93.  
  94. /* global POVRay variables */
  95.  
  96. extern FRAME    Frame;
  97. extern unsigned int Options;
  98. extern char     DisplayFormat;
  99. extern int      First_Line;
  100.  
  101. /*
  102.  * Sets up a connection to the X server and stores informations about the
  103.  * enviroment
  104.  */
  105.  
  106. static          initX()
  107. {
  108.     theDisplay = XOpenDisplay(NULL);
  109.     if (theDisplay == NULL) {
  110.     fprintf(stderr, "ERROR: Cannot establish a connection to the X server %s\n",
  111.         XDisplayName(NULL));
  112.     exit(1);
  113.     }
  114.     theScreen = DefaultScreen(theDisplay);
  115.     theDepth = DefaultDepth(theDisplay, theScreen);
  116.     theWhitePixel = WhitePixel(theDisplay, theScreen);
  117.     theBlackPixel = BlackPixel(theDisplay, theScreen);
  118. }
  119.  
  120. /*
  121.  * This procedure will do the following things: 1)     Set up attributes
  122.  * desired for the window 2)    Set up an icon to our window. 3)     Send
  123.  * hints to the window manager. 4)     Open a window on the display 5)    Tell
  124.  * the X to place the window on the screen 6)    Flush out all the queued up X
  125.  * requests to the X server
  126.  */
  127.  
  128. static Window   openWindow(x, y, width, height, flag, theNewGC)
  129. int             x, y;
  130. int             width, height;
  131. int             flag;
  132. GC             *theNewGC;
  133. {
  134.     XSetWindowAttributes theWindowAttributes;
  135.     XSizeHints      theSizeHints;
  136.     unsigned long   theWindowMask;
  137.     Window          theNewWindow;
  138.     Pixmap          theIconPixmap;
  139.     XWMHints        theWMHints;
  140.  
  141.  
  142.     /*
  143.      * Set up some attributes for the window. Override_redirect tells the
  144.      * window manager to deal width the window or leave it alone
  145.      */
  146.  
  147.     theWindowAttributes.border_pixel = theBlackPixel;
  148.     theWindowAttributes.background_pixel = theWhitePixel;
  149.     theWindowAttributes.override_redirect = False;
  150.     theWindowMask = CWBackPixel | CWBorderPixel | CWOverrideRedirect;
  151.  
  152.     /* Now, open out window */
  153.  
  154.     theNewWindow = XCreateWindow(theDisplay,
  155.                  RootWindow(theDisplay, theScreen),
  156.                  x, y,
  157.                  width, height,
  158.                  BORDER_WIDTH,
  159.                  theDepth,
  160.                  InputOutput,
  161.                  CopyFromParent,
  162.                  theWindowMask,
  163.                  &theWindowAttributes);
  164.  
  165.     /* Create one iconbitmap */
  166.  
  167.     theIconPixmap = XCreateBitmapFromData(theDisplay,
  168.                       theNewWindow,
  169.                       xpov_bits,
  170.                       xpov_width,
  171.                       xpov_height);
  172.  
  173.     /*
  174.      * Now tell the window manager where on screen we should place our
  175.      * window.
  176.      */
  177.  
  178.     theWMHints.icon_pixmap = theIconPixmap;
  179.     theWMHints.initial_state = NormalState;    /* we don't want an iconized
  180.                          * window when it's created */
  181.     theWMHints.flags = IconPixmapHint | StateHint;
  182.  
  183.     XSetWMHints(theDisplay, theNewWindow, &theWMHints);
  184.  
  185.     theSizeHints.flags = PPosition | PSize;
  186.     theSizeHints.x = x;
  187.     theSizeHints.y = y;
  188.     theSizeHints.width = width;
  189.     theSizeHints.height = height;
  190.     /*
  191.      * theSizeHints.min_width    = width; theSizeHints.min_height    =
  192.      * height; theSizeHints.max_width    = width; theSizeHints.max_height =
  193.      * height;
  194.      */
  195.  
  196.     XSetNormalHints(theDisplay, theNewWindow, &theSizeHints);
  197.  
  198.  
  199.     if (createGC(theNewWindow, theNewGC) == 0) {
  200.     XDestroyWindow(theDisplay, theNewWindow);
  201.     return ((Window) 0);
  202.     }
  203.  
  204.     /* make a name for our window */
  205.  
  206.     XStoreName(theDisplay, theNewWindow, "POVRay \0");
  207.  
  208.     /*
  209.      * Now, could we please see the window on the screen? Until now, we have
  210.      * dealed with a window which has been created but noe appeared on the
  211.      * screen. Maping the window places it visibly    on the screen
  212.      */
  213.  
  214.     XMapWindow(theDisplay, theNewWindow);
  215.     XFlush(theDisplay);
  216.     return (theNewWindow);
  217. }
  218.  
  219. static          refreshWindow(theExposedWindow)
  220. Window          theExposedWindow;
  221. {
  222.     int             i = 0, x = 0, y = First_Line;
  223.     register unsigned char *dummy = bitmap;
  224.     while (dummy != bitmapPos) {
  225.     /* draw until most current pixel is drawn */
  226.     if (*dummy)
  227.         XDrawPoint(theDisplay, theWindow, theGC, x, y);
  228.     if (x == Frame.Screen_Width) {
  229.         x = 0;
  230.         y++;
  231.     }
  232.     else {
  233.         dummy++;
  234.         x++;
  235.         i++;
  236.     }
  237.     }
  238.     XFlush(theDisplay);
  239. }
  240.  
  241. /* Creates a new graphics context */
  242.  
  243. static int      createGC(theNewWindow, theNewGC)
  244. Window          theNewWindow;
  245. GC             *theNewGC;
  246. {
  247.     XGCValues       theGCValues;
  248.     *theNewGC = XCreateGC(theDisplay,
  249.               theNewWindow,
  250.               (unsigned long) 0,
  251.               &theGCValues);
  252.  
  253.     if (*theNewGC == 0) {
  254.     return (0);        /* error */
  255.     }
  256.     else {            /* set foreground and background defaults for
  257.                  * the new GC */
  258.     XSetForeground(theDisplay,
  259.                *theNewGC,
  260.                theBlackPixel);
  261.  
  262.     XSetBackground(theDisplay,
  263.                *theNewGC,
  264.                theWhitePixel);
  265.  
  266.     return (1);        /* OK */
  267.     }
  268. }
  269.  
  270. static          initEvents(theWindow)
  271. Window          theWindow;
  272. {
  273.     XSelectInput(theDisplay,
  274.          theWindow,
  275.          EV_MASK);
  276. }
  277.  
  278. void            BWFinished()
  279. {
  280.  
  281. }
  282.  
  283.  
  284. void            BWInit()
  285. {
  286.     int             i;
  287.  
  288.     /*
  289.      * set some room for a bitmap for our picture. I've got to "remember" the
  290.      * whole picture bacuse of resizing of the window, overlapping etc. Then
  291.      * I've got to refresh the picture. This should be easy to convert to an
  292.      * "color version" in future
  293.      */
  294.  
  295.     bitmap = (unsigned char *) malloc(sizeof(unsigned char) *
  296.                 (Frame.Screen_Width * Frame.Screen_Height));
  297.     bitmapPos = bitmap;
  298.     if (bitmap == NULL)
  299.     printf("ERROR: Can not allocate the buffer..\n");
  300.  
  301.     for (i = 0; i < (Frame.Screen_Width * Frame.Screen_Height); i++) {
  302.     *bitmapPos++ = 0;
  303.     }
  304.     bitmapPos = bitmap;
  305.     initX();
  306.     theWindow = openWindow(0, 0, Frame.Screen_Width, Frame.Screen_Height, 0, &theGC);
  307.     initEvents(theWindow);
  308.     XFlush(theDisplay);
  309.     XNextEvent(theDisplay, &theEvent);
  310.     XFlush(theDisplay);
  311. }                /* end of display initilazation */
  312.  
  313. void            BWClose()
  314. {
  315.     sleep(10);            /* an simple delay. 10 seconds. */
  316.     XDestroyWindow(theDisplay, theWindow);
  317.     XFlush(theDisplay);
  318.     XCloseDisplay(theDisplay);
  319.     free(bitmap);
  320. }
  321.  
  322. void            BWPlot(x, y, Red, Green, Blue)
  323. int             x, y;
  324. unsigned char   Red, Green, Blue;
  325. {
  326.     unsigned char   color;
  327.     long            thePixel;
  328.     /* lets find if there are some events waiting for us */
  329.  
  330.     while (XPending(theDisplay) > 0) {    /* now deal with the events.. */
  331.     XNextEvent(theDisplay, &theEvent);
  332.  
  333.     switch (theEvent.type) {
  334.       case Expose:
  335.         /* printf("Window is exposed.\n"); */
  336.         refreshWindow(theEvent.xany.window);
  337.         break;
  338.  
  339.       case MapNotify:
  340.         /* printf("The window is mapped.\n"); */
  341.         refreshWindow(theEvent.xany.window);
  342.         break;
  343.  
  344.       case ButtonPress:
  345.         /* printf("A mouse button was pressed.\n"); */
  346.         break;
  347.  
  348.       case ConfigureNotify:
  349.         /* printf("The window configuration has been changed\n"); */
  350.         refreshWindow(theEvent.xany.window);
  351.         break;
  352.     }
  353.     }
  354.     if (dither(x, y, Red, Green, Blue)) {
  355.     thePixel = BlackPixel(theDisplay, theScreen);
  356.     XDrawPoint(theDisplay, theWindow, theGC, x, y);
  357.     XFlush(theDisplay);
  358.     }
  359.     else {
  360.     thePixel = WhitePixel(theDisplay, theScreen);
  361.     }
  362.     *bitmapPos++ = thePixel;
  363. }
  364.  
  365. /* so we can get at the dimensions */
  366. extern FRAME    Frame;
  367.  
  368. /* x11 stuff */
  369.  
  370. static Bool     evtPred(d, e, a)
  371. Display        *d;
  372. XEvent         *e;
  373. char           *a;
  374. {
  375.     return (True);
  376. }
  377.  
  378. static void     BuildColormap()
  379. {
  380.     XColor          tmp;
  381.     register unsigned short r, g, b, i;
  382.     Colormap        cmap;
  383.  
  384.     /*
  385.      * build a colormap that will contain 216, or 6^3 colors. We won't do
  386.      * anything clever like adding extra grays in the leftover space.
  387.      * Remember, this was written in a few hours.
  388.      */
  389.     cmap = DefaultColormap(theDisplay, theScreen);
  390.  
  391.     i = 0;
  392.     for (r = 0; r < 6; r++) {
  393.     for (g = 0; g < 6; g++) {
  394.         for (b = 0; b < 6; b++, i++) {
  395.         tmp.red = (r * 36) << 8;
  396.         tmp.green = (g * 36) << 8;
  397.         tmp.blue = (b * 36) << 8;
  398.         tmp.flags = DoRed | DoGreen | DoBlue;
  399.         if (!XAllocColor(theDisplay, cmap, &tmp))
  400.             goto crap_out;
  401.         colorpixels[i] = tmp.pixel;
  402.         }
  403.     }
  404.     }
  405. crap_out:            /* couldn't get what we wanted.  Boo-hoo. */
  406.     if (i != 216)
  407.     fprintf(stderr, "warning: could only get %d colors.\n", i);
  408. }
  409.  
  410. void            ColourFinished()
  411. {
  412.     XEvent         *report;
  413.     /* do nothing.  I suppose we could wait... */
  414.     while (1) {
  415.     XNextEvent(theDisplay, &report);
  416.     XPutImage(theDisplay, theWindow, theGC, xi, 0, 0, 0, 0, Frame.Screen_Width,
  417.           Frame.Screen_Height);
  418.     }
  419. }
  420.  
  421. void            display_close()
  422. {
  423.     if(screen_open)
  424.             (display.Close) ();
  425. }
  426.  
  427. void            display_plot(x, y, Red, Green, Blue)
  428. int             x, y;
  429. unsigned char   Red, Green, Blue;
  430. {
  431.     (display.Plot) (x, y, Red, Green, Blue);
  432. }
  433.  
  434. void            display_finished()
  435. {
  436.     if(screen_open)
  437.             (display.Finished) ();
  438. }
  439.  
  440. void            ColourInit()
  441. {
  442.     Pixmap          icon;
  443.     XSizeHints      hints;
  444.     long            size, i;
  445.     XSetWindowAttributes attrib;
  446.  
  447.     if ((theDisplay = XOpenDisplay(display_name)) == NULL) {
  448.     fprintf(stderr, "Can't open X server %s.\n",
  449.         XDisplayName(display_name));
  450.     exit(1);
  451.     }
  452.     theScreen = DefaultScreen(theDisplay);
  453.  
  454.     /* screen dimensions */
  455.     disp_wide = DisplayWidth(theDisplay, theScreen);
  456.     disp_high = DisplayHeight(theDisplay, theScreen);
  457.  
  458.     theWindow = XCreateSimpleWindow(theDisplay, RootWindow(theDisplay, theScreen),
  459.                   (disp_wide - Frame.Screen_Width) / 2,
  460.                   (disp_high - Frame.Screen_Height) / 2,
  461.                   Frame.Screen_Width,
  462.                   Frame.Screen_Height, 2 /* border width */ ,
  463.               BlackPixel(theDisplay, theScreen), WhitePixel(theDisplay, theScreen));
  464.  
  465.     /* create a graphics context for drawing */
  466.     gcvalues.function = GXcopy;
  467.     theGC = XCreateGC(theDisplay, theWindow, GCFunction, &gcvalues);
  468.  
  469.     /* make a cute icon */
  470.     icon = XCreateBitmapFromData(theDisplay, theWindow, xpov_bits, xpov_width,
  471.                  xpov_height);
  472.  
  473.     /* give a few clues about ourself */
  474.     hints.flags = PPosition | PSize | PMinSize;
  475.     hints.x = (disp_wide - Frame.Screen_Width) / 2;
  476.     hints.y = (disp_high - Frame.Screen_Height) / 2;
  477.     hints.width = Frame.Screen_Width;
  478.     hints.height = Frame.Screen_Height;
  479.     hints.min_width = 32;
  480.     hints.min_height = 32;
  481.  
  482.     XSetStandardProperties(theDisplay, theWindow, "povray", "povray", icon, NULL, 0,
  483.                &hints);
  484.  
  485.     /* only want to know about expose events */
  486.     XSelectInput(theDisplay, theWindow, ExposureMask);
  487.     XMapWindow(theDisplay, theWindow);
  488.  
  489.     BuildColormap();
  490.  
  491.     size = Frame.Screen_Width * Frame.Screen_Height;
  492.     data = (char *) XtMalloc(size);
  493.     for (i = 0; i < size; i++)
  494.     data[i] = 0;
  495.     xi = XCreateImage(theDisplay, DefaultVisual(theDisplay, theScreen), 8, ZPixmap, 0, data,
  496.         Frame.Screen_Width, Frame.Screen_Height, 8, Frame.Screen_Width);
  497. };
  498.  
  499. void            ColourClose()
  500. {
  501.     sleep(10);
  502.     XDestroyImage(xi);
  503.     XtFree(data);
  504.     XDestroyWindow(theDisplay, theWindow);
  505.     XCloseDisplay(theDisplay);
  506. }
  507.  
  508.  /* static */ int dither(x, y, Red, Green, Blue)
  509. register unsigned int x, y;
  510. unsigned char   Red, Green, Blue;
  511. {
  512.     /*
  513.      * Perform ordered dithering for halftone screen. For details, see
  514.      * Graphics Gems, Ed. Andrew Glassner, p. 176-178 Floyd-Steinberg dither
  515.      * would look better, but we would need more saved state, making the
  516.      * coding a lot uglier.  Since this is just a display hack and not an
  517.      * image processing package, I don't bother.
  518.      */
  519.     static unsigned int dm[] = {
  520.     0, 192, 48, 240, 12, 204, 60, 252,
  521.     128, 64, 176, 112, 140, 76, 188, 124,
  522.     32, 224, 16, 208, 44, 236, 28, 220,
  523.     160, 96, 144, 80, 172, 108, 156, 92,
  524.     8, 200, 56, 248, 4, 196, 52, 244,
  525.     136, 72, 184, 120, 132, 68, 180, 116,
  526.     40, 232, 24, 216, 36, 228, 20, 212,
  527.     168, 104, 152, 88, 164, 100, 148, 84
  528.     };
  529.     register unsigned long luminence =
  530.     (307 * Red + 599 * Green + 118 * Blue) / 1024;
  531.     return (luminence < dm[(x & 7) + ((y & 7) << 3)]);
  532. }
  533.  
  534. void            ColourPlot(x, y, Red, Green, Blue)
  535. int             x, y;
  536. unsigned char   Red, Green, Blue;
  537. {
  538.     long            thePixel;
  539.     int             r, g, b;
  540.     XEvent          report;
  541.     int             luminence;
  542.  
  543.     /* scale rgb to be in our 216 color space */
  544.     r = (Red * 216) / (256 * 36);
  545.     g = (Green * 216) / (256 * 36);
  546.     b = (Blue * 216) / (256 * 36);
  547.  
  548.     /* find the pixel we got */
  549.     thePixel = colorpixels[(r * 36) + (g * 6) + b];
  550.     XPutPixel(xi, x, y, thePixel);
  551.     /* on each pixel, copy a scanline.  Inefficient, but so what?  See above. */
  552.     XPutImage(theDisplay, theWindow, theGC, xi, 0, y, 0, y, Frame.Screen_Width, 1);
  553.  
  554.     /* poll for exposure events */
  555.     if (XCheckIfEvent(theDisplay, &report, evtPred, "blah")) {
  556.     XPutImage(theDisplay, theWindow, theGC, xi, 0, 0, 0, 0, Frame.Screen_Width, y + 1);
  557.     }
  558. }
  559.  
  560. void unix_init_POVRAY PARAMS((void))
  561. {
  562. }
  563.  
  564. int             matherr(x)
  565. struct exception *x;
  566. {
  567.     switch (x->type) {
  568.       case DOMAIN:
  569.       case OVERFLOW:
  570.     x->retval = 1.0e17;
  571.     break;
  572.  
  573.       case SING:
  574.       case UNDERFLOW:
  575.     x->retval = 0.0;
  576.     break;
  577.  
  578.       default:
  579.     break;
  580.     }
  581.     return (1);
  582. }
  583.  
  584. extern void     BWInit(), BWClose(), BWFinished(), BWPlot();
  585.  
  586. void            display_init()
  587. {
  588.     Pixmap          icon;
  589.     XSizeHints      hints;
  590.     long            size, i;
  591.     XSetWindowAttributes attrib;
  592.  
  593.     if ((theDisplay = XOpenDisplay(display_name)) == NULL) {
  594.     fprintf(stderr, "Can't open X server %s.\n",
  595.         XDisplayName(display_name));
  596.     exit(1);
  597.     }
  598.     
  599.     screen_open = 1;
  600.     
  601.     theScreen = DefaultScreen(theDisplay);
  602.     iscolor = (XDisplayCells(theDisplay, theScreen) > 2);
  603.  
  604.     if (iscolor) {
  605.     display.Init = ColourInit;
  606.     display.Close = ColourClose;
  607.     display.Finished = ColourFinished;
  608.     display.Plot = ColourPlot;
  609.     }
  610.     else {
  611.     display.Init = BWInit;
  612.     display.Close = BWClose;
  613.     display.Finished = BWFinished;
  614.     display.Plot = BWPlot;
  615.     }
  616.  
  617.     XCloseDisplay(theDisplay);
  618.     (display.Init) ();
  619.  
  620. }
  621.