home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / demos / ico / ico.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-19  |  25.3 KB  |  1,054 lines

  1. /* $XConsortium: ico.c,v 1.35 91/07/19 23:08:43 rws Exp $ */
  2. /***********************************************************
  3. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
  4. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  5.  
  6.                         All Rights Reserved
  7.  
  8. Permission to use, copy, modify, and distribute this software and its 
  9. documentation for any purpose and without fee is hereby granted, 
  10. provided that the above copyright notice appear in all copies and that
  11. both that copyright notice and this permission notice appear in 
  12. supporting documentation, and that the names of Digital or MIT not be
  13. used in advertising or publicity pertaining to distribution of the
  14. software without specific, written prior permission.  
  15.  
  16. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  17. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  18. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  19. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  20. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  21. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  22. SOFTWARE.
  23.  
  24. ******************************************************************/
  25. /******************************************************************************
  26.  * Description
  27.  *    Display a wire-frame rotating icosahedron, with hidden lines removed
  28.  *
  29.  * Arguments:
  30.  *    -r        display on root window instead of creating a new one
  31.  *    =wxh+x+y    X geometry for new window (default 600x600 centered)
  32.  *    host:display    X display on which to run
  33.  * (plus a host of others, try -help)
  34.  *****************************************************************************/
  35. /* Additions by jimmc@sci:
  36.  *  faces and colors
  37.  *  double buffering on the display
  38.  *  additional polyhedra
  39.  *  sleep switch
  40.  */
  41.  
  42.  
  43. #include <X11/Xlib.h>
  44. #include <X11/Xatom.h>
  45. #include <X11/Xutil.h>
  46. #include <X11/Xfuncs.h>
  47. #include <stdio.h>
  48. #ifdef MULTIBUFFER
  49. #include <X11/extensions/multibuf.h>
  50. #endif /* MULTIBUFFER */
  51.  
  52. typedef double Transform3D[4][4];
  53.  
  54. #define MIN_ICO_WIDTH 5
  55. #define MIN_ICO_HEIGHT 5
  56. #define DEFAULT_ICO_WIDTH 150
  57. #define DEFAULT_ICO_HEIGHT 150
  58. #define DEFAULT_DELTAX 13
  59. #define DEFAULT_DELTAY 9
  60.  
  61. #include "polyinfo.h"    /* define format of one polyhedron */
  62.  
  63. /* Now include all the files which define the actual polyhedra */
  64. Polyinfo polys[] = {
  65. #include "allobjs.h"
  66. };
  67. int polysize = sizeof(polys)/sizeof(polys[0]);
  68.  
  69. typedef struct {
  70.     int prevX, prevY;
  71.     unsigned long *plane_masks;    /* points into dbpair.plane_masks */
  72.     unsigned long enplanemask;    /* what we enable for drawing */
  73.     XColor *colors;        /* size = 2 ** totalplanes */
  74.     unsigned long *pixels;    /* size = 2 ** planesperbuf */
  75. } DBufInfo;
  76.  
  77. typedef struct {
  78.     int planesperbuf;
  79.     int pixelsperbuf;    /* = 1<<planesperbuf */
  80.     int totalplanes;    /* = 2*planesperbuf */
  81.     int totalpixels;    /* = 1<<totalplanes */
  82.     unsigned long *plane_masks;    /* size = totalplanes */
  83.     unsigned long pixels[1];
  84.     int dbufnum;
  85.     DBufInfo bufs[2];
  86.     DBufInfo *drawbuf, *dpybuf;
  87. } DBufPair;
  88.  
  89. DBufPair dbpair;
  90.  
  91. XColor bgcolor,fgcolor;
  92.  
  93. extern long time();
  94.  
  95. extern long rand();
  96.  
  97. char *ProgramName;
  98. Display *dpy;
  99. Window win, draw_window;
  100. int winX, winY, winW, winH;
  101. int icoW = 0, icoH = 0;
  102. int icoDeltaX = DEFAULT_DELTAX, icoDeltaY = DEFAULT_DELTAY;
  103. Colormap cmap;
  104. GC gc;
  105. int multibuf = 0;
  106. #ifdef MULTIBUFFER
  107. int mbevbase, mberrbase;
  108. Multibuffer multibuffers[2];
  109. Window icowin;
  110. #endif /* MULTIBUFFER */
  111.  
  112. char *Primaries[] = {"red", "green", "blue", "yellow", "cyan", "magenta"};
  113. #define NumberPrimaries 6
  114.  
  115. int nplanesets;
  116. int dsync = 0;
  117. int softdbl = 0, dblbuf = 0;
  118. int sleepcount = 0;
  119. int msleepcount = 0;
  120. int numcolors = 0;
  121. char **colornames;    /* points into argv */
  122. int dofaces = 0;
  123. int doedges = 1;
  124.  
  125. Polyinfo *findpoly();
  126.  
  127. static char *help_message[] = {
  128. "where options include:",
  129. "    -display host:dpy            X server to use",
  130. "    -geometry geom               geometry of window to use",
  131. "    -size WxH                    size of object to rotate",
  132. "    -delta +X+Y                  amount by which to move object",
  133. "    -r                           draw in the root window",
  134. "    -d number                    dashed line pattern for wire frames",
  135. "    -bg color                    background color",
  136. "    -colors color ...            codes to use on sides",
  137. "    -p#                          use # (1 through 8) primary colors",
  138. "    -dbl                         use double buffering (extension if present)",
  139. "    -softdbl                     use software double buffering",
  140. "    -noedges                     don't draw wire frame edges",
  141. "    -faces                       draw faces",
  142. "    -copy                        copy multibuffer frames instead of clearing",
  143. "    -lw number                   line width to use",
  144. "    -i                           invert",
  145. "    -sleep number                seconds to sleep in between draws",
  146. "    -obj objname                 type of polyhedral object to draw",
  147. "    -objhelp                     list polyhedral objects available",
  148. NULL};
  149.  
  150. /******************************************************************************
  151.  * Description
  152.  *    Main routine.  Process command-line arguments, then bounce a bounding
  153.  *    box inside the window.  Call DrawIco() to redraw the icosahedron.
  154.  *****************************************************************************/
  155.  
  156. main(argc, argv)
  157. int argc;
  158. char **argv;
  159.     {
  160.     char *display = NULL;
  161.     char *geom = NULL;
  162.     int useRoot = 0;
  163.     int fg, bg;
  164.     int invert = 0;
  165.     int dash = 0;
  166.     XSetWindowAttributes xswa;
  167.     XWindowAttributes xwa;
  168.     Polyinfo *poly;        /* the poly to draw */
  169.     int icoX, icoY;
  170.     XEvent xev;
  171.     Bool blocking = False;
  172.     unsigned long vmask;
  173.     XGCValues xgcv;
  174.     int linewidth = 0;
  175.     char *background_colorname = NULL;
  176.     char *ico_geom = NULL;
  177.     char *delta_geom = NULL;
  178.     int icodeltax2, icodeltay2;
  179.     extern int _Xdebug;
  180.     int initcolors = 0;
  181. #ifdef MULTIBUFFER
  182.     int update_action = MultibufferUpdateActionBackground;
  183. #endif
  184.  
  185.     ProgramName = argv[0];
  186.  
  187.     /* Process arguments: */
  188.  
  189.     poly = findpoly("icosahedron");    /* default */
  190.  
  191.     while (*++argv) {
  192.         if (!strcmp (*argv, "-display")) {
  193.             display = *++argv;
  194.         } else if (!strncmp (*argv, "-g", 2)) {
  195.             geom = *++argv;
  196.         } else if (**argv == '=')         /* obsolete */
  197.             geom = *argv;
  198.         else if (!strcmp(*argv, "-r"))
  199.             useRoot = 1;
  200.         else if (!strcmp (*argv, "-d"))
  201.             dash = atoi(*++argv);
  202.         else if (!strcmp(*argv, "-colors")) {
  203.             colornames = ++argv;
  204.             for ( ; *argv && *argv[0]!='-'; argv++) ;
  205.             numcolors = argv - colornames;
  206.             --argv;
  207.         }
  208.         else if (!strcmp (*argv, "-copy")) {
  209. #ifdef MULTIBUFFER
  210.             update_action = MultibufferUpdateActionCopied;
  211. #endif
  212.         } else if (!strcmp (*argv, "-lw"))
  213.             linewidth = atoi(*++argv);
  214.         else if (!strcmp (*argv, "-dbl"))
  215. #ifdef MULTIBUFFER
  216.             multibuf = 1;
  217. #else
  218.             dblbuf = 1;
  219. #endif
  220.         else if (!strcmp(*argv, "-softdbl")) {
  221.             dblbuf = 1;
  222.             multibuf = 0;
  223.         }
  224.         else if (!strncmp(*argv, "-p", 2)) {
  225.             numcolors = atoi(argv[0]+2);
  226.             if (numcolors < 1 || numcolors > NumberPrimaries)
  227.               numcolors = NumberPrimaries;
  228.             colornames = Primaries;
  229.             dofaces = 1;
  230.         }
  231.         else if (!strcmp(*argv, "-bg"))
  232.             background_colorname = *++argv;
  233.         else if (!strcmp(*argv, "-noedges"))
  234.             doedges = 0;
  235.         else if (!strcmp(*argv, "-faces"))
  236.             dofaces = 1;
  237.         else if (!strcmp(*argv, "-i"))
  238.             invert = 1;
  239.         else if (!strcmp(*argv, "-size"))
  240.             ico_geom = *++argv;
  241.         else if (!strcmp(*argv, "-delta"))
  242.             delta_geom = *++argv;
  243.         else if (!strcmp (*argv, "-sleep")) {
  244.             float f = 0.0;
  245.             sscanf (*++argv, "%f", &f);
  246.             msleepcount = (int) (f * 1000.0);
  247.             sleepcount = msleepcount / 1000;
  248.         } else if (!strcmp (*argv, "-obj"))
  249.             poly = findpoly(*++argv);
  250.         else if (!strcmp(*argv, "-dsync"))
  251.             dsync = 1;
  252.         else if (!strncmp(*argv, "-sync",  5)) 
  253.             _Xdebug = 1;
  254.         else if (!strcmp(*argv, "-objhelp")) {
  255.             giveObjHelp();
  256.             exit(1);
  257.         }
  258.         else {    /* unknown arg */
  259.             char **cpp;
  260.  
  261.           usage:
  262.             fprintf (stderr, "usage:  %s [-options]\n\n", ProgramName);
  263.             for (cpp = help_message; *cpp; cpp++) {
  264.             fprintf (stderr, "%s\n", *cpp);
  265.             }
  266.             fprintf (stderr, "\n");
  267.             exit (1);
  268.         }
  269.     }
  270.  
  271.     if (!dofaces && !doedges) icoFatal("nothing to draw");
  272.  
  273.     if (!(dpy= XOpenDisplay(display)))
  274.             {
  275.         perror("Cannot open display\n");
  276.         exit(-1);
  277.             }
  278.  
  279. #ifdef MULTIBUFFER
  280.     if (multibuf && !XmbufQueryExtension (dpy, &mbevbase, &mberrbase)) {
  281.         multibuf = 0;
  282.         dblbuf = 1;
  283.     }
  284. #endif
  285.  
  286.     cmap = XDefaultColormap(dpy,DefaultScreen(dpy));
  287.     if (!cmap) {
  288.         icoFatal("no default colormap!");
  289.     }
  290.  
  291.     fg = WhitePixel(dpy, DefaultScreen(dpy));
  292.     bg = BlackPixel(dpy, DefaultScreen(dpy));
  293.     if (background_colorname) {
  294.         XColor cdef, igndef;
  295.  
  296.         if (XAllocNamedColor (dpy, cmap, background_colorname,
  297.                   &cdef, &igndef))
  298.           bg = cdef.pixel;
  299.         else 
  300.           icoFatal ("no such color \"%s\"", background_colorname);
  301.     }
  302.     if (numcolors && (!dofaces || numcolors == 1)) {
  303.         XColor cdef, igndef;
  304.  
  305.         if (XAllocNamedColor (dpy, cmap, colornames[0], &cdef, &igndef))
  306.           fg = cdef.pixel;
  307.         else 
  308.           icoFatal ("no such color \"%s\"", colornames[0]);
  309.     }
  310.  
  311.     if (invert) {
  312.         unsigned long tmp = fg;
  313.         fg = bg;
  314.         bg = tmp;
  315.     }
  316.  
  317.  
  318.     /* Set up window parameters, create and map window if necessary: */
  319.  
  320.     if (useRoot)
  321.         {
  322.         draw_window = DefaultRootWindow(dpy);
  323.         winX = 0;
  324.         winY = 0;
  325.         winW = DisplayWidth(dpy, DefaultScreen(dpy));
  326.         winH = DisplayHeight(dpy, DefaultScreen(dpy));
  327.         }
  328.     else {
  329.         winW = winH = (multibuf ? 300 : 600);
  330.         winX = (DisplayWidth(dpy, DefaultScreen(dpy)) - winW) >> 1;
  331.         winY = (DisplayHeight(dpy, DefaultScreen(dpy)) - winH) >> 1;
  332.         if (geom) 
  333.             XParseGeometry(geom, &winX, &winY,
  334.                        (unsigned int *)&winW,
  335.                        (unsigned int *)&winH);
  336.  
  337.         xswa.event_mask = ExposureMask | StructureNotifyMask;
  338.         xswa.background_pixel = bg;
  339.         xswa.border_pixel = fg;
  340.         draw_window = XCreateWindow(dpy, DefaultRootWindow(dpy), 
  341.             winX, winY, winW, winH, 0, 
  342.             DefaultDepth(dpy, DefaultScreen(dpy)), 
  343.             InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)),
  344.             CWEventMask | CWBackPixel | CWBorderPixel, &xswa);
  345.         XChangeProperty(dpy, draw_window, XA_WM_NAME, XA_STRING, 8, 
  346.                 PropModeReplace, (unsigned char *)"Ico", 3);
  347.         XMapWindow(dpy, draw_window);
  348.         while (1) {
  349.             XNextEvent(dpy, &xev);
  350.             if (xev.type == Expose)
  351.             break;
  352.         }
  353.         if (XGetWindowAttributes(dpy,draw_window,&xwa)==0) {
  354.             icoFatal("cant get window attributes (size)");
  355.         }
  356.         winW = xwa.width;
  357.         winH = xwa.height;
  358.         }
  359.  
  360.     if (ico_geom) 
  361.       XParseGeometry (ico_geom, &icoX, &icoY,
  362.               (unsigned int *)&icoW,
  363.               (unsigned int *)&icoH);
  364.     if (icoW <= 0) icoW = DEFAULT_ICO_WIDTH;
  365.     if (icoH <= 0) icoH = DEFAULT_ICO_HEIGHT;
  366.     if (icoW < MIN_ICO_WIDTH) icoW = MIN_ICO_WIDTH;
  367.     if (icoH < MIN_ICO_HEIGHT) icoH = MIN_ICO_HEIGHT;
  368.  
  369.     if (delta_geom) {
  370.         unsigned int junk;
  371.  
  372.         XParseGeometry (delta_geom, &icoDeltaX, &icoDeltaY, &junk, &junk);
  373.         if (icoDeltaX == 0 && icoDeltaY == 0) {
  374.         icoDeltaX = DEFAULT_DELTAX;
  375.         icoDeltaY = DEFAULT_DELTAY;
  376.         }
  377.     }
  378.  
  379.     win = None;
  380.  
  381. #ifdef MULTIBUFFER
  382.     if (multibuf) {
  383.         if (XmbufCreateBuffers (dpy, draw_window, 2, update_action,
  384.                     MultibufferUpdateHintFrequent,
  385.                     multibuffers) == 2) {
  386.         XCopyArea (dpy, draw_window, multibuffers[1],
  387.                DefaultGC(dpy, DefaultScreen(dpy)),
  388.                0, 0, winW, winH, 0, 0);
  389.         win = multibuffers[1];
  390.         } else 
  391.           icoFatal ("unable to obtain 2 buffers");
  392.         dblbuf = 1;
  393.     }
  394. #endif /* MULTIBUFFER */
  395.     if (win == None) win = draw_window;
  396.  
  397.     /* whether or not we are emulating */
  398.     softdbl = (dblbuf && !multibuf);
  399.  
  400.  
  401.     /* Set up a graphics context: */
  402.  
  403.     vmask = (GCBackground | GCForeground | GCLineWidth);
  404.     xgcv.background = bg;
  405.     xgcv.foreground = fg;
  406.     xgcv.line_width = linewidth;
  407.     if (dash) {
  408.         xgcv.line_style = LineDoubleDash;
  409.         xgcv.dashes = dash;
  410.         vmask |= (GCLineStyle | GCDashList);
  411.     }
  412.     gc = XCreateGC (dpy, draw_window, vmask, &xgcv);
  413.  
  414.     if (dofaces && numcolors>1) {
  415.         int i,t,bits;
  416.         bits = 0;
  417.         for (t=numcolors; t; t=t>>1) bits++;
  418.         initDBufs(fg,bg,bits);
  419.         /* don't set the background color */
  420.         for (i=0; i<numcolors; i++) {
  421.             setBufColname(i+1,colornames[i]);
  422.         }
  423.         initcolors = 1;
  424.     }
  425.     else if (dblbuf || dofaces) {
  426.         initDBufs(fg,bg,1);
  427.         initcolors = 1;
  428.     }
  429.     if (initcolors) {
  430.         setDisplayBuf(dblbuf?1:0);    /* insert new colors */
  431.     }
  432.     if (!numcolors) numcolors=1;
  433.  
  434.     if (dsync)
  435.         XSync(dpy, 0);
  436.  
  437.     /* Get the initial position, size, and speed of the bounding-box: */
  438.  
  439.     srand((int) time(0) % 231);
  440.     icoX = ((winW - icoW) * (rand() & 0xFF)) >> 8;
  441.     icoY = ((winH - icoH) * (rand() & 0xFF)) >> 8;
  442.  
  443.  
  444.     /* Bounce the box in the window: */
  445.  
  446.     icodeltax2 = icoDeltaX * 2;
  447.     icodeltay2 = icoDeltaY * 2;
  448.     for (;;)
  449.         {
  450.         int prevX;
  451.         int prevY;
  452.  
  453.         if (blocking || XPending(dpy)) {
  454.             XNextEvent(dpy, &xev);
  455.  
  456.             switch (xev.type) {
  457.               case ConfigureNotify:
  458.             if (xev.xconfigure.width != winW ||
  459.                 xev.xconfigure.height != winH)
  460.               icoX = icoY = 1;
  461.             winW = xev.xconfigure.width;
  462.             winH = xev.xconfigure.height;
  463.             break;
  464.               case MapNotify:
  465.             blocking = False;
  466.             break;
  467.               case UnmapNotify:
  468.             blocking = True;
  469.             continue;
  470.             }
  471.         }
  472.  
  473.         prevX = icoX;
  474.         prevY = icoY;
  475.  
  476.         icoX += icoDeltaX;
  477.         if (icoX < 0 || icoX + icoW > winW)
  478.             {
  479.             icoX -= icodeltax2;
  480.             icoDeltaX = - icoDeltaX;
  481.             icodeltax2 = icoDeltaX * 2;
  482.             }
  483.         icoY += icoDeltaY;
  484.         if (icoY < 0 || icoY + icoH > winH)
  485.             {
  486.             icoY -= icodeltay2;
  487.             icoDeltaY = - icoDeltaY;
  488.             icodeltay2 = icoDeltaY * 2;
  489.             }
  490.  
  491.         drawPoly(poly, gc, icoX, icoY, icoW, icoH, prevX, prevY);
  492.         }
  493.     }
  494.  
  495. giveObjHelp()
  496. {
  497. int i;
  498. Polyinfo *poly;
  499.     printf("%-16s%-12s  #Vert.  #Edges  #Faces  %-16s\n",
  500.         "Name", "ShortName", "Dual");
  501.     for (i=0; i<polysize; i++) {
  502.         poly = polys+i;
  503.         printf("%-16s%-12s%6d%8d%8d    %-16s\n",
  504.             poly->longname, poly->shortname,
  505.             poly->numverts, poly->numedges, poly->numfaces,
  506.             poly->dual);
  507.     }
  508. }
  509.  
  510. Polyinfo *
  511. findpoly(name)
  512. char *name;
  513. {
  514. int i;
  515. Polyinfo *poly;
  516.     for (i=0; i<polysize; i++) {
  517.         poly = polys+i;
  518.         if (strcmp(name,poly->longname)==0 ||
  519.             strcmp(name,poly->shortname)==0) return poly;
  520.     }
  521.     icoFatal("can't find object %s", name);
  522. }
  523.  
  524. icoClearArea(x,y,w,h)
  525. int x,y,w,h;
  526. {
  527.     if (multibuf) return;
  528.  
  529.     if (dblbuf || dofaces) {
  530.         XSetForeground(dpy, gc, dbpair.drawbuf->pixels[0]);
  531.             /* use background as foreground color for fill */
  532.         XFillRectangle(dpy,win,gc,x,y,w,h);
  533.     }
  534.     else {
  535.         XClearArea(dpy,win,x,y,w,h,0);
  536.     }
  537. }
  538.  
  539. /******************************************************************************
  540.  * Description
  541.  *    Undraw previous polyhedron (by erasing its bounding box).
  542.  *    Rotate and draw the new polyhedron.
  543.  *
  544.  * Input
  545.  *    poly        the polyhedron to draw
  546.  *    gc        X11 graphics context to be used for drawing
  547.  *    icoX, icoY    position of upper left of bounding-box
  548.  *    icoW, icoH    size of bounding-box
  549.  *    prevX, prevY    position of previous bounding-box
  550.  *****************************************************************************/
  551. char drawn[MAXNV][MAXNV];
  552.  
  553. drawPoly(poly, gc, icoX, icoY, icoW, icoH, prevX, prevY)
  554. Polyinfo *poly;
  555. GC gc;
  556. int icoX, icoY, icoW, icoH;
  557. int prevX, prevY;
  558.     {
  559.     static int initialized = 0;
  560.  
  561.     Point3D *v = poly->v;
  562.     int *f = poly->f;
  563.     int NV = poly->numverts;
  564.     int NF = poly->numfaces;
  565.  
  566.     static Transform3D xform;
  567.     static Point3D xv[2][MAXNV];
  568.     static int buffer;
  569.     register int p0;
  570.     register int p1;
  571.     register XPoint *pv2;
  572.     XSegment *pe;
  573.     register Point3D *pxv;
  574.     static double wo2, ho2;
  575.     XPoint v2[MAXNV];
  576.     XSegment edges[MAXEDGES];
  577.     register int i;
  578.     int j,k;
  579.     register int *pf;
  580.     int facecolor;
  581.  
  582.     int pcount;
  583.     double pxvz;
  584.     XPoint ppts[MAXEDGESPERPOLY];
  585.  
  586.     /* Set up points, transforms, etc.:  */
  587.  
  588.     if (!initialized)    
  589.         {
  590.         Transform3D r1;
  591.         Transform3D r2;
  592.  
  593.         FormatRotateMat('x', 5 * 3.1416 / 180.0, r1);
  594.         FormatRotateMat('y', 5 * 3.1416 / 180.0, r2);
  595.         ConcatMat(r1, r2, xform);
  596.  
  597.         bcopy((char *) v, (char *) xv[0], NV * sizeof(Point3D));
  598.         buffer = 0;
  599.  
  600.         wo2 = icoW / 2.0;
  601.         ho2 = icoH / 2.0;
  602.  
  603.         initialized = 1;
  604.         }
  605.  
  606.  
  607.     /* Switch double-buffer and rotate vertices: */
  608.  
  609.     buffer = !buffer;
  610.     PartialNonHomTransform(NV, xform, xv[!buffer], xv[buffer]);
  611.  
  612.  
  613.     /* Convert 3D coordinates to 2D window coordinates: */
  614.  
  615.     pxv = xv[buffer];
  616.     pv2 = v2;
  617.     for (i = NV - 1; i >= 0; --i)
  618.         {
  619.         pv2->x = (int) ((pxv->x + 1.0) * wo2) + icoX;
  620.         pv2->y = (int) ((pxv->y + 1.0) * ho2) + icoY;
  621.         ++pxv;
  622.         ++pv2;
  623.         }
  624.  
  625.  
  626.     /* Accumulate edges to be drawn, eliminating duplicates for speed: */
  627.  
  628.     pxv = xv[buffer];
  629.     pv2 = v2;
  630.     pf = f;
  631.     pe = edges;
  632.     bzero(drawn, sizeof(drawn));
  633.  
  634.     if (dblbuf)
  635.         setDrawBuf(dbpair.dbufnum);
  636.             /* switch drawing buffers if double buffered */
  637.     /* for faces, need to clear before FillPoly */
  638.     if (dofaces && !multibuf) {    /* multibuf uses update background */
  639.         if (softdbl)
  640.             icoClearArea(
  641.                 dbpair.drawbuf->prevX, dbpair.drawbuf->prevY,
  642.                 icoW + 1, icoH + 1);
  643.         icoClearArea(prevX, prevY, icoW + 1, icoH + 1);
  644.     }
  645.  
  646.     if (dsync)
  647.         XSync(dpy, 0);
  648.  
  649.     for (i = NF - 1; i >= 0; --i, pf += pcount)
  650.         {
  651.  
  652.         pcount = *pf++;    /* number of edges for this face */
  653.         pxvz = 0.0;
  654.         for (j=0; j<pcount; j++) {
  655.             p0 = pf[j];
  656.             pxvz += pxv[p0].z;
  657.         }
  658.  
  659.         /* If facet faces away from viewer, don't consider it: */
  660.         if (pxvz<0.0)
  661.             continue;
  662.  
  663.         if (dofaces) {
  664.             if (numcolors)
  665.                 facecolor = i%numcolors + 1;
  666.             else    facecolor = 1;
  667.             XSetForeground(dpy, gc,
  668.                 dbpair.drawbuf->pixels[facecolor]);
  669.             for (j=0; j<pcount; j++) {
  670.                 p0 = pf[j];
  671.                 ppts[j].x = pv2[p0].x;
  672.                 ppts[j].y = pv2[p0].y;
  673.             }
  674.             XFillPolygon(dpy, win, gc, ppts, pcount,
  675.                 Convex, CoordModeOrigin);
  676.         }
  677.  
  678.         if (doedges) {
  679.             for (j=0; j<pcount; j++) {
  680.                 if (j<pcount-1) k=j+1;
  681.                 else k=0;
  682.                 p0 = pf[j];
  683.                 p1 = pf[k];
  684.                 if (!drawn[p0][p1]) {
  685.                     drawn[p0][p1] = 1;
  686.                     drawn[p1][p0] = 1;
  687.                     pe->x1 = pv2[p0].x;
  688.                     pe->y1 = pv2[p0].y;
  689.                     pe->x2 = pv2[p1].x;
  690.                     pe->y2 = pv2[p1].y;
  691.                     ++pe;
  692.                 }
  693.             }
  694.         }
  695.         }
  696.  
  697.     /* Erase previous, draw current icosahedrons; sync for smoothness. */
  698.  
  699.     if (doedges) {
  700.         if (dofaces) {
  701.             XSetForeground(dpy, gc, dbpair.drawbuf->pixels[0]);
  702.                 /* use background as foreground color */
  703.         }
  704.         else {
  705.             if (softdbl)
  706.                 icoClearArea(dbpair.drawbuf->prevX,
  707.                     dbpair.drawbuf->prevY,
  708.                     icoW + 1, icoH + 1);
  709.             if (!multibuf)
  710.               icoClearArea(prevX, prevY, icoW + 1, icoH + 1);
  711.             if (dblbuf || dofaces) {
  712.                 XSetForeground(dpy, gc, dbpair.drawbuf->pixels[
  713.                     dbpair.pixelsperbuf-1]);
  714.             }
  715.         }
  716.         XDrawSegments(dpy, win, gc, edges, pe - edges);
  717.     }
  718.  
  719.     if (dsync)
  720.         XSync(dpy, 0);
  721.  
  722.     if (dblbuf) {
  723.         dbpair.drawbuf->prevX = icoX;
  724.         dbpair.drawbuf->prevY = icoY;
  725.         setDisplayBuf(dbpair.dbufnum);
  726.     }
  727.     if (dblbuf)
  728.         dbpair.dbufnum = 1 - dbpair.dbufnum;
  729.     if (!multibuf && sleepcount) sleep(sleepcount);
  730.     }
  731.  
  732. char *xalloc(nbytes)
  733. int nbytes;
  734. {
  735. char *p, *malloc();
  736.  
  737.     p = malloc((unsigned int)nbytes);
  738.     if (p) return p;
  739.     fprintf(stderr,"ico: no more memory\n");
  740.     exit(1);
  741. }
  742.  
  743. initDBufs(fg,bg,planesperbuf)
  744. int fg,bg;
  745. int planesperbuf;
  746. {
  747. int i,j,jj,j0,j1,k,m,t;
  748. DBufInfo *b, *otherb;
  749.  
  750.     nplanesets = (softdbl ? 2 : 1);
  751.  
  752.     dbpair.planesperbuf = planesperbuf;
  753.     dbpair.pixelsperbuf = 1<<planesperbuf;
  754.     dbpair.totalplanes = nplanesets * planesperbuf;
  755.     dbpair.totalpixels = 1<<dbpair.totalplanes;
  756.     dbpair.plane_masks = (unsigned long *)
  757.         xalloc(dbpair.totalplanes * sizeof(unsigned long));
  758.     dbpair.dbufnum = 0;
  759.     for (i=0; i < nplanesets; i++) {
  760.         b = dbpair.bufs+i;
  761.         b->plane_masks = dbpair.plane_masks + (i*planesperbuf);
  762.         b->colors = (XColor *)
  763.             xalloc(dbpair.totalpixels * sizeof(XColor));
  764.         b->pixels = (unsigned long *)
  765.             xalloc(dbpair.pixelsperbuf * sizeof(unsigned long));
  766.     }
  767.  
  768.     if (dbpair.totalplanes == 1) {
  769.         dbpair.pixels[0] = bg;
  770.         dbpair.plane_masks[0] = fg ^ bg;
  771.     } else {
  772.         t = XAllocColorCells(dpy,cmap,0,
  773.             dbpair.plane_masks,dbpair.totalplanes, dbpair.pixels,1);
  774.                 /* allocate color planes */
  775.         if (t==0) {
  776.             icoFatal("can't allocate enough color planes");
  777.         }
  778.     }
  779.  
  780.     fgcolor.pixel = fg;
  781.     bgcolor.pixel = bg;
  782.     XQueryColor(dpy,cmap,&fgcolor);
  783.     XQueryColor(dpy,cmap,&bgcolor);
  784.  
  785.     setBufColor(0,&bgcolor);
  786.     setBufColor(1,&fgcolor);
  787.     for (i=0; i<nplanesets; i++) {
  788.         b = dbpair.bufs+i;
  789.         if (dblbuf)
  790.             otherb = dbpair.bufs+(1-i);
  791.         for (j0=0; j0<(softdbl?dbpair.pixelsperbuf:1); j0++) {
  792.             for (j1=0; j1<dbpair.pixelsperbuf; j1++) {
  793.             j = (j0<<dbpair.planesperbuf)|j1;
  794.             if (i==0) jj=j;
  795.             else jj= (j1<<dbpair.planesperbuf)|j0;
  796.             b->colors[jj].pixel = dbpair.pixels[0];
  797.             for (k=0, m=j; m; k++, m=m>>1) {
  798.                 if (m&1)
  799.                    b->colors[jj].pixel ^= dbpair.plane_masks[k];
  800.             }
  801.             b->colors[jj].flags = DoRed | DoGreen | DoBlue;
  802.             }
  803.         }
  804.         b->prevX = b->prevY = 0;
  805.         b->enplanemask = 0;
  806.         for (j=0; j<planesperbuf; j++) {
  807.             b->enplanemask |= b->plane_masks[j];
  808.         }
  809.         for (j=0; j<dbpair.pixelsperbuf; j++) {
  810.             b->pixels[j] = dbpair.pixels[0];
  811.             for (k=0, m=j; m; k++, m=m>>1) {
  812.                 if (m&1)
  813.                    b->pixels[j] ^= b->plane_masks[k];
  814.             }
  815.         }
  816.     }
  817.  
  818.     if (!multibuf) {
  819.         setDrawBuf(0);
  820.         XSetBackground(dpy, gc, dbpair.bufs[0].pixels[0]);
  821.         XSetWindowBackground(dpy, draw_window, dbpair.bufs[0].pixels[0]);
  822.         XSetPlaneMask(dpy, gc, AllPlanes);
  823.         icoClearArea(0, 0, winW, winH); /* clear entire window */
  824.     }
  825.  
  826. /*    if (softdbl) setDisplayBuf(1); */
  827. }
  828.  
  829. setBufColname(n,colname)
  830. int n;
  831. char *colname;
  832. {
  833. int t;
  834. XColor dcolor, color;
  835.  
  836.     t = XLookupColor(dpy,cmap,colname,&dcolor,&color);
  837.     if (t==0) {    /* no such color */
  838.         icoFatal("no such color %s",colname);
  839.     }
  840.     setBufColor(n,&color);
  841. }
  842.  
  843. setBufColor(n,color)
  844. int n;        /* color index */
  845. XColor *color;    /* color to set */
  846. {
  847. int i,j,cx;
  848. DBufInfo *b;
  849. unsigned long pix;
  850.  
  851.     for (i=0; i<nplanesets; i++) {
  852.         b = dbpair.bufs+i;
  853.         for (j=0; j<(softdbl?dbpair.pixelsperbuf:1); j++) {
  854.             cx = n + j*dbpair.pixelsperbuf;
  855.             pix = b->colors[cx].pixel;
  856.             b->colors[cx] = *color;
  857.             b->colors[cx].pixel = pix;
  858.             b->colors[cx].flags = DoRed | DoGreen | DoBlue;
  859.         }
  860.     }
  861. }
  862.  
  863. setDrawBuf (n)
  864.     int n;
  865. {
  866.     XGCValues xgcv;
  867.     unsigned long mask;
  868.  
  869. #ifdef MULTIBUFFER
  870.     if (multibuf) {
  871.     win = multibuffers[n];
  872.     n = 0;
  873.     }
  874. #endif /* MULTIBUFFER */
  875.  
  876.     dbpair.drawbuf = dbpair.bufs+n;
  877.     xgcv.foreground = dbpair.drawbuf->pixels[dbpair.pixelsperbuf-1];
  878.     xgcv.background = dbpair.drawbuf->pixels[0];
  879.     mask = GCForeground | GCBackground;
  880.     if (softdbl) {
  881.     xgcv.plane_mask = dbpair.drawbuf->enplanemask;
  882.     mask |= GCPlaneMask;
  883.     }
  884.     XChangeGC(dpy, gc, mask, &xgcv);
  885. }
  886.  
  887. setDisplayBuf(n)
  888. int n;
  889. {
  890. #if MULTIBUFFER
  891.     if (multibuf) {
  892.     static int firsttime = 1;
  893.  
  894.     XmbufDisplayBuffers (dpy, 1, &multibuffers[n], msleepcount, 0);
  895.     if (firsttime) {
  896.         firsttime = 0;
  897.         n = 0;
  898.         goto storecolors;
  899.     }
  900.     } else
  901. #endif
  902.     {
  903.       storecolors:
  904.     dbpair.dpybuf= dbpair.bufs+n;
  905.     if (dbpair.totalpixels > 2)
  906.         XStoreColors(dpy,cmap,dbpair.dpybuf->colors,dbpair.totalpixels);
  907.     }
  908. }
  909.  
  910. icoFatal(fmt,a0)
  911. char *fmt;
  912. {
  913.     fprintf(stderr,"ico: ");
  914.     fprintf(stderr,fmt,a0);
  915.     fprintf(stderr,"\n");
  916.     exit(1);
  917. }
  918.  
  919. /******************************************************************************
  920.  * Description
  921.  *    Concatenate two 4-by-4 transformation matrices.
  922.  *
  923.  * Input
  924.  *    l        multiplicand (left operand)
  925.  *    r        multiplier (right operand)
  926.  *
  927.  * Output
  928.  *    *m        Result matrix
  929.  *****************************************************************************/
  930.  
  931. ConcatMat(l, r, m)
  932. register Transform3D l;
  933. register Transform3D r;
  934. register Transform3D m;
  935.     {
  936.     register int i;
  937.     register int j;
  938.  
  939.     for (i = 0; i < 4; ++i)
  940.         for (j = 0; j < 4; ++j)
  941.             m[i][j] = l[i][0] * r[0][j]
  942.                 + l[i][1] * r[1][j]
  943.                 + l[i][2] * r[2][j]
  944.                 + l[i][3] * r[3][j];
  945.     }
  946.  
  947.  
  948.  
  949. /******************************************************************************
  950.  * Description
  951.  *    Format a matrix that will perform a rotation transformation
  952.  *    about the specified axis.  The rotation angle is measured
  953.  *    counterclockwise about the specified axis when looking
  954.  *    at the origin from the positive axis.
  955.  *
  956.  * Input
  957.  *    axis        Axis ('x', 'y', 'z') about which to perform rotation
  958.  *    angle        Angle (in radians) of rotation
  959.  *    A        Pointer to rotation matrix
  960.  *
  961.  * Output
  962.  *    *m        Formatted rotation matrix
  963.  *****************************************************************************/
  964.  
  965. FormatRotateMat(axis, angle, m)
  966. char axis;
  967. double angle;
  968. register Transform3D m;
  969.     {
  970.     double s, c;
  971.     double sin(), cos();
  972.  
  973.     IdentMat(m);
  974.  
  975.     s = sin(angle);
  976.     c = cos(angle);
  977.  
  978.     switch(axis)
  979.         {
  980.         case 'x':
  981.             m[1][1] = m[2][2] = c;
  982.             m[1][2] = s;
  983.             m[2][1] = -s;
  984.             break;
  985.         case 'y':
  986.             m[0][0] = m[2][2] = c;
  987.             m[2][0] = s;
  988.             m[0][2] = -s;
  989.             break;
  990.         case 'z':
  991.             m[0][0] = m[1][1] = c;
  992.             m[0][1] = s;
  993.             m[1][0] = -s;
  994.             break;
  995.         }
  996.     }
  997.  
  998.  
  999.  
  1000. /******************************************************************************
  1001.  * Description
  1002.  *    Format a 4x4 identity matrix.
  1003.  *
  1004.  * Output
  1005.  *    *m        Formatted identity matrix
  1006.  *****************************************************************************/
  1007.  
  1008. IdentMat(m)
  1009. register Transform3D m;
  1010.     {
  1011.     register int i;
  1012.     register int j;
  1013.  
  1014.     for (i = 3; i >= 0; --i)
  1015.         {
  1016.         for (j = 3; j >= 0; --j)
  1017.             m[i][j] = 0.0;
  1018.         m[i][i] = 1.0;
  1019.         }
  1020.     }
  1021.  
  1022.  
  1023.  
  1024. /******************************************************************************
  1025.  * Description
  1026.  *    Perform a partial transform on non-homogeneous points.
  1027.  *    Given an array of non-homogeneous (3-coordinate) input points,
  1028.  *    this routine multiplies them by the 3-by-3 upper left submatrix
  1029.  *    of a standard 4-by-4 transform matrix.  The resulting non-homogeneous
  1030.  *    points are returned.
  1031.  *
  1032.  * Input
  1033.  *    n        number of points to transform
  1034.  *    m        4-by-4 transform matrix
  1035.  *    in        array of non-homogeneous input points
  1036.  *
  1037.  * Output
  1038.  *    *out        array of transformed non-homogeneous output points
  1039.  *****************************************************************************/
  1040.  
  1041. PartialNonHomTransform(n, m, in, out)
  1042. int n;
  1043. register Transform3D m;
  1044. register Point3D *in;
  1045. register Point3D *out;
  1046.     {
  1047.     for (; n > 0; --n, ++in, ++out)
  1048.         {
  1049.         out->x = in->x * m[0][0] + in->y * m[1][0] + in->z * m[2][0];
  1050.         out->y = in->x * m[0][1] + in->y * m[1][1] + in->z * m[2][1];
  1051.         out->z = in->x * m[0][2] + in->y * m[1][2] + in->z * m[2][2];
  1052.         }
  1053.     }
  1054.