[comp.windows.x] Mandelbrot?

jrr@arvak.cs.cornell.edu (Jim Russell) (05/06/88)

Does anybody out there have a good mandelbrot program for X10 or X11?
If possible, interactive, mouse-driven, etc, with source code, 
preferably written in C?

Thanks in advance,

--chet--
murthy@svax.cs.cornell.edu

Rick.Busdiecker@SPICE.CS.CMU.EDU (05/06/88)

Here's the one I use.  It's not especially interactive and it's
designed for (and so far only been run on) a monochrome screen.  It doesn't
use the toolkit at all and it breaks a number of ``rules'' for X11
applications.

On the brighter side, it let's you spawn off new mandelbrots by typing
character's at the window (see server() and spawn()).  I've had some
problem with the file descriptor for the X server connection which is why
spawn uses system() instead of vfork(), but it works so . . . .

I'd appreciate getting updates if anyone does any more with this.

			Rick Busdiecker
			Expert Technologies, Inc.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

/* Mandelbrot set viewer for the X Window System, Version 11
 *
 * by Rick Busdiecker
 *
 * This is PUBLIC DOMAIN software.  Do whatever you want with it.
 *
 * Try calling with ``-real -0.55 -imag 1.3 -range 2.55 -size 1280 -root'' to fill your root window.
 */

#include <stdio.h>
#include <sys/param.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

float   atof ();
void    server ();
char*   getwd ();

/*
 * Global variables
 */

char*           program_name;
Display*        display;
Window          root;
Window          window;
GC              window_gcontext;
Pixmap          pixmap;
GC              pixmap_gcontext;
int             size                    = 128;
int             depth                   = 20;
float           real_origin             = -2.0;
float           imaginary_origin        =  2.0;
float           range                   =  4.0;
float           contrast_ratio          =  0.95;


void initialize ()
{
    display     = XOpenDisplay (NULL);
    root        = XRootWindow (display, XDefaultScreen (display));
}

Window initial_window ()
{
    Window                      result;
    XSetWindowAttributes        attributes;
    XSizeHints                  hints;
    char                        buffer [1024];
    

    attributes.background_pixel         = 1;
    attributes.border_pixel             = 0;
    attributes.event_mask               = KeyPressMask;

    result = XCreateWindow (display, root, 0, 0, size, size, 2, 0, 0, 0, CWBackPixel | CWBorderPixel | CWEventMask, &attributes);

    hints.flags = PMaxSize | PMinSize;
    hints.max_width = hints.max_height = hints.min_width = hints.min_height = size;
    XSetNormalHints (display, result, &hints);

    XStoreName (display, result, "Mandelbrot");
    XSetIconName (display, result, sprintf (buffer, "Mandelbrot: Position = (%g, %g), Range = %g, Depth = %d",
                                            real_origin, imaginary_origin, range, depth));
    return result;
}

void initialize_window ()
{
    XGCValues   values;

    XMapWindow (display, window);
    XFlush (display);

    values.foreground           = 0;
    values.background           = 1;

    window_gcontext = XCreateGC (display, window, GCForeground | GCBackground, &values);
}

void initialize_bitmap ()
{
    XGCValues   values;
    GC          temporary_gcontext;

    pixmap = XCreatePixmap (display, window, size, size, 1);
    XSetWindowBackgroundPixmap (display, window, pixmap);

    values.foreground           = 0;
    values.background           = 1;
    
    pixmap_gcontext = XCreateGC (display, pixmap, GCForeground | GCBackground, &values);

    values.foreground = 1;
    temporary_gcontext = XCreateGC (display, pixmap, GCForeground | GCBackground, &values);
    XFillRectangle (display, pixmap, temporary_gcontext, 0, 0, size, size);
    XFreeGC (display, temporary_gcontext);
}

void plot (x, y, bit)
int     x;
int     y;
int     bit;
{
    if (bit)
    {
        XDrawPoint (display, window, window_gcontext, x, y);
        XDrawPoint (display, pixmap, pixmap_gcontext, x, y);
    }
}

#define drop_out_distance (4.0)

