[alt.sources] xmb, fast mandelbrot for x-windows, part02/02

dm@rainbow.oulu.fi (Hannu Helminen) (05/23/91)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  cmap.c x.c
# Wrapped by dm@stekt2 on Thu May 23 16:38:45 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f cmap.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cmap.c\"
else
echo shar: Extracting \"cmap.c\" \(15828 characters\)
sed "s/^X//" >cmap.c <<'END_OF_cmap.c'
X
X/* This module is a dull one. It is somewhat important, however,
X * because it handles most of the interface between the program
X * and the user.
X
X * This module will allocate colors, free them; handle events of the
X * colormap window, including gadgets, sliders and spectrum;
X * it will also handle the mapping between iteration levels and
X * colors.
X
X * callable functios:
X * void ToggleCWin(display, window, mode);
X * int HandleCEvent(Display *display, int screen, Window window,
X                    GC gc1, GC gc2, GC gc3, Xevent *event);
X * void AllocColors(Display *display, int screen);
X * void FreeColors(Display *display, int screen);
X * void SetNColors(int number_of_colors);
X * unsigned long ToPixel(int level);
X
X */
X
X#include <X11/Xlib.h>
X#include <math.h>
X#include <stdio.h>
X#include "cmap.h"
X#include "misc.h"
X
X/* Geometries of gadgets.. */
X#define GAD_Y1 5
X#define GAD_Y2 20
X#define GAD_LEFT 10
X#define GAD_GAP 8
X/* ...Sliders... */
X#define TOP_GAP 25
X#define CHAR_X 5
X#define LINE_X 20
X#define BOX_X1 30
X#define BOX_X2 10
X#define BOX_Y1 3
X#define BOX_Y2 3
X#define BOTTOM_GAP 25
X/* ... cmap */
X#define CMAP_Y1 20
X#define CMAP_Y2 5
X#define BLACK_SIZE 4
X
X#define SLIDERSTEPS 64
X#define MAXSLIDE 65536
X
X#define GAMMA 2.2
X
Xstatic char *gadget[]= {"Apply", "Redraw", "Previous", "Restart", "Quit"};
X#define NUMGAD (sizeof(gadget)/sizeof(char *))
Xstatic struct gad_pos{
X  int s, e;
X  } gadpos[NUMGAD];
X
Xstatic long red[SLIDERSTEPS], green[SLIDERSTEPS],
X             blue[SLIDERSTEPS];
Xstatic long red0, green0, blue0;
Xstatic int coff= 0; /* color offset */
X
Xstatic unsigned long *pixel;
Xstatic char *alloc;
Xstatic int allocated= 0;
Xstatic int ncolors= 0;
X/* Does the current colormap reflect position of sliders? */
Xstatic int applied= 0;
X
Xstatic int mapped= 0;
X
Xstatic int width, height;
X
Xvoid ToggleCWin(display, win, mode)
XDisplay *display;
XWindow win;
Xint mode;
X{
Xif (mapped && (mode == CMAP_TOGGLE || mode == CMAP_CLOSE)) {
X  XUnmapWindow(display, win);
X  mapped= 0;
X  }
Xelse if (!mapped && (mode == CMAP_TOGGLE || mode == CMAP_OPEN)) {
X  XMapWindow(display, win);
X  mapped= 1;
X  }
X}
X
X
Xvoid DrawHotSpot(display, win, gc, x, y)
XDisplay *display;
XWindow win;
XGC gc;
Xint x,y;
X{
XXDrawRectangle(display, win, gc, x-3, y-3, 6, 6);
XXDrawRectangle(display, win, gc, x-2, y-2, 4, 4);
X}
X
X
Xvoid DrawSliders(display, win, gc, n)
XDisplay *display;
XWindow win;
XGC gc;
Xint n;
X{
Xint i;
Xint zone= (height-TOP_GAP-BOTTOM_GAP)/3;
Xlong *color;
X
Xswitch(n) {
X  case 0: color= red; break;
X  case 1: color= green; break;
X  case 2: color= blue; break;
X  }
Xfor (i= 0; i < SLIDERSTEPS; i++) {
X  int j= (i+1) % SLIDERSTEPS;
X  int x1= BOX_X1 + 1+i*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
X  int x2= BOX_X1 + 1+(i+1)*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
X  int y1= TOP_GAP + n*zone + BOX_Y1 +
X          1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[i]))/MAXSLIDE;
X  int y2= TOP_GAP + n*zone + BOX_Y1 +
X          1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[j]))/MAXSLIDE;
X
X  XDrawLine(display, win, gc, x1, y1, x2, y2);
X  }
X}
X
X
Xvoid DrawSlider(display, win, gc1, gc2, n, trash)
XDisplay *display;
XWindow win;
XGC gc1, gc2;
Xint n, trash;
X{
Xint zone =(height-TOP_GAP-BOTTOM_GAP) / 3;
Xstatic int oy[3]= {-1, -1, -1};
Xint y;
Xint h;
X
Xswitch(n) {
X  case 0: h= red0; break;
X  case 1: h= green0; break;
X  case 2: h= blue0; break;
X  default: break;
X  }
Xy= TOP_GAP + n*zone + BOX_Y1 + ((zone-BOX_Y1-BOX_Y2)*(MAXSLIDE-h))/MAXSLIDE;
X
Xif (y != oy[n] || trash) {
X  if (oy[n] >= 0)
X    DrawHotSpot(display, win, gc2, LINE_X, oy[n]);
X  DrawHotSpot(display, win, gc1, LINE_X, y);
X  oy[n]= y;
X  XDrawLine(display, win, gc1,
X            LINE_X, TOP_GAP+n*zone+BOX_Y1, LINE_X, TOP_GAP+(n+1)*zone-BOX_Y2);
X  }
X}
X
X
Xvoid DrawSliderBox(display, win, gc, n)
XDisplay *display;
XWindow win;
XGC gc;
Xint n;
X{
Xint zone= (height-TOP_GAP-BOTTOM_GAP)/3;
Xchar ch[2]; 
X
Xch[1]= '\0';
Xswitch(n) {
X  case 0: ch[0]= 'R'; break;
X  case 1: ch[0]= 'G'; break;
X  case 2: ch[0]= 'B'; break;
X  }
XXDrawRectangle(display, win, gc,
X               BOX_X1, TOP_GAP + n*zone + BOX_Y1,
X               width-BOX_X1-BOX_X2, zone-BOX_Y1-BOX_Y2);
XWriteText(display, win, gc, ch, CHAR_X,
X       TOP_GAP + n*zone + BOX_Y1 + (zone-BOX_Y1-BOX_Y2)/2-6 );
X}
X
X
Xvoid DrawColorBox(display, win, gc, gc1)
XDisplay *display;
XWindow win;
XGC gc, gc1;
X{
Xint i;
XXGCValues gcval;
X
Xgcval.foreground= pixel[0];
XXChangeGC(display, gc, GCForeground, &gcval);
X
XXFillRectangle(display, win, gc,
X               LINE_X-BLACK_SIZE, height-CMAP_Y1,
X               2*BLACK_SIZE, CMAP_Y1-CMAP_Y2);
XXDrawRectangle(display, win, gc1,
X               LINE_X-BLACK_SIZE, height-CMAP_Y1,
X               2*BLACK_SIZE, CMAP_Y1-CMAP_Y2);
X
Xfor (i= 1; i < ncolors; i++) {
X  int x1= ((width-BOX_X2-BOX_X1)*(i-1)/(ncolors-1));
X  int x2= ((width-BOX_X2-BOX_X1)*i/(ncolors-1));
X
X  gcval.foreground= pixel[i];
X  XChangeGC(display, gc, GCForeground, &gcval);
X
X  XFillRectangle(display, win, gc,
X                 BOX_X1+x1, height-CMAP_Y1,
X                 x2-x1, CMAP_Y1-CMAP_Y2);
X  }
XXDrawRectangle(display, win, gc1,
X               BOX_X1, height-CMAP_Y1,
X               width-BOX_X2-BOX_X1, CMAP_Y1-CMAP_Y2);
X} /* DrawColorBox() */
X
X
Xint InCmap(x, y)
Xint x, y;
X{
Xint c;
Xif (y < height-CMAP_Y1 || y > height-CMAP_Y2)
X  return(0);
Xc= (x-BOX_X1)*ncolors/(width-BOX_X2-BOX_X1);
Xif (c<= 0 || c >= ncolors)
X  return(0);
Xreturn(c);
X}
X
X
Xint InSlider(x, y, n)
Xint x, y, n;
X{
Xint zone= (height-TOP_GAP-BOTTOM_GAP)/3;
X
Xif (y < TOP_GAP + (n%3)*zone + BOX_Y1 || y > TOP_GAP + ((n%3)+1)*zone - BOX_Y2)
X  return 0;
Xif (n < 3) {
X  if (x > (3*LINE_X - BOX_X1) / 2 && x < (LINE_X+BOX_X1) / 2)
X    return 1;
X  }
Xelse {
X  if (x > BOX_X1 && x < width-BOX_X2)
X    return 1;
X  }
Xreturn 0;
X}
X
X
Xvoid DragSlider(display, win, gc1, gc2, n, x1, y1, x2, y2)
XDisplay *display;
XWindow win;
XGC gc1, gc2;
Xint n, x1, y1, x2, y2;
X{
Xint zone= (height-TOP_GAP-BOTTOM_GAP)/3;
Xint s1= (x1-BOX_X1)*SLIDERSTEPS / (width-BOX_X1-BOX_X2+1);
Xint s2= (x2-BOX_X1)*SLIDERSTEPS / (width-BOX_X1-BOX_X2+1);
Xint c1= ((TOP_GAP + ((n%3)+1)*zone - BOX_Y2) - y1) *
X      (MAXSLIDE-1) / (zone - BOX_Y2 - BOX_Y1);
Xint c2= ((TOP_GAP + ((n%3)+1)*zone - BOX_Y2) - y2) *
X      (MAXSLIDE-1) / (zone - BOX_Y2 - BOX_Y1);
X
Xif (c1 < 0) c1= 0;
Xif (c2 < 0) c2= 0;
Xif (c1 >= MAXSLIDE) c1= MAXSLIDE-1;
Xif (c2 >= MAXSLIDE) c2= MAXSLIDE-1;
Xif (s1 < 0) s1= 0;
Xif (s2 < 0) s2= 0;
Xif (s1 >= SLIDERSTEPS) s1= SLIDERSTEPS-1;
Xif (s2 >= SLIDERSTEPS) s2= SLIDERSTEPS-1;
Xif (s1 > s2) {
X  int tmp= s2; s2= s1; s1= tmp;
X  tmp= c2; c2= c1; c1= tmp;
X  }
X
Xapplied= 0; /* colormap no longer valid */
Xif (n < 3) {
X  switch(n) {
X    case 0: red0= c2; break;
X    case 1: green0= c2; break;
X    case 2: blue0= c2; break;
X    }
X  DrawSlider(display, win, gc1, gc2, n, 0);
X  } /* if */
Xelse {
X  long *color;
X  int i;
X  n -= 3;
X  switch(n) {
X    case 0: color= red; break;
X    case 1: color= green; break;
X    case 2: color= blue; break;
X    }
X  for (i= s1-1; i <= s2; i++) {
X    int j= i;
X    int k= (i+1) % SLIDERSTEPS;
X    int x1, x2, y1, y2;
X
X    if (j < 0) j += SLIDERSTEPS;
X    x1= BOX_X1 + 1+j*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
X    x2= BOX_X1 + 1+(j+1)*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
X    y1= TOP_GAP + n*zone + BOX_Y1 +
X        1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[j]))/MAXSLIDE;
X    y2= TOP_GAP + n*zone + BOX_Y1 +
X        1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[k]))/MAXSLIDE;
X    XDrawLine(display, win, gc2, x1, y1, x2, y2);
X    }
X  if (s1 == s2)
X    color[s1]= c1;
X  else
X    for (i= 0; i <= s2-s1; i++)
X      color[s1+i]= c1*(s2-s1-i)/(s2-s1) + c2*i/(s2-s1);
X  for (i= s1-1; i <= s2; i++) {
X    int j= i;
X    int k= (i+1) % SLIDERSTEPS;
X    int x1, x2, y1, y2;
X
X    if (j < 0) j += SLIDERSTEPS;
X    x1= BOX_X1 + 1+j*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
X    x2= BOX_X1 + 1+(j+1)*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
X    y1= TOP_GAP + n*zone + BOX_Y1 +
X        1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[j]))/MAXSLIDE;
X    y2= TOP_GAP + n*zone + BOX_Y1 +
X        1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[k]))/MAXSLIDE;
X    XDrawLine(display, win, gc1, x1, y1, x2, y2);
X    }
X  } /* else */
X} /* DragSlider() */
X
X
Xvoid DrawGadgets(display, win, gc)
XDisplay *display;
XWindow win;
XGC gc;
X{
Xint i;
Xint x= GAD_LEFT;
Xfor (i= 0; i < NUMGAD; i++) {
X  int len= WriteText(display, win, gc, gadget[i], x+3, GAD_Y1+1);
X  gadpos[i].s= x;
X  gadpos[i].e= x+len+6;
X  XDrawRectangle(display, win, gc, x, GAD_Y1,
X                 len+6, GAD_Y2-GAD_Y1);
X  x+= len+6 + GAD_GAP;
X  }
X}
X
X
Xint CheckGadget(display, win, gc1, gc2, x, y)
XDisplay *display;
XWindow win;
XGC gc1, gc2;
Xint x, y;
X{
Xint i;
Xstatic int drawn= -1;
Xif (y >= GAD_Y1 && y <= GAD_Y2) {
X  for (i= 0; i < NUMGAD; i++) {
X    if (x >= gadpos[i].s && x <= gadpos[i].e) {
X      if (drawn >= 0 && drawn != i)
X        XDrawRectangle(display, win, gc2, gadpos[drawn].s+1, GAD_Y1+1,
X                  gadpos[drawn].e-gadpos[drawn].s-2, GAD_Y2-GAD_Y1-2);
X      if (drawn != i)
X        XDrawRectangle(display, win, gc1, gadpos[i].s+1, GAD_Y1+1,
X                  gadpos[i].e-gadpos[i].s-2, GAD_Y2-GAD_Y1-2);
X      drawn= i;
X      return(i);
X      }
X    } /* for */
X  } /* if */
Xif (drawn >= 0) {
X  XDrawRectangle(display, win, gc2, gadpos[drawn].s+1, GAD_Y1+1,
X                 gadpos[drawn].e-gadpos[drawn].s-2, GAD_Y2-GAD_Y1-2);
X  drawn= -1;
X  }
Xreturn(-1);
X}
X
X
Xint HandleCEvent(display, screen, win, gc, gc1, gc2, event)
XDisplay *display;
Xint screen;
XWindow win;
XGC gc, gc1, gc2;
XXEvent *event;
X{
Xint i;
Xstatic int dragging= -1;
Xstatic int cmaphandle= 0, c1, c2;
Xstatic int dragx, dragy;
Xint gadget;
X
Xswitch (event->type) {
X  case Expose:
X    /* This is a simple application, redraw the whole
X     * window only when no more expose events exist.
X     */
X    if (event->xexpose.count)
X      break;
X    for (i= 0; i < 3; i++) {
X      DrawSliderBox(display, win, gc1, i);
X      DrawSliders(display, win, gc1, i);
X      DrawSlider(display, win, gc1, gc2, i, 1);
X      }
X    DrawColorBox(display, win, gc, gc1);
X    DrawGadgets(display, win, gc1);
X    break;
X                   
X  case ConfigureNotify:
X    width= event->xconfigure.width;
X    height= event->xconfigure.height;
X    break;
X
X  case ButtonPress:
X    switch(event->xbutton.button) {
X      case 1:
X        for (i= 0; i < 6; i++) {
X          dragx= event->xbutton.x;
X          dragy= event->xbutton.y;
X          if (InSlider(dragx, dragy, i)) {
X            dragging= i;
X            SlideCursor(display, win);
X            DragSlider(display, win, gc1, gc2, dragging,
X                    dragx, dragy, dragx, dragy);
X            }
X          }
X        if (dragging >= 0)
X          break;
X        gadget= CheckGadget(display, win, gc1, gc2,
X                       event->xbutton.x, event->xbutton.y);
X        switch(gadget) {
X          case 0: /* apply */
X          case 1: /* redraw */
X            if (!applied) {
X              WaitCursor(display, win);
X              AllocColors(display, screen);
X              NormalCursor(display, win);
X              DrawColorBox(display, win, gc, gc1);
X              }
X            if (gadget == 1)
X              return(DO_REDRAW);
X            break;
X          case 2:
X            return(DO_PREVIOUS);
X          case 3:
X            return(DO_RESTART);
X          case 4:
X            return(DO_QUIT);
X          } /* switch */
X        if (gadget >= 0)
X          break;
X        if (c1= InCmap(event->xbutton.x, event->xbutton.y)) {
X          cmaphandle= 1;
X          VertCursor(display, win);
X          }
X        break;
X      case 2:
X        dragging= -1;
X        WaitCursor(display, win);
X        AllocColors(display, screen);
X        NormalCursor(display, win);
X        DrawColorBox(display, win, gc, gc1);
X        break;
X      default:
X        dragging= -1;
X        ToggleCWin(display, win, CMAP_CLOSE);
X        break;
X      }
X      break;
X  case ButtonRelease:
X    if (dragging >= 0) {
X      dragging= -1;
X      NormalCursor(display, win);
X      }
X    if (cmaphandle) {
X      if (c2= InCmap(event->xbutton.x, event->xbutton.y)) {
X        coff = (coff + c2 - c1) % ncolors;
X        }
X      cmaphandle= 0;
X      NormalCursor(display, win);
X      }
X    break;
X  case MotionNotify:
X    if (dragging >= 0) { 
X      DragSlider(display, win, gc1, gc2, dragging, dragx, dragy,
X              event->xmotion.x, event->xmotion.y);
X      dragx= event->xmotion.x;
X      dragy= event->xmotion.y;
X      }
X    else CheckGadget(display, win, gc1, gc2,
X                event->xmotion.x, event->xmotion.y);
X    break;
X  case KeyPress:
X    dragging= -1;
X    NormalCursor(display, win);
X    ToggleCWin(display, win, CMAP_CLOSE);
X    break;
X  case MapNotify:
X  case ReparentNotify:
X  case UnmapNotify:
X    dragging= -1;
X    break;
X  default:
X    printf("Unknown Event %d\n", event->type);
X    break;
X  } /* switch */
Xreturn(-1);
X} /* HandleCEvent */
X
X
Xvoid SetNColors(nc)
Xint nc;
X{
Xint i;
Xncolors= nc;
X/* Initialize some nice-looking colors... */
Xfor (i= 0; i < SLIDERSTEPS; i++) {
X  float c= i/((double)SLIDERSTEPS) * 3;
X  float r, g, b;
X       if (c < 1) {r= 1-c; g= c;   b= 0;}
X  else if (c < 2) {r= 0;   g= 2-c; b= c-1;}
X  else            {r= c-2; g= 0;   b= 3-c;}
X  red[i]= r*(MAXSLIDE-1);
X  green[i]= g*(MAXSLIDE-1);
X  blue[i]= b*(MAXSLIDE-1);
X  }
Xred0= green0= blue0= 0;
X}
X
X
Xvoid AllocColors(display, screen)
XDisplay *display;
Xint screen;
X{
Xint i, first= -1;
Xint d;
XXColor color;
X
Xif (allocated) 
X  FreeColors(display, screen);
X
Xallocated= 1;
Xapplied= 1; /* colormap is being made valid again */
Xalloc= (char *)malloc(ncolors);
Xpixel= (unsigned long *)malloc(ncolors * sizeof(unsigned long));
Xfor (i= 0; i < ncolors; i++)
X  alloc[i]= 0;
X
Xif (ncolors == 3) {
X  pixel[0]= BlackPixel(display, screen);
X  pixel[1]= WhitePixel(display, screen);
X  pixel[2]= BlackPixel(display, screen);
X  return;
X  }
Xif (ncolors <= 2) {
X  pixel[0]= BlackPixel(display, screen);
X  pixel[1]= WhitePixel(display, screen);
X  return;
X  }
X
X/* Because first entry of colormap is so special, allocate it first. */
Xcolor.red= red0;
Xcolor.green= green0;
Xcolor.blue= blue0;
Xcolor.flags= DoRed | DoGreen | DoBlue;
Xif (XAllocColor(display, DefaultColormap(display, screen), &color)) {
X  pixel[0]= color.pixel;
X  alloc[0]= 1;
X  }
Xelse
X  pixel[0]= BlackPixel(display, screen);
X
X/* Try to allocate colors. The order in which this is done should
X * be as "random" as possible, so that failing requests would
X * not be grouped at the end.
X */
Xd= 1;
Xwhile (d < ncolors) d <<= 1;
Xwhile (d > 1) {
X  int c= d >> 1;
X  do {
X    double r, g, b;
X    int s1= c*SLIDERSTEPS/ncolors;
X    int s2= s1+1;
X    int j= (c*SLIDERSTEPS)%ncolors;
X
X    if (s2 >= SLIDERSTEPS)
X      s2= 0;
X
X    r= (red[s1]*(ncolors-j)/ncolors + red[s2]*j/ncolors)/(double)MAXSLIDE;
X    g= (green[s1]*(ncolors-j)/ncolors + green[s2]*j/ncolors)/(double)MAXSLIDE;
X    b= (blue[s1]*(ncolors-j)/ncolors + blue[s2]*j/ncolors)/(double)MAXSLIDE;
X
X    /* Do reverse gamma correction... */
X    color.red= pow(r, (1/GAMMA))*65535;
X    color.green= pow(g, (1/GAMMA))*65535;
X    color.blue= pow(b, (1/GAMMA))*65535;
X
X    if (XAllocColor(display, DefaultColormap(display, screen), &color)) {
X      pixel[c]= color.pixel;
X      alloc[c]= 1;
X      if (first < 0) first= c; else if (first > c) first= c;
X      } /* if */
X    c += d;
X    } while (c < ncolors);
X    d >>= 1;
X  } /* while */
X
X/* If no colors could be allocated, use black&white. */
Xif (first < 0) {
X  for (i= 1; i < ncolors; i++)
X    pixel[i]= WhitePixel(display, screen);
X  return;
X  }
X/* Fill in gaps... */
Xfor (i= 1; i < ncolors; i++) {
X  if (!alloc[i])
X    pixel[i]= pixel[first];
X  else
X    first= i;
X  }
X} /* AllocColors */
X
X
Xvoid FreeColors(display, screen)
XDisplay *display;
Xint screen;
X{
Xint i;
X
Xif (allocated) {
X  for (i= 0; i < ncolors; i++)
X    if (alloc[i])
X      XFreeColors(display, DefaultColormap(display, screen),
X                  &pixel[i], 1L, 0);
X  free(alloc);
X  free(pixel);
X  }
X}
X
X
Xunsigned long ToPixel(level)
Xint level;
X{
Xif (level != 0)
X  level= ((level+coff) % (ncolors - 1)) + 1;
Xreturn(pixel[level]);
X}
X
END_OF_cmap.c
if test 15828 -ne `wc -c <cmap.c`; then
    echo shar: \"cmap.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f x.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"x.c\"
