/****************************************************************************** ** ** mandelbear.c ** ** Generate Mandelbrot sets of various sorts. ** ******************************************************************************/ /****************************************************************************** ** Include files. ******************************************************************************/ /* -- Minimum include files to use WidgetCreate Library */ #include /* This makes it work with virtual root window managers. */ #include "vroot.h" /* -- application specific include files */ #include #include #include #include #include #include #include #include "bear.xbm" #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) /****************************************************************************** ** Variables ******************************************************************************/ /* Display state */ Display *dpy; Screen *scr; Window win; Pixmap pix; GC gc; int planes; XtAppContext app; Widget appShell; Widget canvas; int minColor = 0; /* lowest available */ int maxColor = 1; /* highest available */ int nColors = 2; /* total number of colors */ /* Command-line options */ Boolean cubic; /* TRUE to plot cubic */ Boolean toRoot; /* TRUE if plotting to root */ Boolean toBitmap; /* TRUE if plotting to PBM */ Boolean toGreymap; /* TRUE if plotting to PGM */ Boolean scanx, scany; /* scan x0 and y0 */ int xsteps, ysteps; /* steps in scan */ String outFile; String inFile; /* Raster-plot state. Initialize to improbable values for later testing */ static int dmax; /* maximum depth */ static int xmax; /* pixmap x size */ static int ymax; /* pixmap y size */ static float zxc = 100; /* center zx value */ static float zyc = 100; /* center zy value */ static float zrad = 100; /* z radius */ static float zx0 = 0; static float zy0 = 0; static int (*mapfunc)(); /* function to map */ static void (*plotfunc)(); /* function to plot a point */ static void (*eachplot)(); /* called after each 2-d plot */ static char msg[80]; /****************************************************************************** ** Function to plot a raster ******************************************************************************/ /* ** PlotRaster() ** ** Make a map of mapfunc(zx, zy) in a raster. ** Kludge around the fact that the y origin is on top. */ void PlotRaster() { register int depth, ix, iy; register double zx0, zy0; register double zxr, zyr; register int rmax; rmax = MIN(xmax, ymax) / 2; zxr = zrad / rmax; zyr = zrad / rmax; for (iy = 0; iy < ymax; ++iy) { zy0 = zyc - zyr * (iy - ymax / 2); /* y grows down, not up. */ for (ix = 0; ix < xmax; ++ix) { zx0 = zxc + zxr * (ix - xmax / 2); depth = (*mapfunc)(zx0, zy0); (*plotfunc)(ix, iy, depth); } } } void PlotDoubleRaster() { register int ix, iy; register double zxr, zyr; register int rmax; if (xsteps == 0) xsteps = xmax; if (ysteps == 0) ysteps = ymax; zxr = 2.0 * zrad / (xsteps -1); zyr = 2.0 * zrad / (ysteps-1); if (scanx && scany) { for (iy = 0; iy < ysteps; ++iy) { zy0 = zyc - zyr * (iy - (ysteps-1) / 2.0); for (ix = 0; ix < xsteps; ++ix) { zx0 = zxc + zxr * (ix - (xsteps-1) / 2.0); PlotRaster(); if (eachplot) (*eachplot)(); } } } else if (scanx) { for (ix = 0; ix < xsteps; ++ix) { zx0 = zxc + zxr * (ix - (xsteps-1) / 2.0); PlotRaster(); if (eachplot) (*eachplot)(); } } else if (scany) { for (iy = 0; iy < ysteps; ++iy) { zy0 = zyc - zyr * (iy - (ysteps-1) / 2.0); PlotRaster(); if (eachplot) (*eachplot)(); } } else { PlotRaster(); if (eachplot) (*eachplot)(); } } /****************************************************************************** ** Functions to map ******************************************************************************/ static int mandelbrot(cx0, cy0) double cx0, cy0; { register int depth; register double zx, zy, tx; zx = cx0 + zx0; zy = cy0 + zy0; for (depth = 0; depth < dmax && zx*zx + zy*zy < 4.0; ++depth) { /* we assume that the compiler eliminates common subexprs */ tx = zx * zx - zy * zy + cx0; zy = 2.0 * zx * zy + cy0; zx = tx; } return (depth); } static int mandelbear(cx0, cy0) double cx0, cy0; { register int depth; register double zx, zy, tx; zx = cx0 + zx0; zy = cy0 + zy0; for (depth = 0; depth < dmax && zx*zx + zy*zy < 4.0; ++depth) { /* we assume that the compiler eliminates common subexprs */ tx = zx * (zx * zx - 3 * zy * zy) + cx0; zy = zy * (3 * zx * zx - zy * zy) + cy0; zx = tx; } return (depth); } /****************************************************************************** ** Functions to plot pixels ******************************************************************************/ static void plotPixel(x, y, depth) int x, y, depth; { if (nColors == 2) { if (depth & 1) XDrawPoint(dpy, pix, gc, x, y); } else { if (depth >= dmax) { XSetForeground(dpy, gc, BlackPixelOfScreen(scr)); } else { XSetForeground(dpy, gc, depth % nColors + minColor); } XDrawPoint(dpy, pix, gc, x, y); } if (x == 0 && y % 4 == 3 && xmax > 200) { XSetWindowBackgroundPixmap(dpy, win, pix); XClearArea(dpy, win, 0, y - 4, xmax, 4, False); } } static void plotStdOut(x, y, depth) int x, y, depth; { if (depth < dmax) putchar('1'); else putchar('0'); if (x == xmax - 1) putchar('\n'); } static void plotStdOutG(x, y, depth) int x, y, depth; { printf(" %d", depth); if (x == xmax - 1) putchar('\n'); } /****************************************************************************** ** Callbacks ******************************************************************************/ /* ** MyQuitCB ** Exit the application. ** There is no reason to destroy the widget tree, so don't bother. */ static void MyQuitCB( widget, widgetName, ignored ) Widget widget; char* widgetName; caddr_t ignored; { exit(0); } /****************************************************************************** ** navigation/file-handling ******************************************************************************/ /* ** AfterEachPlot */ void AfterEachPlot() { XtInputMask m; if (scanx || scany) { XSetWindowBackgroundPixmap(dpy, win, pix); XClearWindow(dpy, win); /* * Check for events. * === it would be better to use a work procedure === */ for ( ; m = XtAppPending(app); ) { XtAppProcessEvent(app, XtIMAll); } } printf("%g+%gi \r", zx0, zy0); fflush(stdout); } /****************************************************************************** ** Setups ******************************************************************************/ void PlotToPbm() { if (dmax == 0) dmax = 8; if (xmax == 0) xmax = 96; if (ymax == 0) ymax = 96; if (outFile) freopen(outFile, "w", stdout); /* Print PBM header and bitmap */ printf("P1\n%d %d\n", xmax, ymax); plotfunc = plotStdOut; PlotRaster(); exit(0); } void PlotToPgm() { if (dmax == 0) dmax = 256; if (xmax == 0) xmax = 96; if (ymax == 0) ymax = 96; if (outFile) freopen(outFile, "w", stdout); /* Print PGM header and bitmap */ printf("P2\n%d %d %d\n", xmax, ymax, dmax); plotfunc = plotStdOutG; PlotRaster(); exit(0); } int SetUpPixmap() /* * Return 1 if pixmap already set up, else 0 */ { XWindowAttributes atts; XGetWindowAttributes(dpy, win, &atts); if (atts.width != xmax || atts.height != ymax) { if (pix) XFreePixmap(dpy, pix); pix = 0; } xmax = atts.width; ymax = atts.height; if (!pix) { pix = XCreatePixmap(dpy, win, xmax, ymax, planes); XSetForeground(dpy, gc, BlackPixelOfScreen(scr)); XFillRectangle(dpy, pix, gc, 0, 0, xmax, ymax); return (0); } return (1); } void PlotToRoot() { win = RootWindowOfScreen(scr); if (dmax == 0) dmax = nColors == 2? 256 : nColors; plotfunc= plotPixel; XSetWindowBackgroundPixmap(dpy, win, pix); if (scanx || scany) eachplot = AfterEachPlot; PlotDoubleRaster(); XSetWindowBackgroundPixmap(dpy, win, pix); XClearWindow(dpy, win); XFlush(dpy); } void PlotToWidget() { XClearWindow(dpy, win); if (SetUpPixmap()) { XSetWindowBackgroundPixmap(dpy, win, pix); return; } if (dmax == 0) dmax = nColors == 2? 256 : nColors; plotfunc= plotPixel; if (scanx || scany) eachplot = AfterEachPlot; XSetWindowBackgroundPixmap(dpy, win, pix); PlotDoubleRaster(); XSetWindowBackgroundPixmap(dpy, win, pix); XClearWindow(dpy, win); } /****************************************************************************** * Initialization Functions ******************************************************************************/ static XtActionsRec actionTable[] = { {"CanvasHandleExpose", PlotToWidget}, {"MyQuitACT", MyQuitCB}, }; static String fallbackResources[] = { "Mandelbear.geometry: 96x96", "*input: True", "*sensitive: True", "*cursor: left_ptr", "*canvas.foreground: white", "*canvas.background: black", "*canvas.label: ", 0 }; /* Augmenting translations from fallback resources only gets first line */ static String canvasTranslations = ": CanvasHandleExpose() \n\ : MyQuitACT()\n"; static XrmOptionDescRec options[] = { {"-root", ".toRoot", XrmoptionNoArg, (caddr_t)"on"}, {"-pbm", ".toBitmap", XrmoptionNoArg, (caddr_t)"on"}, {"-pgm", ".toGreymap", XrmoptionNoArg, (caddr_t)"on"}, {"-cubic", ".cubic", XrmoptionNoArg, (caddr_t)"on"}, {"-scanx", ".scanx", XrmoptionNoArg, (caddr_t)"on"}, {"-scany", ".scany", XrmoptionNoArg, (caddr_t)"on"}, {"-width", ".width", XrmoptionSepArg, (caddr_t)NULL}, {"-height", ".height", XrmoptionSepArg, (caddr_t)NULL}, {"-xsteps", ".xsteps", XrmoptionSepArg, (caddr_t)NULL}, {"-ysteps", ".ysteps", XrmoptionSepArg, (caddr_t)NULL}, {"-x0", ".x0", XrmoptionSepArg, (caddr_t)NULL}, {"-y0", ".y0", XrmoptionSepArg, (caddr_t)NULL}, {"-xc", ".xc", XrmoptionSepArg, (caddr_t)NULL}, {"-yc", ".yc", XrmoptionSepArg, (caddr_t)NULL}, {"-radius", ".radius", XrmoptionSepArg, (caddr_t)NULL}, {"-depth", ".dmax", XrmoptionSepArg, (caddr_t)NULL}, {"-o", ".outFile", XrmoptionSepArg, (caddr_t)NULL}, {"-f", ".inFile", XrmoptionSepArg, (caddr_t)NULL}, }; static XtResource resources[] = { {"cubic", XtCBoolean, XtRBoolean, sizeof(Boolean), (int)&cubic, XtRString, "off"}, {"scanx", XtCBoolean, XtRBoolean, sizeof(Boolean), (int)&scanx, XtRString, "off"}, {"scany", XtCBoolean, XtRBoolean, sizeof(Boolean), (int)&scany, XtRString, "off"}, {"toRoot", XtCBoolean, XtRBoolean, sizeof(Boolean), (int)&toRoot, XtRString, "off"}, {"toBitmap", XtCBoolean, XtRBoolean, sizeof(Boolean), (int)&toBitmap, XtRString, "off"}, {"toGreymap", XtCBoolean, XtRBoolean, sizeof(Boolean), (int)&toGreymap, XtRString, "off"}, {"xsteps", "Count", XtRInt, sizeof(int), (int)&xsteps, XtRString, "0"}, {"ysteps", "Count", XtRInt, sizeof(int), (int)&ysteps, XtRString, "0"}, {"width", "Count", XtRInt, sizeof(int), (int)&xmax, XtRString, "96"}, {"height", "Count", XtRInt, sizeof(int), (int)&ymax, XtRString, "96"}, {"x0", "Real", XtRFloat, sizeof(float), (int)&zx0, XtRString, "0.0"}, {"y0", "Imaginary", XtRFloat, sizeof(float), (int)&zy0, XtRString, "0.0"}, {"xc", "Real", XtRFloat, sizeof(float), (int)&zxc, XtRString, "100"}, {"yc", "Imaginary", XtRFloat, sizeof(float), (int)&zyc, XtRString, "100"}, {"radius", "Real", XtRFloat, sizeof(float), (int)&zrad, XtRString, "100"}, {"dmax", "Depth", XtRInt, sizeof(int), (int)&dmax, XtRString, 0}, {"outFile", XtCString, XtRString, sizeof(String), (int)&outFile, XtRString, 0}, {"inFile", XtCString, XtRString, sizeof(String), (int)&inFile, XtRString, 0}, }; /* ** InitializeColors() ** ** Figure out how many colors we can get away with. ** (Uses standard colormap; assumes colors are sequential) */ void InitializeColors() { if (planes == 1) return; /* monochrome */ /* fake it, assuming standard map installed with xstdcmap */ minColor = 2; maxColor = 125; nColors = maxColor - minColor; } /****************************************************************************** ** main program ******************************************************************************/ main(argc, argv) int argc; char* argv[]; { char* appClass; XWindowAttributes atts; XGCValues values; unsigned long vm = 0; Arg args[10]; int ax; appClass = (char*) XtMalloc ( strlen ( argv[0] ) + 1 ); strcpy (appClass, argv[0]); /* * initialize first letter to make class, or first two if * first is already capitalized, or don't worry about it. */ if (islower(appClass[0])) appClass[0] = toupper(appClass[0]); else if (islower(appClass[1])) appClass[1] = toupper(appClass[1]); /* Intialize Toolkit (creating the application shell) */ appShell = XtAppInitialize ( &app, /* appContext return */ appClass, /* app class */ options, XtNumber(options), /* description of cmd line options */ &argc, argv, fallbackResources, 0, 0 ); ax = 0; XtSetArg(args[ax], "iconPixmap", (XtArgVal) XCreateBitmapFromData (XtDisplay(appShell), XtScreen(appShell)->root, bear_bits, bear_width, bear_height )); ++ax; XtSetValues (appShell, args, ax); /* Register action routines */ XtAppAddActions( app, actionTable, XtNumber(actionTable)); /* Create a canvas widget to draw into * Set up translations, which doesn't work right * when done as part of the fallback resources. */ canvas = XtCreateManagedWidget("canvas", widgetClass, appShell, NULL, 0); XtAugmentTranslations(canvas, XtParseTranslationTable(canvasTranslations)); /* * Get application resources and display info * If output is to root, just do it. */ XtGetApplicationResources( appShell, NULL, resources, XtNumber(resources), NULL, 0); dpy = XtDisplay(appShell); scr = XtScreen(appShell); /* * If the user didn't specify coordinates, set appropriate defaults * Print out the defaults so the user can see them. */ if (cubic) { if (zxc > 99) zxc = 0.0; if (zyc > 99) zyc = .75; if (zrad> 99) zrad= .75; mapfunc = mandelbear; } else { if (zxc > 99) zxc = -.5; if (zyc > 99) zyc = 0; if (zrad> 99) zrad= 1.5; mapfunc = mandelbrot; } if (toBitmap) PlotToPbm(); if (toGreymap) PlotToPgm(); if (toRoot) { win = RootWindowOfScreen(scr); gc = XCreateGC(dpy, win, vm, &values); planes = PlanesOfScreen(scr); InitializeColors(); dmax = nColors; (void)SetUpPixmap(); } fprintf(stderr, "%s -x0 %g -y0 %g -xc %g -yc %g -width %d -height %d -radius %g, -depth %d%s%s\n", argv[0], zx0, zy0, zxc, zyc, xmax, ymax, zrad, dmax, cubic? " -cubic" : "", toRoot? " -root" : ""); /* * If plotting on the root window, go ahead and do it. * Otherwise, realize the widget tree. */ if (toRoot) { PlotToRoot(); exit(0); } XtRealizeWidget ( appShell ); win = XtWindow(canvas); gc = XCreateGC(dpy, win, vm, &values); planes = PlanesOfScreen(scr); InitializeColors(); XGetWindowAttributes(dpy, win, &atts); xmax = atts.width; ymax = atts.height; XtAppMainLoop(app); exit(0); }