void compute_image ()
{
    register int y;

    for (y = 0; y < size; y++)
    {
        register int x;
        
        for (x = 0; x < size; x++)
        {
            float       real_mu = real_origin + (float)x * range / (float)size;
            float       imaginary_mu = imaginary_origin - (float)y * range / (float)size;
            float       real_z = 0.0;
            float       imaginary_z = 0.0;
            int         iteration;
            
            for (iteration = 0; iteration < depth; iteration++)
            {
                float new_real_z = real_z * real_z - imaginary_z * imaginary_z - real_mu;

                server (0);

                imaginary_z = 2 * real_z * imaginary_z - imaginary_mu;
                real_z = new_real_z;

                if (real_z * real_z + imaginary_z * imaginary_z >= drop_out_distance)
                {
                    plot (x, y, ((float)iteration > contrast_ratio * (float)depth) ? 1 : iteration & 1);
                    goto throw;
                }
            }
throw:
            /* C doesn't seem to deal well with a label that doesn't have code following it.  This ``null statement'' is enough
             * though.
             */
            ;
        }
    }
}

int match_p (string_1, string_2, minimum)
char*   string_1;
char*   string_2;
int     minimum;
{
    int length_1        = strlen (string_1);
    int length_2        = strlen (string_2);
    int short_length    = (length_1 < length_2) ? length_1 : length_2;

    if ((length_1 < minimum) || (length_2 < minimum))
        return 0;
    return !strncmp (string_1, string_2, short_length);
}

char* next_argument (count, vector)
int*    count;
char*** vector;
{
    if (--*count == 0)
    {
        fprintf (stderr, "Missing expected command line argument!\n");
        exit (-1);
    }
    return *++*vector;
}       

void spawn (real, imaginary, new_range, new_depth, new_size)
float   real;
float   imaginary;
float   new_range;
int     new_depth;
int     new_size;
{
    char        buffer [2048];
    
    if (! fork ())
    {
        close (3);
        system (sprintf (buffer,
                         "%s -contrast_ratio %g -depth %d -imaginary_origin %g -size %d -range %g -real_origin %g &",
                         program_name, contrast_ratio, new_depth, imaginary, new_size, new_range, real));
    }
}

void server (block_p)
int     block_p;
{
    XEvent      event;
    char        input = '\0';
    
    if (block_p || XPending (display))
    {
        XNextEvent (display, &event); 
        switch (event.type)
        {
        case KeyPress:
            if (XLookupString (&event, &input, 1, NULL, NULL) == 1)
            {
                switch (input)
                {
                    /* Movement */
                case 'u': spawn (real_origin, imaginary_origin + range / 2.0, range, depth, size); break;
                case 'd': spawn (real_origin, imaginary_origin - range / 2.0, range, depth, size); break;
                case 'l': spawn (real_origin - range / 2.0, imaginary_origin, range, depth, size); break;
                case 'r': spawn (real_origin + range / 2.0, imaginary_origin, range, depth, size); break;

                    /* Size */
                case 'e': spawn (real_origin, imaginary_origin, range, depth, 2 * size); break;
                case 's': spawn (real_origin, imaginary_origin, range, depth, size / 2); break;

                    /* Depth */
                case 'D': spawn (real_origin, imaginary_origin, range, 2 * depth, size); break;

                    /* Zoom quadrant */
                case 'c': spawn (real_origin + range / 4.0, imaginary_origin - range / 4.0, range / 2.0, depth, size); break;
                case '1': spawn (real_origin + range / 2.0, imaginary_origin, range / 2.0, depth, size); break;
                case '2': spawn (real_origin, imaginary_origin, range / 2.0, depth, size); break;
                case '3': spawn (real_origin, imaginary_origin - range / 2.0, range / 2.0, depth, size); break;
                case '4': spawn (real_origin + range / 2.0, imaginary_origin - range / 2.0, range / 2.0, depth, size); break;

                    /* Quit */
                case 'q':
                    XCloseDisplay (display);
                    exit (0);
                default: ;
                }
            }
        }       
    }
}

/*
 * Switches:
 *   [c]ontrast_ratio
 *   [d]epth
 *   [i]maginary_origin
 *   [s]ize
 *   [ra]nge
 *   [re]al_origin
 *   [ro]oot
 */