else
echo shar: Extracting \"x.c\" \(22670 characters\)
sed "s/^X//" >x.c <<'END_OF_x.c'
X
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#include <X11/Xos.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/param.h>
X#include <termio.h>
X#include <stdio.h>
X#include <strings.h>
X#include "mb.h"
X#include "cmap.h"
X#include "misc.h"
X#include "pix.h"
X
X#ifdef USE_NETWORK
X#include "ipc.h"
X#endif
X
X#define GEOM_PLACE 1
X#define GEOM_RIGHT 2
X#define GEOM_DOWN 4
X#define GEOM_SIZE 8
X#define GEOM_ERROR 16
X
X/* Just to make sure that the number of colors will be reasonable
X * on a 24-bit true-color display ;)
X */
X#define MAXCOLORS 1024
X
X/* dummy procedure for XCheckIfEvent */
XBool dummy() {return(1);}
X
X#ifdef USE_NETWORK
X/* Terminology: server is the one who shows pictures, and
X * clients do the calculations. 
X */
X
X#define MODE_STANDALONE 0
X#define MODE_SERVER 1
X#define MODE_CLIENT 2
X
X#define RSHCMD "rsh %s \"xnetmb -nice 10 -port %d -server %s&\" </dev/null >/dev/null"
X#endif
X
Xstatic Display *display;
Xstatic int screen;
Xstatic Window win= 0, cwin= 0;
Xstatic GC gc, gc_inv, gc_set, gc_clear;
X#ifdef USE_NETWORK
Xstatic int mode= MODE_STANDALONE;
Xstatic int portnum= DEF_PORT;
Xstatic char *server;
X#endif
X
Xvoid DrawSplitImage();
Xvoid CalcImage();
Xvoid DrawImage();
Xvoid DrawRect();
X#define EraseRect() DrawRect(0, 0,0, 0,0, 0,0);
X
Xstatic double xc= 0.0, yc= 0.0, cx= 0.0, cy= 0.0, d= 0.0, scale= 8.0;
Xstatic int iter= 500, flags= 0;
Xunsigned int width= 300, height= 300;
X
X
Xint ParseComplex(string, x, y)
Xchar *string;
Xdouble *x, *y;
X{
Xchar ii, sign;
X/* x+-yi */
Xif (sscanf(string, "%lf%lf%c", x, y, &ii) == 3 &&
X    ii == 'i')
X  ;
X/* x+-iy  */
Xelse if (sscanf(string, "%lf%ci%lf", x, &sign, y) == 3 &&
X         (sign == '+' || sign == '-')) {
X  if  (sign == '-') *y = -*y;
X  }
X/* x+-i */
Xelse if (sscanf(string, "%lf%c%c", x, &sign, &ii) == 3 &&
X         (sign == '+' || sign == '-') && ii == 'i') {
X  if (sign == '-')
X    *y= -1.0;
X  else
X    *y= 1.0;
X  }
X/* +-iy */
Xelse if (sscanf(string, "%c%c%lf", &ii, &sign, y) == 3 &&
X      (sign == '+' || sign == '-') && ii == 'i') {
X  *x= 0.0;
X  if (sign == '-')
X    *y= -*y;
X  }
X/* yi */
Xelse if (sscanf(string, "%lf%c", y, &ii) == 2 && ii == 'i')
X  *x= 0.0;
X/* iy */
Xelse if (sscanf(string, "%c%lf", &ii, y) == 2 && ii == 'i')
X  *x= 0.0;
X/* +-i */
Xelse if (sscanf(string, "%c%c", &sign, &ii) == 2 &&
X      (sign == '-' || sign == '+') && ii == 'i') {
X  *x= 0.0;
X  if (sign == '-')
X    *y= -1.0;
X  else
X    *y= 1.0;
X  }
X/* i */
Xelse if (sscanf(string, "%c", &ii) == 1 && ii == 'i') {
X  *x= 0.0;
X  *y= 1.0;
X  }
X/* x */
Xelse if (sscanf(string, "%lf", x) == 1)
X  *y= 0.0;
Xelse
X  return(0);
Xreturn(1);
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
XXSizeHints size_hints;
XXEvent event;
XXGCValues gcval;
XXWindowAttributes xwattr;
XXSetWindowAttributes xswattr;
Xunsigned int border_width= 1;
Xunsigned int display_width, display_height;
Xint win_x= 0, win_y= 0;
Xint cwin_x= 0, cwin_y= 0;
Xint dragx, dragy;
Xint buttonpressed;
Xint ncolors= 0;
Xint zebra= 0;
Xdouble xstore1= xc, ystore1= yc, scalestore1= scale;
Xdouble xstore2= xc, ystore2= yc, scalestore2= scale;
Xint flagstore= flags;
Xint wingeom= 0;
Xchar **mach;
Xint nmach= 0;
Xchar *window_name= "XMandelbrot";
Xchar *icon_name= "XMandel";
Xchar *cwindow_name= "MBcolors";
Xchar *cicon_name= "MBcolors";
Xchar *display_name= NULL;
X
Xint i;
X
X/* Command line options... boring.
X * (OH NO, it is my pseudo-intelligent commenting style attack again.
X * Sigh... Please be patient and hope for the best.)
X */
Xfor (i= 1; i < argc; i++) {
X  if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "-display")) {
X    if (++i >= argc) {
X      fprintf(stderr, "%s: error in cmd line option 'display'\n",
X          argv[0]);
X      exit(1);
X      }
X    display_name= argv[i];
X    }
X
X  else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "-geometry")) {
X    char sign1, sign2;
X    if (++i >= argc) {
X      fprintf(stderr, "%s: error in cmd line option 'geometry'\n",
X          argv[0]);
X      exit(1);
X      }
X    switch (sscanf(argv[i], "%ux%u%c%d%c%d",
X        &width, &height, &sign1, &win_x, &sign2, &win_y)) {
X      case 6:
X        wingeom= GEOM_PLACE | GEOM_SIZE;
X        if (sign1 == '-') wingeom |= GEOM_RIGHT;
X        else if (sign1 != '+') wingeom |= GEOM_ERROR;
X        if (sign2 == '-') wingeom |= GEOM_DOWN;
X        else if (sign2 != '+') wingeom |= GEOM_ERROR;
X        if (wingeom & GEOM_ERROR) {
X          fprintf(stderr,
X              "%s: error in cmd line option 'geometry'\n",
X                  argv[0]);
X          exit(1);
X          }
X        break;
X      case 2:
X        wingeom= GEOM_SIZE;
X        /* There is nothing else here to be done. */
X        break;
X      default:
X        fprintf(stderr, "%s: error in cmd line option 'geometry'\n",
X            argv[0]);
X        exit(1);
X      }
X    }
X
X  else if (!strcmp(argv[i], "-z") || !strcmp(argv[i], "-zebra")) {
X    /* Need to know which of the two -z options this is... */
X    if (!strcmp(argv[i], "-z") && i+1 < argc &&
X        ParseComplex(argv[i+1], &xc, &yc)) {
X      i++;
X      xstore1= xc; ystore1= yc;
X      }
X    else
X      zebra= 1;
X    }
X
X  else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "-nice")) {
X    if (++i >= argc) {
X      fprintf(stderr, "%s: error in cmd line option 'nice'\n",
X          argv[0]);
X      exit(1);
X      }
X    setpriority(PRIO_PROCESS,getpid(), atoi(argv[i]));
X    }
X
X  else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "-iters")) {
X    if (++i >= argc) {
X      fprintf(stderr, "%s: error in cmd line option 'iters'\n",
X          argv[0]);
X      exit(1);
X      }
X    iter= atoi(argv[i]);
X    }
X
X  else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "-colors")) {
X    if (++i >= argc) {
X      fprintf(stderr, "%s: error in cmd line option 'colors\n",
X          argv[0]);
X      exit(1);
X      }
X    ncolors= atoi(argv[i]);
X    if (ncolors < 2)
X      ncolors= 2;
X    }
X
X  else if (!strcmp(argv[i], "-j")) {
X    if (++i >= argc || !ParseComplex(argv[i], &cx, &cy)) {
X      fprintf(stderr, "%s: error in cmd line option 'j'\n",
X              argv[0]);
X      exit(1);
X      }
X    flagstore = (flags |= JULIA);
X    }
X
X  else if (!strcmp(argv[i], "-x")) {
X    if (++i >= argc || sscanf(argv[i], "%lf", &scale) < 1) {
X      fprintf(stderr, "%s: error in cmd line option 'x'\n",
X              argv[0]);
X      exit(1);
X      }
X    scalestore1 = (scale *= 2);
X    }
X      
X#ifdef USE_NETWORK
X  else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "-server")) {
X    int k;
X    if (++i >= argc || mode != MODE_STANDALONE) {
X      fprintf(stderr, "%s: error in cmd line option 'server'\n",
X          argv[0]);
X      exit(1);
X      }
X    /* We are the client, and server is specified here. */
X    mode= MODE_CLIENT;
X    server= argv[i];
X    /* daemon  */
X    for (k= getdtablesize() - 1; k >= 0; --k)
X      close(k);
X    k= open("/dev/null", O_RDONLY);
X    if (k >= 0) {
X      ioctl(k, TIOCNOTTY, 0);
X      close(k);
X      }
X    }
X#endif
X
X#ifdef USE_NETWORK
X  else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "-port")) {
X    if (++i >= argc) {
X      fprintf(stderr, "%s: error in cmd line option 'iters'\n",
X          argv[0]);
X      exit(1);
X      }
X    portnum= atoi(argv[i]);
X    }
X#endif
X
X#ifdef USE_NETWORK
X  else if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "-machines")) {
X    if (mode != MODE_STANDALONE) {
X      fprintf(stderr, "%s: error in command line option 'machines'\n",
X        argv[0]);
X      exit(1);
X      }
X      
X    mode= MODE_SERVER;
X    mach= &argv[i+1];
X    while (++i < argc && argv[i][0] != '-')
X      nmach++;
X    --i;
X    }
X#endif
X
X  else if (!strcmp(argv[i], "-guru")) {
X    if (++i >= argc) {
X      fprintf(stderr, "%s: You are not a guru.\n", argv[0]);
X      exit(1);
X      }
X    if (!strcmp(argv[i], "fast")) {
X      flagstore= (flags |= FAST);
X      }
X    else {
X      fprintf(stderr, "%s: You are not a guru.\n", argv[0]);
X      exit(1);
X      }
X    }
X
X  else {
X    fprintf(stderr, "%s: unrecognized cmd line option '%s'\n\n",
X            argv[0], argv[i]);
X    fprintf(stderr,
X            "Usage: %s -display <name> -geometry <geometry>\n",
X        argv[0]);
X    fprintf(stderr,
X            "-zebra -nice <value> -iters <i> -colors <number>\n");
X    fprintf(stderr,
X            "-z <x+yi> -j <cx+cyi> -x <scale>\n");
X#ifdef USE_NETWORK
X    fprintf(stderr,
X            "-server <name> -port <port> -machines [list of rsh machines]\n");
X#endif
X    fprintf(stderr, "\nAll options may be abbreviated.\n\n");
X    exit(1);
X    }
X  } /* for */
X
X#ifdef USE_NETWORK
Xif (mode == MODE_CLIENT) {
X  Client_run(server, portnum);
X  exit(0);
X  }
Xelse if (mode == MODE_SERVER) {
X  char cmd[sizeof(RSHCMD) + 2*MAXHOSTNAMELEN], host[MAXHOSTNAMELEN];
X  if (gethostname(host, MAXHOSTNAMELEN) < 0) {
X    perror("unable to find my name");
X    exit(1);
X    }
X  CreateServer(portnum);
X  printf("Starting remote machines:");
X  for (i= 0; i < nmach; i++) {
X    sprintf(cmd, RSHCMD, mach[i], portnum, host);
X    printf (" %s", mach[i]); fflush(stdout);
X    if ((system(cmd) >> 8) > 0) {
X      fprintf(stderr, "%s: unable to rsh %s\n", argv[0],
X          mach[i]);
X      }
X    }
X  --i;
X  putchar('\n');
X  }
X#endif
X
X/* Open the display, if possible. */
Xif(!(display= XOpenDisplay(display_name))) {
X  fprintf(stderr, "cannot reach X server %s\n",
X        XDisplayName(display_name));
X  exit(1);
X  }
X
Xscreen= DefaultScreen(display);
X
Xdisplay_width= DisplayWidth(display, screen);
Xdisplay_height= DisplayHeight(display, screen);
X
Xif (!(wingeom & GEOM_PLACE)) {
X  win_x= display_width / 2 - (int)width;
X  win_y= 2 * display_height / 3;
X  }
Xelse {
X  if (wingeom & GEOM_RIGHT) win_x= (int)display_width - win_x - (int)width;
X  if (wingeom & GEOM_DOWN) win_y= (int)display_height - win_y - (int)height;
X  }
X
Xcwin_x= display_width / 2 - 200;
Xcwin_y= display_height - 250;
X
X
Xif (ncolors == 0)
X  ncolors= 1 << (DefaultDepth(display, screen));
Xif (zebra) ncolors= 3;
Xif (ncolors > MAXCOLORS)
X  ncolors= MAXCOLORS;
XSetNColors(ncolors);
X
Xxswattr.background_pixel= WhitePixel(display, screen);
Xxswattr.border_pixel= BlackPixel(display, screen);
Xwin= XCreateWindow(display, RootWindow(display, screen), win_x, win_y,
X                    width, height, border_width, CopyFromParent,
X                    InputOutput, CopyFromParent,
X                    CWBackPixel | CWBorderPixel, &xswattr);
Xcwin= XCreateWindow(display, RootWindow(display, screen), cwin_x, cwin_y,
X                     400, 200, border_width, CopyFromParent,
X                     InputOutput, CopyFromParent,
X                     CWBackPixel | CWBorderPixel, &xswattr);
X
Xif (!win  || !cwin) {
X#ifdef USE_NETWORK
X  if (mode == MODE_SERVER)
X    CloseDown();
X#endif
X  perror("could not open window");
X  myExit();
X  exit(0);
X  }
X
Xsize_hints.flags= PMinSize;
Xif (wingeom & GEOM_PLACE) size_hints.flags |= PPosition;
Xif (wingeom & GEOM_SIZE) size_hints.flags |= PSize;
X
Xsize_hints.width= width;
Xsize_hints.height= height;
Xsize_hints.min_width= 50;
Xsize_hints.min_height= 50;
Xsize_hints.x= win_x;
Xsize_hints.y= win_y;
XXSetStandardProperties(display, win, window_name, icon_name,
X                       None, NULL, 0, &size_hints);
X
Xsize_hints.flags= PPosition | PSize | PMinSize;
Xsize_hints.width= 400;
Xsize_hints.height= 200;
Xsize_hints.min_width= 200;
Xsize_hints.min_height= 100;
Xsize_hints.x= cwin_x;
Xsize_hints.y= cwin_y;
XXSetStandardProperties(display, cwin, cwindow_name, cicon_name,
X                       None, NULL, 0, &size_hints);
X
XXSelectInput(display, win, ExposureMask | KeyPressMask |
X             ButtonPressMask | ButtonReleaseMask |
X             PointerMotionMask | StructureNotifyMask);
XXSelectInput(display, cwin, ExposureMask | KeyPressMask |
X             ButtonPressMask | ButtonReleaseMask |
X             PointerMotionMask | StructureNotifyMask);
X
Xgcval.foreground= BlackPixel(display, screen);
Xgcval.background= WhitePixel(display, screen);
Xgc= XCreateGC(display, win, GCForeground | GCBackground, &gcval);
Xgc_set= XCreateGC(display, win, GCForeground | GCBackground, &gcval);
X
Xgcval.foreground= WhitePixel(display, screen);
Xgc_clear= XCreateGC(display, win, GCForeground | GCBackground, &gcval);
X
Xgcval.function= GXinvert;
Xgc_inv= XCreateGC(display, win, GCFunction, &gcval);
X
Xif (!AllocFonts(display, gc_set)) {
X  fprintf(stderr, "Could not open fonts... no text will be drawn");
X  }
XAllocColors(display, screen);
X
XAllocCursors(display);
XNormalCursor(display, win);
XNormalCursor(display, cwin);
X
XXMapWindow(display, win);
Xbuttonpressed= 0;
X
Xfor (;;) {
X#ifdef USE_NETWORK
X  if (mode == MODE_SERVER) 
X    CheckClients(NOBLOCK);
X
X  if (mode == MODE_SERVER && PendingRequests()) {
X    while (!XCheckIfEvent(display, &event, dummy, (char *)NULL)) 
X      CheckClients(1);
X    if (!PendingRequests()) {
X      NormalCursor(display, win);
X      NormalCursor(display, cwin);
X      }
X    }
X  else 
X    XNextEvent(display, &event);
X#else
X  XNextEvent(display, &event);
X#endif
X
X  if (event.xany.window == cwin) {
X    switch (HandleCEvent(display, screen, cwin, gc,
X                  gc_set, gc_clear, &event)) {
X      case DO_REDRAW:
X#ifdef USE_NETWORK
X            if (mode == MODE_SERVER) Invalidate();
X#endif
X        XClearArea(display, win, 0, 0, width, height, 1);
X        break;
X      case DO_PREVIOUS:
X        if (xc != xstore1 || yc != ystore1 ||
X            scale != scalestore1 || flags != flagstore) {
X          xc= xstore1; yc= ystore1;
X          scale= scalestore1;
X          flags= flagstore;
X          d= scale / (width + height);
X#ifdef USE_NETWORK
X            if (mode == MODE_SERVER) Invalidate();
X#endif
X          XClearArea(display, win, 0, 0, width, height, 1);
X          }
X        break;
X      case DO_RESTART:
X        xstore1= xc; ystore1= yc;
X        scalestore1= scale;
X        flagstore= flags;
X
X        xc= 0.0; yc= 0.0;
X        scale= 8.0; flags &= ~JULIA;
X        d= scale / (width + height);
X#ifdef USE_NETWORK
X            if (mode == MODE_SERVER) Invalidate();
X#endif
X        XClearArea(display, win, 0, 0, width, height, 1);
X        break;
X        
X      case DO_QUIT:
X#ifdef USE_NETWORK
X      if (mode == MODE_SERVER)
X        CloseDown();
X#endif
X        myExit();
X        exit(0);
X      } /* switch */
X    }
X  else switch(event.type) {
X    case Expose:
X      WaitCursor(display, win);
X      WaitCursor(display, cwin);
X      CalcImage (event.xexpose.x, event.xexpose.y,
X                 event.xexpose.width, event.xexpose.height);
X      break;
X
X    case ConfigureNotify:
X#ifdef USE_NETWORK
X      if (mode == MODE_SERVER) {
X        if (width != event.xconfigure.width ||
X            height != event.xconfigure.height)
X          Invalidate();
X        }
X#endif
X      width= event.xconfigure.width;
X      height= event.xconfigure.height;
X      d= scale / (width + height);
X      break;
X
X    case ButtonPress: 
X      switch (event.xbutton.button) {
X        case 1: 
X          ZoomCursor(display, win);
X          dragx= event.xbutton.x;
X          dragy= event.xbutton.y;
X          buttonpressed= 1;
X          break;
X
X        case 2: /* julia stuff here */
X          if (buttonpressed) {
X            EraseRect();
X            buttonpressed= 0;
X            NormalCursor(display, win);
X            }
X          else if (!(flags & JULIA)) {
X            /* toggle to julia set; save current context */
X            xstore1= xstore2= xc; ystore1= ystore2= yc;
X            scalestore1= scalestore2= scale;
X            flagstore= flags;
X
X            flags |= JULIA;
X            cx= xc - d * (width/2.0 - event.xbutton.x);
X            cy= yc + d * (height/2.0 - event.xbutton.y);
X            xc= 0.0; yc= 0.0;
X            scale= 8.0;
X            d= scale / (width + height);
X#ifdef USE_NETWORK
X            if (mode == MODE_SERVER) Invalidate();
X#endif
X            XClearArea(display, win, 0, 0, width, height, 1);
X            }
X          else {
X            /* toggle to mb set; restore context */
X            xc= xstore2; yc= ystore2;
X            scale= scalestore2;
X            flags &= ~JULIA;
X            d= scale / (width + height);
X#ifdef USE_NETWORK
X            if (mode == MODE_SERVER) Invalidate();
X#endif
X            XClearArea(display, win, 0, 0, width, height, 1);
X            }
X          break;
X            
X        case 3: /* open colormap window */
X          if (buttonpressed) {
X            EraseRect();
X            buttonpressed= 0;
X            NormalCursor(display, win);
X            }
X          else
X            ToggleCWin(display, cwin, CMAP_TOGGLE);
X          break;
X        default: 
X          break;
X        }
X      break;
X
X    case ButtonRelease:
X      switch (event.xbutton.button) {
X        case 1:
X          if (buttonpressed) {
X            int xdiff, ydiff;
X            xstore1= xc; ystore1= yc;
X            scalestore1= scale;
X            flagstore= flags;
X
X            xdiff= dragx - event.xbutton.x;
X            ydiff= dragy - event.xbutton.y;
X            if (xdiff < 0) xdiff= -xdiff;
X            if (ydiff < 0) ydiff= -ydiff;
X            if (xdiff/(double)width < ydiff/(double)height)
X              scale *= (ydiff/(double)height);
X            else
X              scale *= (xdiff/(double)width);
X            buttonpressed= 0;
X            EraseRect();
X
X            xc= xc - d * ((int)width - (dragx + event.xbutton.x)) / 2.0;
X            yc= yc + d * ((int)height - (dragy + event.xbutton.y)) / 2.0;
X            d= scale / (width + height);
X#ifdef USE_NETWORK
X            if (mode == MODE_SERVER) Invalidate();
X#endif
X            XClearArea(display, win, 0, 0, width, height, 1);
X            }
X        default:
X          break;
X        }
X      break;
X
X    case MotionNotify:
X      if (buttonpressed)
X        DrawRect(1, dragx, dragy, event.xmotion.x, event.xmotion.y,
X                 (int)width, (int)height);
X      break;
X
X    case KeyPress:
X#ifdef USE_NETWORK
X      if (mode == MODE_SERVER)
X        CloseDown();
X#endif
X      myExit();
X      exit(0);
X
X    case MapNotify:
X      /* Determine size of set (depends on width & height) */
X      XGetWindowAttributes(display, win, &xwattr);
X      width= xwattr.width; height= xwattr.height;
X      d= scale / (width + height);
X      break;
X
X    case ReparentNotify:
X    case UnmapNotify:
X      /* I can't think of anything reasonable to do here... */
X      break;
X
X    default:
X      printf("Unknown Event %d\n", event.type);
X      break;
X    } /* switch */
X  } /* for(ever) */
X} /* main */
X
X
XmyExit()
X{
XFreeFonts(display);
XXFreeGC(display, gc);
XXFreeGC(display, gc_inv);
XXFreeGC(display, gc_set);
XXFreeGC(display, gc_clear);
X
XFreeColors(display, screen);
Xif (win) XDestroyWindow(display, win);
Xif (cwin) XDestroyWindow(display, cwin);
XXCloseDisplay(display);
X}
X
X
X/* Split the image into comfortably small chunks, which
X * are then fed to DrawSplitImage() 
X */
Xvoid CalcImage(xoff, yoff, w, h)
Xint xoff, yoff, w, h;
X{
Xint xd=1, yd=1, xn, yn;
X/* do not accidentally crawl arond some area...
X */
Xif (xc - d*(width/2.0 - xoff) < -.5 &&
X    yc + d*(height/2.0 - yoff) > .5 &&
X    xc - d*(width/2.0 - xoff-w) > .5 &&
X    yc + d*(height/2.0 - yoff-h) < -.5) {
X  int x0= width/2 - xc/d;
X  int y0= height/2 + yc/d;
X  int xdist= x0 - xoff;
X  int ydist= y0 - yoff;
X  if (w > 2*xdist) xdist= w-xdist;
X  if (h > 2*ydist) ydist= h-ydist;
X  if (xdist > ydist) {
X    CalcImage(xoff, yoff, x0-xoff, h);
X    CalcImage(x0, yoff, w-(x0-xoff), h);
X    }
X  else {
X    CalcImage(xoff, yoff, w, y0-yoff);
X    CalcImage(xoff, y0, w, h-(y0-yoff));
X    }
X  return;
X  }  /* if */
Xwhile (w*h/(xd*yd) > 65536) {
X  if (w*yd < h*xd) /* <==> w/xd<h/yd */
X    yd++;
X  else
X    xd++;
X  }
Xfor (yn= 0; yn < yd; yn++)
X  for (xn= 0; xn < xd; xn++) {
X    DrawSplitImage(xoff + xn*w/xd, yoff+yn*h/yd,
X              (xn+1)*w/xd - xn*w/xd,
X                   (yn+1)*h/yd - yn*h/yd);
X    }
X#ifdef USE_NETWORK
Xif (mode == MODE_STANDALONE || !PendingRequests() ) {
X  NormalCursor(display, win);
X  NormalCursor(display, cwin);
X  }
X#else
XNormalCursor(display, win);
XNormalCursor(display, cwin);
X#endif
X}
X
X
X/* Calculate chunks either in local or in remote machines
X */
Xvoid DrawSplitImage(xoff, yoff, w, h)
Xint xoff, yoff, w, h;
X{
Xdouble x,y;
Xu_short *dest;
Xint tmpflags;
X
Xx= xc - d*(width/2.0 - xoff);
Xy= yc + d*(height/2.0 - yoff);
X
XXDrawRectangle(display, win, gc_set, xoff, yoff, w-1, h-1);
XXFlush(display);
X
X#ifdef USE_NETWORK
Xif (mode == MODE_SERVER)  {
X  /* Try to delegate */
X  if (CalcRequest(x, y, d, d, cx, cy, w, h, iter, flags, xoff, yoff))
X    return;
X  }
X#endif
X/* Always use FASTmode when using local machine */
Xtmpflags= flags;
Xflags |= FAST;
Xiterate(x, y, d, d, cx, cy, w, h, iter, flags, &dest);
XDrawImage(xoff, yoff, w, h, dest);
Xflags= tmpflags;
X}
X
X
Xvoid DrawImage(xoff, yoff, w, h, dest)
Xint xoff, yoff, w, h;
Xu_short *dest;
X{
Xint px, py;
Xu_short *ptr, color;
Xlong len, i;
XXGCValues gcval;
XXPoint *xpts;
Xlong npts= 512;
Xint fastmode= flags & FAST;
X
Xptr= dest;
Xxpts= (XPoint *)malloc(npts * sizeof(XPoint));
X
Xif (!fastmode)
X  initialize(w, h);
Xfor (;;) {
X  /* In fast mode, first_point() and next_point() are omitted.
X   * Server will be faster but there will be over 100% more traffic
X   * in the net.
X   */
X  if (fastmode) {
X    px= *ptr++;
X    if (px != LASTPIX)
X      py= *ptr++;
X    }
X  if (fastmode && px == LASTPIX)
X    break;
X  if (!fastmode && first_point(&px, &py) ==0)
X    break;
X  color= *ptr++;
X  gcval.foreground= ToPixel((int)(color & 0x7fff));
X  XChangeGC(display, gc, GCForeground, &gcval);
X
X  if (color & 0x8000) {
X    XDrawPoint(display, win, gc, px+xoff, py+yoff);
X    }
X  else {
X    int dir, bitindex= 7;
X
X    len= *ptr++;
X    if (len > npts) {
X      free(xpts);
X      xpts= (XPoint *)malloc((npts= len) * sizeof(XPoint));
X      }
X    for (i= 0; i < len; i++) {
X      dir= ((*ptr) >> (bitindex*2)) & 3;
X      if (!fastmode)
X        next_point(dir);
X
X      XDrawPoint(display, win, gc, px+xoff, py+yoff);
X      xpts[i].x= px+xoff;
X      xpts[i].y= py+yoff;
X      switch (dir) {
X        case UP: py--; break;
X        case DOWN: py++; break;
X        case LEFT: px--; break;
X        case RIGHT: px++; break;
X        }
X      if (--bitindex < 0) {
X        ptr++;
X        bitindex= 7;
X        }
X      }
X    if (bitindex != 7)
X      ptr++;
X    XFillPolygon(display, win, gc, xpts, len, Complex, CoordModeOrigin);
X    } /* else */
X  } /* for */
Xif (!fastmode)
X  deinit();
Xfree(dest);
Xfree(xpts);
X} /* DrawImage */
X
X
Xvoid DrawRect(mode, x1, y1, x2, y2, w, h)
Xint mode, x1, y1, x2, y2, w, h;
X{
Xstatic int drawn= 0;
Xstatic int dx, dy, dw, dh;
X
Xif (drawn)
X  XDrawRectangle(display, win, gc_inv, dx, dy, dw, dh);
Xdrawn= 0;
X
Xif (mode == 0)
X  return;
X
Xdw= x2 - x1; dh= y2 - y1;
Xif (dw == 0 && dh == 0)
X  return;
X
Xdx= x1; dy= y1;
Xif (dw < 0) {
X  dw= -dw;
X  dx= x2;
X  }
Xif (dh < 0) {
X  dh= -dh;
X  dy= y2;
X  }
X
Xif (dw/(double)w > dh/(double)h) {
X  dh= dw * (h/(double)w);
X  dy= (y1 + y2 - dh)/2;
X  }
Xelse {
X  dw= dh * (w/(double)h);
X  dx= (x1 + x2 - dw)/2;
X  }
XXDrawRectangle(display, win, gc_inv, dx, dy, dw, dh);
Xdrawn= 1;
X} /* drawrect */
X
END_OF_x.c
if test 22670 -ne `wc -c <x.c`; then
    echo shar: \"x.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0