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