int main (argument_count, argument_vector)
int     argument_count;
char**  argument_vector;
{
    int root_p = 0;
    
    program_name = *argument_vector;
    
    while (--argument_count > 0)
    {
        char*   argument = *++argument_vector;
        
        if (*argument == '-')
        {
            char*       option = argument + 1;
            
            if (match_p (option, "contrast_ratio", 1))
            contrast_ratio = atof (next_argument (&argument_count, &argument_vector));
            else if (match_p (option, "depth", 1))
            depth = atoi (next_argument (&argument_count, &argument_vector));
            else if (match_p (option, "help", 1)|| match_p (option, "?", 1))
            {
                printf ("%s [-contrast-ratio <float>] [-depth <integer>] [-help] [-?]\n\
        [-imaginary_origin <float>] [-size <integer>] [-range <float>]\n\
        [-real_origin <float>] [-root]\n", program_name);
                exit (0);
            }
            else if (match_p (option, "imaginary_origin", 1))
            imaginary_origin = atof (next_argument (&argument_count, &argument_vector));
            else if (match_p (option, "size", 1))
            size = atoi (next_argument (&argument_count, &argument_vector));
            else if (match_p (option, "range", 2))
            range = atof (next_argument (&argument_count, &argument_vector));
            else if (match_p (option, "real_origin", 2))
            real_origin = atof (next_argument (&argument_count, &argument_vector));
            else if (match_p (option, "root", 2))
            root_p = 1;
            else
            {
                fprintf (stderr, "%s: Unknown option ``%s''\n", program_name, option);
                exit (-1);
            }
        }
        else
        {
            fprintf (stderr, "Expecting a command line option but found `%s'.\n", argument);
            exit (-1);
        }
    }
    initialize ();
    if (root_p)
    window = root;
    else
    window = initial_window ();
    initialize_window ();
    initialize_bitmap ();
    compute_image ();
    XClearWindow(display, root);
    XFlush (display);
    if (! root_p)
    while (1)
    {
        server (1);
    }
} 

