home *** CD-ROM | disk | FTP | other *** search
- From: csimmons@jewel.oracle.com (Charles Simmons)
- Newsgroups: alt.sources
- Subject: Interactive Mandelbrots on a Heterogenous Network
- Message-ID: <1990Apr3.072622.5513@oracle.com>
- Date: 3 Apr 90 07:26:22 GMT
-
- This program is used to interactively display the Mandelbrot set. Its
- primary feature is the ability to use a heterogeneous network of compute
- servers to compute the set in parallel. To use this program without
-
- An X server and X libraries,
- sockets,
- Unix,
- a floating point processor (preferably using IEEE format),
- a color display.
-
- This program has, at one time or another, run on each of the following
- platforms:
-
- Sun 3, Sun 4
- DecStation 3100
- Pyramid
- Sequent
- Convex
- Apollo DN10000
- some Apollo 68K based workstation
-
- Contact me directly for additional software needed to run this program
- on the NCube.
-
- -- Chuck Simmons
- csimmons@oracle.oracle.com
-
-
- # This is a shell archive. Remove anything before this line, then
- # unpack it by saving it in a file and typing "sh file". (Files
- # unpacked will be owned by you and have default permissions.)
- #
- # This archive contains:
- # client.c gui.c gui.h mandel.mk
-
- : =-=-=-=-=-=-= first line of shar 1 of 1 =-=-=-=-=-=-=-=-=-
- echo x - client.c
- sed -e 's/^X//' > "client.c" << '//E*O*F client.c//'
- X/*
- X * Mandel by Rob Swiston and Chuck Simmons
- X * Copyright (C) 1989, 1990 by Rob Swiston and Chuck Simmons
- X *
- X * This program is free software; you can redistribute it and/or modify
- X * it under the terms of version 1 of the GNU General Public License as
- X * published by the Free Software Foundation.
- X *
- X * This program is distributed in the hope that it will be useful,
- X * but WITHOUT ANY WARRANTY; without even the implied warranty of
- X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X * GNU General Public License for more details.
- X *
- X * You should have received a copy of the GNU General Public License
- X * along with this program; if not, write to the Free Software
- X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X */
- X
- X/*
- X * Here we have the client side of the mandelbrot program. Primarily,
- X * we create connections to servers and farm out portions of the
- X * computation to the servers. Periodically, we give control back
- X * to our caller, telling our caller whether or not we are completely
- X * done filling a window.
- X */
- X
- X/*
- X * Initialize the client. Here, we want to establish connections to
- X * our servers. We return a context area.
- X */
- X
- X#include <sys/types.h>
- X#include <sys/timeb.h>
- X#ifndef DST_NONE
- X# include <sys/time.h>
- X#endif
- X
- X#include <stdio.h>
- X#include "mandel.h"
- X#include "gui.h"
- X#include "net.h"
- X#include "client.h"
- X
- X#define HOSTLEN 40
- X
- X/*
- X * Specify the number of lines we want to have outstanding for
- X * each server. Setting this too high will lead to long delays
- X * when drawing a new window. The reason for this is that when
- X * the window is nearly completely drawn, we will send each line
- X * to many servers to make sure we get a response back. Setting
- X * this too low will lead to a very minor performance degradation
- X * (in theory) because servers will have nothing to do while waiting
- X * for a line to arrive.
- X */
- X#define NLINES 2
- X
- X#define bswap(x) ((((x) << 8) & 0xff00) | (((x) >> 8) & 0xff))
- X
- Xtypedef struct line_id {
- X struct line_id *next; /* pointer to next line in queue */
- X int winid; /* identifier of window for this line */
- X int line; /* number of line being worked on */
- X} line_id_t;
- X
- Xtypedef struct connection {
- X int sock; /* socket descriptor */
- X char host[HOSTLEN]; /* name of host */
- X line_id_t *q_head; /* head of q of lines */
- X line_id_t *q_tail; /* tail of queue */
- X int flops; /* estimated flops performed */
- X} connection_t;
- X
- Xtypedef struct client_info {
- X color_x_t *buf; /* buffer colors for a line */
- X
- X int ncon; /* number of connections */
- X connection_t *con; /* connections to servers */
- X fd_set open_set; /* list of open sockets */
- X int max_fd; /* maxium socket number */
- X
- X int winid; /* identifier for window we are drawing */
- X int line; /* next line to work on */
- X int ndrawn_lines; /* count of drawn lines */
- X char *drawn_line; /* list of lines that have been drawn */
- X
- X int flops; /* estimated floating point operations performed */
- X time_t start_time; /* real time at which we started window */
- X} client_info_t;
- X
- X/*
- X * Operations on the line queue.
- X */
- X
- X/* Allocate and free a line. */
- X
- X#define line_alloc() (line_id_t *) malloc (sizeof (line_id_t))
- X#define line_free(p) free ((char *) p)
- X
- X/*
- X * Add a line to the end of a connection's queue. Return the
- X * added line.
- X */
- X
- Xline_id_t *
- Xline_push (conp)
- Xconnection_t *conp;
- X{
- X line_id_t *p;
- X
- X p = line_alloc ();
- X if (!p) return NULL;
- X
- X if (conp->q_tail) conp->q_tail->next = p;
- X else conp->q_head = p;
- X
- X conp->q_tail = p;
- X p->next = NULL;
- X return p;
- X}
- X
- X/*
- X * Pop a line off the queue.
- X */
- X
- Xvoid
- Xline_pop (conp)
- Xconnection_t *conp;
- X{
- X line_id_t *p;
- X
- X p = conp->q_head;
- X
- X conp->q_head = p->next;
- X if (conp->q_head == NULL) conp->q_tail = NULL;
- X line_free (p);
- X}
- X
- X/*
- X * Return TRUE if a connection has fewer than NLINES lines outstanding.
- X */
- X
- Xint
- Xclient_has_room (conp)
- Xconnection_t *conp;
- X{
- X line_id_t *p;
- X int i;
- X
- X for (i = 0, p = conp->q_head; i < NLINES && p; i++, p = p->next);
- X
- X return i < NLINES;
- X}
- X
- X/* Return the y-coordinate of a line. */
- X
- Xdouble
- Xline_y_coord (winp, line)
- Xchar *winp;
- Xint line;
- X{
- X return win_ymin(winp) + (line * win_rheight(winp)) / win_pheight(winp);
- X}
- X
- X/* Return the line of a y-coordinate. */
- X
- Xint
- Xy_line_coord (winp, y)
- Xchar *winp;
- Xdouble y;
- X{
- X double t;
- X t = win_pheight (winp) * (y - win_ymin (winp)) / win_rheight (winp);
- X return (int) (t + 0.5); /* round to nearest int */
- X}
- X
- X/*
- X * Initialize the client. We allocate a context area, and we
- X * establish connections to each server.
- X */
- X
- Xchar *
- Xclient_init (winp)
- Xchar *winp;
- X{
- X client_info_t *clientp;
- X FILE *hostf;
- X char name[HOSTLEN];
- X int port;
- X int buflen;
- X int ncons;
- X connection_t *con;
- X
- X clientp = (client_info_t *) malloc (sizeof (*clientp));
- X if (!clientp) {
- X (void) fprintf (stderr, "client_init: Out of storage.\n");
- X exit (1);
- X }
- X
- X /*
- X * Allocate storage to hold the colors of 1 line and
- X * to hold the list of drawn lines. We allocate the
- X * maximum amount of storage that we might need for a window.
- X * Note that our buffer pretty much really needs to be this
- X * large. Consider the case where we send out requests for
- X * a long line, and then the window shrinks. The servers
- X * well send back really large requests which we would like
- X * to have fit in our buffer.
- X */
- X buflen = sizeof (clientp->buf[0]) * win_max_width (winp);
- X clientp->buf = (color_x_t *) malloc (buflen);
- X
- X buflen = sizeof (clientp->drawn_line[0]) * win_max_height (winp);
- X clientp->drawn_line = (char *) malloc (buflen);
- X
- X if (!clientp->buf || !clientp->drawn_line) {
- X (void) fprintf (stderr, "client_init: Out of storage.\n");
- X exit (1);
- X }
- X
- X clientp->winid = 0;
- X FD_ZERO (&clientp->open_set);
- X clientp->max_fd = -1;
- X clientp->ncon = 0;
- X
- X /* Create connections to the servers. */
- X hostf = fopen (HOSTFILE, "r");
- X if (!hostf) {
- X perror (HOSTFILE);
- X exit (1);
- X }
- X
- X ncons = client_lines (hostf);
- X buflen = sizeof (clientp->con[0]) * ncons;
- X clientp->con = (connection_t *) malloc (buflen);
- X if (!clientp->con) {
- X (void) fprintf (stderr, "client_init: Out of storage.\n");
- X exit (1);
- X }
- X
- X while (client_scan_line (hostf, name, &port, &ncons)) {
- X (void) fprintf (stderr,
- X "Connecting to %s at port %d (%d connections)\n",
- X name, port, ncons);
- X
- X while (ncons > 0) { /* create 'ncons' connections to this obj */
- X con = &(clientp->con[clientp->ncon]);
- X
- X (void) strcpy (con->host, name);
- X con->q_head = con->q_tail = NULL;
- X con->sock = net_copen (con->host, port);
- X if (con->sock < 0) {
- X con->sock = net_copen (con->host, bswap (port));
- X }
- X if (con->sock < 0) {
- X (void) fprintf (stderr,
- X "Cannot open socket to %s: ",
- X con->host);
- X perror ("");
- X break; /* give up on this host */
- X }
- X else {
- X clientp->ncon += 1;
- X FD_SET (con->sock, &clientp->open_set);
- X if (con->sock > clientp->max_fd) {
- X clientp->max_fd = con->sock;
- X }
- X }
- X
- X ncons -= 1;
- X }
- X }
- X
- X if (clientp->ncon == 0) {
- X (void) fprintf (stderr, "client_init: No connections.\n");
- X exit (1);
- X }
- X
- X (void) fclose (hostf);
- X return (char *) clientp;
- X}
- X
- X/*
- X * Read a line from the host file.
- X */
- X
- Xint
- Xclient_scan_line (f, name, portp, nconsp)
- XFILE *f;
- Xchar *name;
- Xint *portp;
- Xint *nconsp;
- X{
- X char buf[256];
- X int status;
- X
- X if (fgets (buf, HOSTLEN, f) == NULL) {
- X return 0; /* eof */
- X }
- X status = sscanf (buf, "%s %d %d", name, portp, nconsp);
- X if (status != 3) {
- X (void) fprintf (stderr,
- X "client_scan_line: syntax error in line '%s'.\n",
- X buf);
- X (void) fprintf (stderr,
- X " format is 'name port_num num_connections'.\n");
- X return 0;
- X }
- X return 1;
- X}
- X
- X/*
- X * Count the number of connections we need to make.
- X */
- X
- Xint
- Xclient_lines (f)
- XFILE *f;
- X{
- X char buf[256];
- X char name[HOSTLEN];
- X int port, ncons;
- X int total;
- X
- X total = 0;
- X while (client_scan_line (f, name, &port, &ncons)) {
- X total += ncons;
- X }
- X
- X rewind (f);
- X return total;
- X}
- X
- X/*
- X * Reset the client. Here, we farm out an initial line of the
- X * window to each server after resetting ourselves to begin
- X * drawing the first line of the window.
- X */
- X
- Xint
- Xclient_reset (clientp, winp)
- Xclient_info_t *clientp;
- Xchar *winp;
- X{
- X void client_send ();
- X
- X int i, j;
- X
- X bzero (clientp->drawn_line,
- X sizeof (clientp->drawn_line[0]) * win_pheight (winp));
- X
- X clientp->winid += 1; /* change window id */
- X clientp->line = -1; /* reset starting line */
- X clientp->ndrawn_lines = 0; /* nothing drawn yet */
- X clientp->flops = 0; /* no floating point ops done yet */
- X clientp->start_time = time ((time_t *) 0);
- X
- X for (i = 0; i < clientp->ncon; i++) {
- X clientp->con[i].flops = 0;
- X }
- X
- X /*
- X * Send NLINES lines to each connection. We loop on
- X * the connections in the inner loop so that consecutive
- X * lines will be sent to different processors. We only send
- X * lines to those processors who are in need of additional lines.
- X */
- X for (j = 0; j < NLINES; j++)
- X for (i = 0; i < clientp->ncon; i++) {
- X if (client_has_room (&(clientp->con[i]))) {
- X client_send (clientp, &(clientp->con[i]), winp);
- X }
- X }
- X
- X return client_resume (clientp, winp);
- X}
- X
- X/*
- X * Close down a server connection after an error occurs.
- X */
- X
- Xvoid
- Xclient_close (clientp, conp)
- Xclient_info_t *clientp;
- Xconnection_t *conp;
- X{
- X int i;
- X
- X i = conp - &(clientp->con[0]);
- X FD_CLR (conp->sock, &clientp->open_set);
- X close (conp->sock);
- X while (conp->q_head) line_pop (conp); /* free some storage */
- X
- X if (i != clientp->ncon-1) { /* compress list of clients */
- X clientp->con[i] = clientp->con[clientp->ncon-1];
- X }
- X clientp->ncon -= 1;
- X
- X if (clientp->ncon == 0) {
- X (void) fprintf (stderr,
- X "client_close: All connections died.\n");
- X exit (1);
- X }
- X}
- X
- X/*
- X * Send a line out over the network, updating our client structure.
- X */
- X
- Xvoid
- Xclient_send (clientp, conp, winp)
- Xclient_info_t *clientp;
- Xconnection_t *conp;
- Xchar *winp;
- X{
- X extern int arg_iterations;
- X
- X int status;
- X line_id_t *p;
- X
- X if (clientp->ndrawn_lines >= win_pheight (winp)) return;
- X
- X /* increment client's line index to next undrawn line */
- X do {
- X if (clientp->line == win_pheight (winp) - 1) {
- X clientp->line = 0;
- X }
- X else clientp->line += 1;
- X } while (clientp->drawn_line[clientp->line]);
- X
- X p = line_push (conp);
- X if (!p) return; /* don't send anything if we don't have the storage */
- X
- X p->winid = clientp->winid;
- X p->line = clientp->line;
- X
- X status = net_csend (conp->sock, win_xmin (winp),
- X line_y_coord (winp, clientp->line),
- X win_xmax (winp), win_pwidth (winp), arg_iterations);
- X
- X if (status < 0) {
- X (void) fprintf (stderr,
- X "client_send: net_csend to %s failed: ",
- X conp->host);
- X perror ("");
- X client_close (clientp, conp);
- X }
- X}
- X
- X/*
- X * Receive a buffer off the network, and draw it. Also, send another
- X * line.
- X */
- X
- Xvoid
- Xclient_recv (clientp, conp, winp)
- Xclient_info_t *clientp;
- Xconnection_t *conp;
- Xchar *winp;
- X{
- X int buflen;
- X int winid;
- X int line, line2;
- X int last_x, i, flops;
- X int draw_it;
- X double y;
- X
- X buflen = net_crecv (conp->sock, clientp->buf);
- X if (buflen < 0) {
- X (void) fprintf (stderr,
- X "client_recv: net_crecv from %s failed: ",
- X conp->host);
- X perror ("");
- X client_close (clientp, conp);
- X }
- X else {
- X winid = conp->q_head->winid;
- X line = conp->q_head->line;
- X line_pop (conp);
- X
- X /* do nothing if this line was for a previous window */
- X draw_it = FALSE; /* assume this line is boring */
- X line2 = -1; /* no symmetry found yet */
- X if (winid == clientp->winid && !clientp->drawn_line[line]) {
- X /* mark this line as drawn */
- X clientp->drawn_line[line] = TRUE;
- X clientp->ndrawn_lines += 1;
- X draw_it = TRUE; /* remember to draw the line */
- X }
- X
- X /*
- X * Check for symmetry about the X-Axis. If we have symmetry,
- X * get the line number of the symmetrical line. Do this here
- X * so that we will mark the line of symmetry as being drawn
- X * before sending out the next line to compute.
- X */
- X if (draw_it ) {
- X /* get y-coordinate of symmetrical line */
- X y = -line_y_coord (winp, line);
- X if (y >= win_ymin (winp) && y <= win_ymax (winp)) {
- X line2 = y_line_coord (winp, y);
- X
- X if (line2 >= 0 && line2 < win_pheight (winp) &&
- X !clientp->drawn_line[line2])
- X {
- X clientp->drawn_line[line2] = TRUE;
- X clientp->ndrawn_lines += 1;
- X }
- X else line2 = -1; /* don't draw line 2 */
- X }
- X }
- X
- X /* send a new line out quickly */
- X client_send (clientp, conp, winp);
- X if (!draw_it) return;
- X
- X /* Compute flops used to calculate this line. */
- X flops = 0;
- X last_x = 0;
- X for (i = 0; i < buflen; i++) {
- X flops += clientp->buf[i].color
- X * (clientp->buf[i].x - last_x + 1);
- X last_x = clientp->buf[i].x + 1;
- X }
- X clientp->flops += flops;
- X conp->flops += flops;
- X
- X /* draw the line on the screen */
- X win_render_line (winp, clientp->buf, buflen, line);
- X
- X if (line2 != -1) { /* draw the symmetrical line? */
- X win_rerender_line (winp, line2);
- X }
- X }
- X}
- X
- X/*
- X * Resume a client wherever we left off. We wait for a server
- X * to report that she has finished computing a line. We then
- X * draw the line and farm out a new line, if we have one available.
- X *
- X * When we receive a line from a client, or when a timeout expires,
- X * we will give control to our caller so that user input can be processed.
- X */
- X
- Xint
- Xclient_resume (clientp, winp)
- Xclient_info_t *clientp;
- Xchar *winp;
- X{
- X fd_set read_set;
- X struct timeval tv;
- X int nfound;
- X int max_fd;
- X int buflen;
- X int i;
- X
- X tv.tv_sec = 1; /* init timeout */
- X tv.tv_usec = 0;
- X
- X read_set = clientp->open_set;
- X#if 0
- X(void) fprintf (stderr, "before read_set=0x%x, max_fd=%d\n",
- X ((int *)(&read_set))[0], clientp->max_fd);
- X#endif
- X nfound = select (clientp->max_fd+1, &read_set, (fd_set *)NULL,
- X (fd_set *)NULL, &tv);
- X#if 0
- X(void) fprintf (stderr, "after read_set=0x%x, max_fd=%d\n",
- X ((int *)(&read_set))[0], clientp->max_fd);
- X#endif
- X
- X if (nfound < 0) {
- X perror ("client_resume: select failed");
- X exit (1);
- X }
- X
- X /* scan for events */
- X for (i = 0; i < clientp->ncon && nfound; i++) {
- X if (!FD_ISSET (clientp->con[i].sock, &read_set)) {
- X continue;
- X }
- X
- X nfound -= 1;
- X client_recv (clientp, &(clientp->con[i]), winp);
- X }
- X
- X if (clientp->ndrawn_lines < win_pheight (winp)) {
- X return TRUE; /* resume later */
- X }
- X else {
- X time_t elapsed;
- X
- X /*
- X * Report the flops rating.
- X */
- X elapsed = time ((time_t *)0) - clientp->start_time;
- X if (elapsed == 0) elapsed = 1; /* a little white lie */
- X
- X (void) printf ("Megaflops: %10.2f\n",
- X (clientp->flops * 9.0) / (elapsed * 1000000.0));
- X
- X for (i = 0; i < clientp->ncon; i++) {
- X (void) printf ("%16s: %10.2f\n",
- X clientp->con[i].host,
- X (clientp->con[i].flops * 9.0)
- X / (elapsed * 1000000.0));
- X }
- X (void) fflush (stdout);
- X
- X
- X return FALSE; /* tell caller we need a new window */
- X }
- X}
- //E*O*F client.c//
-
- echo x - gui.c
- sed -e 's/^X//' > "gui.c" << '//E*O*F gui.c//'
- X/*
- X * Mandel by Rob Swiston and Chuck Simmons
- X * Copyright (C) 1989, 1990 by Rob Swiston and Chuck Simmons
- X *
- X * This program is free software; you can redistribute it and/or modify
- X * it under the terms of version 1 of the GNU General Public License as
- X * published by the Free Software Foundation.
- X *
- X * This program is distributed in the hope that it will be useful,
- X * but WITHOUT ANY WARRANTY; without even the implied warranty of
- X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X * GNU General Public License for more details.
- X *
- X * You should have received a copy of the GNU General Public License
- X * along with this program; if not, write to the Free Software
- X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X */
- X
- X/*
- X * This file contains all the routines used to implement the
- X * graphical user interface. The complete user interface is
- X * implemented in this file. If you want to change windowing
- X * systems, you need to rewrite this file.
- X *
- X * This file interfaces with the client server. From the user
- X * interface, we can call routines to initialize the client,
- X * reset the client to operate with a new window, and resume the
- X * client to continue operating with an existing window.
- X *
- X * The client can in turn call some of the routines in this file
- X * to draw on the current window.
- X */
- X
- X#include <stdio.h>
- X#include <X11/Xos.h>
- X#include <X11/Xlib.h>
- X#include <X11/Xutil.h>
- X#include <X11/Xatom.h>
- X#include <X11/cursorfont.h>
- X
- X#ifdef apollo
- X# include </sys5.3/usr/include/math.h>
- X#else
- X# include <math.h>
- X#endif
- X
- X#include "mandel.h"
- X#include "gui.h"
- X#include "client.h"
- X
- X/* Don't include 'malloc.h' since it doesn't exist on BSD systems. */
- Xchar *malloc ();
- Xvoid free ();
- X
- X/* Let's not take a chance with 'string(s).h'. */
- Xchar *strchr ();
- X
- X/* pointers to graphics argument strings */
- Xchar *arg_display = 0;
- Xchar *arg_geometry = 0;
- Xint arg_use_root = 0;
- Xint arg_iterations = 256;
- Xdouble arg_x_center = 0.0;
- Xdouble arg_y_center = 0.0;
- Xdouble arg_pix_size = 4.0 / HPIXELS;
- Xint arg_mud_num = 3;
- Xdouble arg_mud_max = 0.60;
- Xchar *arg_colorfile = 0;
- Xint arg_show_time = 0;
- X
- Xchar *prog_name;
- X
- Xtypedef struct loc {
- X int x, y; /* coordinates of a pixel */
- X} loc_t;
- X
- X/* Define a context area for holding information about a display area. */
- Xtypedef struct win_info {
- X Display *dsp;
- X Window win;
- X union { Pixmap p; Window w; } pix; /* holds the image */
- X GC gc; /* graphics context */
- X XImage *image; /* imaging buffer */
- X int color_len; /* last pixel in colormap we can use */
- X unsigned long *pixels;
- X Cursor busy; /* cursor to use when computing */
- X Cursor nbusy; /* cursor to use when not computing */
- X int black, white; /* black and white pixels */
- X
- X /* describe the imaging area */
- X int hpixels, vpixels; /* size of display area in pixels */
- X double x, y; /* center of display area */
- X double pix_size; /* size of a pixel */
- X
- X /* The following is used when drawing on the root window. */
- X#define SAVE_LIST_LEN 1
- X loc_t black_list[SAVE_LIST_LEN];
- X loc_t color_list[SAVE_LIST_LEN];
- X int black_num; /* number of items in black_list */
- X int color_num; /* number of items in color_list */
- X} win_info_t;
- X
- X/*
- X * The following routines exist to hide information from the client
- X * routine.
- X */
- X
- X/* width and height of window in pixels */
- X#define W_PWIDTH(w) ((w)->hpixels)
- X#define W_PHEIGHT(w) ((w)->vpixels)
- X
- X/* width and height in real numbers */
- X#define W_RWIDTH(w) ((w)->hpixels * (w)->pix_size)
- X#define W_RHEIGHT(w) ((w)->vpixels * (w)->pix_size)
- X
- X/* co-ordinates of window edges */
- X#define W_XMIN(w) ((w)->x - W_RWIDTH(w) / 2)
- X#define W_XMAX(w) ((w)->x + W_RWIDTH(w) / 2)
- X#define W_YMIN(w) ((w)->y - W_RHEIGHT(w) / 2)
- X#define W_YMAX(w) ((w)->y + W_RHEIGHT(w) / 2)
- X
- Xint win_pwidth (winp) win_info_t *winp; { return W_PWIDTH (winp); }
- Xint win_pheight (winp) win_info_t *winp; { return W_PHEIGHT (winp); }
- X
- X/* 'real' co-ordinates of upper-left and lower-right of window */
- Xdouble win_xmin (winp) win_info_t *winp; { return W_XMIN (winp); }
- Xdouble win_xmax (winp) win_info_t *winp; { return W_XMAX (winp); }
- Xdouble win_ymin (winp) win_info_t *winp; { return W_YMIN (winp); }
- Xdouble win_ymax (winp) win_info_t *winp; { return W_YMAX (winp); }
- X
- X/* 'real' width and height */
- Xdouble win_rwidth (winp) win_info_t *winp; { return W_RWIDTH (winp); }
- Xdouble win_rheight (winp) win_info_t *winp; { return W_RHEIGHT (winp); }
- X
- X/* maximum width and height */
- Xint
- Xwin_max_width (winp)
- Xwin_info_t *winp;
- X{
- X return DisplayWidth (winp->dsp, DefaultScreen (winp->dsp));
- X}
- X
- Xint
- Xwin_max_height (winp)
- Xwin_info_t *winp;
- X{
- X return DisplayHeight (winp->dsp, DefaultScreen (winp->dsp));
- X}
- X
- X#define OPTIONS "c:d:g:i:m:n:p:rs:x:y:"
- X
- Xvoid
- Xusage (err)
- Xchar *err;
- X{
- X if (err) fprintf (stderr, "%s: %s\n", prog_name, err);
- X fprintf (stderr, "Usage: %s [options...]\n", prog_name);
- X fprintf (stderr, "where options include:\n");
- X fprintf (stderr, " -c colorfile file of colors to use\n");
- X fprintf (stderr, " -d host:display X server to use\n");
- X fprintf (stderr, " -g geometry size of window\n");
- X fprintf (stderr, " -i count iteration count\n");
- X fprintf (stderr, " -m mud_max max val for muddy colors\n");
- X fprintf (stderr, " -n mud_num # of muddy colors per hue\n");
- X fprintf (stderr, " -p pixel_size size of a pixel\n");
- X fprintf (stderr, " -r draw on root window\n");
- X fprintf (stderr, " -s show_time show initial color map\n");
- X fprintf (stderr, " -x x x coord of center\n");
- X fprintf (stderr, " -y y y coord of center\n");
- X exit (1);
- X}
- X
- Xvoid
- Xparse_args (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern char *optarg;
- X extern int optind;
- X
- X int c;
- X
- X prog_name = argv[0];
- X
- X while ((c = getopt (argc, argv, OPTIONS)) != -1) {
- X switch (c) {
- X case 'c': arg_colorfile = optarg; break;
- X case 'd': arg_display = optarg; break;
- X case 'g': arg_geometry = optarg; break;
- X
- X case 'i':
- X arg_iterations = strtol (optarg, (char *)0, 0);
- X if (arg_iterations <= 0) {
- X usage ("-i argument must be positive.");
- X }
- X break;
- X
- X case 'm':
- X arg_mud_max = atof (optarg);
- X if (arg_mud_max < 0.0 || arg_mud_max > 1.0) {
- X usage ("-m argument must be in 0.0 .. 1.0.");
- X }
- X break;
- X
- X case 'n':
- X arg_mud_num = strtol (optarg, (char *)0, 0);
- X if (arg_mud_num <= 0) {
- X usage ("-n argument must be positive.");
- X }
- X break;
- X
- X case 'p':
- X arg_pix_size = atof (optarg);
- X if (arg_pix_size <= 0.0) {
- X usage ("-p argument must be positive.");
- X }
- X break;
- X
- X case 'r': arg_use_root = 1; break;
- X
- X case 's':
- X arg_show_time = strtol (optarg, (char *)0, 0);
- X if (arg_show_time <= 0) {
- X usage ("-s argument must be positive.");
- X }
- X break;
- X
- X case 'x': arg_x_center = atof (optarg); break;
- X case 'y': arg_y_center = atof (optarg); break;
- X
- X default:
- X {
- X char buf[80];
- X (void) sprintf (buf, "Unrecognized argument '%s'.", optarg);
- X usage (buf);
- X }
- X }
- X }
- X
- X if (optind != argc) {
- X usage ("Unrecognized argument '%s'.", argv[optind]);
- X }
- X}
- X
- X/*
- X * Given the integer coordinates of a pixel location, make that pixel
- X * the center of our image.
- X */
- X
- Xvoid
- Xwin_new_center (winp, ix, iy)
- Xwin_info_t *winp;
- Xint ix, iy;
- X{
- X winp->x += winp->pix_size * 0.5 * (2 * ix - winp->hpixels);
- X winp->y += winp->pix_size * 0.5 * (2 * iy - winp->vpixels);
- X}
- X
- X/*
- X * Here, the client has just finished generating the image for the
- X * root window. Display the picture and choose new co-ordinates.
- X * To choose new co-ordinates, we select two locations at random,
- X * such that one location is in the set and one location is out
- X * of the set. These locations become our new coordinates. The
- X * new co-ordinates are selected from within the current co-ordinates.
- X * After zooming in for awhile, we begin zooming out.
- X */
- X
- X#define MAX_ROOT_ZOOM_DEPTH 16
- X
- Xvoid
- Xwin_new_root (winp)
- Xwin_info_t *winp;
- X{
- X static int depth = 0; /* how far in we are */
- X static int dir = 1;
- X
- X XSetWindowBackgroundPixmap (winp->dsp, winp->win, winp->pix.p);
- X XClearWindow (winp->dsp, winp->win);
- X XFreePixmap (winp->dsp, winp->pix.p);
- X
- X winp->pix.p = XCreatePixmap (winp->dsp, winp->win,
- X winp->hpixels, winp->vpixels,
- X DefaultDepth (winp->dsp, DefaultScreen (winp->dsp)));
- X
- X XSync (winp->dsp, False);
- X sleep (1);
- X
- X if (dir == -1 ) {
- X /*
- X * Zoom out. Leave the center where it is, but make the pixels
- X * bigger.
- X */
- X winp->pix_size *= 3;
- X
- X depth -= 1;
- X if (depth == 0) dir = 1;
- X }
- X else {
- X /*
- X * Zoom in on a desirable point. Make the desirable point the
- X * center of the image, and make the pixels smaller.
- X */
- X int ix, iy;
- X
- X /* get integer coords of pixel */
- X ix = (winp->black_list[0].x + winp->color_list[0].x) / 2;
- X iy = (winp->black_list[0].y + winp->color_list[0].y) / 2;
- X
- X win_new_center (winp, ix, iy);
- X winp->pix_size /= 3;
- X
- X depth += 1;
- X if (depth == MAX_ROOT_ZOOM_DEPTH) dir = -1;
- X }
- X}
- X
- Xint
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X win_info_t *win_create();
- X void win_set_lr();
- X
- X win_info_t *winp;
- X char *client_ctx;
- X int resume;
- X
- X parse_args (argc, argv);
- X winp = win_create ();
- X
- X winp->x = arg_x_center;
- X winp->y = arg_y_center;
- X winp->pix_size = arg_pix_size;
- X
- X client_ctx = client_init (winp);
- X
- X resume = 0;
- X for (;;) {
- X /* Let the client run. */
- X if (resume) {
- X resume = client_resume (client_ctx, winp);
- X }
- X else {
- X /*
- X * Here, user has asked for a new window.
- X */
- X XClearWindow (winp->dsp, winp->win);
- X (void) printf ("%s: window at (%g,%g) pix_size=%g\n",
- X argv[0], winp->x, winp->y,
- X winp->pix_size);
- X (void) fflush (stdout);
- X
- X resume = client_reset (client_ctx, winp);
- X }
- X
- X if (!arg_use_root) { /* interact with user */
- X resume = win_handle_user (winp, resume);
- X }
- X else if (!resume) { /* client is done with window */
- X win_new_root (winp);
- X }
- X else sleep (0); /* don't hog the processor */
- X }
- X}
- X
- X/*
- X * Given a window, change the pixel width and height of the window.
- X * We are given a desired width and height. If possible, we will
- X * use this width and height. However, if the width and height
- X * would cause the window to fall off the edge of the screen, then
- X * we will reduce the width and height proportionately.
- X *
- X * Return 1 if we change the width/height; 0 the width/height stay the
- X * same; and -1 if the window would become real small.
- X *
- X * All resizing requests should probably be routed through this
- X * routine.
- X */
- X
- Xint
- Xwin_set_wh (winp, w, h)
- Xwin_info_t *winp;
- Xint w, h; /* target width and height */
- X{
- X int scr;
- X int dw, dh; /* display width and height */
- X int new_x, new_y;
- X XWindowAttributes win_attr;
- X XSizeHints hints;
- X
- X scr = DefaultScreen (winp->dsp);
- X
- X dw = DisplayWidth (winp->dsp, scr);
- X dh = DisplayHeight (winp->dsp, scr);
- X
- X if (w > dw) {
- X h = (h * dw) / w; /* preserve shape of window */
- X w = dw;
- X }
- X if (h > dh) {
- X w = (w * dh) / h;
- X h = dh;
- X }
- X
- X if (w == winp->hpixels && h == winp->vpixels) return 0;
- X if (w < 4 || h < 4) return -1; /* don't get too small */
- X
- X winp->hpixels = w;
- X winp->vpixels = h;
- X
- X /* Adjust the window's size. If necessary, move the window. */
- X XResizeWindow (winp->dsp, winp->win, winp->hpixels, winp->vpixels);
- X XGetWindowAttributes (winp->dsp, winp->win, &win_attr);
- X
- X new_x = dw - winp->hpixels;
- X new_y = dh - winp->vpixels;
- X if (win_attr.x > new_x || win_attr.y > new_y) {
- X if (win_attr.x < new_x) new_x = win_attr.x;
- X if (win_attr.y < new_y) new_y = win_attr.y;
- X
- X XMoveWindow (winp->dsp, winp->win, new_x, new_y);
- X
- X win_attr.x = new_x;
- X win_attr.y = new_y;
- X }
- X
- X /*
- X * Tell the window manager what we did. Note: problems
- X * may or may not occur if the window manager refuses our
- X * request.
- X */
- X hints.x = win_attr.x;
- X hints.y = win_attr.y;
- X hints.width = winp->hpixels;
- X hints.height = winp->vpixels;
- X hints.flags = USPosition | USSize; /* the user specified these */
- X XSetNormalHints (winp->dsp, winp->win, &hints);
- X
- X /*
- X * Now, wait for the configuration notify event. Toss all
- X * other events in the meantime.
- X */
- X for (;;) {
- X XEvent event;
- X
- X XNextEvent (winp->dsp, &event);
- X
- X if (event.type == ConfigureNotify
- X && event.xconfigure.window == winp->win)
- X {
- X /* set width and height to actual values */
- X winp->hpixels = event.xconfigure.width;
- X winp->vpixels = event.xconfigure.height;
- X break;
- X }
- X }
- X
- X return 1;
- X}
- X
- X/*
- X * Given a window and co-ordinates of a box within that window,
- X * adjust the X and Y co-ordinates of the window, and resize the
- X * window to the new shape. Note that the box may actually overlap
- X * the window.
- X *
- X * Return TRUE if we actually change something. Don't change anything
- X * if the new co-ordinates would require either a zero width or a
- X * zero height.
- X */
- X
- Xint
- Xwin_set_box (winp, x1, y1, x2, y2)
- Xwin_info_t *winp;
- Xint x1, y1, x2, y2; /* pixel locations of the box */
- X{
- X int ix, iy; /* center pixel of box */
- X double old_x, old_y;
- X double new_area, old_area;
- X double scale;
- X int t;
- X
- X if ((x1 == x2) || (y1 == y2)) return FALSE;
- X
- X /* get length of sides */
- X ix = x1 - x2;
- X if (ix < 0) ix = -ix;
- X
- X iy = y1 - y2;
- X if (iy < 0) iy = -iy;
- X
- X /* Change the shape of the window. Preserve the area. */
- X old_area = winp->hpixels * winp->vpixels;
- X new_area = ix * iy;
- X scale = old_area / new_area;
- X scale = sqrt (scale);
- X
- X old_x = winp->x;
- X old_y = winp->y;
- X win_new_center (winp, (x1 + x2) / 2, (y1 + y2) / 2);
- X
- X t = win_set_wh (winp, (int)(ix * scale), (int)(iy * scale));
- X if (t == -1) {
- X winp->x = old_x; /* restore old center */
- X winp->y = old_y;
- X return FALSE;
- X }
- X
- X winp->pix_size /= scale;
- X
- X return TRUE;
- X}
- X
- X/*
- X * Handle user requests. If 'resume' is TRUE, we need to
- X * return as quickly as possible. If 'resume' is false,
- X * we return when we have something more to compute.
- X *
- X * Return TRUE if the client can resume drawing in the window.
- X * If we modify the window, the client cannot resume.
- X */
- X
- Xint
- Xwin_handle_user (winp, resume)
- Xwin_info_t *winp;
- Xint resume;
- X{
- X int win_new_box ();
- X
- X XEvent event;
- X char key;
- X int i;
- X
- X for (;;) {
- X /* Get an event. */
- X if (resume) {
- X if (!XCheckWindowEvent (winp->dsp, winp->win,
- X KeyPressMask | ButtonPressMask
- X | ButtonReleaseMask | ButtonMotionMask
- X | PointerMotionHintMask
- X | StructureNotifyMask,
- X &event))
- X {
- X return TRUE;
- X }
- X }
- X else {
- X XNextEvent (winp->dsp, &event);
- X }
- X
- X switch (event.type) {
- X case ConfigureNotify:
- X /*
- X * See if the window has been resized.
- X */
- X if (event.xconfigure.window == winp->win
- X && (event.xconfigure.width != winp->hpixels
- X || event.xconfigure.height != winp->vpixels))
- X {
- X /* use the width/height we've been given */
- X winp->hpixels = event.xconfigure.width;
- X winp->vpixels = event.xconfigure.height;
- X return FALSE; /* can't resume */
- X }
- X break;
- X
- X case ButtonPress:
- X /*
- X * Get a new window.
- X */
- X if (win_new_box (winp, event.xbutton.x,
- X event.xbutton.y))
- X {
- X return FALSE; /* can't resume */
- X }
- X break;
- X
- X case KeyPress:
- X XLookupString (&event, &key, 1, NULL, NULL);
- X switch (key) {
- X case 'q': /* quit */
- X exit (0);
- X /* NOTREACHED */
- X
- X case 'z':
- X winp->pix_size *= 3;
- X return FALSE;
- X
- X case 'e': /* expand window */
- X i = win_set_wh (winp, winp->hpixels * 2,
- X winp->vpixels * 2);
- X
- X if (i > 0) return FALSE; /* can't resume */
- X break;
- X
- X case 's': /* shrink window */
- X i = win_set_wh (winp, winp->hpixels / 2,
- X winp->vpixels / 2);
- X if (i > 0) return FALSE; /* can't resume */
- X break;
- X }
- X }
- X }
- X}
- X
- X/*
- X * The mouse button is currently depressed. We follow the pointer
- X * around drawing a box. When the mouse is no longer depressed,
- X * we attempt to update the window based on the shape and co-ordinates
- X * of the new box.
- X *
- X * Return TRUE if we modify the window, otherwise FALSE.
- X */
- X
- Xint
- Xwin_new_box (winp, x1, y1)
- Xwin_info_t *winp;
- Xint x1, y1; /* starting corner of box */
- X{
- X XEvent event;
- X int x2, y2; /* second corner of box */
- X int first_time = 1;
- X
- X XSetFunction (winp->dsp, winp->gc, GXxor);
- X XSetForeground (winp->dsp, winp->gc, -1);
- X XSetBackground (winp->dsp, winp->gc, -1);
- X
- X for (;;) {
- X XNextEvent (winp->dsp, &event);
- X switch (event.type) {
- X case ButtonRelease:
- X /*
- X * We have selected a new window. Reset the
- X * window and save the co-ordinates.
- X */
- X /* erase current box */
- X if (!first_time) {
- X XDrawRectangle (winp->dsp, winp->win,
- X winp->gc, x1, y1, x2-x1, y2-y1);
- X }
- X
- X x2 = event.xbutton.x;
- X y2 = event.xbutton.y;
- X
- X /* reset drawing mode */
- X XSetFunction (winp->dsp, winp->gc, GXcopy);
- X
- X /* Compute new co-ordinates and resize window. */
- X return win_set_box (winp, x1, y1, x2, y2);
- X
- X case MotionNotify: {
- X /*
- X * Redraw our box.
- X */
- X
- X Window root, child;
- X int root_x, root_y, win_x, win_y;
- X unsigned int keys_buttons;
- X
- X while (XCheckMaskEvent (winp->dsp, ButtonMotionMask,
- X &event));
- X
- X if (!XQueryPointer (winp->dsp, event.xmotion.window,
- X &root, &child, &root_x, &root_y,
- X &win_x, &win_y, &keys_buttons))
- X {
- X break; /* not in this window */
- X }
- X
- X /* undraw the previous box, if it exists */
- X if (!first_time) {
- X XDrawRectangle (winp->dsp, winp->win,
- X winp->gc, x1, y1, x2-x1, y2-y1);
- X }
- X
- X x2 = win_x;
- X y2 = win_y;
- X
- X /* draw new box */
- X first_time = 0;
- X XDrawRectangle (winp->dsp, winp->win,
- X winp->gc, x1, y1, x2-x1, y2-y1);
- X break;
- X }
- X }
- X }
- X}
- X
- X/*
- X * Create the initial window.
- X */
- X
- Xwin_info_t *
- Xwin_create ()
- X{
- X Colormap init_color_map ();
- X Colormap read_color_map ();
- X void win_display_colormap ();
- X
- X win_info_t *winp;
- X int scr;
- X Colormap cmap;
- X XSetWindowAttributes xswa;
- X XColor black, white;
- X XWMHints wm_hints;
- X int winX, winY, winH, winW;
- X int cursor_shape1 = XC_watch;
- X int cursor_shape2 = XC_top_left_arrow;
- X int bufsize;
- X int i;
- X
- X winp = (win_info_t *) malloc (sizeof (*winp));
- X if (!winp) {
- X (void) fprintf (stderr, "win_create: Out of memory.\n");
- X exit (1);
- X }
- X
- X winp->dsp = XOpenDisplay (arg_display);
- X if (!winp->dsp) {
- X perror ("win_create: Cannot open display.");
- X exit (1);
- X }
- X
- X scr = DefaultScreen (winp->dsp);
- X
- X if (arg_colorfile) {
- X cmap = read_color_map (winp);
- X if (winp->color_len <= 1) {
- X if (winp->pixels) free ((char *)winp->pixels);
- X cmap = init_color_map (winp);
- X }
- X }
- X else cmap = init_color_map (winp);
- X
- X black.pixel = BlackPixel (winp->dsp, scr);
- X if (!arg_use_root) XQueryColor (winp->dsp, cmap, &black);
- X winp->black = black.pixel;
- X
- X white.pixel = WhitePixel (winp->dsp, scr);
- X if (!arg_use_root) XQueryColor (winp->dsp, cmap, &white);
- X winp->white = white.pixel;
- X
- X if (arg_use_root) { /* let's be a background pattern... */
- X winp->win = DefaultRootWindow (winp->dsp);
- X winX = 0;
- X winY = 0;
- X winW = DisplayWidth (winp->dsp, scr);
- X winH = DisplayHeight (winp->dsp, scr);
- X winp->gc = DefaultGC (winp->dsp, scr);
- X
- X /*
- X * Buffer the image in a pixmap.
- X */
- X winp->pix.p = XCreatePixmap (winp->dsp, winp->win,
- X winW, winH,
- X DefaultDepth (winp->dsp, scr));
- X }
- X else {
- X winW = HPIXELS;
- X winH = VPIXELS;
- X winX = 0;
- X winY = 0;
- X
- X if (arg_geometry) {
- X XParseGeometry (arg_geometry, &winX, &winY,
- X &winW, &winH);
- X }
- X
- X xswa.event_mask = 0;
- X xswa.background_pixel = black.pixel;
- X xswa.backing_store = WhenMapped;
- X
- X winp->win = XCreateWindow (winp->dsp,
- X RootWindow (winp->dsp, scr),
- X winX, winY, winW, winH, 0,
- X DefaultDepth (winp->dsp, scr), InputOutput,
- X DefaultVisual (winp->dsp, scr),
- X CWEventMask | CWBackPixel | CWBackingStore,
- X &xswa);
- X
- X /* Tell the window manager about ourself. */
- X XStoreName (winp->dsp, winp->win, "Mandel");
- X XSetIconName (winp->dsp, winp->win, "Mandel");
- X
- X wm_hints.input = True; /* passive input */
- X wm_hints.initial_state = NormalState;
- X wm_hints.flags = InputHint | StateHint;
- X XSetWMHints (winp->dsp, winp->win, &wm_hints);
- X
- X XMapWindow (winp->dsp, winp->win);
- X XSync (winp->dsp, False);
- X
- X XSelectInput (winp->dsp, winp->win,
- X KeyPressMask | ButtonPressMask | ButtonReleaseMask
- X | StructureNotifyMask | ButtonMotionMask
- X | PointerMotionHintMask);
- X
- X winp->gc = XCreateGC (winp->dsp, winp->win, 0, NULL);
- X
- X /*
- X * Render the image directly to the screen.
- X */
- X winp->pix.w = winp->win;
- X
- X winp->busy = XCreateFontCursor (winp->dsp, cursor_shape1);
- X winp->nbusy = XCreateFontCursor (winp->dsp, cursor_shape2);
- X XDefineCursor (winp->dsp, winp->win, winp->nbusy);
- X }
- X
- X winp->hpixels = winW;
- X winp->vpixels = winH;
- X
- X winp->black_num = winp->color_num = 0; /* empty */
- X for (i = 0; i < SAVE_LIST_LEN; i++) {
- X winp->black_list[i].x =
- X winp->black_list[i].y =
- X winp->color_list[i].x =
- X winp->color_list[i].y = 0;
- X }
- X
- X XSetForeground (winp->dsp, winp->gc, white.pixel);
- X XSetBackground (winp->dsp, winp->gc, black.pixel);
- X XSetFunction (winp->dsp, winp->gc, GXcopy);
- X
- X /*
- X * Having problems on the Sun. Put in a clear and sync
- X * in an attempt to delay some messages.
- X */
- X sleep (1);
- X XClearWindow (winp->dsp, winp->win);
- X XSync (winp->dsp, False);
- X
- X if (arg_show_time) win_display_colormap (winp);
- X
- X /*
- X * Allocate a buffer area for imaging. The purpose of this
- X * buffer is to reduce the amount of work required from the
- X * XServer. We allocate a buffer one line high and the
- X * full width of the screen.
- X *
- X * Note: We use an XYPixmap because the Apollo workstations
- X * seem to have problems with ZPixmaps.
- X */
- X#define USE_ZPIXMAP
- X winp->image = XCreateImage (winp->dsp,
- X DefaultVisual (winp->dsp, scr),
- X DefaultDepth (winp->dsp, scr),
- X#ifdef USE_ZPIXMAP
- X ZPixmap,
- X#else
- X XYPixmap,
- X#endif
- X 0, /* offset to first pixel */
- X (char *) 0, /* pointer to image data */
- X DisplayWidth (winp->dsp, scr),
- X 1, /* height of image */
- X 32, /* alignment of scan lines */
- X 0);
- X if (!winp->image) {
- X (void) fprintf (stderr,
- X "win_create: Cannot allocate image.\n");
- X exit (1);
- X }
- X#if 1
- X winp->image->byte_order = 0;
- X winp->image->bitmap_bit_order = 0;
- X#endif
- X
- X /* Allocate a data area for the image. */
- X#ifdef USE_ZPIXMAP
- X /* use this calculation for ZPixmap format */
- X bufsize = winp->image->bytes_per_line;
- X#else
- X /* use this calculation for XYPixmap format */
- X bufsize = winp->image->bytes_per_line * winp->image->depth;
- X#endif
- X winp->image->data = malloc ((unsigned) bufsize);
- X if (!winp->image->data) {
- X (void) fprintf (stderr,
- X "win_create: Cannot allocate %d bytes for image data.\n",
- X bufsize);
- X exit (1);
- X }
- X
- X return winp;
- X}
- X
- X/*
- X * Display the initial colormap. We can handle up to 256 colors here.
- X */
- X
- Xvoid
- Xwin_display_colormap (winp)
- Xwin_info_t *winp;
- X{
- X int i;
- X int r, c;
- X int pixel;
- X
- X for (i = 0; i < winp->color_len; i++) {
- X if (winp->pixels) pixel = winp->pixels[i];
- X else pixel = i;
- X
- X c = i % 16;
- X r = i / 16;
- X
- X XSetForeground (winp->dsp, winp->gc, pixel);
- X XFillRectangle (winp->dsp, winp->win, winp->gc,
- X (winp->hpixels * c) / 16,
- X (winp->vpixels * r) / 16,
- X winp->hpixels / 16,
- X winp->vpixels / 16);
- X#if 0
- X /*
- X * On the 'sun', this doesn't seem to work unless
- X * we have this 'XSync' lying around.
- X */
- X XSync (winp->dsp, False);
- X sleep (1);
- X#endif
- X }
- X
- X XSync (winp->dsp, False);
- X sleep (arg_show_time);
- X}
- X
- X/*
- X * Read colors for the colormap from a file. Return the colormap.
- X */
- X
- X#define COLORLEN 80
- X#define is_white(c) ((c) == ' ' || (c) == '\t')
- X#define scan_white(p) while (*(p) && is_white(*(p))) (p) += 1
- X#define scan_black(p) while (*(p) && !is_white(*(p))) (p) += 1
- X
- Xstatic Colormap
- Xread_color_map (winp)
- Xwin_info_t *winp;
- X{
- X FILE *f;
- X char colorname[COLORLEN];
- X int scr;
- X int npixels;
- X int i;
- X Colormap cmap;
- X XColor xcolor;
- X
- X scr = DefaultScreen (winp->dsp);
- X
- X /* set initial length and offset */
- X winp->color_len = XDisplayCells (winp->dsp, scr);
- X winp->pixels = NULL;
- X
- X cmap = XDefaultColormap (winp->dsp, scr);
- X
- X /* open the file of color names */
- X f = fopen (arg_colorfile, "r");
- X if (!f) {
- X (void) fprintf (stderr,
- X "read_color_map: Cannot open file %s.\n",
- X arg_colorfile);
- X perror ("");
- X return cmap;
- X }
- X
- X /* allocate pixel storage */
- X for (npixels = winp->color_len; npixels; npixels--) {
- X winp->pixels = (unsigned long *) malloc (
- X sizeof (*(winp->pixels)) * npixels);
- X if (winp->pixels) break;
- X }
- X
- X if (!npixels) {
- X (void) fprintf (stderr,
- X "read_color_map: Can't allocate pixel storage.\n");
- X winp->color_len = 0;
- X return cmap;
- X }
- X
- X /* read the colors */
- X for (i = 0; i < npixels; ) {
- X char *p, *start;
- X
- X if (fgets (colorname, COLORLEN, f) == NULL) break;
- X p = strchr (colorname, ';');
- X if (!p) p = strchr (colorname, '\n');
- X if (p) *p = '\0'; /* toss end of line */
- X
- X start = colorname;
- X scan_white (start); /* find start of string */
- X
- X p = start;
- X scan_black (p); /* find end of string */
- X if (p == start) continue; /* empty line */
- X
- X *p = '\0'; /* terminate the string */
- X
- X if (!XParseColor (winp->dsp, cmap, start, &xcolor)) {
- X (void) fprintf (stderr,
- X "read_color_map: color name '%s' isn't in database.\n",
- X start);
- X continue;
- X }
- X
- X if (!XAllocColor (winp->dsp, cmap, &xcolor)) {
- X /*
- X * Although we can't allocate any more colors,
- X * we may be able to share some already existing
- X * color. Keep looping to give it a try.
- X */
- X continue;
- X }
- X
- X winp->pixels[i] = xcolor.pixel;
- X i += 1;
- X }
- X
- X winp->color_len = i; /* remember length of pixel array */
- X
- X (void) fclose (f);
- X return cmap;
- X}
- X
- X/*
- X * Allocate a color map.
- X */
- X
- Xstatic Colormap
- Xinit_color_map (winp)
- Xwin_info_t *winp;
- X{
- X void convertHSI_to_RGB();
- X
- X int scr;
- X Colormap cmap;
- X double hue, intensity, saturation;
- X int r, g, b;
- X XColor celldef;
- X int i;
- X int npixels;
- X double mud;
- X int m;
- X int dir;
- X
- X scr = DefaultScreen (winp->dsp);
- X
- X /* set initial length and offset */
- X winp->color_len = XDisplayCells (winp->dsp, scr);
- X winp->pixels = NULL;
- X
- X cmap = XDefaultColormap (winp->dsp, scr);
- X
- X /* allocate color map */
- X for (npixels = winp->color_len; npixels; npixels--) {
- X winp->pixels = (unsigned long *) malloc (
- X sizeof (*(winp->pixels)) * npixels);
- X if (!winp->pixels) continue;
- X
- X if (!XAllocColorCells (winp->dsp, cmap, False,
- X (unsigned long *)0, 0,
- X winp->pixels, npixels))
- X {
- X free ((char *)winp->pixels);
- X continue;
- X }
- X
- X break;
- X }
- X
- X if (!npixels) {
- X (void) fprintf (stderr,
- X "init_color_map: Can't allocate colormap.\n");
- X return cmap;
- X }
- X
- X /* Set the colors for each allocated pixel. */
- X
- X winp->color_len = npixels;
- X hue = 0.0;
- X mud = 0.0;
- X dir = 1;
- X
- X for (i = 0; i < npixels; i++) {
- X convertHSI_to_RGB (hue, mud, &r, &g, &b);
- X celldef.pixel = winp->pixels[i];
- X celldef.red = r;
- X celldef.green = g;
- X celldef.blue = b;
- X celldef.flags = DoBlue | DoGreen | DoRed;
- X celldef.pad = NULL;
- X
- X XStoreColor (winp->dsp, cmap, &celldef);
- X
- X m = i % arg_mud_num;
- X if (m == arg_mud_num - 1) { /* increment hue */
- X hue += 1.0 * arg_mud_num / (double) (npixels);
- X dir = -dir; /* change direction */
- X }
- X else if (dir > 0) { /* increase mud */
- X mud = mud + arg_mud_max / arg_mud_num;
- X }
- X else { /* decrease mud */
- X mud = mud - arg_mud_max / arg_mud_num;
- X }
- X }
- X
- X return cmap;
- X}
- X
- X/*
- X * Given a hue, saturation, and brightness (intensity), generate
- X * r, g, and b values. Here, we ignore the saturation and brightness
- X * since we know what we want. We use sine curves to ramp values up
- X * and down quickly, so that the colors will be more interesting.
- X */
- X
- X#define ramp_up(h) sin (M_PI_2 * (h))
- X#define ramp_down(h) cos (M_PI_2 * (h))
- X
- Xvoid
- XconvertHSI_to_RGB (hue, mud, R, G, B)
- Xdouble hue, mud;
- Xint *R,*G,*B ;
- X
- X{
- X double r,g,b ;
- X int i;
- X
- X hue = (double) (hue*6) ;
- X i = (int) (hue);
- X hue = hue - i; /* normalize 'hue' into range 0..1 */
- X switch (i)
- X {
- X case 0 :
- X r = 1.0;
- X g = ramp_up (hue);
- X b = ramp_up (mud);
- X break;
- X case 1:
- X r = ramp_down (hue);
- X g = 1.0;
- X b = ramp_up (mud);
- X break;
- X case 2:
- X r = ramp_up (mud);
- X g = 1.0;
- X b = ramp_up (hue);
- X break;
- X case 3:
- X r = ramp_up (mud);
- X g = ramp_down (hue);
- X b = 1.0;
- X break;
- X case 4:
- X r = ramp_up (hue);
- X g = ramp_up (mud);
- X b = 1.0;
- X break;
- X case 5:
- X r = 1.0;
- X g = ramp_up (mud);
- X b = ramp_down (hue);
- X break;
- X }
- X
- X *R = (int) (r*65535) ;
- X *G = (int) (g*65535) ;
- X *B = (int) (b*65535) ;
- X
- X}
- X
- X
- X/*
- X * Flush the graphics package.
- X */
- X
- Xvoid
- Xwin_flush (winp)
- Xwin_info_t *winp;
- X{
- X XSync (winp->dsp, False);
- X}
- X
- X/*
- X * Change the shape of the cursor on the screen. Only done if not
- X * on root.
- X */
- X
- Xvoid
- Xwin_busy (winp, state)
- Xwin_info_t *winp;
- Xint state;
- X{
- X if (!arg_use_root) {
- X XDefineCursor (winp->dsp, winp->win, state ? winp->busy : winp->nbusy);
- X }
- X}
- X
- X/*
- X * Draw a colored line. The 'color' is a postive number. We
- X * will take this color modulo the available colors.
- X */
- X
- Xvoid
- Xwin_draw_colored_line (winp, color, from_x, from_y, to_x, to_y)
- Xwin_info_t *winp;
- Xint color;
- Xint from_x, from_y, to_x, to_y;
- X{
- X int pixel;
- X
- X pixel = color % winp->color_len;
- X if (winp->pixels) pixel = winp->pixels[pixel];
- X
- X XSetForeground (winp->dsp, winp->gc, pixel);
- X XDrawLine (winp->dsp, winp->win, winp->gc, from_x, from_y, to_x, to_y);
- X}
- X
- X/*
- X * Given a run-length encoded line, draw the line on the screen.
- X * Here, we buffer the line into an image, and then send the image
- X * to the screen. This technique is designed to reduce the amount
- X * of work required by the XServer.
- X *
- X * If we understood the internal format of an Image better, we could
- X * probably generate the image data using low-level techniques that
- X * would greatly enhance the speed of this routine. Eventually, we
- X * might want to farm out some of these computations to the compute
- X * servers, but that would run the risk of making the compute servers
- X * more difficult to port.
- X *
- X * When we are imaging on the root window, we store the pixel
- X * co-ordinates where we think it would be interesting to expand
- X * the image. We willl choose the right side of a black line
- X * that is followed by a colored line. And we will prefer a short
- X * line.
- X */
- X
- Xvoid
- Xwin_render_line (winp, buf, buflen, linenum)
- Xwin_info_t *winp;
- Xcolor_x_t *buf; /* run-length encoded line */
- Xint buflen; /* number of elements pointed to by 'buf' */
- Xint linenum; /* line number of the window to be drawn */
- X{
- X int last_x;
- X int i, j;
- X unsigned long pixel;
- X
- X /* Fill the image with colors. */
- X last_x = 0;
- X for (i = 0; i < buflen; i++) {
- X if (buf[i].color == arg_iterations) { /* black? */
- X pixel = winp->black;
- X
- X /* record various black and colored locations */
- X if (arg_use_root) {
- X if (i < buflen - 1
- X && buf[i].x - last_x + 1 < 5)
- X {
- X winp->black_list[0].x = buf[i].x + 1;
- X winp->black_list[0].y = linenum;
- X winp->color_list[0].x = buf[i].x + 1;
- X winp->color_list[0].y = linenum;
- X }
- X }
- X }
- X else {
- X pixel = buf[i].color % winp->color_len;
- X if (winp->pixels) pixel = winp->pixels[pixel];
- X }
- X
- X /* Fill a line segment with this pixel. */
- X for (j = last_x; j <= buf[i].x; j++) {
- X XPutPixel (winp->image, j, 0, pixel);
- X }
- X
- X last_x = buf[i].x + 1;
- X }
- X
- X /* Put the image on the screen. */
- X XPutImage (winp->dsp, winp->pix.w, winp->gc, winp->image,
- X 0, 0, 0, linenum, winp->hpixels, 1);
- X}
- X
- X/*
- X * Draw the image that we last drew on the screen. This exists
- X * purely to take advantage of the symmetry that exists about the
- X * X-axis of the mandelbrot set. This routine isn't absolutely
- X * necessary.
- X */
- X
- Xvoid
- Xwin_rerender_line (winp, linenum)
- Xwin_info_t *winp;
- Xint linenum;
- X{
- X XPutImage (winp->dsp, winp->pix.w, winp->gc, winp->image,
- X 0, 0, 0, linenum, winp->hpixels, 1);
- X}
- //E*O*F gui.c//
-
- echo x - gui.h
- sed -e 's/^X//' > "gui.h" << '//E*O*F gui.h//'
- X/*
- X * Mandel by Rob Swiston and Chuck Simmons
- X * Copyright (C) 1989, 1990 by Rob Swiston and Chuck Simmons
- X *
- X * This program is free software; you can redistribute it and/or modify
- X * it under the terms of version 1 of the GNU General Public License as
- X * published by the Free Software Foundation.
- X *
- X * This program is distributed in the hope that it will be useful,
- X * but WITHOUT ANY WARRANTY; without even the implied warranty of
- X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X * GNU General Public License for more details.
- X *
- X * You should have received a copy of the GNU General Public License
- X * along with this program; if not, write to the Free Software
- X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X */
- X
- X/*
- X * Definitions needed to use the GUI routines.
- X */
- X
- X/*
- X * Routines.
- X */
- X
- Xvoid win_flush (/* void *winp */); /* flush pending output */
- Xvoid win_busy (/* void *winp, int state */); /* change cursor */
- Xvoid win_draw_colored_line (/* void *winp, int color,
- X int x1, int y1, int x2, int y2 */);
- Xvoid win_render_line (/* void *winp, color_x_t *buf,
- X int buflen, int linenum */);
- Xvoid win_rerender_line (/* void *winp, int linenum */);
- X
- X/* width and height of window in pixels */
- Xint win_pwidth (/* void *winp */);
- Xint win_pheight (/* void *winp */);
- X
- X/* 'real' co-ordinates of upper-left and lower-right of window */
- Xdouble win_xmin (/* void *winp */);
- Xdouble win_xmax (/* void *winp */);
- Xdouble win_ymin (/* void *winp */);
- Xdouble win_ymax (/* void *winp */);
- X
- X/* 'real' width and height */
- Xdouble win_rwidth (/* void *winp */);
- Xdouble win_rheight (/* void *winp */);
- X
- X/* maximum width and height of screen */
- Xint win_max_width (/* void *winp */);
- Xint win_max_height (/* void *winp */);
- X
- X
- //E*O*F gui.h//
-
- echo x - mandel.mk
- sed -e 's/^X//' > "mandel.mk" << '//E*O*F mandel.mk//'
- X# Mandel by Rob Swiston and Chuck Simmons
- X# Copyright (C) 1989, 1990 by Rob Swiston and Chuck Simmons
- X#
- X# This program is free software; you can redistribute it and/or modify
- X# it under the terms of version 1 of the GNU General Public License as
- X# published by the Free Software Foundation.
- X#
- X# This program is distributed in the hope that it will be useful,
- X# but WITHOUT ANY WARRANTY; without even the implied warranty of
- X# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X# GNU General Public License for more details.
- X#
- X# You should have received a copy of the GNU General Public License
- X# along with this program; if not, write to the Free Software
- X# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- X# Define 'VAX_BYTE_ORDER' on mips, vax, sequent, ncube, etc.
- X# Define CONVEX or IS_370 on appropriate machines.
- X
- X#CFLAGS = -O -DCONVEX
- X#CFLAGS = -O -DIS_370
- X#CFLAGS = -O -DVAX_BYTE_ORDER
- XCFLAGS = -O
- X
- XSHIP1FILES=client.c gui.c gui.h mandel.mk
- XSHIP2FILES=LICENSE hostfile mandel.h mserver.c net.c net.h client.h \
- X colormap.data compute.c README
- X
- X# NCube specific stuff.
- XNINCLUDES = -I/home/csimmons/ora/6028/port/ncube/standard_def
- XNCCFLAGS = $(CFLAGS) $(INCLUDES)
- XNCC=ngcc
- XROOT=/usr/lib/ncube2
- XLIB=$(ROOT)/lib
- XBIN=$(ROOT)/bin
- X
- Xall: mandel mserver
- X
- Xmandel: client.o gui.o cnet.o
- X $(CC) -o $@ client.o gui.o cnet.o -lX11 -lm
- X
- Xmserver: snet.o compute.o mserver.o
- X $(CC) -o $@ snet.o compute.o mserver.o
- X
- Xcnet.o: net.c
- X $(CC) $(CFLAGS) -DCLIENT -c net.c
- X mv net.o cnet.o
- X
- Xsnet.o: net.c
- X $(CC) $(CFLAGS) -DSERVER -c net.c
- X mv net.o snet.o
- X
- Xship: $(SHIP1FILES) $(SHIP2FILES)
- X shar $(SHIP1FILES) > mandel1.shar
- X shar $(SHIP2FILES) > mandel2.shar
- X
- X# Everything below this point is NCube specific.
- X
- X# compute.o isn't ever executed, but it is needed to resolve a
- X# reference. Yucko.
- X
- Xnc_sunserver: nc_sunserver.o snet.o compute.o
- X $(CC) -o $@ nc_sunserver.o snet.o compute.o $(LIB)/libncube.a
- X
- Xnc_cubeserver: nc_cubeserver.o nc_get_color.o
- X $(NCC) -o $@ nc_cubeserver.o nc_get_color.o
- X
- X#nc_cubeserver: nc_cubeserver.o nc_mandel_line.o
- X# $(NCC) -o $@ nc_cubeserver.o nc_mandel_line.o
- X
- Xnc_cubeserver.o: nc_cubeserver.c
- X $(NCC) $(NCCFLAGS) -c nc_cubeserver.c
- X
- Xnc_get_color.o: nc_get_color.s
- X $(NCC) -O -c nc_get_color.s
- X
- Xnc_mandel_line.o: nc_mandel_line.c
- X $(NCC) $(NCCFLAGS) -c nc_mandel_line.c
- X
- X
- //E*O*F mandel.mk//
-
- exit 0
-