home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1123 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  52.5 KB

  1. From: csimmons@jewel.oracle.com (Charles Simmons)
  2. Newsgroups: alt.sources
  3. Subject: Interactive Mandelbrots on a Heterogenous Network
  4. Message-ID: <1990Apr3.072622.5513@oracle.com>
  5. Date: 3 Apr 90 07:26:22 GMT
  6.  
  7. This program is used to interactively display the Mandelbrot set.  Its
  8. primary feature is the ability to use a heterogeneous network of compute
  9. servers to compute the set in parallel.  To use this program without
  10.  
  11.     An X server and X libraries,
  12.     sockets,
  13.     Unix,
  14.     a floating point processor (preferably using IEEE format),
  15.     a color display.
  16.  
  17. This program has, at one time or another, run on each of the following
  18. platforms:
  19.  
  20.     Sun 3, Sun 4
  21.     DecStation 3100
  22.     Pyramid
  23.     Sequent
  24.     Convex
  25.     Apollo DN10000
  26.     some Apollo 68K based workstation
  27.  
  28. Contact me directly for additional software needed to run this program
  29. on the NCube.
  30.  
  31. -- Chuck Simmons
  32. csimmons@oracle.oracle.com
  33.  
  34.  
  35. # This is a shell archive.  Remove anything before this line, then
  36. # unpack it by saving it in a file and typing "sh file".  (Files
  37. # unpacked will be owned by you and have default permissions.)
  38. #
  39. # This archive contains:
  40. # client.c gui.c gui.h mandel.mk
  41.  
  42. : =-=-=-=-=-=-= first line of shar 1 of 1 =-=-=-=-=-=-=-=-=-
  43. echo x - client.c
  44. sed -e 's/^X//' > "client.c" << '//E*O*F client.c//'
  45. X/*
  46. X * Mandel by Rob Swiston and Chuck Simmons
  47. X * Copyright (C) 1989, 1990 by Rob Swiston and Chuck Simmons
  48. X *
  49. X * This program is free software; you can redistribute it and/or modify
  50. X * it under the terms of version 1 of the GNU General Public License as
  51. X * published by the Free Software Foundation.
  52. X *
  53. X * This program is distributed in the hope that it will be useful,
  54. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  55. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  56. X * GNU General Public License for more details.
  57. X *
  58. X * You should have received a copy of the GNU General Public License
  59. X * along with this program; if not, write to the Free Software
  60. X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  61. X */
  62. X
  63. X/*
  64. X * Here we have the client side of the mandelbrot program.  Primarily,
  65. X * we create connections to servers and farm out portions of the
  66. X * computation to the servers.  Periodically, we give control back
  67. X * to our caller, telling our caller whether or not we are completely
  68. X * done filling a window.
  69. X */
  70. X
  71. X/*
  72. X * Initialize the client.  Here, we want to establish connections to
  73. X * our servers.  We return a context area.
  74. X */
  75. X
  76. X#include <sys/types.h>
  77. X#include <sys/timeb.h>
  78. X#ifndef DST_NONE
  79. X# include <sys/time.h>
  80. X#endif
  81. X
  82. X#include <stdio.h>
  83. X#include "mandel.h"
  84. X#include "gui.h"
  85. X#include "net.h"
  86. X#include "client.h"
  87. X
  88. X#define HOSTLEN 40
  89. X
  90. X/*
  91. X * Specify the number of lines we want to have outstanding for
  92. X * each server.  Setting this too high will lead to long delays
  93. X * when drawing a new window.  The reason for this is that when
  94. X * the window is nearly completely drawn, we will send each line
  95. X * to many servers to make sure we get a response back.  Setting
  96. X * this too low will lead to a very minor performance degradation
  97. X * (in theory) because servers will have nothing to do while waiting
  98. X * for a line to arrive.
  99. X */
  100. X#define NLINES 2
  101. X
  102. X#define bswap(x) ((((x) << 8) & 0xff00) | (((x) >> 8) & 0xff))
  103. X
  104. Xtypedef struct line_id {
  105. X    struct line_id *next; /* pointer to next line in queue */
  106. X    int winid; /* identifier of window for this line */
  107. X    int line; /* number of line being worked on */
  108. X} line_id_t;
  109. X
  110. Xtypedef struct connection {
  111. X    int sock; /* socket descriptor */
  112. X    char host[HOSTLEN]; /* name of host */
  113. X    line_id_t *q_head; /* head of q of lines */
  114. X    line_id_t *q_tail; /* tail of queue */
  115. X    int flops; /* estimated flops performed */
  116. X} connection_t;
  117. X
  118. Xtypedef struct client_info {
  119. X    color_x_t *buf; /* buffer colors for a line */
  120. X
  121. X    int ncon; /* number of connections */
  122. X    connection_t *con; /* connections to servers */
  123. X    fd_set open_set; /* list of open sockets */
  124. X    int max_fd; /* maxium socket number */
  125. X
  126. X    int winid; /* identifier for window we are drawing */
  127. X    int line; /* next line to work on */
  128. X    int ndrawn_lines; /* count of drawn lines */
  129. X    char *drawn_line; /* list of lines that have been drawn */
  130. X
  131. X    int flops; /* estimated floating point operations performed */
  132. X    time_t start_time; /* real time at which we started window */
  133. X} client_info_t;
  134. X
  135. X/*
  136. X * Operations on the line queue.
  137. X */
  138. X
  139. X/* Allocate and free a line. */
  140. X
  141. X#define line_alloc() (line_id_t *) malloc (sizeof (line_id_t))
  142. X#define line_free(p) free ((char *) p)
  143. X
  144. X/*
  145. X * Add a line to the end of a connection's queue.  Return the
  146. X * added line.
  147. X */
  148. X
  149. Xline_id_t *
  150. Xline_push (conp)
  151. Xconnection_t *conp;
  152. X{
  153. X    line_id_t *p;
  154. X
  155. X    p = line_alloc ();
  156. X    if (!p) return NULL;
  157. X
  158. X    if (conp->q_tail) conp->q_tail->next = p;
  159. X    else conp->q_head = p;
  160. X
  161. X    conp->q_tail = p;
  162. X    p->next = NULL;
  163. X    return p;
  164. X}
  165. X
  166. X/*
  167. X * Pop a line off the queue.
  168. X */
  169. X
  170. Xvoid
  171. Xline_pop (conp)
  172. Xconnection_t *conp;
  173. X{
  174. X    line_id_t *p;
  175. X
  176. X    p = conp->q_head;
  177. X
  178. X    conp->q_head = p->next;
  179. X    if (conp->q_head == NULL) conp->q_tail = NULL;
  180. X    line_free (p);
  181. X}
  182. X
  183. X/*
  184. X * Return TRUE if a connection has fewer than NLINES lines outstanding.
  185. X */
  186. X
  187. Xint
  188. Xclient_has_room (conp)
  189. Xconnection_t *conp;
  190. X{
  191. X    line_id_t *p;
  192. X    int i;
  193. X
  194. X    for (i = 0, p = conp->q_head; i < NLINES && p; i++, p = p->next);
  195. X
  196. X    return i < NLINES;
  197. X}
  198. X
  199. X/* Return the y-coordinate of a line. */
  200. X
  201. Xdouble
  202. Xline_y_coord (winp, line)
  203. Xchar *winp;
  204. Xint line;
  205. X{
  206. X    return win_ymin(winp) + (line * win_rheight(winp)) / win_pheight(winp);
  207. X}
  208. X
  209. X/* Return the line of a y-coordinate. */
  210. X
  211. Xint
  212. Xy_line_coord (winp, y)
  213. Xchar *winp;
  214. Xdouble y;
  215. X{
  216. X    double t;
  217. X    t = win_pheight (winp) * (y - win_ymin (winp)) / win_rheight (winp);
  218. X    return (int) (t + 0.5); /* round to nearest int */
  219. X}
  220. X
  221. X/*
  222. X * Initialize the client.  We allocate a context area, and we
  223. X * establish connections to each server.
  224. X */
  225. X
  226. Xchar *
  227. Xclient_init (winp)
  228. Xchar *winp;
  229. X{
  230. X    client_info_t *clientp;
  231. X    FILE *hostf;
  232. X    char name[HOSTLEN];
  233. X    int port;
  234. X    int buflen;
  235. X    int ncons;
  236. X    connection_t *con;
  237. X
  238. X    clientp = (client_info_t *) malloc (sizeof (*clientp));
  239. X    if (!clientp) {
  240. X        (void) fprintf (stderr, "client_init: Out of storage.\n");
  241. X        exit (1);
  242. X    }
  243. X
  244. X    /*
  245. X     * Allocate storage to hold the colors of 1 line and
  246. X     * to hold the list of drawn lines.  We allocate the
  247. X     * maximum amount of storage that we might need for a window.
  248. X     * Note that our buffer pretty much really needs to be this
  249. X     * large.  Consider the case where we send out requests for
  250. X     * a long line, and then the window shrinks.  The servers
  251. X     * well send back really large requests which we would like
  252. X     * to have fit in our buffer.
  253. X      */
  254. X    buflen = sizeof (clientp->buf[0]) * win_max_width (winp);
  255. X    clientp->buf = (color_x_t *) malloc (buflen);
  256. X
  257. X    buflen = sizeof (clientp->drawn_line[0]) * win_max_height (winp);
  258. X    clientp->drawn_line = (char *) malloc (buflen);
  259. X
  260. X    if (!clientp->buf || !clientp->drawn_line) {
  261. X        (void) fprintf (stderr, "client_init: Out of storage.\n");
  262. X        exit (1);
  263. X    }
  264. X
  265. X    clientp->winid = 0;
  266. X    FD_ZERO (&clientp->open_set);
  267. X    clientp->max_fd = -1;
  268. X    clientp->ncon = 0;
  269. X
  270. X    /* Create connections to the servers. */
  271. X    hostf = fopen (HOSTFILE, "r");
  272. X    if (!hostf) {
  273. X        perror (HOSTFILE);
  274. X        exit (1);
  275. X    }
  276. X
  277. X    ncons = client_lines (hostf);
  278. X    buflen = sizeof (clientp->con[0]) * ncons;
  279. X    clientp->con = (connection_t *) malloc (buflen);
  280. X    if (!clientp->con) {
  281. X        (void) fprintf (stderr, "client_init: Out of storage.\n");
  282. X        exit (1);
  283. X    }
  284. X
  285. X    while (client_scan_line (hostf, name, &port, &ncons)) {
  286. X        (void) fprintf (stderr,
  287. X            "Connecting to %s at port %d (%d connections)\n",
  288. X            name, port, ncons);
  289. X
  290. X        while (ncons > 0) { /* create 'ncons' connections to this obj */
  291. X            con = &(clientp->con[clientp->ncon]);
  292. X
  293. X            (void) strcpy (con->host, name);
  294. X            con->q_head = con->q_tail = NULL;
  295. X            con->sock = net_copen (con->host, port);
  296. X            if (con->sock < 0) {
  297. X                con->sock = net_copen (con->host, bswap (port));
  298. X            }
  299. X            if  (con->sock < 0) {
  300. X                (void) fprintf (stderr,
  301. X                    "Cannot open socket to %s: ",
  302. X                    con->host);
  303. X                perror ("");
  304. X                break; /* give up on this host */
  305. X            }
  306. X            else {
  307. X                clientp->ncon += 1;
  308. X                FD_SET (con->sock, &clientp->open_set);
  309. X                if (con->sock > clientp->max_fd) {
  310. X                    clientp->max_fd = con->sock;
  311. X                }
  312. X            }
  313. X
  314. X            ncons -= 1;
  315. X        }
  316. X    }
  317. X
  318. X    if (clientp->ncon == 0) {
  319. X        (void) fprintf (stderr, "client_init: No connections.\n");
  320. X        exit (1);
  321. X    }
  322. X
  323. X    (void) fclose (hostf);
  324. X    return (char *) clientp;
  325. X}
  326. X
  327. X/*
  328. X * Read a line from the host file.
  329. X */
  330. X
  331. Xint
  332. Xclient_scan_line (f, name, portp, nconsp)
  333. XFILE *f;
  334. Xchar *name;
  335. Xint *portp;
  336. Xint *nconsp;
  337. X{
  338. X    char buf[256];
  339. X    int status;
  340. X
  341. X    if (fgets (buf, HOSTLEN, f) == NULL) {
  342. X        return 0; /* eof */
  343. X    }
  344. X    status = sscanf (buf, "%s %d %d", name, portp, nconsp);
  345. X    if (status != 3) {
  346. X        (void) fprintf (stderr,
  347. X            "client_scan_line: syntax error in line '%s'.\n",
  348. X            buf);
  349. X        (void) fprintf (stderr,
  350. X            "    format is 'name port_num num_connections'.\n");
  351. X        return 0;
  352. X    }
  353. X    return 1;
  354. X}
  355. X
  356. X/*
  357. X * Count the number of connections we need to make.
  358. X */
  359. X
  360. Xint
  361. Xclient_lines (f)
  362. XFILE *f;
  363. X{
  364. X    char buf[256];
  365. X    char name[HOSTLEN];
  366. X    int port, ncons;
  367. X    int total;
  368. X
  369. X    total = 0;
  370. X    while (client_scan_line (f, name, &port, &ncons)) {
  371. X        total += ncons;
  372. X    }
  373. X
  374. X    rewind (f);
  375. X    return total;
  376. X}
  377. X
  378. X/*
  379. X * Reset the client.  Here, we farm out an initial line of the
  380. X * window to each server after resetting ourselves to begin
  381. X * drawing the first line of the window.
  382. X */
  383. X
  384. Xint
  385. Xclient_reset (clientp, winp)
  386. Xclient_info_t *clientp;
  387. Xchar *winp;
  388. X{
  389. X    void client_send ();
  390. X
  391. X    int i, j;
  392. X
  393. X    bzero (clientp->drawn_line,
  394. X        sizeof (clientp->drawn_line[0]) * win_pheight (winp));
  395. X
  396. X    clientp->winid += 1; /* change window id */
  397. X    clientp->line = -1; /* reset starting line */
  398. X    clientp->ndrawn_lines = 0; /* nothing drawn yet */
  399. X    clientp->flops = 0; /* no floating point ops done yet */
  400. X    clientp->start_time = time ((time_t *) 0);
  401. X
  402. X    for (i = 0; i < clientp->ncon; i++) {
  403. X        clientp->con[i].flops = 0;
  404. X    }
  405. X
  406. X    /*
  407. X     * Send NLINES lines to each connection.  We loop on
  408. X     * the connections in the inner loop so that consecutive
  409. X     * lines will be sent to different processors.  We only send
  410. X     * lines to those processors who are in need of additional lines.
  411. X     */
  412. X    for (j = 0; j < NLINES; j++)
  413. X    for (i = 0; i < clientp->ncon; i++) {
  414. X        if (client_has_room (&(clientp->con[i]))) {
  415. X            client_send (clientp, &(clientp->con[i]), winp);
  416. X        }
  417. X    }
  418. X
  419. X    return client_resume (clientp, winp);
  420. X}
  421. X
  422. X/*
  423. X * Close down a server connection after an error occurs.
  424. X */
  425. X
  426. Xvoid
  427. Xclient_close (clientp, conp)
  428. Xclient_info_t *clientp;
  429. Xconnection_t *conp;
  430. X{
  431. X    int i;
  432. X
  433. X    i = conp - &(clientp->con[0]);
  434. X    FD_CLR (conp->sock, &clientp->open_set);
  435. X    close (conp->sock);
  436. X    while (conp->q_head) line_pop (conp); /* free some storage */
  437. X
  438. X    if (i != clientp->ncon-1) { /* compress list of clients */
  439. X        clientp->con[i] = clientp->con[clientp->ncon-1];
  440. X    }
  441. X    clientp->ncon -= 1;
  442. X
  443. X    if (clientp->ncon == 0) {
  444. X        (void) fprintf (stderr,
  445. X            "client_close: All connections died.\n");
  446. X        exit (1);
  447. X    }
  448. X}
  449. X
  450. X/*
  451. X * Send a line out over the network, updating our client structure.
  452. X */
  453. X
  454. Xvoid
  455. Xclient_send (clientp, conp, winp)
  456. Xclient_info_t *clientp;
  457. Xconnection_t *conp;
  458. Xchar *winp;
  459. X{
  460. X    extern int arg_iterations;
  461. X
  462. X    int status;
  463. X    line_id_t *p;
  464. X
  465. X    if (clientp->ndrawn_lines >= win_pheight (winp)) return;
  466. X
  467. X    /* increment client's line index to next undrawn line */
  468. X    do {
  469. X        if (clientp->line == win_pheight (winp) - 1) {
  470. X            clientp->line = 0;
  471. X        }
  472. X        else clientp->line += 1;
  473. X    } while (clientp->drawn_line[clientp->line]);
  474. X
  475. X    p = line_push (conp);
  476. X    if (!p) return; /* don't send anything if we don't have the storage */
  477. X
  478. X    p->winid = clientp->winid;
  479. X    p->line = clientp->line;
  480. X
  481. X    status = net_csend (conp->sock, win_xmin (winp),
  482. X            line_y_coord (winp, clientp->line),
  483. X            win_xmax (winp), win_pwidth (winp), arg_iterations);
  484. X
  485. X    if (status < 0) {
  486. X        (void) fprintf (stderr,
  487. X            "client_send: net_csend to %s failed: ",
  488. X            conp->host);
  489. X        perror ("");
  490. X        client_close (clientp, conp);
  491. X    }
  492. X}
  493. X
  494. X/*
  495. X * Receive a buffer off the network, and draw it.  Also, send another
  496. X * line.
  497. X */
  498. X
  499. Xvoid
  500. Xclient_recv (clientp, conp, winp)
  501. Xclient_info_t *clientp;
  502. Xconnection_t *conp;
  503. Xchar *winp;
  504. X{
  505. X    int buflen;
  506. X    int winid;
  507. X    int line, line2;
  508. X    int last_x, i, flops;
  509. X    int draw_it;
  510. X    double y;
  511. X
  512. X    buflen = net_crecv (conp->sock, clientp->buf);
  513. X    if (buflen < 0) {
  514. X        (void) fprintf (stderr,
  515. X            "client_recv: net_crecv from %s failed: ",
  516. X            conp->host);
  517. X        perror ("");
  518. X        client_close (clientp, conp);
  519. X    }
  520. X    else {
  521. X        winid = conp->q_head->winid;
  522. X        line = conp->q_head->line;
  523. X        line_pop (conp);
  524. X
  525. X        /* do nothing if this line was for a previous window */
  526. X        draw_it = FALSE; /* assume this line is boring */
  527. X        line2 = -1; /* no symmetry found yet */
  528. X        if (winid == clientp->winid && !clientp->drawn_line[line]) {
  529. X            /* mark this line as drawn */
  530. X            clientp->drawn_line[line] = TRUE;
  531. X            clientp->ndrawn_lines += 1;
  532. X            draw_it = TRUE; /* remember to draw the line */
  533. X        }
  534. X
  535. X        /*
  536. X         * Check for symmetry about the X-Axis.  If we have symmetry,
  537. X         * get the line number of the symmetrical line.  Do this here
  538. X         * so that we will mark the line of symmetry as being drawn
  539. X         * before sending out the next line to compute.
  540. X         */
  541. X        if (draw_it ) {
  542. X            /* get y-coordinate of symmetrical line */
  543. X            y = -line_y_coord (winp, line);
  544. X            if (y >= win_ymin (winp) && y <= win_ymax (winp)) {
  545. X                line2 = y_line_coord (winp, y);
  546. X
  547. X                if (line2 >= 0 && line2 < win_pheight (winp) &&
  548. X                    !clientp->drawn_line[line2])
  549. X                {
  550. X                    clientp->drawn_line[line2] = TRUE;
  551. X                    clientp->ndrawn_lines += 1;
  552. X                }
  553. X                else line2 = -1; /* don't draw line 2 */
  554. X            }
  555. X        }
  556. X
  557. X        /* send a new line out quickly */
  558. X        client_send (clientp, conp, winp);
  559. X        if (!draw_it) return;
  560. X
  561. X        /* Compute flops used to calculate this line. */
  562. X        flops = 0;
  563. X        last_x = 0;
  564. X        for (i = 0; i < buflen; i++) {
  565. X            flops += clientp->buf[i].color
  566. X                    * (clientp->buf[i].x - last_x + 1);
  567. X            last_x = clientp->buf[i].x + 1;
  568. X        }
  569. X        clientp->flops += flops;
  570. X        conp->flops += flops;
  571. X
  572. X        /* draw the line on the screen */
  573. X        win_render_line (winp, clientp->buf, buflen, line);
  574. X
  575. X        if (line2 != -1) { /* draw the symmetrical line? */
  576. X            win_rerender_line (winp, line2);
  577. X        }
  578. X    }
  579. X}
  580. X
  581. X/*
  582. X * Resume a client wherever we left off.  We wait for a server
  583. X * to report that she has finished computing a line.  We then
  584. X * draw the line and farm out a new line, if we have one available.
  585. X *
  586. X * When we receive a line from a client, or when a timeout expires,
  587. X * we will give control to our caller so that user input can be processed.
  588. X */
  589. X
  590. Xint
  591. Xclient_resume (clientp, winp)
  592. Xclient_info_t *clientp;
  593. Xchar *winp;
  594. X{
  595. X    fd_set read_set;
  596. X    struct timeval tv;
  597. X    int nfound;
  598. X    int max_fd;
  599. X    int buflen;
  600. X    int i;
  601. X
  602. X    tv.tv_sec = 1; /* init timeout */
  603. X    tv.tv_usec = 0;
  604. X
  605. X    read_set = clientp->open_set;
  606. X#if 0
  607. X(void) fprintf (stderr, "before read_set=0x%x, max_fd=%d\n",
  608. X        ((int *)(&read_set))[0], clientp->max_fd);
  609. X#endif
  610. X    nfound = select (clientp->max_fd+1, &read_set, (fd_set *)NULL,
  611. X            (fd_set *)NULL, &tv);
  612. X#if 0
  613. X(void) fprintf (stderr, "after read_set=0x%x, max_fd=%d\n",
  614. X        ((int *)(&read_set))[0], clientp->max_fd);
  615. X#endif
  616. X
  617. X    if (nfound < 0) {
  618. X        perror ("client_resume: select failed");
  619. X        exit (1);
  620. X    }
  621. X
  622. X    /* scan for events */
  623. X    for (i = 0; i < clientp->ncon && nfound; i++) {
  624. X        if (!FD_ISSET (clientp->con[i].sock, &read_set)) {
  625. X            continue;
  626. X        }
  627. X
  628. X        nfound -= 1;
  629. X        client_recv (clientp, &(clientp->con[i]), winp);
  630. X    }
  631. X
  632. X    if (clientp->ndrawn_lines < win_pheight (winp)) {
  633. X        return TRUE; /* resume later */
  634. X    }
  635. X    else {
  636. X        time_t elapsed;
  637. X
  638. X        /*
  639. X         * Report the flops rating.
  640. X         */
  641. X        elapsed = time ((time_t *)0) - clientp->start_time;
  642. X        if (elapsed == 0) elapsed = 1; /* a little white lie */
  643. X
  644. X        (void) printf ("Megaflops: %10.2f\n",
  645. X            (clientp->flops  * 9.0) / (elapsed * 1000000.0));
  646. X
  647. X        for (i = 0; i < clientp->ncon; i++) {
  648. X            (void) printf ("%16s: %10.2f\n",
  649. X                clientp->con[i].host,
  650. X                (clientp->con[i].flops * 9.0)
  651. X                    / (elapsed * 1000000.0));
  652. X        }
  653. X        (void) fflush (stdout);
  654. X
  655. X
  656. X        return FALSE; /* tell caller we need a new window */
  657. X    }
  658. X}
  659. //E*O*F client.c//
  660.  
  661. echo x - gui.c
  662. sed -e 's/^X//' > "gui.c" << '//E*O*F gui.c//'
  663. X/*
  664. X * Mandel by Rob Swiston and Chuck Simmons
  665. X * Copyright (C) 1989, 1990 by Rob Swiston and Chuck Simmons
  666. X *
  667. X * This program is free software; you can redistribute it and/or modify
  668. X * it under the terms of version 1 of the GNU General Public License as
  669. X * published by the Free Software Foundation.
  670. X *
  671. X * This program is distributed in the hope that it will be useful,
  672. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  673. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  674. X * GNU General Public License for more details.
  675. X *
  676. X * You should have received a copy of the GNU General Public License
  677. X * along with this program; if not, write to the Free Software
  678. X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  679. X */
  680. X
  681. X/*
  682. X * This file contains all the routines used to implement the
  683. X * graphical user interface.  The complete user interface is
  684. X * implemented in this file.  If you want to change windowing
  685. X * systems, you need to rewrite this file.
  686. X *
  687. X * This file interfaces with the client server.  From the user
  688. X * interface, we can call routines to initialize the client,
  689. X * reset the client to operate with a new window, and resume the
  690. X * client to continue operating with an existing window.
  691. X *
  692. X * The client can in turn call some of the routines in this file
  693. X * to draw on the current window.
  694. X */
  695. X
  696. X#include <stdio.h>
  697. X#include <X11/Xos.h>
  698. X#include <X11/Xlib.h>
  699. X#include <X11/Xutil.h>
  700. X#include <X11/Xatom.h>
  701. X#include <X11/cursorfont.h>
  702. X
  703. X#ifdef apollo
  704. X# include </sys5.3/usr/include/math.h>
  705. X#else
  706. X# include <math.h>
  707. X#endif
  708. X
  709. X#include "mandel.h"
  710. X#include "gui.h"
  711. X#include "client.h"
  712. X
  713. X/* Don't include 'malloc.h' since it doesn't exist on BSD systems. */
  714. Xchar *malloc ();
  715. Xvoid  free ();
  716. X
  717. X/* Let's not take a chance with 'string(s).h'. */
  718. Xchar *strchr ();
  719. X
  720. X/* pointers to graphics argument strings */
  721. Xchar  *arg_display = 0;
  722. Xchar  *arg_geometry = 0;
  723. Xint    arg_use_root = 0;
  724. Xint    arg_iterations = 256;
  725. Xdouble arg_x_center = 0.0;
  726. Xdouble arg_y_center = 0.0;
  727. Xdouble arg_pix_size = 4.0 / HPIXELS;
  728. Xint    arg_mud_num = 3;
  729. Xdouble arg_mud_max = 0.60;
  730. Xchar  *arg_colorfile = 0;
  731. Xint    arg_show_time = 0;
  732. X
  733. Xchar *prog_name;
  734. X
  735. Xtypedef struct loc {
  736. X    int x, y; /* coordinates of a pixel */
  737. X} loc_t;
  738. X
  739. X/* Define a context area for holding information about a display area. */
  740. Xtypedef struct win_info {
  741. X    Display *dsp;
  742. X    Window win;
  743. X    union { Pixmap p; Window w; } pix; /* holds the image */
  744. X    GC gc; /* graphics context */
  745. X    XImage *image; /* imaging buffer */
  746. X    int color_len; /* last pixel in colormap we can use */
  747. X    unsigned long *pixels;
  748. X    Cursor busy; /* cursor to use when computing */
  749. X    Cursor nbusy; /* cursor to use when not computing */
  750. X    int black, white; /* black and white pixels */
  751. X
  752. X    /* describe the imaging area */
  753. X    int hpixels, vpixels; /* size of display area in pixels */
  754. X    double x, y; /* center of display area */
  755. X    double pix_size; /* size of a pixel */
  756. X
  757. X    /* The following is used when drawing on the root window. */
  758. X#define SAVE_LIST_LEN 1
  759. X    loc_t black_list[SAVE_LIST_LEN];
  760. X    loc_t color_list[SAVE_LIST_LEN];
  761. X    int black_num; /* number of items in black_list */
  762. X    int color_num; /* number of items in color_list */
  763. X} win_info_t;
  764. X
  765. X/*
  766. X * The following routines exist to hide information from the client
  767. X * routine.
  768. X */
  769. X
  770. X/* width and height of window in pixels */
  771. X#define W_PWIDTH(w)  ((w)->hpixels)
  772. X#define W_PHEIGHT(w) ((w)->vpixels)
  773. X
  774. X/* width and height in real numbers */
  775. X#define W_RWIDTH(w)  ((w)->hpixels * (w)->pix_size)
  776. X#define W_RHEIGHT(w) ((w)->vpixels * (w)->pix_size)
  777. X
  778. X/* co-ordinates of window edges */
  779. X#define W_XMIN(w)    ((w)->x - W_RWIDTH(w) / 2)
  780. X#define W_XMAX(w)    ((w)->x + W_RWIDTH(w) / 2)
  781. X#define W_YMIN(w)    ((w)->y - W_RHEIGHT(w) / 2)
  782. X#define W_YMAX(w)    ((w)->y + W_RHEIGHT(w) / 2)
  783. X
  784. Xint win_pwidth  (winp) win_info_t *winp; { return W_PWIDTH (winp); }
  785. Xint win_pheight (winp) win_info_t *winp; { return W_PHEIGHT (winp); }
  786. X
  787. X/* 'real' co-ordinates of upper-left and lower-right of window */
  788. Xdouble win_xmin (winp) win_info_t *winp; { return W_XMIN (winp); }
  789. Xdouble win_xmax (winp) win_info_t *winp; { return W_XMAX (winp); }
  790. Xdouble win_ymin (winp) win_info_t *winp; { return W_YMIN (winp); }
  791. Xdouble win_ymax (winp) win_info_t *winp; { return W_YMAX (winp); }
  792. X
  793. X/* 'real' width and height */
  794. Xdouble win_rwidth  (winp) win_info_t *winp; { return W_RWIDTH (winp); }
  795. Xdouble win_rheight (winp) win_info_t *winp; { return W_RHEIGHT (winp); }
  796. X
  797. X/* maximum width and height */
  798. Xint
  799. Xwin_max_width (winp)
  800. Xwin_info_t *winp;
  801. X{
  802. X    return DisplayWidth (winp->dsp, DefaultScreen (winp->dsp));
  803. X}
  804. X
  805. Xint
  806. Xwin_max_height (winp)
  807. Xwin_info_t *winp;
  808. X{
  809. X    return DisplayHeight (winp->dsp, DefaultScreen (winp->dsp));
  810. X}
  811. X
  812. X#define OPTIONS "c:d:g:i:m:n:p:rs:x:y:"
  813. X
  814. Xvoid
  815. Xusage (err)
  816. Xchar *err;
  817. X{
  818. X    if (err) fprintf (stderr, "%s: %s\n", prog_name, err);
  819. X    fprintf (stderr, "Usage: %s [options...]\n", prog_name);
  820. X    fprintf (stderr, "where options include:\n");
  821. X    fprintf (stderr, "    -c colorfile        file of colors to use\n");
  822. X    fprintf (stderr, "    -d host:display     X server to use\n");
  823. X    fprintf (stderr, "    -g geometry         size of window\n");
  824. X    fprintf (stderr, "    -i count            iteration count\n");
  825. X    fprintf (stderr, "    -m mud_max          max val for muddy colors\n");
  826. X    fprintf (stderr, "    -n mud_num          # of muddy colors per hue\n");
  827. X    fprintf (stderr, "    -p pixel_size       size of a pixel\n");
  828. X    fprintf (stderr, "    -r                  draw on root window\n");
  829. X    fprintf (stderr, "    -s show_time        show initial color map\n");
  830. X    fprintf (stderr, "    -x x                x coord of center\n");
  831. X    fprintf (stderr, "    -y y                y coord of center\n");
  832. X    exit (1);
  833. X}
  834. X
  835. Xvoid
  836. Xparse_args (argc, argv)
  837. Xint argc;
  838. Xchar **argv;
  839. X{
  840. X    extern char *optarg;
  841. X    extern int optind;
  842. X
  843. X    int c;
  844. X
  845. X    prog_name = argv[0];
  846. X
  847. X    while ((c = getopt (argc, argv, OPTIONS)) != -1) {
  848. X    switch (c) {
  849. X    case 'c': arg_colorfile = optarg; break;
  850. X    case 'd': arg_display   = optarg; break;
  851. X    case 'g': arg_geometry  = optarg; break;
  852. X
  853. X    case 'i':
  854. X        arg_iterations = strtol (optarg, (char *)0, 0);
  855. X        if (arg_iterations <= 0) {
  856. X        usage ("-i argument must be positive.");
  857. X        }
  858. X        break;
  859. X
  860. X    case 'm':
  861. X        arg_mud_max = atof (optarg);
  862. X        if (arg_mud_max < 0.0 || arg_mud_max > 1.0) {
  863. X        usage ("-m argument must be in 0.0 .. 1.0.");
  864. X        }
  865. X        break;
  866. X
  867. X    case 'n':
  868. X        arg_mud_num = strtol (optarg, (char *)0, 0);
  869. X        if (arg_mud_num <= 0) {
  870. X        usage ("-n argument must be positive.");
  871. X        }
  872. X        break;
  873. X
  874. X    case 'p':
  875. X        arg_pix_size = atof (optarg);
  876. X        if (arg_pix_size <= 0.0) {
  877. X        usage ("-p argument must be positive.");
  878. X        }
  879. X        break;
  880. X
  881. X    case 'r': arg_use_root = 1; break;
  882. X
  883. X    case 's':
  884. X        arg_show_time = strtol (optarg, (char *)0, 0);
  885. X        if (arg_show_time <= 0) {
  886. X        usage ("-s argument must be positive.");
  887. X        }
  888. X            break;
  889. X
  890. X    case 'x': arg_x_center = atof (optarg); break;
  891. X    case 'y': arg_y_center = atof (optarg); break;
  892. X
  893. X    default:
  894. X        {
  895. X        char buf[80];
  896. X        (void) sprintf (buf, "Unrecognized argument '%s'.", optarg);
  897. X        usage (buf);
  898. X        }
  899. X        }
  900. X    }
  901. X
  902. X    if (optind != argc) {
  903. X    usage ("Unrecognized argument '%s'.", argv[optind]);
  904. X    }
  905. X}
  906. X
  907. X/*
  908. X * Given the integer coordinates of a pixel location, make that pixel
  909. X * the center of our image.
  910. X */
  911. X
  912. Xvoid
  913. Xwin_new_center (winp, ix, iy)
  914. Xwin_info_t *winp;
  915. Xint ix, iy;
  916. X{
  917. X    winp->x += winp->pix_size * 0.5 * (2 * ix - winp->hpixels);
  918. X    winp->y += winp->pix_size * 0.5 * (2 * iy - winp->vpixels);
  919. X}
  920. X
  921. X/*
  922. X * Here, the client has just finished generating the image for the
  923. X * root window.  Display the picture and choose new co-ordinates.
  924. X * To choose new co-ordinates, we select two locations at random,
  925. X * such that one location is in the set and one location is out
  926. X * of the set.  These locations become our new coordinates.  The
  927. X * new co-ordinates are selected from within the current co-ordinates.
  928. X * After zooming in for awhile, we begin zooming out.
  929. X */
  930. X
  931. X#define MAX_ROOT_ZOOM_DEPTH 16
  932. X
  933. Xvoid
  934. Xwin_new_root (winp)
  935. Xwin_info_t *winp;
  936. X{
  937. X    static int depth = 0; /* how far in we are */
  938. X    static int dir = 1;
  939. X
  940. X    XSetWindowBackgroundPixmap (winp->dsp, winp->win, winp->pix.p);
  941. X    XClearWindow (winp->dsp, winp->win);
  942. X    XFreePixmap (winp->dsp, winp->pix.p);
  943. X
  944. X    winp->pix.p = XCreatePixmap (winp->dsp, winp->win,
  945. X             winp->hpixels, winp->vpixels,
  946. X             DefaultDepth (winp->dsp, DefaultScreen (winp->dsp)));
  947. X
  948. X    XSync (winp->dsp, False);
  949. X    sleep (1);
  950. X
  951. X    if (dir == -1 ) {
  952. X    /*
  953. X     * Zoom out.  Leave the center where it is, but make the pixels
  954. X     * bigger.
  955. X     */
  956. X    winp->pix_size *= 3;
  957. X
  958. X    depth -= 1;
  959. X    if (depth == 0) dir = 1;
  960. X    }
  961. X    else {
  962. X    /*
  963. X     * Zoom in on a desirable point.  Make the desirable point the
  964. X     * center of the image, and make the pixels smaller.
  965. X     */
  966. X    int ix, iy;
  967. X
  968. X    /* get integer coords of pixel */
  969. X    ix = (winp->black_list[0].x + winp->color_list[0].x) / 2;
  970. X    iy = (winp->black_list[0].y + winp->color_list[0].y) / 2;
  971. X
  972. X    win_new_center (winp, ix, iy);
  973. X    winp->pix_size /= 3;
  974. X
  975. X    depth += 1;
  976. X        if (depth == MAX_ROOT_ZOOM_DEPTH) dir = -1;
  977. X    }
  978. X}
  979. X
  980. Xint
  981. Xmain (argc, argv)
  982. Xint argc;
  983. Xchar **argv;
  984. X{
  985. X    win_info_t *win_create();
  986. X    void win_set_lr();
  987. X
  988. X    win_info_t *winp;
  989. X    char *client_ctx;
  990. X    int resume;
  991. X
  992. X    parse_args (argc, argv);
  993. X    winp = win_create ();
  994. X
  995. X    winp->x = arg_x_center;
  996. X    winp->y = arg_y_center;
  997. X    winp->pix_size = arg_pix_size;
  998. X
  999. X    client_ctx = client_init (winp);
  1000. X
  1001. X    resume = 0;
  1002. X    for (;;) {
  1003. X        /* Let the client run. */
  1004. X        if (resume) {
  1005. X            resume = client_resume (client_ctx, winp);
  1006. X        }
  1007. X        else {
  1008. X                /*
  1009. X             * Here, user has asked for a new window.
  1010. X             */
  1011. X            XClearWindow (winp->dsp, winp->win);
  1012. X            (void) printf ("%s: window at (%g,%g) pix_size=%g\n",
  1013. X                       argv[0], winp->x, winp->y,
  1014. X                       winp->pix_size);
  1015. X            (void) fflush (stdout);
  1016. X
  1017. X            resume = client_reset (client_ctx, winp);
  1018. X        }
  1019. X
  1020. X        if (!arg_use_root) { /* interact with user */
  1021. X            resume = win_handle_user (winp, resume);
  1022. X        }
  1023. X        else if (!resume) { /* client is done with window */
  1024. X            win_new_root (winp);
  1025. X        }
  1026. X        else sleep (0); /* don't hog the processor */
  1027. X    }
  1028. X}
  1029. X
  1030. X/*
  1031. X * Given a window, change the pixel width and height of the window.
  1032. X * We are given a desired width and height.  If possible, we will
  1033. X * use this width and height.  However, if the width and height
  1034. X * would cause the window to fall off the edge of the screen, then
  1035. X * we will reduce the width and height proportionately.
  1036. X *
  1037. X * Return 1 if we change the width/height; 0 the width/height stay the
  1038. X * same; and -1 if the window would become real small.
  1039. X *
  1040. X * All resizing requests should probably be routed through this
  1041. X * routine.
  1042. X */
  1043. X
  1044. Xint
  1045. Xwin_set_wh (winp, w, h)
  1046. Xwin_info_t *winp;
  1047. Xint w, h; /* target width and height */
  1048. X{
  1049. X    int scr;
  1050. X    int dw, dh; /* display width and height */
  1051. X    int new_x, new_y;
  1052. X    XWindowAttributes win_attr;
  1053. X    XSizeHints hints;
  1054. X
  1055. X    scr = DefaultScreen (winp->dsp);
  1056. X
  1057. X    dw = DisplayWidth (winp->dsp, scr);
  1058. X    dh = DisplayHeight (winp->dsp, scr);
  1059. X
  1060. X    if (w > dw) {
  1061. X        h = (h * dw) / w; /* preserve shape of window */
  1062. X        w = dw;
  1063. X    }
  1064. X    if (h > dh) {
  1065. X        w = (w * dh) / h;
  1066. X        h = dh;
  1067. X    }
  1068. X
  1069. X    if (w == winp->hpixels && h == winp->vpixels) return 0;
  1070. X    if (w < 4 || h < 4) return -1; /* don't get too small */
  1071. X
  1072. X    winp->hpixels = w;
  1073. X    winp->vpixels = h;
  1074. X
  1075. X    /* Adjust the window's size.  If necessary, move the window. */
  1076. X    XResizeWindow (winp->dsp, winp->win, winp->hpixels, winp->vpixels);
  1077. X    XGetWindowAttributes (winp->dsp, winp->win, &win_attr);
  1078. X
  1079. X    new_x = dw - winp->hpixels;
  1080. X    new_y = dh - winp->vpixels;
  1081. X    if (win_attr.x > new_x || win_attr.y > new_y) {
  1082. X        if (win_attr.x < new_x) new_x = win_attr.x;
  1083. X        if (win_attr.y < new_y) new_y = win_attr.y;
  1084. X
  1085. X        XMoveWindow (winp->dsp, winp->win, new_x, new_y);
  1086. X
  1087. X        win_attr.x = new_x;
  1088. X        win_attr.y = new_y;
  1089. X    }
  1090. X
  1091. X    /*
  1092. X     * Tell the window manager what we did.  Note:  problems
  1093. X     * may or may not occur if the window manager refuses our
  1094. X     * request.
  1095. X     */
  1096. X    hints.x = win_attr.x;
  1097. X    hints.y = win_attr.y;
  1098. X    hints.width = winp->hpixels;
  1099. X    hints.height = winp->vpixels;
  1100. X    hints.flags = USPosition | USSize; /* the user specified these */
  1101. X    XSetNormalHints (winp->dsp, winp->win, &hints);
  1102. X
  1103. X    /*
  1104. X     * Now, wait for the configuration notify event.  Toss all
  1105. X     * other events in the meantime.
  1106. X     */
  1107. X    for (;;) {
  1108. X        XEvent event;
  1109. X
  1110. X        XNextEvent (winp->dsp, &event);
  1111. X
  1112. X        if (event.type == ConfigureNotify
  1113. X            && event.xconfigure.window == winp->win)
  1114. X        {
  1115. X            /* set width and height to actual values */
  1116. X            winp->hpixels = event.xconfigure.width;
  1117. X            winp->vpixels = event.xconfigure.height;
  1118. X            break;
  1119. X        }
  1120. X    }
  1121. X
  1122. X    return 1;
  1123. X}
  1124. X
  1125. X/*
  1126. X * Given a window and co-ordinates of a box within that window,
  1127. X * adjust the X and Y co-ordinates of the window, and resize the
  1128. X * window to the new shape.  Note that the box may actually overlap
  1129. X * the window.
  1130. X *
  1131. X * Return TRUE if we actually change something.  Don't change anything
  1132. X * if the new co-ordinates would require either a zero width or a
  1133. X * zero height.
  1134. X */
  1135. X
  1136. Xint
  1137. Xwin_set_box (winp, x1, y1, x2, y2)
  1138. Xwin_info_t *winp;
  1139. Xint x1, y1, x2, y2; /* pixel locations of the box */
  1140. X{
  1141. X    int ix, iy; /* center pixel of box */
  1142. X    double old_x, old_y;
  1143. X    double new_area, old_area;
  1144. X    double scale;
  1145. X    int t;
  1146. X
  1147. X    if ((x1 == x2) || (y1 == y2)) return FALSE;
  1148. X
  1149. X    /* get length of sides */
  1150. X    ix = x1 - x2;
  1151. X    if (ix < 0) ix = -ix;
  1152. X
  1153. X    iy = y1 - y2;
  1154. X    if (iy < 0) iy = -iy;
  1155. X
  1156. X    /* Change the shape of the window.  Preserve the area. */
  1157. X    old_area = winp->hpixels * winp->vpixels;
  1158. X    new_area = ix * iy;
  1159. X    scale = old_area / new_area;
  1160. X    scale = sqrt (scale);
  1161. X
  1162. X    old_x = winp->x;
  1163. X    old_y = winp->y;
  1164. X    win_new_center (winp, (x1 + x2) / 2, (y1 + y2) / 2);
  1165. X
  1166. X    t = win_set_wh (winp, (int)(ix * scale), (int)(iy * scale));
  1167. X    if (t == -1) {
  1168. X    winp->x = old_x; /* restore old center */
  1169. X    winp->y = old_y;
  1170. X    return FALSE;
  1171. X    }
  1172. X
  1173. X    winp->pix_size /= scale;
  1174. X
  1175. X    return TRUE;
  1176. X}
  1177. X
  1178. X/*
  1179. X * Handle user requests.  If 'resume' is TRUE, we need to
  1180. X * return as quickly as possible.  If 'resume' is false,
  1181. X * we return when we have something more to compute.
  1182. X *
  1183. X * Return TRUE if the client can resume drawing in the window.
  1184. X * If we modify the window, the client cannot resume.
  1185. X */
  1186. X
  1187. Xint
  1188. Xwin_handle_user (winp, resume)
  1189. Xwin_info_t *winp;
  1190. Xint resume;
  1191. X{
  1192. X    int win_new_box ();
  1193. X
  1194. X    XEvent event;
  1195. X    char key;
  1196. X    int i;
  1197. X
  1198. X    for (;;) {
  1199. X        /* Get an event. */
  1200. X        if (resume) {
  1201. X            if (!XCheckWindowEvent (winp->dsp, winp->win,
  1202. X                KeyPressMask | ButtonPressMask
  1203. X                | ButtonReleaseMask | ButtonMotionMask
  1204. X                | PointerMotionHintMask
  1205. X                | StructureNotifyMask,
  1206. X                &event))
  1207. X            {
  1208. X                return TRUE;
  1209. X            }
  1210. X        }
  1211. X        else {
  1212. X            XNextEvent (winp->dsp, &event);
  1213. X        }
  1214. X
  1215. X        switch (event.type) {
  1216. X        case ConfigureNotify:
  1217. X            /*
  1218. X             * See if the window has been resized.
  1219. X             */
  1220. X            if (event.xconfigure.window == winp->win
  1221. X                && (event.xconfigure.width != winp->hpixels
  1222. X                    || event.xconfigure.height != winp->vpixels))
  1223. X            {
  1224. X                /* use the width/height we've been given */
  1225. X                winp->hpixels = event.xconfigure.width;
  1226. X                winp->vpixels = event.xconfigure.height;
  1227. X                return FALSE; /* can't resume */
  1228. X            }
  1229. X            break;
  1230. X
  1231. X        case ButtonPress:
  1232. X            /*
  1233. X             * Get a new window.
  1234. X             */
  1235. X            if (win_new_box (winp, event.xbutton.x,
  1236. X                        event.xbutton.y))
  1237. X            {
  1238. X                return FALSE; /* can't resume */
  1239. X            }
  1240. X            break;
  1241. X
  1242. X        case KeyPress:
  1243. X            XLookupString (&event, &key, 1, NULL, NULL);
  1244. X            switch (key) {
  1245. X            case 'q': /* quit */
  1246. X                exit (0);
  1247. X                /* NOTREACHED */
  1248. X
  1249. X            case 'z':
  1250. X                winp->pix_size *= 3;
  1251. X                return FALSE;
  1252. X
  1253. X            case 'e': /* expand window */ 
  1254. X                i = win_set_wh (winp, winp->hpixels * 2,
  1255. X                        winp->vpixels * 2);
  1256. X
  1257. X                if (i > 0) return FALSE; /* can't resume */
  1258. X                break;
  1259. X
  1260. X            case 's': /* shrink window */
  1261. X                i = win_set_wh (winp, winp->hpixels / 2,
  1262. X                        winp->vpixels / 2);
  1263. X                if (i > 0) return FALSE; /* can't resume */
  1264. X                break;
  1265. X            }
  1266. X        }
  1267. X    }
  1268. X}
  1269. X
  1270. X/*
  1271. X * The mouse button is currently depressed.  We follow the pointer
  1272. X * around drawing a box.  When the mouse is no longer depressed,
  1273. X * we attempt to update the window based on the shape and co-ordinates
  1274. X * of the new box.
  1275. X *
  1276. X * Return TRUE if we modify the window, otherwise FALSE.
  1277. X */
  1278. X
  1279. Xint
  1280. Xwin_new_box (winp, x1, y1)
  1281. Xwin_info_t *winp;
  1282. Xint x1, y1; /* starting corner of box */
  1283. X{
  1284. X    XEvent event;
  1285. X    int x2, y2; /* second corner of box */
  1286. X    int first_time = 1;
  1287. X
  1288. X    XSetFunction (winp->dsp, winp->gc, GXxor);
  1289. X    XSetForeground (winp->dsp, winp->gc, -1);
  1290. X    XSetBackground (winp->dsp, winp->gc, -1);
  1291. X
  1292. X    for (;;) {
  1293. X        XNextEvent (winp->dsp, &event);
  1294. X        switch (event.type) {
  1295. X        case ButtonRelease:
  1296. X            /*
  1297. X             * We have selected a new window.  Reset the
  1298. X             * window and save the co-ordinates.
  1299. X             */
  1300. X            /* erase current box */
  1301. X            if (!first_time) {
  1302. X                XDrawRectangle (winp->dsp, winp->win,
  1303. X                    winp->gc, x1, y1, x2-x1, y2-y1);
  1304. X            }
  1305. X
  1306. X            x2 = event.xbutton.x;
  1307. X            y2 = event.xbutton.y;
  1308. X
  1309. X            /* reset drawing mode */
  1310. X            XSetFunction (winp->dsp, winp->gc, GXcopy);
  1311. X
  1312. X            /* Compute new co-ordinates and resize window. */
  1313. X            return win_set_box (winp, x1, y1, x2, y2);
  1314. X
  1315. X        case MotionNotify: {
  1316. X            /*
  1317. X             * Redraw our box.
  1318. X             */
  1319. X
  1320. X            Window root, child;
  1321. X            int root_x, root_y, win_x, win_y;
  1322. X            unsigned int keys_buttons;
  1323. X
  1324. X            while (XCheckMaskEvent (winp->dsp, ButtonMotionMask,
  1325. X                    &event));
  1326. X
  1327. X            if (!XQueryPointer (winp->dsp, event.xmotion.window,
  1328. X                &root, &child, &root_x, &root_y,
  1329. X                &win_x, &win_y, &keys_buttons))
  1330. X            {
  1331. X                break; /* not in this window */
  1332. X            }
  1333. X
  1334. X            /* undraw the previous box, if it exists */
  1335. X            if (!first_time) {
  1336. X                XDrawRectangle (winp->dsp, winp->win,
  1337. X                    winp->gc, x1, y1, x2-x1, y2-y1);
  1338. X            }
  1339. X
  1340. X            x2 = win_x;
  1341. X            y2 = win_y;
  1342. X
  1343. X            /* draw new box */
  1344. X            first_time = 0;
  1345. X            XDrawRectangle (winp->dsp, winp->win,
  1346. X                winp->gc, x1, y1, x2-x1, y2-y1);
  1347. X            break;
  1348. X            }
  1349. X        }
  1350. X    }
  1351. X}
  1352. X
  1353. X/*
  1354. X * Create the initial window.
  1355. X */
  1356. X
  1357. Xwin_info_t *
  1358. Xwin_create ()
  1359. X{
  1360. X    Colormap init_color_map ();
  1361. X    Colormap read_color_map ();
  1362. X    void win_display_colormap ();
  1363. X
  1364. X    win_info_t *winp;
  1365. X    int scr;
  1366. X    Colormap cmap;
  1367. X    XSetWindowAttributes xswa;
  1368. X    XColor black, white;
  1369. X    XWMHints wm_hints;
  1370. X    int winX, winY, winH, winW;
  1371. X        int cursor_shape1 = XC_watch;
  1372. X        int cursor_shape2 = XC_top_left_arrow;
  1373. X    int bufsize;
  1374. X    int i;
  1375. X
  1376. X    winp = (win_info_t *) malloc (sizeof (*winp));
  1377. X    if (!winp) {
  1378. X        (void) fprintf (stderr, "win_create: Out of memory.\n");
  1379. X        exit (1);
  1380. X    }
  1381. X
  1382. X    winp->dsp = XOpenDisplay (arg_display);
  1383. X    if (!winp->dsp) {
  1384. X        perror ("win_create: Cannot open display.");
  1385. X        exit (1);
  1386. X    }
  1387. X
  1388. X    scr = DefaultScreen (winp->dsp);
  1389. X
  1390. X    if (arg_colorfile) {
  1391. X        cmap = read_color_map (winp);
  1392. X        if (winp->color_len <= 1) {
  1393. X            if (winp->pixels) free ((char *)winp->pixels);
  1394. X            cmap = init_color_map (winp);
  1395. X        }
  1396. X    }
  1397. X    else cmap = init_color_map (winp);
  1398. X
  1399. X    black.pixel = BlackPixel (winp->dsp, scr);
  1400. X    if (!arg_use_root) XQueryColor (winp->dsp, cmap, &black);
  1401. X    winp->black = black.pixel;
  1402. X
  1403. X    white.pixel = WhitePixel (winp->dsp, scr);
  1404. X    if (!arg_use_root) XQueryColor (winp->dsp, cmap, &white);
  1405. X    winp->white = white.pixel;
  1406. X
  1407. X    if (arg_use_root) { /* let's be a background pattern... */
  1408. X        winp->win = DefaultRootWindow (winp->dsp);
  1409. X        winX = 0;
  1410. X        winY = 0;
  1411. X        winW = DisplayWidth  (winp->dsp, scr);
  1412. X        winH = DisplayHeight (winp->dsp, scr);
  1413. X        winp->gc = DefaultGC (winp->dsp, scr);
  1414. X
  1415. X        /*
  1416. X         * Buffer the image in a pixmap.
  1417. X         */
  1418. X        winp->pix.p = XCreatePixmap (winp->dsp, winp->win,
  1419. X                         winW, winH,
  1420. X                         DefaultDepth (winp->dsp, scr));
  1421. X    }
  1422. X    else {
  1423. X        winW = HPIXELS;
  1424. X        winH = VPIXELS;
  1425. X        winX = 0;
  1426. X        winY = 0;
  1427. X
  1428. X        if (arg_geometry) {
  1429. X            XParseGeometry (arg_geometry, &winX, &winY,
  1430. X                            &winW, &winH);
  1431. X        }
  1432. X
  1433. X        xswa.event_mask = 0;
  1434. X        xswa.background_pixel = black.pixel;
  1435. X        xswa.backing_store = WhenMapped;
  1436. X
  1437. X        winp->win = XCreateWindow (winp->dsp,
  1438. X            RootWindow (winp->dsp, scr),
  1439. X            winX, winY, winW, winH, 0,
  1440. X            DefaultDepth (winp->dsp, scr), InputOutput,
  1441. X            DefaultVisual (winp->dsp, scr),
  1442. X            CWEventMask | CWBackPixel | CWBackingStore,
  1443. X            &xswa);
  1444. X
  1445. X        /* Tell the window manager about ourself. */
  1446. X        XStoreName (winp->dsp, winp->win, "Mandel");
  1447. X        XSetIconName (winp->dsp, winp->win, "Mandel");
  1448. X
  1449. X        wm_hints.input = True; /* passive input */
  1450. X        wm_hints.initial_state = NormalState;
  1451. X        wm_hints.flags = InputHint | StateHint;
  1452. X        XSetWMHints (winp->dsp, winp->win, &wm_hints);
  1453. X
  1454. X        XMapWindow (winp->dsp, winp->win);
  1455. X        XSync (winp->dsp, False);
  1456. X    
  1457. X        XSelectInput (winp->dsp, winp->win,
  1458. X            KeyPressMask | ButtonPressMask | ButtonReleaseMask
  1459. X            | StructureNotifyMask | ButtonMotionMask
  1460. X            | PointerMotionHintMask);
  1461. X
  1462. X        winp->gc = XCreateGC (winp->dsp, winp->win, 0, NULL);
  1463. X
  1464. X        /*
  1465. X         * Render the image directly to the screen.
  1466. X         */
  1467. X        winp->pix.w = winp->win;
  1468. X
  1469. X        winp->busy = XCreateFontCursor (winp->dsp, cursor_shape1);
  1470. X        winp->nbusy = XCreateFontCursor (winp->dsp, cursor_shape2);
  1471. X        XDefineCursor (winp->dsp, winp->win, winp->nbusy);
  1472. X    }
  1473. X
  1474. X    winp->hpixels = winW;
  1475. X    winp->vpixels = winH;
  1476. X
  1477. X    winp->black_num = winp->color_num = 0; /* empty */
  1478. X    for (i = 0; i < SAVE_LIST_LEN; i++) {
  1479. X        winp->black_list[i].x =
  1480. X        winp->black_list[i].y =
  1481. X        winp->color_list[i].x =
  1482. X        winp->color_list[i].y = 0;
  1483. X    }
  1484. X
  1485. X    XSetForeground (winp->dsp, winp->gc, white.pixel);
  1486. X    XSetBackground (winp->dsp, winp->gc, black.pixel);
  1487. X    XSetFunction (winp->dsp, winp->gc, GXcopy);
  1488. X
  1489. X    /*
  1490. X     * Having problems on the Sun.  Put in a clear and sync
  1491. X     * in an attempt to delay some messages.
  1492. X     */
  1493. X    sleep (1);
  1494. X    XClearWindow (winp->dsp, winp->win);
  1495. X    XSync (winp->dsp, False);
  1496. X
  1497. X    if (arg_show_time) win_display_colormap (winp);
  1498. X
  1499. X    /*
  1500. X     * Allocate a buffer area for imaging.  The purpose of this
  1501. X     * buffer is to reduce the amount of work required from the
  1502. X     * XServer.  We allocate a buffer one line high and the
  1503. X     * full width of the screen.
  1504. X     *
  1505. X     * Note:  We use an XYPixmap because the Apollo workstations
  1506. X     * seem to have problems with ZPixmaps.
  1507. X     */
  1508. X#define USE_ZPIXMAP
  1509. X    winp->image = XCreateImage (winp->dsp, 
  1510. X            DefaultVisual (winp->dsp, scr),
  1511. X            DefaultDepth (winp->dsp, scr),
  1512. X#ifdef USE_ZPIXMAP
  1513. X            ZPixmap,
  1514. X#else
  1515. X            XYPixmap,
  1516. X#endif
  1517. X            0, /* offset to first pixel */
  1518. X            (char *) 0, /* pointer to image data */
  1519. X            DisplayWidth  (winp->dsp, scr),
  1520. X            1, /* height of image */
  1521. X            32, /* alignment of scan lines */
  1522. X            0);
  1523. X    if (!winp->image) {
  1524. X        (void) fprintf (stderr,
  1525. X            "win_create: Cannot allocate image.\n");
  1526. X        exit (1);
  1527. X    }
  1528. X#if 1
  1529. X    winp->image->byte_order = 0;
  1530. X    winp->image->bitmap_bit_order = 0;
  1531. X#endif
  1532. X
  1533. X    /* Allocate a data area for the image. */
  1534. X#ifdef USE_ZPIXMAP
  1535. X    /* use this calculation for ZPixmap format */
  1536. X    bufsize = winp->image->bytes_per_line;
  1537. X#else
  1538. X    /* use this calculation for XYPixmap format */
  1539. X    bufsize = winp->image->bytes_per_line * winp->image->depth;
  1540. X#endif
  1541. X    winp->image->data = malloc ((unsigned) bufsize);
  1542. X    if (!winp->image->data) {
  1543. X        (void) fprintf (stderr,
  1544. X          "win_create: Cannot allocate %d bytes for image data.\n",
  1545. X          bufsize);
  1546. X        exit (1);
  1547. X    }
  1548. X
  1549. X    return winp;
  1550. X}
  1551. X
  1552. X/*
  1553. X * Display the initial colormap.  We can handle up to 256 colors here.
  1554. X */
  1555. X
  1556. Xvoid
  1557. Xwin_display_colormap (winp)
  1558. Xwin_info_t *winp;
  1559. X{
  1560. X    int i;
  1561. X        int r, c;
  1562. X        int pixel;
  1563. X        for (i = 0; i < winp->color_len; i++) {
  1564. X                if (winp->pixels) pixel = winp->pixels[i];
  1565. X        else pixel = i;
  1566. X
  1567. X        c = i % 16;
  1568. X        r = i / 16;
  1569. X                XSetForeground (winp->dsp, winp->gc, pixel);
  1570. X                XFillRectangle (winp->dsp, winp->win, winp->gc,
  1571. X                        (winp->hpixels * c) / 16,
  1572. X                        (winp->vpixels * r) / 16,
  1573. X                        winp->hpixels / 16,
  1574. X                        winp->vpixels / 16);
  1575. X#if 0
  1576. X        /*
  1577. X         * On the 'sun', this doesn't seem to work unless
  1578. X         * we have this 'XSync' lying around.
  1579. X         */
  1580. X        XSync (winp->dsp, False);
  1581. X        sleep (1);
  1582. X#endif
  1583. X        }
  1584. X
  1585. X    XSync (winp->dsp, False);
  1586. X    sleep (arg_show_time);
  1587. X}
  1588. X
  1589. X/*
  1590. X * Read colors for the colormap from a file.  Return the colormap.
  1591. X */
  1592. X
  1593. X#define COLORLEN 80
  1594. X#define is_white(c) ((c) == ' ' || (c) == '\t')
  1595. X#define scan_white(p) while (*(p) && is_white(*(p))) (p) += 1
  1596. X#define scan_black(p) while (*(p) && !is_white(*(p))) (p) += 1
  1597. X
  1598. Xstatic Colormap
  1599. Xread_color_map (winp)
  1600. Xwin_info_t *winp;
  1601. X{
  1602. X    FILE *f;
  1603. X    char colorname[COLORLEN];
  1604. X    int scr;
  1605. X    int npixels;
  1606. X    int i;
  1607. X    Colormap cmap;
  1608. X    XColor xcolor;
  1609. X
  1610. X    scr = DefaultScreen (winp->dsp);
  1611. X
  1612. X    /* set initial length and offset */
  1613. X    winp->color_len = XDisplayCells (winp->dsp, scr);
  1614. X    winp->pixels = NULL;
  1615. X
  1616. X    cmap = XDefaultColormap (winp->dsp, scr);
  1617. X
  1618. X    /* open the file of color names */
  1619. X    f = fopen (arg_colorfile, "r");
  1620. X    if (!f) {
  1621. X        (void) fprintf (stderr,
  1622. X            "read_color_map: Cannot open file %s.\n",
  1623. X            arg_colorfile);
  1624. X        perror ("");
  1625. X        return cmap;
  1626. X    }
  1627. X
  1628. X    /* allocate pixel storage */
  1629. X    for (npixels = winp->color_len; npixels; npixels--) {
  1630. X        winp->pixels = (unsigned long *) malloc (
  1631. X                sizeof (*(winp->pixels)) * npixels);
  1632. X        if (winp->pixels) break;
  1633. X    }
  1634. X
  1635. X    if (!npixels) {
  1636. X        (void) fprintf (stderr,
  1637. X            "read_color_map: Can't allocate pixel storage.\n");
  1638. X        winp->color_len = 0;
  1639. X        return cmap;
  1640. X    }
  1641. X
  1642. X    /* read the colors */
  1643. X    for (i = 0; i < npixels; ) {
  1644. X        char *p, *start;
  1645. X
  1646. X        if (fgets (colorname, COLORLEN, f) == NULL) break;
  1647. X        p = strchr (colorname, ';');
  1648. X        if (!p) p = strchr (colorname, '\n');
  1649. X        if (p) *p = '\0'; /* toss end of line */
  1650. X
  1651. X        start = colorname;
  1652. X        scan_white (start); /* find start of string */
  1653. X
  1654. X        p = start;
  1655. X        scan_black (p); /* find end of string */
  1656. X        if (p == start) continue; /* empty line */
  1657. X
  1658. X        *p = '\0'; /* terminate the string */
  1659. X
  1660. X        if (!XParseColor (winp->dsp, cmap, start, &xcolor)) {
  1661. X            (void) fprintf (stderr,
  1662. X            "read_color_map: color name '%s' isn't in database.\n",
  1663. X                start);
  1664. X            continue;
  1665. X        }
  1666. X
  1667. X        if (!XAllocColor (winp->dsp, cmap, &xcolor)) {
  1668. X            /*
  1669. X             * Although we can't allocate any more colors,
  1670. X             * we may be able to share some already existing
  1671. X             * color.  Keep looping to give it a try.
  1672. X             */
  1673. X            continue;
  1674. X        }
  1675. X
  1676. X        winp->pixels[i] = xcolor.pixel;
  1677. X        i += 1;
  1678. X    }
  1679. X
  1680. X    winp->color_len = i; /* remember length of pixel array */
  1681. X
  1682. X    (void) fclose (f);
  1683. X    return cmap;
  1684. X}
  1685. X
  1686. X/*
  1687. X * Allocate a color map.
  1688. X */
  1689. X
  1690. Xstatic Colormap
  1691. Xinit_color_map (winp)
  1692. Xwin_info_t *winp;
  1693. X{
  1694. X    void convertHSI_to_RGB();
  1695. X
  1696. X    int scr;
  1697. X    Colormap cmap;
  1698. X    double hue, intensity, saturation;
  1699. X    int r, g, b;
  1700. X    XColor celldef;
  1701. X    int i;
  1702. X    int npixels;
  1703. X    double mud;
  1704. X    int m;
  1705. X    int dir;
  1706. X
  1707. X    scr = DefaultScreen (winp->dsp);
  1708. X
  1709. X    /* set initial length and offset */
  1710. X    winp->color_len = XDisplayCells (winp->dsp, scr);
  1711. X    winp->pixels = NULL;
  1712. X
  1713. X    cmap = XDefaultColormap (winp->dsp, scr);
  1714. X
  1715. X    /* allocate color map */
  1716. X    for (npixels = winp->color_len; npixels; npixels--) {
  1717. X        winp->pixels = (unsigned long *) malloc (
  1718. X                sizeof (*(winp->pixels)) * npixels);
  1719. X        if (!winp->pixels) continue;
  1720. X
  1721. X        if (!XAllocColorCells (winp->dsp, cmap, False,
  1722. X            (unsigned long *)0, 0,
  1723. X            winp->pixels, npixels))
  1724. X        {
  1725. X            free ((char *)winp->pixels);
  1726. X            continue;
  1727. X        }
  1728. X
  1729. X        break;
  1730. X    }
  1731. X
  1732. X    if (!npixels) {
  1733. X        (void) fprintf (stderr,
  1734. X            "init_color_map: Can't allocate colormap.\n");
  1735. X        return cmap;
  1736. X    }
  1737. X
  1738. X    /* Set the colors for each allocated pixel. */
  1739. X
  1740. X    winp->color_len = npixels;
  1741. X    hue = 0.0;
  1742. X    mud = 0.0;
  1743. X    dir = 1;
  1744. X
  1745. X    for (i = 0; i < npixels; i++) {
  1746. X        convertHSI_to_RGB (hue, mud, &r, &g, &b);
  1747. X        celldef.pixel = winp->pixels[i];
  1748. X        celldef.red = r;
  1749. X        celldef.green = g;
  1750. X        celldef.blue = b;
  1751. X        celldef.flags = DoBlue | DoGreen | DoRed;
  1752. X        celldef.pad = NULL;
  1753. X
  1754. X        XStoreColor (winp->dsp, cmap, &celldef);
  1755. X
  1756. X        m = i % arg_mud_num;
  1757. X        if (m == arg_mud_num - 1) { /* increment hue */
  1758. X            hue += 1.0 * arg_mud_num / (double) (npixels);
  1759. X            dir = -dir; /* change direction */
  1760. X        }
  1761. X        else if (dir > 0) { /* increase mud */
  1762. X            mud = mud + arg_mud_max / arg_mud_num;
  1763. X        }
  1764. X        else { /* decrease mud */
  1765. X            mud = mud - arg_mud_max / arg_mud_num;
  1766. X        }
  1767. X    }
  1768. X
  1769. X    return cmap;
  1770. X}
  1771. X
  1772. X/*
  1773. X * Given a hue, saturation, and brightness (intensity), generate
  1774. X * r, g, and b values.  Here, we ignore the saturation and brightness
  1775. X * since we know what we want.  We use sine curves to ramp values up
  1776. X * and down quickly, so that the colors will be more interesting.
  1777. X */
  1778. X
  1779. X#define ramp_up(h) sin (M_PI_2 * (h))
  1780. X#define ramp_down(h) cos (M_PI_2 * (h))
  1781. X
  1782. Xvoid
  1783. XconvertHSI_to_RGB (hue, mud, R, G, B)
  1784. Xdouble hue, mud;
  1785. Xint *R,*G,*B ;
  1786. X
  1787. X{
  1788. X double r,g,b ;
  1789. X int i;
  1790. X
  1791. X hue = (double) (hue*6) ;
  1792. X i = (int) (hue);
  1793. X hue = hue - i; /* normalize 'hue' into range 0..1 */
  1794. X switch (i)
  1795. X {
  1796. X  case 0 :
  1797. X        r = 1.0;
  1798. X        g = ramp_up (hue);
  1799. X        b = ramp_up (mud);
  1800. X        break;
  1801. X  case 1:
  1802. X        r = ramp_down (hue);
  1803. X        g = 1.0;
  1804. X        b = ramp_up (mud);
  1805. X        break;
  1806. X  case 2:
  1807. X        r = ramp_up (mud);
  1808. X        g = 1.0;
  1809. X        b = ramp_up (hue);
  1810. X        break;
  1811. X  case 3:
  1812. X        r = ramp_up (mud);
  1813. X        g = ramp_down (hue);
  1814. X        b = 1.0;
  1815. X        break;
  1816. X  case 4:
  1817. X        r = ramp_up (hue);
  1818. X        g = ramp_up (mud);
  1819. X        b = 1.0;
  1820. X        break;
  1821. X  case 5:
  1822. X        r = 1.0;
  1823. X        g = ramp_up (mud);
  1824. X        b = ramp_down (hue);
  1825. X        break;
  1826. X  }
  1827. X
  1828. X *R = (int) (r*65535) ;
  1829. X *G = (int) (g*65535) ;
  1830. X *B = (int) (b*65535) ;
  1831. X
  1832. X}
  1833. X
  1834. X
  1835. X/*
  1836. X * Flush the graphics package.
  1837. X */
  1838. X
  1839. Xvoid
  1840. Xwin_flush (winp)
  1841. Xwin_info_t *winp;
  1842. X{
  1843. X    XSync (winp->dsp, False);
  1844. X}
  1845. X
  1846. X/*
  1847. X * Change the shape of the cursor on the screen.  Only done if not
  1848. X * on root.
  1849. X */
  1850. X
  1851. Xvoid
  1852. Xwin_busy (winp, state)
  1853. Xwin_info_t *winp;
  1854. Xint state;
  1855. X{
  1856. X    if (!arg_use_root) {
  1857. X    XDefineCursor (winp->dsp, winp->win, state ? winp->busy : winp->nbusy);
  1858. X    }
  1859. X}
  1860. X
  1861. X/*
  1862. X * Draw a colored line.  The 'color' is a postive number.  We
  1863. X * will take this color modulo the available colors.
  1864. X */
  1865. X
  1866. Xvoid
  1867. Xwin_draw_colored_line (winp, color, from_x, from_y, to_x, to_y)
  1868. Xwin_info_t *winp;
  1869. Xint color;
  1870. Xint from_x, from_y, to_x, to_y;
  1871. X{
  1872. X    int pixel;
  1873. X
  1874. X    pixel = color % winp->color_len;
  1875. X    if (winp->pixels) pixel = winp->pixels[pixel];
  1876. X
  1877. X    XSetForeground (winp->dsp, winp->gc, pixel);
  1878. X    XDrawLine (winp->dsp, winp->win, winp->gc, from_x, from_y, to_x, to_y);
  1879. X}
  1880. X
  1881. X/*
  1882. X * Given a run-length encoded line, draw the line on the screen.
  1883. X * Here, we buffer the line into an image, and then send the image
  1884. X * to the screen.  This technique is designed to reduce the amount
  1885. X * of work required by the XServer.
  1886. X *
  1887. X * If we understood the internal format of an Image better, we could
  1888. X * probably generate the image data using low-level techniques that
  1889. X * would greatly enhance the speed of this routine.  Eventually, we
  1890. X * might want to farm out some of these computations to the compute
  1891. X * servers, but that would run the risk of making the compute servers
  1892. X * more difficult to port.
  1893. X *
  1894. X * When we are imaging on the root window, we store the pixel
  1895. X * co-ordinates where we think it would be interesting to expand
  1896. X * the image.  We willl choose the right side of a black line
  1897. X * that is followed by a colored line.  And we will prefer a short
  1898. X * line.
  1899. X */
  1900. X
  1901. Xvoid
  1902. Xwin_render_line (winp, buf, buflen, linenum)
  1903. Xwin_info_t *winp;
  1904. Xcolor_x_t *buf; /* run-length encoded line */
  1905. Xint buflen; /* number of elements pointed to by 'buf' */
  1906. Xint linenum; /* line number of the window to be drawn */
  1907. X{
  1908. X    int last_x;
  1909. X    int i, j;
  1910. X    unsigned long pixel;
  1911. X
  1912. X    /* Fill the image with colors. */
  1913. X    last_x = 0;
  1914. X    for (i = 0; i < buflen; i++) {
  1915. X        if (buf[i].color == arg_iterations) { /* black? */
  1916. X            pixel = winp->black;
  1917. X
  1918. X            /* record various black and colored locations */
  1919. X            if (arg_use_root) {
  1920. X                if (i < buflen - 1
  1921. X                && buf[i].x - last_x + 1 < 5)
  1922. X                {
  1923. X                winp->black_list[0].x = buf[i].x + 1;
  1924. X                winp->black_list[0].y = linenum;
  1925. X                winp->color_list[0].x = buf[i].x + 1;
  1926. X                winp->color_list[0].y = linenum;
  1927. X                }
  1928. X            }
  1929. X        }
  1930. X        else {
  1931. X            pixel = buf[i].color % winp->color_len;
  1932. X            if (winp->pixels) pixel = winp->pixels[pixel];
  1933. X        }
  1934. X
  1935. X        /* Fill a line segment with this pixel. */
  1936. X        for (j = last_x; j <= buf[i].x; j++) {
  1937. X            XPutPixel (winp->image, j, 0, pixel);
  1938. X        }
  1939. X
  1940. X        last_x = buf[i].x + 1;
  1941. X    }
  1942. X
  1943. X    /* Put the image on the screen. */
  1944. X    XPutImage (winp->dsp, winp->pix.w, winp->gc, winp->image,
  1945. X            0, 0, 0, linenum, winp->hpixels, 1);
  1946. X}
  1947. X
  1948. X/*
  1949. X * Draw the image that we last drew on the screen.  This exists
  1950. X * purely to take advantage of the symmetry that exists about the
  1951. X * X-axis of the mandelbrot set.  This routine isn't absolutely
  1952. X * necessary.
  1953. X */
  1954. X
  1955. Xvoid
  1956. Xwin_rerender_line (winp, linenum)
  1957. Xwin_info_t *winp;
  1958. Xint linenum;
  1959. X{
  1960. X    XPutImage (winp->dsp, winp->pix.w, winp->gc, winp->image,
  1961. X            0, 0, 0, linenum, winp->hpixels, 1);
  1962. X}
  1963. //E*O*F gui.c//
  1964.  
  1965. echo x - gui.h
  1966. sed -e 's/^X//' > "gui.h" << '//E*O*F gui.h//'
  1967. X/*
  1968. X * Mandel by Rob Swiston and Chuck Simmons
  1969. X * Copyright (C) 1989, 1990 by Rob Swiston and Chuck Simmons
  1970. X *
  1971. X * This program is free software; you can redistribute it and/or modify
  1972. X * it under the terms of version 1 of the GNU General Public License as
  1973. X * published by the Free Software Foundation.
  1974. X *
  1975. X * This program is distributed in the hope that it will be useful,
  1976. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  1977. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1978. X * GNU General Public License for more details.
  1979. X *
  1980. X * You should have received a copy of the GNU General Public License
  1981. X * along with this program; if not, write to the Free Software
  1982. X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1983. X */
  1984. X
  1985. X/*
  1986. X * Definitions needed to use the GUI routines.
  1987. X */
  1988. X
  1989. X/*
  1990. X * Routines.
  1991. X */
  1992. X
  1993. Xvoid win_flush (/* void *winp */); /* flush pending output */
  1994. Xvoid win_busy (/* void *winp, int state */); /* change cursor */
  1995. Xvoid win_draw_colored_line (/* void *winp, int color,
  1996. X                int x1, int y1, int x2, int y2 */);
  1997. Xvoid win_render_line (/* void *winp, color_x_t *buf,
  1998. X                int buflen, int linenum */);
  1999. Xvoid win_rerender_line (/* void *winp, int linenum */);
  2000. X
  2001. X/* width and height of window in pixels */
  2002. Xint win_pwidth  (/* void *winp */);
  2003. Xint win_pheight (/* void *winp */);
  2004. X
  2005. X/* 'real' co-ordinates of upper-left and lower-right of window */
  2006. Xdouble win_xmin (/* void *winp */);
  2007. Xdouble win_xmax (/* void *winp */);
  2008. Xdouble win_ymin (/* void *winp */);
  2009. Xdouble win_ymax (/* void *winp */);
  2010. X
  2011. X/* 'real' width and height */
  2012. Xdouble win_rwidth  (/* void *winp */);
  2013. Xdouble win_rheight (/* void *winp */);
  2014. X
  2015. X/* maximum width and height of screen */
  2016. Xint win_max_width (/* void *winp */);
  2017. Xint win_max_height (/* void *winp */);
  2018. X
  2019. X
  2020. //E*O*F gui.h//
  2021.  
  2022. echo x - mandel.mk
  2023. sed -e 's/^X//' > "mandel.mk" << '//E*O*F mandel.mk//'
  2024. X# Mandel by Rob Swiston and Chuck Simmons
  2025. X# Copyright (C) 1989, 1990 by Rob Swiston and Chuck Simmons
  2026. X#
  2027. X# This program is free software; you can redistribute it and/or modify
  2028. X# it under the terms of version 1 of the GNU General Public License as
  2029. X# published by the Free Software Foundation.
  2030. X#
  2031. X# This program is distributed in the hope that it will be useful,
  2032. X# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2033. X# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2034. X# GNU General Public License for more details.
  2035. X#
  2036. X# You should have received a copy of the GNU General Public License
  2037. X# along with this program; if not, write to the Free Software
  2038. X# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  2039. X
  2040. X# Define 'VAX_BYTE_ORDER' on mips, vax, sequent, ncube, etc.
  2041. X# Define CONVEX or IS_370 on appropriate machines.
  2042. X
  2043. X#CFLAGS = -O -DCONVEX
  2044. X#CFLAGS = -O -DIS_370
  2045. X#CFLAGS = -O -DVAX_BYTE_ORDER
  2046. XCFLAGS = -O
  2047. X
  2048. XSHIP1FILES=client.c gui.c gui.h mandel.mk
  2049. XSHIP2FILES=LICENSE hostfile mandel.h mserver.c net.c net.h client.h \
  2050. X        colormap.data compute.c README
  2051. X
  2052. X# NCube specific stuff.
  2053. XNINCLUDES = -I/home/csimmons/ora/6028/port/ncube/standard_def
  2054. XNCCFLAGS = $(CFLAGS) $(INCLUDES)
  2055. XNCC=ngcc
  2056. XROOT=/usr/lib/ncube2
  2057. XLIB=$(ROOT)/lib
  2058. XBIN=$(ROOT)/bin
  2059. X
  2060. Xall: mandel mserver
  2061. X
  2062. Xmandel: client.o gui.o cnet.o
  2063. X    $(CC) -o $@ client.o gui.o cnet.o -lX11 -lm
  2064. X
  2065. Xmserver: snet.o compute.o mserver.o
  2066. X    $(CC) -o $@ snet.o compute.o mserver.o
  2067. X
  2068. Xcnet.o: net.c
  2069. X    $(CC) $(CFLAGS) -DCLIENT -c net.c
  2070. X    mv net.o cnet.o
  2071. X
  2072. Xsnet.o: net.c
  2073. X    $(CC) $(CFLAGS) -DSERVER -c net.c
  2074. X    mv net.o snet.o
  2075. X
  2076. Xship: $(SHIP1FILES) $(SHIP2FILES)
  2077. X    shar $(SHIP1FILES) > mandel1.shar
  2078. X    shar $(SHIP2FILES) > mandel2.shar
  2079. X
  2080. X# Everything below this point is NCube specific.
  2081. X
  2082. X# compute.o isn't ever executed, but it is needed to resolve a
  2083. X# reference.  Yucko.
  2084. X
  2085. Xnc_sunserver: nc_sunserver.o snet.o compute.o
  2086. X    $(CC) -o $@ nc_sunserver.o snet.o compute.o $(LIB)/libncube.a
  2087. X
  2088. Xnc_cubeserver: nc_cubeserver.o nc_get_color.o
  2089. X    $(NCC) -o $@ nc_cubeserver.o nc_get_color.o
  2090. X
  2091. X#nc_cubeserver: nc_cubeserver.o nc_mandel_line.o
  2092. X#    $(NCC) -o $@ nc_cubeserver.o nc_mandel_line.o
  2093. X
  2094. Xnc_cubeserver.o: nc_cubeserver.c
  2095. X    $(NCC) $(NCCFLAGS) -c nc_cubeserver.c
  2096. X
  2097. Xnc_get_color.o: nc_get_color.s
  2098. X    $(NCC) -O -c nc_get_color.s
  2099. X
  2100. Xnc_mandel_line.o: nc_mandel_line.c
  2101. X    $(NCC) $(NCCFLAGS) -c nc_mandel_line.c
  2102. X
  2103. X
  2104. //E*O*F mandel.mk//
  2105.  
  2106. exit 0
  2107.