turner@daisy.UUCP (D'arc Angel) (05/10/88)

I don't know how good this is.....

#define DEBUG 0

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/X.h>


#define MAX_COLORS  6

   Display *display;
   Window window;
   int screen;

               extern int optind;
               extern char *optarg, getopt();
   int cycling;

main (argc, argv)
int argc;
char *argv[];
{
   int colors[MAX_COLORS+1];
   int ncolors;
   int width;
   int height;

   window = winit (argc, argv, &width, &height);

   XSync(display, DEBUG);

   ncolors = set_colors (colors);

   make_fractal (window, width, height, colors, ncolors);

   if(cycling)
     cycle_colors (colors, ncolors);

   pause ();

   uninit (window);

   exit (0);
}

winit (argc, argv, width, height)
int argc;
char *argv[];
int *width;
int *height;
{
   XWindowAttributes window_attr;
   int i;
   char *hostname = NULL;
   char *geometry = NULL;
   int geomx, geomy, geomw, geomh;
   char c;

   geomx = 0; geomy = 0; geomw = 256; geomh = 256; /* defaults */
   cycling = 1;

               while ((c = getopt(argc, argv, "g:d:c")) != EOF)
                    switch (c) {
                    case 'g':
		      geometry = optarg;
		      XParseGeometry(geometry, &geomx, &geomy, &geomw, &geomh);
		      break;
		    case 'd':
		      hostname = optarg;
		      break;
		    case 'c': /* turn off cycling */
		      cycling = 0;
		      break;
		    default:
		      usage();
		    }
   
   if ((display = XOpenDisplay (hostname)) == NULL)
   {
      printf ("%s: Unable to connect to display.\n", argv[0]);
      exit (1);
   }


   screen = DefaultScreen(display);

   if ((window = XCreateSimpleWindow (display, RootWindow(display, screen),
	geomx, geomy, geomw, geomh, 5, BlackPixel(display, screen), 
	WhitePixel(display, screen))) == NULL)
   {
      printf ("%s: Unable to create window.\n", argv[0]);
      exit (1);
   }

   XGetWindowAttributes(display, window, &window_attr);
   *width  = window_attr.width;
   *height = window_attr.height;

   return (window);
}

int set_colors (colors)
int colors[];
{
   static char *name[] = {"Red", "Yellow", "Green", "Cyan", "Blue", "Magenta",
                          "Black"};
   XColor hw_def;
   XColor exact_def;
   Colormap cmap;
   int ncolors;
   int planes;
   int i;

   cmap = DefaultColormap(display, 0);

   for (ncolors = 6; ncolors >= 0; ncolors--)
      if (XAllocColorCells (display, cmap, 0, &planes, 0, colors, ncolors+1))
         break;
   name[ncolors] = name[6];

   for (i = 0; i <= ncolors; i++)
   {
      XAllocNamedColor (display, cmap, name[i], &hw_def, &exact_def);
      exact_def.pixel = colors[i];
      XStoreColors (display, cmap, &exact_def, 1);
   }

   return (ncolors);
}

cycle_colors (colors, ncolors)
int colors[];
int ncolors;
{
   static char *name[] = {"Red", "Yellow", "Green", "Cyan", "Blue", "Magenta"};
   XColor hw_def;
   XColor exact_def[6];
   Colormap cmap;
   int ist;
   int i;


   cmap = DefaultColormap(display, 0);

   for (i = 0; i < ncolors; i++)
         XAllocNamedColor (display, cmap, name[i], &hw_def, &exact_def[i]);

   for (ist = 0; ; ist = (ist + ncolors - 1) % ncolors)
   {
      for (i = 0; i < ncolors; i++)
      {
         exact_def[i].pixel = colors[(ist + i) % ncolors];
	 XStoreColors (display, cmap, &exact_def[i], 1);

      }
   }
}

make_fractal (window, max_pixels_x, max_pixels_y, colors, ncolors)
Window window;
int max_pixels_x;
int max_pixels_y;
int *colors;
int ncolors;
{
   static GC gc = NULL;
   XGCValues values;
   unsigned long valuemask;

   register int ix;
   register int iy;
   register int i;
   register double x;
   register double y;
   register double yl;
   register double x2;
   register double y2;
   static int max_iterations = 1000;
   static double max_value   = 10.0;
   static double xcenter     =  0.0;
   static double ycenter     =  0.0;
   static double width       =  2.0;
   static double height      =  2.4;
   static double p           =  0.32;
   static double q           =  0.043;
   double min_x;
   double max_x;
   double min_y;
   double max_y;
   double pixwd;
   double pixht;
   int rows;
   int iclr;
   int mirror;


   if ((width / (double) max_pixels_x) > (height / (double) max_pixels_y))
      height = width * ((double) max_pixels_y / (double) max_pixels_x);
   else
      width = height * ((double) max_pixels_x / (double) max_pixels_y);

   check_values (&max_iterations, &xcenter, &ycenter, &width, &height, 
                 &max_value, &p, &q);

   mirror = ((xcenter == 0.0) && (ycenter == 0.0));
   if ((width / (double) max_pixels_x) > (height / (double) max_pixels_y))
      height = width * ((double) max_pixels_y / (double) max_pixels_x);
   else
      width = height * ((double) max_pixels_x / (double) max_pixels_y);
   max_x = xcenter + width / 2.0;
   min_x = xcenter - width / 2.0;
   max_y = ycenter + height / 2.0;
   min_y = ycenter - height / 2.0;

   rows = (mirror ? (max_pixels_y + 1) / 2 : max_pixels_y);
   pixwd = (max_x - min_x) / ((double) (max_pixels_x-1));
   pixht = (max_y - min_y) / ((double) (max_pixels_y-1));

   XMapWindow (display, window);

   for (iy = 0; iy < rows; iy++)
   {
      yl = pixht * (double) iy + min_y;
      for (ix = 0; ix < max_pixels_x; ix++)
      {
         x = pixwd * (double) ix + min_x;
         y = yl;
         for (i = 0; i < max_iterations; i++)
         {
            x2 = x * x;
            y2 = y * y;
            if (x2 + y2 > max_value)
               break;
            y = ((double) 2.0) * x * y + q;
            x = x2 - y2 + p;
         }
         iclr = ((i < max_iterations) ? i % ncolors : ncolors);
	 if(gc == NULL)
	   gc = XCreateGC(display, window, 0, &values);
	 XSetFillStyle(display, gc, FillSolid);
	 XSetForeground(display, gc, colors[iclr]);
	 XFillRectangle(display, window, gc, ix, max_pixels_y-iy-1, 1, 1);
         if (mirror)
	     XFillRectangle(display, window, gc, max_pixels_x-ix-1, iy, 1, 1);
      }
   }
}

uninit (window)
Window window;
{
   XUnmapWindow (window);
}

check_values (max_iterations, xcenter, ycenter, width, height, max_value, p, q)
int *max_iterations;
double *xcenter;
double *ycenter;
double *width;
double *height;
double *max_value;
double *p;
double *q;
{
   static struct {char *desc;
                  char *fmt;
                  char *addr;} pardef[] = 
      {{"Maximum iterations:", "%d",  (char *) 0},
       {"Maximum value:     ", "%lf", (char *) 0},
       {"X Center:          ", "%lf", (char *) 0},
       {"Y Center:          ", "%lf", (char *) 0},
       {"Width:             ", "%lf", (char *) 0},
       {"Height:            ", "%lf", (char *) 0},
       {"P:                 ", "%lf", (char *) 0},
       {"Q:                 ", "%lf", (char *) 0}};
   int field;
   int ndx;
   int end;
   char resp[256];
   char format[256];


   pardef[0].addr = (char *) max_iterations;
   pardef[1].addr = (char *) max_value;
   pardef[2].addr = (char *) xcenter;
   pardef[3].addr = (char *) ycenter;
   pardef[4].addr = (char *) width;
   pardef[5].addr = (char *) height;
   pardef[6].addr = (char *) p;
   pardef[7].addr = (char *) q;

   do
   {
      printf ("\n\n");
      for (ndx = 0; ndx < sizeof (pardef) / sizeof (*pardef); ndx++)
      {
         sprintf (format, "%4d.  %s %s   \n", ndx + 1, pardef[ndx].desc, 
                  pardef[ndx].fmt);
         if (!strcmp (pardef[ndx].fmt, "%lf"))
            printf (format, *((double *) pardef[ndx].addr));
         else if (!strcmp (pardef[ndx].fmt, "%d"))
            printf (format, *((int *) pardef[ndx].addr));
         else if (!strcmp (pardef[ndx].fmt, "%s"))
            printf (format, (char *) pardef[ndx].addr);
      }
      printf ("\n\nWhat do you want to change: ");
      end = !gets (resp);
      if (!end)
         end = !*resp;
      if (!end)
      {
         sscanf (resp, "%d", &field);
         if ((field > 0) && (field <= sizeof (pardef) / sizeof (*pardef)))
         {
            field--;
            printf ("\n\n%s ", pardef[field].desc);
            if (gets (resp))
               sscanf (resp, pardef[field].fmt, pardef[field].addr);
         }
      }
   }
   while (!end);
}

usage()
{
  fprintf(stderr, "Usage is:\n");
  fprintf(stderr, "\tXFractal [-d displayname] [-g geometry] [-c] [-h]\n");
  fprintf(stderr, "Where:\n");
  fprintf(stderr, "-c\t\tdo not cycle colors when done drawing\n");
  fprintf(stderr, "-h\t\ttype this message\n");
  fprintf(stderr, "\n");
  fprintf(stderr, "Note: to turn off the mirroring of the image around the X \n");
  fprintf(stderr, "\taxis, select a center (items 3 and 4) other than 0,0\n");
  exit(1);
}
-- 
Laissez les bons temps rouler                     -  Queen Ida
...{decwrl|ucbvax}!imagen!atari!daisy!turner (James M. Turner)
Daisy Systems, 700 E. Middlefield Rd, P.O. Box 7006, 
Mountain View CA 94039-7006.                          (415)960-0123

mao@blipyramid.BLI.COM (Mike Olson) (05/12/88)

turner's mandelbrot set plotter for color workstations is nice.  i fixed
one bug in the set_colors() routine.  the code had assumed that you were
on screen 0 of your display.  in the case of color sun workstations, this
isn't true.  both the monochrome and color screens are available, and are
numbered, respectively, 0 and 1.  context diff follows.  'man2.c' is the
version i pulled off the net.  'man3.c' is the fixed version.

					mike olson
					britton lee, inc.
					...!ucbvax!mtxinu!blia!mao
					olson@ucbvax.berkeley.edu

*** man2.c	Wed May 11 09:53:04 1988
--- man3.c	Wed May 11 10:40:16 1988
***************
*** 128,134
     int planes;
     int i;
  
!    cmap = DefaultColormap(display, 0);
  
     for (ncolors = 6; ncolors >= 0; ncolors--)
        if (XAllocColorCells (display, cmap, 0, &planes, 0, colors, ncolors+1))

--- 128,134 -----
     int planes;
     int i;
  
!    cmap = DefaultColormap(display, DefaultScreen(display));
  
     for (ncolors = 6; ncolors >= 0; ncolors--)
        if (XAllocColorCells (display, cmap, 0, &planes, 0, colors, ncolors+1))