home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / julia / julia.c_hess < prev    next >
Encoding:
Text File  |  1995-05-03  |  43.1 KB  |  1,505 lines

  1. /*************************************************************************
  2.  *                                                                       *
  3.  *  Copyright (c) 1992, 1993 Ronald Joe Record                           *
  4.  *                                                                       *
  5.  *  All rights reserved. No part of this program or publication may be   *
  6.  *  reproduced, transmitted, transcribed, stored in a retrieval system,  *
  7.  *  or translated into any language or computer language, in any form or *
  8.  *  by any means, electronic, mechanical, magnetic, optical, chemical,   *
  9.  *  biological, or otherwise, without the prior written permission of:   *
  10.  *                                                                       *
  11.  *      Ronald Joe Record (408) 458-3718                                 *
  12.  *      212 Owen St., Santa Cruz, California 95062 USA                   *
  13.  *                                                                       *
  14.  *************************************************************************/
  15.  
  16. /* Julia - calculate and display Julia sets */
  17. /*        or when invoked as mandel */
  18. /* Mandel - calculate and display Mandelbrot sets */
  19.  
  20. /* Written by Ronald Record (rr@sco.com) 18 Mar 1993 */
  21.  
  22. #include <math.h>
  23. #include <memory.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <values.h>
  27. #include "x.h"
  28. #include <X11/cursorfont.h>
  29. #include "defines.h"
  30. #include "libXrr.h"
  31. #include "julia.h"
  32. #include "patchlevel.h"
  33.  
  34. static char *version = JULIA_VERSION;
  35. int button = 0, xpos = -1, ypos = -1, autodive = 0, dive_index = 0;
  36. static int dflag = 1;
  37. FILE *infile;
  38.  
  39. extern void BufferPoint(), InitBuffer(), FlushBuffer();
  40.  
  41. main(ac, av)
  42.     int ac;
  43.     char **av;
  44. {
  45.     char *cmdnam;
  46.     char *cut;
  47.     int i, j;
  48.     XSizeHints hint;
  49.     Cursor cursor;
  50.     extern void init_canvas(), init_data(), init_color(), parseargs();
  51.     extern void Clear(), restor_picture(); 
  52.  
  53.     if ((cmdnam = strrchr(av[0], '/')) != 0) {
  54.         path = strdup(av[0]);
  55.         cut = strrchr(path, '/');
  56.         cut[1] = 0;
  57.         cmdnam++;
  58.     }
  59.     else
  60.         cmdnam = av[0];
  61.     if (!strncmp(cmdnam, "julia", 5))
  62.         func = Funcs[0];
  63.     else if (!strncmp(cmdnam, "mandel", 6))
  64.         func = Funcs[1];
  65.     else /* how did this happen ? */
  66.         func = Funcs[0];
  67.     parseargs(ac, av);
  68.     dpy = XOpenDisplay("");
  69.     screen = DefaultScreen(dpy);
  70.     background = BlackPixel(dpy, screen);
  71.     if (width < 1)
  72.         width = XDisplayWidth(dpy, screen);
  73.     if (height < 1)
  74.         height = XDisplayHeight(dpy, screen);
  75.     if (dflag)
  76.         delta = Min(a_range, b_range) / (double)Max(height, width);
  77.     setupmem();
  78.     InitBuffer(&Points, maxcolor);
  79.     init_data();
  80.     if (displayplanes > 1)
  81.         foreground = startcolor;
  82.     else
  83.         foreground = WhitePixel(dpy,XDefaultScreen(dpy));
  84.     if (xpos == -1)
  85.         hint.x = (XDisplayWidth(dpy, screen) - width)/2;
  86.     else
  87.         hint.x = xpos;
  88.     if (ypos == -1)
  89.         hint.y = (XDisplayHeight(dpy, screen) - height)/2;
  90.     else
  91.         hint.y = ypos;
  92.     hint.width = width;
  93.     hint.height = height;
  94.     hint.flags = PPosition | PSize;
  95.     /*
  96.      * Create the window to display the Julia or Mandelbrot set
  97.      */
  98.     canvas = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
  99.         hint.x, hint.y, hint.width, hint.height,
  100.         5, foreground, background);
  101.     if (func == compjulia) {
  102.         XSetStandardProperties(dpy, canvas, "Julia by Ron Record", 
  103.                 "Julia", None, av, ac, &hint);
  104.         XChangeProperty( dpy, canvas, XA_WM_CLASS, XA_STRING, 8,
  105.                         PropModeReplace, "julia", strlen("julia"));
  106.     }
  107.     else {
  108.         XSetStandardProperties(dpy, canvas, "Mandel by Ron Record", 
  109.                 "Mandel", None, av, ac, &hint);
  110.         XChangeProperty( dpy, canvas, XA_WM_CLASS, XA_STRING, 8,
  111.                         PropModeReplace, "mandel", strlen("mandel"));
  112.     }
  113.     init_canvas();
  114.     XSelectInput(dpy,canvas,KeyPressMask|ButtonPressMask|ButtonMotionMask|
  115.         ButtonReleaseMask|ExposureMask|StructureNotifyMask);
  116.     cmap = XCreateColormap(dpy, canvas, DefaultVisual(dpy, screen), AllocAll);
  117.     XMapRaised(dpy, canvas);
  118.     if (displayplanes > 1)
  119.         if (func == compjulia)
  120.             init_color(dpy, canvas, cmap, Colors, startcolor, startcolor,
  121.                     maxcolor, numwheels, "julia", "Julia", 0);
  122.         else
  123.             init_color(dpy, canvas, cmap, Colors, startcolor, startcolor,
  124.                     maxcolor, numwheels, "mandel", "Mandel", 0);
  125.     else
  126.         XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), 
  127.                 Colors, numcolors);
  128.     pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), width, height, 
  129.                            DefaultDepth(dpy, screen));
  130.     rubber_data.band_cursor=XCreateFontCursor(dpy, XC_hand2);
  131.     CreateXorGC();
  132.     Clear();
  133.     cursor = XCreateFontCursor(dpy, XC_crosshair);
  134.     XDefineCursor(dpy, canvas, cursor);
  135.     if (restfile)
  136.         restor_picture();
  137.     if (demo)
  138.         for(;;) {
  139.             main_event();
  140.             if (!run) {
  141.                 DemoSpin(dpy, cmap, Colors, startcolor, maxcolor, delay, 2);
  142.                 main_event();
  143.                 for (i=0; i<=MAXWHEELS; i++) {
  144.                     init_color(dpy, canvas, cmap, Colors, startcolor, 
  145.                             startcolor, maxcolor, i, "julia", "Julia", 0);
  146.                     sleep(1);
  147.                     main_event();
  148.                 }
  149.                 XCloseDisplay(dpy);
  150.                 exit(0);
  151.             }
  152.         }
  153.     else
  154.         for(;;)
  155.             main_event();
  156. }
  157.  
  158. main_event()
  159. {
  160.     int n;
  161.     XEvent event;
  162.  
  163.     if ((*func)() == TRUE)
  164.         run=0;
  165.     n = XEventsQueued(dpy, QueuedAfterFlush);
  166.     while (n--) {
  167.         XNextEvent(dpy, &event);
  168.         switch(event.type) {
  169.             case KeyPress: Getkey(&event); break;
  170.             case Expose: redisplay(canvas, &event); break;
  171.             case ConfigureNotify: resize(); break;
  172.             case ButtonPress: StartRubberBand(canvas, &rubber_data, &event);
  173.                  break;
  174.             case MotionNotify: TrackRubberBand(canvas, &rubber_data, &event);
  175.                  break;
  176.             case ButtonRelease: EndRubberBand(canvas, &rubber_data, &event);
  177.                  break;
  178.         }
  179.     }
  180. }
  181.  
  182. void
  183. dive() 
  184. {
  185.     static int i, j;
  186.     extern void set_new_params();
  187.  
  188.     for (i=0;i<expind[frame];i++)
  189.       if (exponents[frame][i] > 0)
  190.         if (exponents[frame][i] == maxcnt) {
  191.             dive_index = i;
  192.             break;
  193.           }
  194.     i = dive_index / width;    /* number of horizontal lines up */
  195.     j = dive_index % width; /* number of vertical lines over */
  196.     rubber_data.p_min = min_a+((double)j*a_range/(double)width)-(a_range/4.0);
  197.     rubber_data.q_min = min_b+((double)i*b_range/(double)height)-(b_range/4.0);
  198.     rubber_data.p_max = min_a+((double)j*a_range/(double)width)+(a_range/4.0);
  199.     rubber_data.q_max = min_b+((double)i*b_range/(double)height)+(b_range/4.0);
  200.     autodive--;
  201.     set_new_params(canvas, &rubber_data, 1);
  202. }
  203.  
  204. void
  205. recalc() 
  206. {
  207.     static int i, index, x, y;
  208.     
  209.     mincnt = MAXINT - 1; maxcnt = 0;
  210.     for (i=0;i<expind[frame];i++) {
  211.       if (exponents[frame][i]) {
  212.         if (ABS(exponents[frame][i]) < mincnt)
  213.             mincnt = ABS(exponents[frame][i]);
  214.         if (ABS(exponents[frame][i]) > maxcnt)
  215.             if (ABS(exponents[frame][i]) != kmax)
  216.                 maxcnt = ABS(exponents[frame][i]);
  217.       }
  218.     }
  219. }
  220.  
  221. draw() 
  222. {
  223.     extern void save_to_file(), redraw(), store_to_file();
  224.  
  225.     FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  226.     dorecalc = 1;
  227.     recalc();
  228.     if (autodive) {
  229.         dive();
  230.         return FALSE;
  231.     }
  232.     else {
  233.         redraw(exponents[frame], expind[frame], 1);
  234.         if (savefile)
  235.             save_to_file();
  236.         else if (storefile)
  237.             store_to_file();
  238.         return TRUE;
  239.     }
  240.     return TRUE;
  241. }
  242.  
  243. find_period(x0, y0)
  244. double x0, y0;
  245. {
  246.     static int k;
  247.     static double x1, y1, x2, y2;
  248.  
  249.     k = 0; x2 = x0; y2 = y0;
  250.     while ( k < kmax ) {
  251.         x1 = x0*x0 - y0*y0 + a;
  252.         y1 = 2*x0*y0 + b;
  253.         k++;
  254.         if ((x1*x1 + y1*y1) > M)
  255.             return(k+kmax);
  256.         else {
  257.             if ((ABS(x1 - x2) < delta) && (ABS(y1 - y2) < delta))
  258.                 return(-k);
  259.             x0 = x1;
  260.             y0 = y1;
  261.         }
  262.     }
  263.     return(kmax);
  264. }
  265.  
  266. compmandel()
  267. {
  268.     register i;
  269.     static int k;
  270.     double x, r, x0, y0, x1, y1;
  271.  
  272.     if (!run)
  273.         return TRUE;
  274.     k = 0;
  275.     x0 = 0.0; y0 = 0.0;    /* start iteration with the critical point */
  276.     while ( k < kmax ) {
  277.         x1 = x0*x0 - y0*y0 + a; /* this is the Real version of the */
  278.         y1 = 2*x0*y0 + b;       /* Complex formula z -> z^2 + c    */
  279.         k++;
  280.         if ((x1*x1 + y1*y1) > M) /* could use a variety of exit criteria */
  281.             break;
  282.         else {
  283.             x0 = x1;
  284.             y0 = y1;
  285.         }
  286.     }
  287.     if (second && (k == kmax))   /* there is a second attractor and  */
  288.         k = find_period(x0, y0); /* we color according to its period */
  289.     if (sendpoint(k) == TRUE)
  290.         return FALSE;
  291.     else {
  292.         if (draw())
  293.             run = 0;
  294.            return(run);
  295.     }
  296. }
  297.  
  298. compjulia()
  299. {
  300.     register i;
  301.     static int k;
  302.     double x, r, x0, y0, x1, y1;
  303.  
  304.     if (!run)
  305.         return TRUE;
  306.     k = 0;
  307.     x0 = a; y0 = b;
  308.     while ( k < kmax ) {
  309.         x1 = x0*x0 - y0*y0 + p; /* the Real version of the Complex */
  310.         y1 = 2*x0*y0 + q;       /* formula z -> z^2 + c            */
  311.         k++;
  312.         if ((x1*x1 + y1*y1) > M) /* could use a variety of exit criteria */
  313.             break;
  314.         else {
  315.             if (second) /*if not going to infinity, color according to period*/
  316.                 if ((ABS(x1 - xper) < delta) && (ABS(y1 - yper) < delta)) {
  317.                     k = -k;
  318.                     break;
  319.                 }
  320.             x0 = x1;
  321.             y0 = y1;
  322.         }
  323.     }
  324.     if (sendpoint(k) == TRUE)
  325.         return FALSE;
  326.     else {
  327.         if (draw())
  328.             run = 0;
  329.            return(run);
  330.     }
  331. }
  332.  
  333. int
  334. find_pt() /* find a point on the second attractor if it exists */
  335. {
  336.     static int i;
  337.     double x2, y2, x3, y3;
  338.  
  339.     x2 = 0.0; y2 = 0.0; /* the critical point */
  340.     for (i=0; i<kmax; i++) {
  341.         x3 = x2*x2 - y2*y2 + p;
  342.         y3 = 2*x2*y2 + q;
  343.         if ((x3*x3 + y3*y3) > M)
  344.             return(1); /* not a second attractor */
  345.         x2 = x3; y2 = y3;
  346.     }
  347.     xper = x3; yper = y3;
  348.     return(0);
  349. }
  350.  
  351. setmaxmin()
  352. {
  353.     if (wflag) {
  354.         if (aflag)
  355.             if (Aflag)
  356.                 a_range = max_a - min_a;
  357.             else
  358.                 max_a = min_a + a_range;
  359.         else {
  360.             if (Aflag)
  361.                 min_a = max_a - a_range;
  362.             else {
  363.                 max_a = center_x + (a_range/2.0);
  364.                 min_a = center_x - (a_range/2.0);
  365.             }
  366.         }
  367.     }
  368.     else if (aflag) {
  369.         if (Aflag)
  370.             a_range = max_a - min_a;
  371.         else {
  372.             max_a = min_a + 2.0*(center_x - min_a);
  373.             a_range = max_a - min_a;
  374.         }
  375.     }
  376.     else {
  377.         if (func == compjulia)
  378.             a_range = DEF_WIDTH;
  379.         else
  380.             a_range = DEF_M_WIDTH;
  381.         if (Aflag)
  382.             min_a = max_a - a_range;
  383.         else {
  384.             max_a = center_x + (a_range/2.0);
  385.             min_a = center_x - (a_range/2.0);
  386.         }
  387.     }
  388.     if (hflag) {
  389.         if (bflag)
  390.             if (Bflag)
  391.                 b_range = max_b - min_b;
  392.             else
  393.                 max_b = min_b + b_range;
  394.         else {
  395.             if (Bflag)
  396.                 min_b = max_b - b_range;
  397.             else {
  398.                 max_b = center_y + (b_range/2.0);
  399.                 min_b = center_y - (b_range/2.0);
  400.             }
  401.         }
  402.     }
  403.     else if (bflag) {
  404.         if (Bflag)
  405.             b_range = max_b - min_b;
  406.         else {
  407.             b_range = 2.0*(center_y - min_b);
  408.             max_b = min_b + b_range;
  409.         }
  410.     }
  411.     else {
  412.         if (func == compjulia)
  413.             b_range = DEF_HEIGHT;
  414.         else
  415.             b_range = DEF_M_HEIGHT;
  416.         if (Bflag)
  417.             min_b = max_b - b_range;
  418.         else {
  419.             max_b = center_y + (b_range/2.0);
  420.             min_b = center_y - (b_range/2.0);
  421.         }
  422.     }
  423.     center_x = min_a + (a_range/2.0);
  424.     center_y = min_b + (b_range/2.0);
  425.     a_minimums[0] = min_a; b_minimums[0] = min_b;
  426.     a_maximums[0] = max_a; b_maximums[0] = max_b;
  427. }
  428.  
  429. void
  430. parseargs(ac, av)
  431. int ac;
  432. char **av;
  433. {
  434.     static int c;
  435.     static int i;
  436.     char *ch;
  437.     extern int optind;
  438.     extern char *optarg;
  439.     extern double atof();
  440.     extern void usage(), restor_params();
  441.  
  442.     if (func == compjulia) {
  443.         min_a = -1.5; max_a = 1.5;
  444.         center_x = 0.0;
  445.     }
  446.     else {
  447.         min_a = -2.25; max_a = 0.75;
  448.         center_x = -0.75;
  449.         outname = "mandel.out";
  450.         savname = "mandel.sav";
  451.     }
  452.     while ((c=getopt(ac,av,
  453.         "LSTduvA:B:D:F:K:W:H:M:N:O:X:Y:a:b:c:i:o:p:q:w:h:r:s:x:y:"))!=EOF) {
  454.         switch (c) {
  455.         case 'A':    max_a=atof(optarg); Aflag++; break;
  456.         case 'B':    max_b=atof(optarg); Bflag++; break;
  457.         case 'D':    if (strcmp(optarg, "elay")) {
  458.                         dflag=0;
  459.                         delta=atof(optarg); 
  460.                      }
  461.                      else
  462.                         delay = atoi(av[optind++]);
  463.                      break;
  464.         case 'F':    autodive=atoi(optarg); break;
  465.         case 'H':    height=atoi(optarg); break;
  466.         case 'K':    kmax=atoi(optarg); break;
  467.         case 'L':    logindex=0; break;
  468.         case 'M':    M=atoi(optarg); break;
  469.         case 'N':    maxcolor=ABS(atoi(optarg)); 
  470.                 if ((maxcolor - startcolor) <= 0)
  471.                     startcolor = 0;
  472.                 break;
  473.         case 'O':    color_offset=atoi(optarg); break;
  474.         case 'S':    /* Don't look for a second attractor */
  475.                 second = 0; break;
  476.         case 'T':    /* Do look for a second attractor */
  477.                 second = 1; break;
  478.         case 'W':    width=atoi(optarg); break;
  479.         case 'X':    xpos=atoi(optarg); break;
  480.         case 'Y':    ypos=atoi(optarg); break;
  481.         case 'a':    min_a=atof(optarg); aflag++; break;
  482.         case 'b':    min_b=atof(optarg); bflag++; break;
  483.         case 'c':    numwheels=atoi(optarg); break;
  484.         case 'd':    demo++; break;
  485.         case 'h':    b_range=atof(optarg); hflag++; break;
  486.         case 'i':    restfile++; inname=optarg; break;
  487.         case 'o':    savefile++; outname=optarg; break;
  488.         case 'p':    p = atof(optarg); break;
  489.         case 'q':    q = atof(optarg); break;
  490.         case 'r':    res=atoi(optarg); break;
  491.         case 's':    storefile++; savname=optarg; break;
  492.         case 'u':    usage(); break;
  493.         case 'v':    show=1; break;
  494.         case 'w':    a_range=atof(optarg); wflag++; break;
  495.         case 'x':    center_x=atof(optarg); break;
  496.         case 'y':    center_y=atof(optarg); break;
  497.         case '?':    usage(); break;
  498.         }
  499.     }
  500.     if (restfile) {
  501.         restor_params();
  502.         width *= res; height *= res;
  503.         center_x = min_a + (a_range/2.0);
  504.         center_y = min_b + (b_range/2.0);
  505.         a_minimums[0] = min_a; b_minimums[0] = min_b;
  506.         a_maximums[0] = max_a; b_maximums[0] = max_b;
  507.     }
  508.     else {
  509.         setmaxmin();
  510.     }
  511.     if (second && (func == compjulia))
  512.         if (find_pt())
  513.             second = 0; /* couldn't find a second attractor */
  514. }
  515.  
  516. void
  517. usage()
  518. {
  519.     if (func == compjulia)
  520.       fprintf(stderr,"julia [-Ls][-W#][-H#][-a#][-b#][-w#][-h#]\n");
  521.     else
  522.       fprintf(stderr,"mandel [-BLs][-W#][-H#][-a#][-b#][-w#][-h#]\n");
  523.     fprintf(stderr,"\t[-M#][-S#][-D#][-f string][-r#][-O#][-C#][-c#][-m#]\n");
  524.     fprintf(stderr,"\t\tWhere: -C# specifies the minimum color index\n");
  525.     fprintf(stderr,"\t\t-r# specifies the maximum rgb value\n");
  526.     fprintf(stderr,"\t\t-u displays this message\n");
  527.     fprintf(stderr,"\t\t-a# specifies the minimum horizontal parameter\n");
  528.     fprintf(stderr,"\t\t-b# specifies the minimum vertical parameter\n");
  529.     fprintf(stderr,"\t\t-A# specifies the maximum horizontal parameter\n");
  530.     fprintf(stderr,"\t\t-B# specifies the maximum vertical parameter\n");
  531.     fprintf(stderr,"\t\t-w# specifies the horizontal parameter range\n");
  532.     fprintf(stderr,"\t\t-h# specifies the vertical parameter range\n");
  533.     fprintf(stderr,"\t\t-K# specifies the iteration limit\n");
  534.     fprintf(stderr,"\t\t-M# specifies the escape detection radius\n");
  535.     fprintf(stderr,"\t\t-H# specifies the initial window height\n");
  536.     fprintf(stderr,"\t\t-W# specifies the initial window width\n");
  537.     fprintf(stderr,"\t\t-O# specifies the color offset\n");
  538.     fprintf(stderr,"\t\t-c# specifies the desired color wheel\n");
  539.     if (func == compjulia) {
  540.       fprintf(stderr,"\t\t-p# specifies the real part of the parameter\n");
  541.       fprintf(stderr,"\t\t-q# specifies the complex part of the parameter\n");
  542.     }
  543.     fprintf(stderr,"\tDuring display :\n");
  544.     fprintf(stderr,"\t\tThe left mouse button zooms in on an area\n");
  545.     if (func == compmandel)
  546.       fprintf(stderr,"\t\tThe middle mouse button selects a Julia parameter\n");
  547.     fprintf(stderr,"\t\te or E recalculates color indices\n");
  548.     fprintf(stderr,"\t\tf or F saves exponents to a file\n");
  549.     fprintf(stderr,"\t\tr or R redraws\n");
  550.     fprintf(stderr,"\t\ts or t spins the colorwheel\n");
  551.     fprintf(stderr,"\t\tw or W changes the color wheel\n");
  552.     fprintf(stderr,"\t\tx or X clears the window\n");
  553.     fprintf(stderr,"\t\tq or Q exits\n");
  554.     exit(1);
  555. }
  556.  
  557. Cycle_frames()
  558. {
  559.     static int i;
  560.     extern void redraw();
  561.  
  562.     for (i=0;i<=maxframe;i++)
  563.         redraw(exponents[i], expind[i], 1); 
  564. }
  565.  
  566. Getkey(event)
  567. XKeyEvent *event;
  568. {
  569.     unsigned char key;
  570.     static int i, running, spinning=0, spindir=0;
  571.     extern int _numdivs;
  572.     extern void init_color(), print_values(), print_help(), write_cmap();
  573.     extern void go_init(), go_back(), go_down(), Clear(), store_to_file();
  574.     extern void save_to_file(), Redraw(), redraw(), set_new_params();
  575.  
  576.     if (XLookupString(event, (char *)&key, sizeof(key), (KeySym *)0,
  577.             (XComposeStatus *) 0) > 0)
  578.         switch (key) {
  579.             case '\015': /* write out current colormap to $HOME/.<prog>map */
  580.                     if (func == compjulia)
  581.                         write_cmap(dpy,cmap,Colors,maxcolor,"julia","Julia");
  582.                     else
  583.                         write_cmap(dpy,cmap,Colors,maxcolor,"mandel","Mandel");
  584.                     break;
  585.             case '\030':    /* <ctrl>-X */
  586.                 if (_numdivs > 1)
  587.                     _numdivs--;
  588.                 else
  589.                     _numdivs = MAXDIVS;
  590.                 if (displayplanes > 1)
  591.                     if (func == compjulia)
  592.                         init_color(dpy,canvas,cmap,Colors,startcolor,
  593.                             startcolor,maxcolor,numwheels,"julia","Julia",0);
  594.                     else
  595.                         init_color(dpy,canvas,cmap,Colors,startcolor,
  596.                             startcolor,maxcolor,numwheels,"mandel","Mandel",0);
  597.                 break;
  598.             case '\031':    /* <ctrl>-Y */
  599.                 if (_numdivs < MAXDIVS)
  600.                     _numdivs++;
  601.                 else
  602.                     _numdivs = 1;
  603.                 if (displayplanes > 1)
  604.                     if (func == compjulia)
  605.                         init_color(dpy,canvas,cmap,Colors,startcolor,
  606.                             startcolor,maxcolor,numwheels,"julia","Julia",0);
  607.                     else
  608.                         init_color(dpy,canvas,cmap,Colors,startcolor,
  609.                             startcolor,maxcolor,numwheels,"mandel","Mandel",0);
  610.                 break;
  611.             case ')': delay += 25; break;
  612.             case '(': delay -= 25; if (delay < 0) delay = 0; break;
  613.             case '>': kmax *= 2; break;
  614.             case '<': kmax /= 2; if (kmax < 1) kmax = 1; break;
  615.             case ']': delta *= 2.0; break;
  616.             case '[': delta /= 2.0; break;
  617.             case '+': M *= 2; break;
  618.             case '-': M /= 2; if (M < 2) M = 2; break;
  619.             case '9': /* zoom in to center quarter */
  620.                       rubber_data.p_min = center_x - (a_range/4.0);
  621.                       rubber_data.q_min = center_y - (b_range/4.0);
  622.                       rubber_data.p_max = center_x + (a_range/4.0);
  623.                       rubber_data.q_max = center_y + (b_range/4.0);
  624.                       set_new_params(canvas, &rubber_data, 0);
  625.                       break;
  626.             case '0': /* zoom out by doubling window size */
  627.                       rubber_data.p_min = center_x - a_range;
  628.                       rubber_data.q_min = center_y - b_range;
  629.                       rubber_data.p_max = center_x + a_range;
  630.                       rubber_data.q_max = center_y + b_range;
  631.                       set_new_params(canvas, &rubber_data, 0);
  632.                       break;
  633.             case 'B': /* toggle autodive around deepest iteration count */
  634.                       autodive = (!autodive);
  635.                       if (autodive) {
  636.                           recalc();
  637.                           dive();
  638.                       }
  639.                       break;
  640.             case 'b': /* toggle coloration for second attractor */
  641.                       second = (!second);
  642.                         redraw(exponents[frame], expind[frame], 1);
  643.                       break;
  644.             case 'd': go_down(); break;
  645.             case 'D': FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  646.                             0, maxcolor); 
  647.                       break;
  648.             case 'e':
  649.             case 'E': FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  650.                             0, maxcolor);
  651.                         dorecalc = (!dorecalc);
  652.                         if (dorecalc)
  653.                           recalc(); 
  654.                         else
  655.                           maxcnt = 0;
  656.                         redraw(exponents[frame], expind[frame], 1);
  657.                         break;
  658.             case 'f': FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  659.                                     0, maxcolor); 
  660.                       store_to_file(); break;
  661.             case 'F': FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  662.                                     0, maxcolor); 
  663.                       save_to_file(); break;
  664.             case 'i': 
  665.                   if (stripe_interval > 0) {
  666.                       stripe_interval--;
  667.                       if (displayplanes > 1) {
  668.                           running = run; run = 0;
  669.                           if (func == compjulia)
  670.                             init_color(dpy,canvas,cmap,Colors,startcolor,
  671.                                startcolor,maxcolor,numwheels,"julia","Julia",0);
  672.                           else
  673.                             init_color(dpy,canvas,cmap,Colors,startcolor,
  674.                              startcolor,maxcolor,numwheels,"mandel","Mandel",0);
  675.                           run = running;
  676.                       }
  677.                   }
  678.                   break;
  679.             case 'I': stripe_interval++;
  680.                   if (displayplanes > 1) {
  681.                       running = run; run = 0;
  682.                       if (func == compjulia)
  683.                         init_color(dpy,canvas,cmap,Colors,startcolor,
  684.                             startcolor,maxcolor,numwheels,"julia","Julia",0);
  685.                       else
  686.                         init_color(dpy,canvas,cmap,Colors,startcolor,
  687.                             startcolor,maxcolor,numwheels,"mandel","Mandel",0);
  688.                       run = running;
  689.                   }
  690.                   break;
  691.             case 'l':
  692.             case 'L': logindex = (!logindex); break;
  693.             case 'p':
  694.             case 'P': negative = (!negative); 
  695.                       FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  696.                                     0, maxcolor); 
  697.                       redraw(exponents[frame], expind[frame], 1); 
  698.                         break;
  699.             case 'r': FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  700.                                 0, maxcolor); 
  701.                       redraw(exponents[frame],expind[frame],1); 
  702.                         break;
  703.             case 'R': FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  704.                                     0, maxcolor); 
  705.                       Redraw(); 
  706.                       break;
  707.             case 'S':
  708.                   spinning = 0; break;
  709.             case 's':
  710.                   spinning = 1; spindir = (!spindir);
  711.                   Spin(dpy, cmap, Colors, startcolor, maxcolor, delay, spindir);
  712.                   break;
  713.             case 'u': go_back(); break;
  714.             case 'U': go_init(); break;
  715.             case 'v':
  716.             case 'V': print_values(); break;
  717.             case '\027': /* (ctrl-W) read color palette from $HOME/.juliamap */
  718.                   numwheels = 0;
  719.                   if (displayplanes > 1) {
  720.                       running = run; run = 0;
  721.                       if (func == compjulia)
  722.                         init_color(dpy,canvas,cmap,Colors,startcolor,
  723.                             startcolor,maxcolor,numwheels,"julia","Julia",0);
  724.                       else
  725.                         init_color(dpy,canvas,cmap,Colors,startcolor,
  726.                             startcolor,maxcolor,numwheels,"mandel","Mandel",0);
  727.                       run = running;
  728.                   }
  729.                   break;
  730.             case 'W': if (numwheels < MAXWHEELS)
  731.                           numwheels++;
  732.                       else
  733.                           numwheels = 0;
  734.                       if (displayplanes > 1) {
  735.                           running = run; run = 0;
  736.                           if (func == compjulia)
  737.                             init_color(dpy,canvas,cmap,Colors,startcolor,
  738.                                startcolor,maxcolor,numwheels,"julia","Julia",0);
  739.                           else
  740.                             init_color(dpy,canvas,cmap,Colors,startcolor,
  741.                              startcolor,maxcolor,numwheels,"mandel","Mandel",0);
  742.                           run = running;
  743.                       }
  744.                       break;
  745.             case 'w': if (numwheels > 0)
  746.                           numwheels--;
  747.                       else
  748.                           numwheels = MAXWHEELS;
  749.                       if (displayplanes > 1) {
  750.                           running = run; run = 0;
  751.                           if (func == compjulia)
  752.                             init_color(dpy,canvas,cmap,Colors,startcolor,
  753.                                startcolor,maxcolor,numwheels,"julia","Julia",0);
  754.                           else
  755.                             init_color(dpy,canvas,cmap,Colors,startcolor,
  756.                              startcolor,maxcolor,numwheels,"mandel","Mandel",0);
  757.                           run = running;
  758.                       }
  759.                       break;
  760.             case 'x': Clear(); break;
  761.             case 'X': Destroy_frame(); break;
  762.             case 'z': running = run; run = 0;
  763.                   Cycle_frames(); 
  764.                   run = running; redraw(exponents[frame], expind[frame], 1);
  765.                   break;
  766.             case 'Z': running = run; run = 0;
  767.                   while (!XPending(dpy)) Cycle_frames(); 
  768.                   run = running; redraw(exponents[frame], expind[frame], 1); 
  769.                   break;
  770.             case 'q':
  771.             case 'Q': XCloseDisplay(dpy); exit(0); break;
  772.             case '?':
  773.             case 'h':
  774.             case 'H': print_help(); break;
  775.             default:  break;
  776.         }
  777.         if (spinning)
  778.             Spin(dpy, cmap, Colors, startcolor, maxcolor, delay, spindir);
  779. }
  780.  
  781. sendpoint(count)
  782. int count;
  783. {
  784.     static int i, j, index, m, n;
  785.     static double ratio;
  786.  
  787.     if ((count == kmax) || ((count < 0) && (!second)))
  788.         index = 0;
  789.     else {
  790.         if (maxcnt) {
  791.             if (logindex)
  792.                 ratio = log((double)ABS(count))/log((double)maxcnt);
  793.             else
  794.                 ratio = (double)ABS(count)/(double)maxcnt;
  795.             ratio /= (double)(second + 1);
  796.             if (count > 0)
  797.                 index=((numfreecols-1)*ratio)+startcolor;
  798.             else
  799.                 index=numcolors-((numfreecols-1)*ratio)-1;
  800.         }
  801.         else {
  802.             i = numfreecols / (second + 1);
  803.             if (ABS(count) < 32)
  804.                 if (count > 0)
  805.                     index = (count % i) + startcolor;
  806.                 else
  807.                     index = numcolors - (ABS(count) % i) - 1;
  808.             else {
  809.                 if (ABS(count) < 64)
  810.                     if (count > 0)
  811.                         index = ((count/8) % i) + startcolor;
  812.                     else
  813.                         index = numcolors - ((ABS(count)/8) % i) - 1;
  814.                 else
  815.                     if (count > 0)
  816.                         index = ((count/16) % i) + startcolor;
  817.                     else
  818.                         index = numcolors - ((ABS(count)/16) % i) - 1;
  819.             }
  820.         }
  821.     }
  822.     for (i=0; i<res; i++)
  823.         for (j=0; j<res; j++) {
  824.             m = point.x + j;
  825.             n = point.y + i;
  826.             BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, index,
  827.                         m, height - n);
  828.             if (symetrical)
  829.               if (func == compjulia)
  830.                 BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, index, 
  831.                             m+(2*(w2-m))-rem, height - (n+(2*(h2-n))));
  832.               else
  833.                 BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, index, 
  834.                             m, height - (n+(2*(h2-n))));
  835.         }
  836.     if (save)
  837.         exponents[frame][expind[frame]++] = count;
  838.     a += a_inc;
  839.     point.x += res;
  840.     if (point.x >= width) {
  841.         point.y += res;
  842.         point.x = 0;
  843.         if (save) {
  844.             b += b_inc;
  845.             a = min_a;
  846.         }
  847.         if ((point.y >= height) || (symetrical && (point.y > h2))) {
  848.             FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  849.             return FALSE;
  850.         }
  851.         else
  852.             return TRUE;
  853.     }
  854.     return TRUE;
  855. }
  856.  
  857. void 
  858. redisplay (w, event)
  859. Window          w;
  860. XExposeEvent    *event;
  861. {
  862.     /*
  863.      * Extract the exposed area from the event and copy
  864.      * from the saved pixmap to the window.
  865.      */
  866.     XCopyArea(dpy, pixmap, canvas, Data_GC[0], 
  867.            event->x, event->y, event->width, event->height, 
  868.            event->x, event->y);
  869. }
  870.  
  871. void
  872. resize()
  873. {
  874.     Window r;
  875.     int n, x, y;
  876.     unsigned int bw, d, new_w, new_h;
  877.     XWindowChanges values;
  878.     extern void Clear(), Redraw();
  879.  
  880.     XGetGeometry(dpy,canvas,&r,&x,&y,&new_w,&new_h,&bw,&d);
  881. printf("(x,y) = (%d,%d) new_w=%d new_h=%d width=%d height=%d bw=%d\n",
  882. x,y,new_w,new_h,width,height,bw);
  883.     if ((new_w == width) && (new_h == height))
  884.         return;
  885.     width = new_w; height = new_h;
  886.     if (xpos == -1)
  887.         values.x = (XDisplayWidth(dpy, screen) - width) / 2;
  888.     else
  889.         values.x = x;
  890.     if (ypos == -1)
  891.         values.y = (XDisplayHeight(dpy, screen) - height) / 2;
  892.     else
  893.         values.y = y;
  894.     XConfigureWindow(dpy, canvas, CWX|CWY,&values);
  895.     w2 = width / 2; h2 = height / 2;
  896.     if ((2*w2) == width)
  897.         rem = 1;
  898.     else
  899.         rem = 0;
  900.     XClearWindow(dpy, canvas);
  901.     if (pixmap)
  902.         XFreePixmap(dpy, pixmap);
  903.     pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), 
  904.             width, height, DefaultDepth(dpy, screen));
  905.     a_inc = a_range / (double)width;
  906.     b_inc = b_range / (double)height;
  907.     point.x = 0;
  908.     point.y = 0;
  909.     run = 1;
  910.     a = rubber_data.p_min = min_a;
  911.     b = rubber_data.q_min = min_b;
  912.     rubber_data.p_max = max_a;
  913.     rubber_data.q_max = max_b;
  914.     if (dflag)
  915.         delta = Min(a_range, b_range) / (double)Max(height, width);
  916.     freemem();
  917.     setupmem();
  918.     for (n=0;n<MAXFRAMES;n++)
  919.         if ((n <= maxframe) && (n != frame))
  920.             resized[n] = 1;
  921.     InitBuffer(&Points, maxcolor);
  922.     Clear();
  923.     Redraw();
  924. }
  925.  
  926. void
  927. redraw(exparray, index, cont)
  928. int *exparray;
  929. int index, cont;
  930. {
  931.     static int i;
  932.     static int x_sav, y_sav;
  933.     static double a_sav, b_sav;
  934.  
  935.     x_sav = point.x;
  936.     y_sav = point.y;
  937.     a_sav = a;
  938.     b_sav = b;
  939.  
  940.     point.x = 0;
  941.     point.y = 0;
  942.  
  943.     save=0;
  944.     for (i=0;i<index;i++)
  945.         sendpoint(exparray[i]);
  946.     save=1;
  947.     
  948.     if (cont) {
  949.         point.x = x_sav;
  950.         point.y = y_sav;
  951.         a = a_sav;
  952.         b = b_sav;
  953.     }
  954.     else {
  955.         a = point.x * a_inc + min_a;
  956.         b = point.y * b_inc + min_b;
  957.     }
  958.     FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  959. }
  960.  
  961. void
  962. Redraw() 
  963. {
  964.     dorecalc = maxcnt = 0;
  965.     FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  966.     point.x = 0;
  967.     point.y = 0;
  968.     run = 1;
  969.     a = min_a;
  970.     b = min_b;
  971.     expind[frame] = 0;
  972.     resized[frame] = 0;
  973. }
  974.  
  975. /* Store colormap indices in file so we can read them in later */
  976. void
  977. store_to_file() 
  978. {
  979.     FILE *outfile;
  980.     static int i;
  981.  
  982.     outfile = fopen(savname,"w");
  983.     if(!outfile) {
  984.         perror(savname);
  985.         XCloseDisplay(dpy);
  986.         exit(-1);
  987.     }
  988.  
  989.     fprintf(outfile,"# width=%d height=%d run=%d\n",width,height,run);
  990.     fprintf(outfile,"# kmax=%d (p,q)=(%.12lg,%.12lg)\n", kmax, p, q);
  991.     fprintf(outfile,"# min_a=%.12lg  a_rng=%.12lg  max_a=%.12lg\n",
  992.             min_a,a_range,max_a);
  993.     fprintf(outfile,"# min_b=%.12lg  b_rng=%.12lg  max_b=%.12lg\n",
  994.             min_b,b_range,max_b);
  995.     fprintf(outfile,"# a=%.12lg  b=%.12lg  res=%d\n",a,b,res);
  996.     fprintf(outfile,"# point.x=%d point.y=%d\n",point.x,point.y);
  997.     fprintf(outfile,"# expind=%d\n",expind[frame]);
  998.     fprintf(outfile,"%d\n",numcolors-1);
  999.  
  1000.     for (i=0;i<expind[frame];i++)
  1001.         fprintf(outfile,"%d\n",exponents[frame][i]);
  1002.     fclose(outfile);
  1003. }
  1004.  
  1005. /* Store color pics in PPM format and monochrome in PGM */
  1006. void
  1007. save_to_file() 
  1008. {
  1009.     FILE *outfile;
  1010.     unsigned char c;
  1011.     XImage *ximage;
  1012.     static int i,j;
  1013.     struct Colormap {
  1014.         unsigned char red;
  1015.         unsigned char green;
  1016.         unsigned char blue;
  1017.     };
  1018.     struct Colormap *colormap=NULL;
  1019.  
  1020.     if (colormap)
  1021.         free(colormap);
  1022.     if ((colormap=
  1023.         (struct Colormap *)malloc(sizeof(struct Colormap)*maxcolor))
  1024.             == NULL) {
  1025.         fprintf(stderr,"Error malloc'ing colormap array\n");
  1026.         XCloseDisplay(dpy);
  1027.         exit(-1);
  1028.     }
  1029.     outfile = fopen(outname,"w");
  1030.     if(!outfile) {
  1031.         perror(outname);
  1032.         XCloseDisplay(dpy);
  1033.         exit(-1);
  1034.     }
  1035.  
  1036.     ximage=XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
  1037.  
  1038.     if (displayplanes > 1) {
  1039.         for (i=0;i<maxcolor;i++) {
  1040.             colormap[i].red=(unsigned char)(Colors[i].red >> 8);
  1041.             colormap[i].green=(unsigned char)(Colors[i].green >> 8);
  1042.             colormap[i].blue =(unsigned char)(Colors[i].blue >> 8);
  1043.         }
  1044.         fprintf(outfile,"P%d %d %d\n",6,width,height);
  1045.     }
  1046.     else
  1047.         fprintf(outfile,"P%d %d %d\n",5,width,height);
  1048.     fprintf(outfile,"# kmax=%d (p,q)=(%.12lg,%.12lg)\n", kmax, p, q);
  1049.     fprintf(outfile,"# min_a=%.12lg  a_rng=%.12lg  max_a=%.12lg\n",
  1050.             min_a,a_range,max_a);
  1051.     fprintf(outfile,"# min_b=%.12lg  b_rng=%.12lg  max_b=%.12lg\n",
  1052.             min_b,b_range,max_b);
  1053.     fprintf(outfile,"%d\n",numcolors-1);
  1054.  
  1055.     for (j=0;j<height;j++)
  1056.         for (i=0;i<width;i++) {
  1057.             c = (unsigned char)XGetPixel(ximage,i,j);
  1058.             if (displayplanes > 1)
  1059.                 fwrite((char *)&colormap[c],sizeof colormap[0],1,outfile);
  1060.             else
  1061.                 fwrite((char *)&c,sizeof c,1,outfile);
  1062.         }
  1063.     fclose(outfile);
  1064. }
  1065.  
  1066. /* Read saved file with parameters */
  1067. void
  1068. restor_params() 
  1069. {
  1070.     unsigned char s[16];
  1071.  
  1072.     infile = fopen(inname,"r");
  1073.     if(!infile) {
  1074.         perror(inname);
  1075.         exit(-1);
  1076.     }
  1077.  
  1078.     fscanf(infile,"%1s%6s%d%7s%d%4s%d",&s,&s,&width,&s,&height,&s,&run);
  1079.     fscanf(infile,"%1s%5s%d%7s%lg%1s%lg%1s", &s,&s,&kmax,&s,&p,&s,&q,&s);
  1080. /* printf("kmax=%d p=%.12lg q=%.12lg\n",kmax,p,q); */
  1081.     fscanf(infile,"%1s%6s%lg%6s%lg%6s%lg", &s,&s,&min_a,&s,&a_range,&s,&max_a);
  1082. /* printf("min_a=%.12lg a_range=%.12lg max_a=%.12lg\n",min_a,a_range,max_a); */
  1083.     fscanf(infile,"%1s%6s%lg%6s%lg%6s%lg", &s,&s,&min_b,&s,&b_range,&s,&max_b);
  1084. /* printf("min_b=%.12lg b_range=%.12lg max_b=%.12lg\n",min_b,b_range,max_b); */
  1085.     fscanf(infile,"%1s%2s%lg%2s%lg%4s%d", &s,&s,&a,&s,&b,&s,&res);
  1086. /* printf("a=%.12lg b=%.12lg\n",a,b); */
  1087.     fscanf(infile,"%1s%8s%d%8s%d",&s,&s,&point.x,&s,&point.y);
  1088. /* printf("point.x=%d point.y=%d\n",point.x,point.y); */
  1089.     fscanf(infile,"%1s%7s%d",&s,&s,&expind[0]);
  1090.     fread(&numcolors, sizeof numcolors, 1, infile);
  1091.     numcolors++;
  1092.     rubber_data.p_min = a_minimums[frame] = min_a ;
  1093.     rubber_data.q_min = b_minimums[frame] = min_b ;
  1094.     rubber_data.p_max = a_maximums[frame] = max_a;
  1095.     rubber_data.q_max = b_maximums[frame] = max_b ;
  1096. }
  1097.  
  1098. void
  1099. restor_picture() {
  1100.     static int i, k, l, h, w;
  1101.     unsigned char c;
  1102.     unsigned char s[8];
  1103.     XEvent event;
  1104.  
  1105.     for (i=0;i<expind[frame];i++)
  1106.         fscanf(infile, "%d", &exponents[frame][i]);
  1107.     fclose(infile);
  1108.     if (!run) {
  1109.         dorecalc = 1;
  1110.         recalc();
  1111.     }
  1112.     redraw(exponents[frame], expind[frame], 1); 
  1113.     FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  1114. }
  1115.  
  1116. void
  1117. Clear() 
  1118. {
  1119.     XFillRectangle(dpy, pixmap, Data_GC[0], 0, 0, width, height);
  1120.     XCopyArea(dpy, pixmap, canvas, Data_GC[0], 
  1121.                 0, 0, width, height, 0, 0);
  1122.     InitBuffer(&Points, maxcolor);
  1123. }
  1124.  
  1125. void
  1126. show_defaults() 
  1127. {
  1128.  
  1129.     printf("Width=%d  Height=%d  numcolors=%d\n", width,height,numcolors);
  1130.     printf("min_a=%.12lg  a_range=%.12lg  max_a=%.12lg\n", min_a,a_range,max_a);
  1131.     printf("min_b=%.12lg  b_range=%.12lg  max_b=%.12lg\n", min_b,b_range,max_b);
  1132.     printf("mincnt=%d  maxcnt=%d\n", mincnt,maxcnt);
  1133.     exit(0);
  1134. }
  1135.  
  1136. void
  1137. CreateXorGC()
  1138. {
  1139.     XGCValues values;
  1140.  
  1141.     values.foreground = foreground;
  1142.     values.line_style = LineSolid;
  1143.     values.function = GXxor;
  1144.     RubberGC = XCreateGC(dpy, DefaultRootWindow(dpy),
  1145.           GCForeground | GCBackground | GCFunction | GCLineStyle, &values);
  1146. }
  1147.  
  1148. void
  1149. SetupCorners(corners, data)
  1150. XPoint *corners;
  1151. image_data_t *data;
  1152. {
  1153.     corners[0].x = data->rubber_band.start_x;
  1154.     corners[0].y = data->rubber_band.start_y;
  1155.     corners[1].x = data->rubber_band.start_x;
  1156.     corners[1].y = data->rubber_band.last_y;
  1157.     corners[2].x = data->rubber_band.last_x;
  1158.     corners[2].y = data->rubber_band.last_y;
  1159.     corners[3].x = data->rubber_band.last_x;
  1160.     corners[3].y = data->rubber_band.start_y;
  1161.     corners[4] = corners[0];
  1162. }
  1163.  
  1164. void 
  1165. StartRubberBand(w, data, event)
  1166. Window w;
  1167. image_data_t *data;
  1168. XButtonEvent *event;
  1169. {
  1170.     XPoint corners[5];
  1171.     static char xystr[40];
  1172.  
  1173.     nostart = 0;
  1174.     switch (event->button) {
  1175.         case Button1:
  1176.             data->rubber_band.last_x = data->rubber_band.start_x = event->x;
  1177.             data->rubber_band.last_y = data->rubber_band.start_y = event->y;
  1178.             button = 1;
  1179.             SetupCorners(corners, data);
  1180.             XDrawLines(dpy, canvas, RubberGC,
  1181.                 corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
  1182.             break;
  1183.         case Button2:
  1184.             button = 2;
  1185.             if (func == compmandel) {
  1186.                 p = min_a + (((double)event->x/(double)width)*a_range);
  1187.                 q = max_b - (((double)event->y/(double)height)*b_range);
  1188.                 sprintf(xystr," (%.12lg,%.12lg) ", p, q);
  1189.                 XDrawImageString(dpy, canvas, Data_GC[1], width/4, height - 20, 
  1190.                                 xystr, strlen(xystr));
  1191.             }
  1192.             break;
  1193.     }
  1194. }
  1195.  
  1196. void 
  1197. TrackRubberBand(w, data, event)
  1198. Window w;
  1199. image_data_t *data;
  1200. XMotionEvent *event;
  1201. {
  1202.     XPoint corners[5];
  1203.     int xdiff, ydiff, diff;
  1204.     static char xystr[40];
  1205.  
  1206.     if (nostart)
  1207.         return;
  1208.     if (button == 1) {
  1209.         SetupCorners(corners, data);
  1210.         XDrawLines(dpy, canvas, RubberGC, corners, 
  1211.                       sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
  1212.         ydiff = event->y - data->rubber_band.start_y;
  1213.         xdiff = event->x - data->rubber_band.start_x;
  1214.         data->rubber_band.last_x = data->rubber_band.start_x + xdiff;
  1215.         data->rubber_band.last_y = data->rubber_band.start_y + ydiff;
  1216.         if (data->rubber_band.last_y < data->rubber_band.start_y ||
  1217.                data->rubber_band.last_x < data->rubber_band.start_x) {
  1218.                    data->rubber_band.last_y = data->rubber_band.start_y;
  1219.                    data->rubber_band.last_x = data->rubber_band.start_x;
  1220.         }
  1221.         SetupCorners(corners, data);
  1222.         XDrawLines(dpy, canvas, RubberGC, corners, 
  1223.                       sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
  1224.     }
  1225.     else if (button == 2) {
  1226.         if (func == compmandel) {
  1227.             p = min_a + (((double)event->x/(double)width)*a_range);
  1228.             q = max_b - (((double)event->y/(double)height)*b_range);
  1229.             sprintf(xystr," (%.12lg,%.12lg) ", p, q);
  1230.             XDrawImageString(dpy, canvas, Data_GC[1], width/4, height - 20, 
  1231.                             xystr, strlen(xystr));
  1232.         }
  1233.     }
  1234. }
  1235.  
  1236. void
  1237. set_new_params(w, data, center)
  1238. Window w;
  1239. image_data_t *data;
  1240. int center;
  1241. {
  1242.     extern void Clear();
  1243.  
  1244.     frame = (maxframe + 1) % MAXFRAMES;
  1245.     if (frame > maxframe)
  1246.         maxframe = frame;
  1247.     a_range = data->p_max - data->p_min;
  1248.     b_range = data->q_max - data->q_min;
  1249.     a_minimums[frame] = min_a = data->p_min;
  1250.     b_minimums[frame] = min_b = data->q_min;
  1251.     if (center) {
  1252.         center_x = min_a + (a_range/2.0);
  1253.         center_y = min_b + (b_range/2.0);
  1254.         if ((center_x == 0.0) && (center_y == 0.0))
  1255.             symetrical = 1;
  1256.         else if ((func == compmandel) && (center_y == 0.0))
  1257.             symetrical = 1;
  1258.         else
  1259.             symetrical = 0;
  1260.     }
  1261.     a_inc = a_range / (double)width;
  1262.     b_inc = b_range / (double)height;
  1263.     point.x = 0;
  1264.     point.y = 0;
  1265.     run = 1;
  1266.     a = min_a;
  1267.     b = min_b;
  1268.     a_maximums[frame] = max_a = data->p_max;
  1269.     b_maximums[frame] = max_b = data->q_max;
  1270.     expind[frame] = 0; dorecalc = maxcnt = 0;
  1271.     if (dflag)
  1272.         delta = Min(a_range, b_range) / (double)Max(height, width);
  1273.     Clear();
  1274. }
  1275.  
  1276. void 
  1277. EndRubberBand(w, data, event)
  1278. Window w;
  1279. image_data_t *data;
  1280. XButtonEvent *event;
  1281. {
  1282.     XPoint corners[5];
  1283.     XPoint top, bot;
  1284.     double r_delta, diff;
  1285.     char pval[64], qval[64];
  1286.     char wval[16], hval[16], kval[16];
  1287.     char xval[8], yval[8];
  1288.  
  1289.     nostart = 1;
  1290.     switch (event->button) {
  1291.         case Button1:
  1292.             SetupCorners(corners, data);
  1293.             XDrawLines(dpy, canvas, RubberGC,
  1294.                 corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
  1295.             if (data->rubber_band.start_x >= data->rubber_band.last_x ||
  1296.                 data->rubber_band.start_y >= data->rubber_band.last_y)
  1297.                 return;
  1298.             top.x = data->rubber_band.start_x;
  1299.             bot.x = data->rubber_band.last_x;
  1300.             top.y = data->rubber_band.start_y;
  1301.             bot.y = data->rubber_band.last_y;
  1302.             diff = data->q_max - data->q_min;
  1303.             r_delta = (double)(height - bot.y) / (double)height;
  1304.             data->q_min += diff * r_delta;
  1305.             r_delta = (double)top.y / (double)height;
  1306.             data->q_max -= diff * r_delta;
  1307.             diff = data->p_max - data->p_min;
  1308.             r_delta = (double)top.x / (double)width;
  1309.             data->p_min += diff * r_delta;
  1310.             r_delta = (double)(width - bot.x) / (double)width;
  1311.             data->p_max -= diff * r_delta;
  1312.             fflush(stdout);
  1313.             set_new_params(w, data, 1);
  1314.             break;
  1315.         case Button2:
  1316.             if (func == compmandel) {
  1317.               if ((event->x >= 0) && (event->x <= width) && 
  1318.                   (event->y >= 0) && (event->y <= height)) {
  1319.                 switch (fork()) {
  1320.                     case -1:
  1321.                         fprintf(stderr,"Can't create new process\n");
  1322.                         return;
  1323.                     case 0:
  1324.                         xpos = event->x*XDisplayWidth(dpy, screen)/width;
  1325.                         xpos -= (width/4); if (xpos < 0) xpos = 0;
  1326.                         ypos = event->y*XDisplayHeight(dpy, screen)/height;
  1327.                         ypos -= (height/4); if (ypos < 0) ypos = 0;
  1328.                         p = min_a + (((double)event->x/(double)width)*a_range);
  1329.                         q = max_b - (((double)event->y/(double)height)*b_range);
  1330.                         sprintf(xval, "%d", xpos);
  1331.                         sprintf(yval, "%d", ypos);
  1332.                         sprintf(wval, "%d", width/2);
  1333.                         sprintf(hval, "%d", height/2);
  1334.                         sprintf(kval, "%d", kmax);
  1335.                         sprintf(pval, "%.12lg", p);
  1336.                         sprintf(qval, "%.12lg", q);
  1337.                         if (path)
  1338.                             strcat(path, "julia");
  1339.                         else
  1340.                             path = strdup("julia");
  1341.                         execlp(path,path,"-X",xval,"-Y",yval,"-p",pval,
  1342.                                "-q",qval,"-W",wval,"-H",hval,"-K",kval,NULL);
  1343.                         exit(0);
  1344.                 }
  1345.               }
  1346.               XCopyArea(dpy,pixmap,canvas,Data_GC[1],0,0,width,height,0,0);
  1347.             }
  1348.             break;
  1349.     }
  1350.     button = 0;
  1351. }
  1352.  
  1353. void
  1354. go_down() 
  1355. {
  1356.     static int i;
  1357.     
  1358.     frame++;
  1359.     if (frame > maxframe)
  1360.         frame = 0;
  1361.     jumpwin();
  1362. }
  1363.  
  1364. void
  1365. go_back() 
  1366. {
  1367.     static int i;
  1368.     
  1369.     frame--;
  1370.     if (frame < 0)
  1371.         frame = maxframe;
  1372.     jumpwin();
  1373. }
  1374.  
  1375. jumpwin()
  1376. {
  1377.     if (!maxframe)
  1378.         return;
  1379.     rubber_data.p_min = min_a = a_minimums[frame];
  1380.     rubber_data.q_min = min_b = b_minimums[frame];
  1381.     rubber_data.p_max = max_a = a_maximums[frame];
  1382.     rubber_data.q_max = max_b = b_maximums[frame];
  1383.     a_range = max_a - min_a;
  1384.     b_range = max_b - min_b;
  1385.     center_x = min_a + (a_range/2.0);
  1386.     center_y = min_b + (b_range/2.0);
  1387.     if ((center_x == 0.0) && (center_y == 0.0))
  1388.         symetrical = 1;
  1389.     else if ((func == compmandel) && (center_y == 0.0))
  1390.         symetrical = 1;
  1391.     else
  1392.         symetrical = 0;
  1393.     a_inc = a_range / (double)width;
  1394.     b_inc = b_range / (double)height;
  1395.     point.x = 0;
  1396.     point.y = 0;
  1397.     a = min_a;
  1398.     b = min_b;
  1399.     dorecalc = maxcnt = 0;
  1400.     Clear();
  1401.     if (resized[frame])
  1402.         Redraw();
  1403.     else
  1404.         redraw(exponents[frame], expind[frame], 0);
  1405.     if ((point.y >= height) || (symetrical && (point.y > (height/2)))) {
  1406.         run = 0;
  1407.         dorecalc = 1;
  1408.         recalc();
  1409.         redraw(exponents[frame], expind[frame], 1);
  1410.     }
  1411.     else
  1412.         run = 1;
  1413. }
  1414.  
  1415. void
  1416. go_init() 
  1417. {
  1418.     static int i;
  1419.     
  1420.     if (frame) {
  1421.         frame = 0;
  1422.         jumpwin();
  1423.     }
  1424. }
  1425.  
  1426. Destroy_frame()
  1427. {
  1428.     static int i;
  1429.  
  1430.     for (i=frame; i<maxframe; i++) {
  1431.         exponents[frame] = exponents[frame+1];
  1432.         expind[frame] = expind[frame+1];
  1433.         a_minimums[frame] = a_minimums[frame+1];
  1434.         b_minimums[frame] = b_minimums[frame+1];
  1435.         a_maximums[frame] = a_maximums[frame+1];
  1436.         b_maximums[frame] = b_maximums[frame+1];
  1437.     }
  1438.     maxframe--;
  1439.     go_back();
  1440. }
  1441.  
  1442. void
  1443. print_help() 
  1444. {
  1445.     printf("During run-time, interactive control can be exerted via : \n");
  1446.     printf("Mouse buttons allow rubber-banding of a zoom box\n");
  1447.     printf("D flushes the drawing buffer\n");
  1448.     printf("e or E recalculates color indices\n");
  1449.     printf("f or F saves exponents to a file\n");
  1450.     printf("h or H or ? displays this message\n");
  1451.     printf("i decrements, I increments the stripe interval\n");
  1452.     printf("p or P reverses the colormap for negative/positive exponents\n");
  1453.     printf("r redraws without recalculating\n");
  1454.     printf("R redraws while recalculating with new values\n");
  1455.     printf("s or S spins the colorwheel\n");
  1456.     printf("u pops back up to the last zoom\n");
  1457.     printf("U pops back up to the first picture\n");
  1458.     printf("v or V displays the values of various settings\n");
  1459.     printf("w decrements, W increments the color wheel index\n");
  1460.     printf("x or X clears the window\n");
  1461.     printf("q or Q exits\n");
  1462. }
  1463.  
  1464. void
  1465. print_values() 
  1466. {
  1467.     static int i;
  1468.  
  1469.     if (func == compjulia)
  1470.         printf("julia: (p,q)=(%.12lg, %.12lg)\n", p, q);
  1471.     else
  1472.         printf("mandel:\n");
  1473.     printf("\nmincnt=%d maxcnt=%d run=%d\n",mincnt,maxcnt,run);
  1474.     printf("width=%d height=%d res=%d\n",width,height,res);
  1475.     printf("kmax=%d M=%d\n", kmax,M); 
  1476.     printf("point.x=%d point.y=%d\n",point.x,point.y); 
  1477.     printf("a=%.12lg  b=%.12lg\n",a,b);
  1478.     printf("min_a=%.12lg  max_a=%.12lg\n",min_a,max_a);
  1479.     printf("min_b=%.12lg  max_b=%.12lg\n",min_b,max_b);
  1480.     printf("center=(%.12lg, %.12lg) a_rng=%.12lg b_rng=%.12lg\n",
  1481.             center_x,center_y,a_range,b_range);
  1482.     printf("numcolors=%d\n",numcolors-1);
  1483. }
  1484.  
  1485. freemem()
  1486. {
  1487.     static int i;
  1488.  
  1489.     for (i=0;i<MAXFRAMES;i++)
  1490.         free(exponents[i]);
  1491. }
  1492.  
  1493. setupmem()
  1494. {
  1495.     static int i;
  1496.  
  1497.     for (i=0;i<MAXFRAMES;i++) {
  1498.         if((exponents[i]=
  1499.             (int *)malloc(sizeof(int)*width*height))==NULL){
  1500.                 fprintf(stderr,"Error malloc'ing exponent array.\n");
  1501.                 exit(-1);
  1502.         }
  1503.     }
  1504. }
  1505.