New comit of SDL2
[supertux.git] / src / SDL2 / external / libpng-1.6.2 / contrib / gregbook / rpng2-x.c
1 /*---------------------------------------------------------------------------
2
3    rpng2 - progressive-model PNG display program                  rpng2-x.c
4
5    This program decodes and displays PNG files progressively, as if it were
6    a web browser (though the front end is only set up to read from files).
7    It supports gamma correction, user-specified background colors, and user-
8    specified background patterns (for transparent images).  This version is
9    for the X Window System (tested by the author under Unix and by Martin
10    Zinser under OpenVMS; may work under OS/2 with a little tweaking).
11
12    Thanks to Adam Costello and Pieter S. van der Meulen for the "diamond"
13    and "radial waves" patterns, respectively.
14
15    to do (someday, maybe):
16     - fix expose/redraw code:  don't draw entire row if only part exposed
17     - 8-bit (colormapped) X support
18     - finish resizable checkerboard-gradient (sizes 4-128?)
19     - use %.1023s to simplify truncation of title-bar string?
20
21   ---------------------------------------------------------------------------
22
23    Changelog:
24     - 1.01:  initial public release
25     - 1.02:  modified to allow abbreviated options; fixed char/uchar mismatch
26     - 1.10:  added support for non-default visuals; fixed X pixel-conversion
27     - 1.11:  added -usleep option for demos; fixed command-line parsing bug
28     - 1.12:  added -pause option for demos and testing
29     - 1.20:  added runtime MMX-enabling/disabling and new -mmx* options
30     - 1.21:  fixed some small X memory leaks (thanks to François Petitjean)
31     - 1.22:  fixed XFreeGC() crash bug (thanks to Patrick Welche)
32     - 1.23:  added -bgpat 0 mode (std white/gray checkerboard, 8x8 squares)
33     - 1.30:  added -loop option for -bgpat (ifdef FEATURE_LOOP); fixed bpp =
34               24; added support for X resources (thanks to Gerhard Niklasch)
35     - 1.31:  added code to skip unused chunks (thanks to Glenn Randers-Pehrson)
36     - 1.32:  added AMD64/EM64T support (__x86_64__); added basic expose/redraw
37               handling
38     - 2.00:  dual-licensed (added GNU GPL)
39     - 2.01:  fixed 64-bit typo in readpng2.c; fixed -pause usage description
40     - 2.02:  fixed improper display of usage screen on PNG error(s); fixed
41               unexpected-EOF and file-read-error cases; fixed Trace() cut-and-
42               paste bugs
43     - 2.03:  deleted runtime MMX-enabling/disabling and obsolete -mmx* options
44
45   ---------------------------------------------------------------------------
46
47       Copyright (c) 1998-2008 Greg Roelofs.  All rights reserved.
48
49       This software is provided "as is," without warranty of any kind,
50       express or implied.  In no event shall the author or contributors
51       be held liable for any damages arising in any way from the use of
52       this software.
53
54       The contents of this file are DUAL-LICENSED.  You may modify and/or
55       redistribute this software according to the terms of one of the
56       following two licenses (at your option):
57
58
59       LICENSE 1 ("BSD-like with advertising clause"):
60
61       Permission is granted to anyone to use this software for any purpose,
62       including commercial applications, and to alter it and redistribute
63       it freely, subject to the following restrictions:
64
65       1. Redistributions of source code must retain the above copyright
66          notice, disclaimer, and this list of conditions.
67       2. Redistributions in binary form must reproduce the above copyright
68          notice, disclaimer, and this list of conditions in the documenta-
69          tion and/or other materials provided with the distribution.
70       3. All advertising materials mentioning features or use of this
71          software must display the following acknowledgment:
72
73             This product includes software developed by Greg Roelofs
74             and contributors for the book, "PNG: The Definitive Guide,"
75             published by O'Reilly and Associates.
76
77
78       LICENSE 2 (GNU GPL v2 or later):
79
80       This program is free software; you can redistribute it and/or modify
81       it under the terms of the GNU General Public License as published by
82       the Free Software Foundation; either version 2 of the License, or
83       (at your option) any later version.
84
85       This program is distributed in the hope that it will be useful,
86       but WITHOUT ANY WARRANTY; without even the implied warranty of
87       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
88       GNU General Public License for more details.
89
90       You should have received a copy of the GNU General Public License
91       along with this program; if not, write to the Free Software Foundation,
92       Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
93
94   ---------------------------------------------------------------------------*/
95
96 #define PROGNAME  "rpng2-x"
97 #define LONGNAME  "Progressive PNG Viewer for X"
98 #define VERSION   "2.03 of 25 February 2010"
99 #define RESNAME   "rpng2"       /* our X resource application name */
100 #define RESCLASS  "Rpng"       /* our X resource class name */
101
102 #include <stdio.h>
103 #include <stdlib.h>
104 #include <ctype.h>
105 #include <string.h>
106 #include <setjmp.h>       /* for jmpbuf declaration in readpng2.h */
107 #include <time.h>
108 #include <math.h>         /* only for PvdM background code */
109 #include <X11/Xlib.h>
110 #include <X11/Xutil.h>
111 #include <X11/Xos.h>
112 #include <X11/keysym.h>   /* defines XK_* macros */
113
114 #ifdef VMS
115 #  include <unistd.h>
116 #endif
117
118 /* all for PvdM background code: */
119 #ifndef PI
120 #  define PI             3.141592653589793238
121 #endif
122 #define PI_2             (PI*0.5)
123 #define INV_PI_360       (360.0 / PI)
124 #define MAX(a,b)         (a>b?a:b)
125 #define MIN(a,b)         (a<b?a:b)
126 #define CLIP(a,min,max)  MAX(min,MIN((a),max))
127 #define ABS(a)           ((a)<0?-(a):(a))
128 #define CLIP8P(c)        MAX(0,(MIN((c),255)))   /* 8-bit pos. integer (uch) */
129 #define ROUNDF(f)        ((int)(f + 0.5))
130
131 #define QUIT(e,k) ((e.type == ButtonPress && e.xbutton.button == Button1) ||  \
132                   (e.type == KeyPress &&   /*  v--- or 1 for shifted keys */  \
133                   ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape)))
134
135 #define NO_24BIT_MASKS /* undef case not fully written--only for redisplay() */
136
137 #define rgb1_max   bg_freq
138 #define rgb1_min   bg_gray
139 #define rgb2_max   bg_bsat
140 #define rgb2_min   bg_brot
141
142 /* #define DEBUG */     /* this enables the Trace() macros */
143
144 #include "readpng2.h"   /* typedefs, common macros, readpng2 prototypes */
145
146
147 /* could just include png.h, but this macro is the only thing we need
148  * (name and typedefs changed to local versions); note that side effects
149  * only happen with alpha (which could easily be avoided with
150  * "ush acopy = (alpha);") */
151
152 #define alpha_composite(composite, fg, alpha, bg) {               \
153     ush temp = ((ush)(fg)*(ush)(alpha) +                          \
154                 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128);  \
155     (composite) = (uch)((temp + (temp >> 8)) >> 8);               \
156 }
157
158
159 #define INBUFSIZE 4096   /* with pseudo-timing on (1 sec delay/block), this
160                           *  block size corresponds roughly to a download
161                           *  speed 10% faster than theoretical 33.6K maximum
162                           *  (assuming 8 data bits, 1 stop bit and no other
163                           *  overhead) */
164
165 /* local prototypes */
166 static void rpng2_x_init (void);
167 static int  rpng2_x_create_window (void);
168 static int  rpng2_x_load_bg_image (void);
169 static void rpng2_x_display_row (ulg row);
170 static void rpng2_x_finish_display (void);
171 static void rpng2_x_redisplay_image (ulg startcol, ulg startrow,
172                                      ulg width, ulg height);
173 #ifdef FEATURE_LOOP
174 static void rpng2_x_reload_bg_image (void);
175 static int  is_number (char *p);
176 #endif
177 static void rpng2_x_cleanup (void);
178 static int  rpng2_x_msb (ulg u32val);
179
180
181 static char titlebar[1024], *window_name = titlebar;
182 static char *appname = LONGNAME;
183 static char *icon_name = PROGNAME;
184 static char *res_name = RESNAME;
185 static char *res_class = RESCLASS;
186 static char *filename;
187 static FILE *infile;
188
189 static mainprog_info rpng2_info;
190
191 static uch inbuf[INBUFSIZE];
192 static int incount;
193
194 static int pat = 6;        /* must be less than num_bgpat */
195 static int bg_image = 0;
196 static int bgscale, bgscale_default = 16;
197 static ulg bg_rowbytes;
198 static uch *bg_data;
199
200 int pause_after_pass = FALSE;
201 int demo_timing = FALSE;
202 ulg usleep_duration = 0L;
203
204 static struct rgb_color {
205     uch r, g, b;
206 } rgb[] = {
207     {  0,   0,   0},    /*  0:  black */
208     {255, 255, 255},    /*  1:  white */
209     {173, 132,  57},    /*  2:  tan */
210     { 64, 132,   0},    /*  3:  medium green */
211     {189, 117,   1},    /*  4:  gold */
212     {253, 249,   1},    /*  5:  yellow */
213     {  0,   0, 255},    /*  6:  blue */
214     {  0,   0, 120},    /*  7:  medium blue */
215     {255,   0, 255},    /*  8:  magenta */
216     { 64,   0,  64},    /*  9:  dark magenta */
217     {255,   0,   0},    /* 10:  red */
218     { 64,   0,   0},    /* 11:  dark red */
219     {255, 127,   0},    /* 12:  orange */
220     {192,  96,   0},    /* 13:  darker orange */
221     { 24,  60,   0},    /* 14:  dark green-yellow */
222     { 85, 125, 200},    /* 15:  ice blue */
223     {192, 192, 192}     /* 16:  Netscape/Mosaic gray */
224 };
225 /* not used for now, but should be for error-checking:
226 static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
227  */
228
229 /*
230     This whole struct is a fairly cheesy way to keep the number of
231     command-line options to a minimum.  The radial-waves background
232     type is a particularly poor fit to the integer elements of the
233     struct...but a few macros and a little fixed-point math will do
234     wonders for ya.
235
236     type bits:
237        F E D C B A 9 8 7 6 5 4 3 2 1 0
238                              | | | | |
239                              | | +-+-+-- 0 = sharp-edged checkerboard
240                              | |         1 = soft diamonds
241                              | |         2 = radial waves
242                              | |       3-7 = undefined
243                              | +-- gradient #2 inverted?
244                              +-- alternating columns inverted?
245  */
246 static struct background_pattern {
247     ush type;
248     int rgb1_max, rgb1_min;     /* or bg_freq, bg_gray */
249     int rgb2_max, rgb2_min;     /* or bg_bsat, bg_brot (both scaled by 10)*/
250 } bg[] = {
251     {0,     1,1, 16,16},        /* checkered:  white vs. light gray (basic) */
252     {0+8,   2,0,  1,15},        /* checkered:  tan/black vs. white/ice blue */
253     {0+24,  2,0,  1,0},         /* checkered:  tan/black vs. white/black */
254     {0+8,   4,5,  0,2},         /* checkered:  gold/yellow vs. black/tan */
255     {0+8,   4,5,  0,6},         /* checkered:  gold/yellow vs. black/blue */
256     {0,     7,0,  8,9},         /* checkered:  deep blue/black vs. magenta */
257     {0+8,  13,0,  5,14},        /* checkered:  orange/black vs. yellow */
258     {0+8,  12,0, 10,11},        /* checkered:  orange/black vs. red */
259     {1,     7,0,  8,0},         /* diamonds:  deep blue/black vs. magenta */
260     {1,    12,0, 11,0},         /* diamonds:  orange vs. dark red */
261     {1,    10,0,  7,0},         /* diamonds:  red vs. medium blue */
262     {1,     4,0,  5,0},         /* diamonds:  gold vs. yellow */
263     {1,     3,0,  0,0},         /* diamonds:  medium green vs. black */
264     {2,    16, 100,  20,   0},  /* radial:  ~hard radial color-beams */
265     {2,    18, 100,  10,   2},  /* radial:  soft, curved radial color-beams */
266     {2,    16, 256, 100, 250},  /* radial:  very tight spiral */
267     {2, 10000, 256,  11,   0}   /* radial:  dipole-moire' (almost fractal) */
268 };
269 static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern);
270
271
272 /* X-specific variables */
273 static char *displayname;
274 static XImage *ximage;
275 static Display *display;
276 static int depth;
277 static Visual *visual;
278 static XVisualInfo *visual_list;
279 static int RShift, GShift, BShift;
280 static ulg RMask, GMask, BMask;
281 static Window window;
282 static GC gc;
283 static Colormap colormap;
284
285 static int have_nondefault_visual = FALSE;
286 static int have_colormap = FALSE;
287 static int have_window = FALSE;
288 static int have_gc = FALSE;
289
290
291
292
293 int main(int argc, char **argv)
294 {
295 #ifdef sgi
296     char tmpline[80];
297 #endif
298     char *p, *bgstr = NULL;
299     int rc, alen, flen;
300     int error = 0;
301     int timing = FALSE;
302     int have_bg = FALSE;
303 #ifdef FEATURE_LOOP
304     int loop = FALSE;
305     long loop_interval = -1;            /* seconds (100,000 max) */
306 #endif
307     double LUT_exponent;                /* just the lookup table */
308     double CRT_exponent = 2.2;          /* just the monitor */
309     double default_display_exponent;    /* whole display system */
310     XEvent e;
311     KeySym k;
312
313
314     /* First initialize a few things, just to be sure--memset takes care of
315      * default background color (black), booleans (FALSE), pointers (NULL),
316      * etc. */
317
318     displayname = (char *)NULL;
319     filename = (char *)NULL;
320     memset(&rpng2_info, 0, sizeof(mainprog_info));
321
322
323     /* Set the default value for our display-system exponent, i.e., the
324      * product of the CRT exponent and the exponent corresponding to
325      * the frame-buffer's lookup table (LUT), if any.  This is not an
326      * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
327      * ones), but it should cover 99% of the current possibilities. */
328
329 #if defined(NeXT)
330     /* third-party utilities can modify the default LUT exponent */
331     LUT_exponent = 1.0 / 2.2;
332     /*
333     if (some_next_function_that_returns_gamma(&next_gamma))
334         LUT_exponent = 1.0 / next_gamma;
335      */
336 #elif defined(sgi)
337     LUT_exponent = 1.0 / 1.7;
338     /* there doesn't seem to be any documented function to
339      * get the "gamma" value, so we do it the hard way */
340     infile = fopen("/etc/config/system.glGammaVal", "r");
341     if (infile) {
342         double sgi_gamma;
343
344         fgets(tmpline, 80, infile);
345         fclose(infile);
346         sgi_gamma = atof(tmpline);
347         if (sgi_gamma > 0.0)
348             LUT_exponent = 1.0 / sgi_gamma;
349     }
350 #elif defined(Macintosh)
351     LUT_exponent = 1.8 / 2.61;
352     /*
353     if (some_mac_function_that_returns_gamma(&mac_gamma))
354         LUT_exponent = mac_gamma / 2.61;
355      */
356 #else
357     LUT_exponent = 1.0;   /* assume no LUT:  most PCs */
358 #endif
359
360     /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
361     default_display_exponent = LUT_exponent * CRT_exponent;
362
363
364     /* If the user has set the SCREEN_GAMMA environment variable as suggested
365      * (somewhat imprecisely) in the libpng documentation, use that; otherwise
366      * use the default value we just calculated.  Either way, the user may
367      * override this via a command-line option. */
368
369     if ((p = getenv("SCREEN_GAMMA")) != NULL)
370         rpng2_info.display_exponent = atof(p);
371     else
372         rpng2_info.display_exponent = default_display_exponent;
373
374
375     /* Now parse the command line for options and the PNG filename. */
376
377     while (*++argv && !error) {
378         if (!strncmp(*argv, "-display", 2)) {
379             if (!*++argv)
380                 ++error;
381             else
382                 displayname = *argv;
383         } else if (!strncmp(*argv, "-gamma", 2)) {
384             if (!*++argv)
385                 ++error;
386             else {
387                 rpng2_info.display_exponent = atof(*argv);
388                 if (rpng2_info.display_exponent <= 0.0)
389                     ++error;
390             }
391         } else if (!strncmp(*argv, "-bgcolor", 4)) {
392             if (!*++argv)
393                 ++error;
394             else {
395                 bgstr = *argv;
396                 if (strlen(bgstr) != 7 || bgstr[0] != '#')
397                     ++error;
398                 else {
399                     have_bg = TRUE;
400                     bg_image = FALSE;
401                 }
402             }
403         } else if (!strncmp(*argv, "-bgpat", 4)) {
404             if (!*++argv)
405                 ++error;
406             else {
407                 pat = atoi(*argv);
408                 if (pat >= 0 && pat < num_bgpat) {
409                     bg_image = TRUE;
410                     have_bg = FALSE;
411                 } else
412                     ++error;
413             }
414         } else if (!strncmp(*argv, "-usleep", 2)) {
415             if (!*++argv)
416                 ++error;
417             else {
418                 usleep_duration = (ulg)atol(*argv);
419                 demo_timing = TRUE;
420             }
421         } else if (!strncmp(*argv, "-pause", 2)) {
422             pause_after_pass = TRUE;
423         } else if (!strncmp(*argv, "-timing", 2)) {
424             timing = TRUE;
425 #ifdef FEATURE_LOOP
426         } else if (!strncmp(*argv, "-loop", 2)) {
427             loop = TRUE;
428             if (!argv[1] || !is_number(argv[1]))
429                 loop_interval = 2;
430             else {
431                 ++argv;
432                 loop_interval = atol(*argv);
433                 if (loop_interval < 0)
434                     loop_interval = 2;
435                 else if (loop_interval > 100000)   /* bit more than one day */
436                     loop_interval = 100000;
437             }
438 #endif
439         } else {
440             if (**argv != '-') {
441                 filename = *argv;
442                 if (argv[1])   /* shouldn't be any more args after filename */
443                     ++error;
444             } else
445                 ++error;   /* not expecting any other options */
446         }
447     }
448
449     if (!filename)
450         ++error;
451
452
453     /* print usage screen if any errors up to this point */
454
455     if (error) {
456         fprintf(stderr, "\n%s %s:  %s\n\n", PROGNAME, VERSION, appname);
457         readpng2_version_info();
458         fprintf(stderr, "\n"
459           "Usage:  %s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n"
460 #ifdef FEATURE_LOOP
461           "        %*s [-usleep dur | -timing] [-pause] [-loop [sec]] file.png\n\n"
462 #else
463           "        %*s [-usleep dur | -timing] [-pause] file.png\n\n"
464 #endif
465           "    xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
466           "    exp \ttransfer-function exponent (``gamma'') of the display\n"
467           "\t\t  system in floating-point format (e.g., ``%.1f''); equal\n"
468           "\t\t  to the product of the lookup-table exponent (varies)\n"
469           "\t\t  and the CRT exponent (usually 2.2); must be positive\n"
470           "    bg  \tdesired background color in 7-character hex RGB format\n"
471           "\t\t  (e.g., ``#ff7700'' for orange:  same as HTML colors);\n"
472           "\t\t  used with transparent images; overrides -bgpat\n"
473           "    pat \tdesired background pattern number (0-%d); used with\n"
474           "\t\t  transparent images; overrides -bgcolor\n"
475 #ifdef FEATURE_LOOP
476           "    -loop\tloops through background images after initial display\n"
477           "\t\t  is complete (depends on -bgpat)\n"
478           "    sec \tseconds to display each background image (default = 2)\n"
479 #endif
480           "    dur \tduration in microseconds to wait after displaying each\n"
481           "\t\t  row (for demo purposes)\n"
482           "    -timing\tenables delay for every block read, to simulate modem\n"
483           "\t\t  download of image (~36 Kbps)\n"
484           "    -pause\tpauses after displaying each pass until mouse clicked\n"
485           "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
486           "is displayed) to quit.\n"
487           "\n", PROGNAME,
488           (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat-1);
489         exit(1);
490     }
491
492
493     if (!(infile = fopen(filename, "rb"))) {
494         fprintf(stderr, PROGNAME ":  can't open PNG file [%s]\n", filename);
495         ++error;
496     } else {
497         incount = fread(inbuf, 1, INBUFSIZE, infile);
498         if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
499             fprintf(stderr, PROGNAME
500               ":  [%s] is not a PNG file: incorrect signature\n",
501               filename);
502             ++error;
503         } else if ((rc = readpng2_init(&rpng2_info)) != 0) {
504             switch (rc) {
505                 case 2:
506                     fprintf(stderr, PROGNAME
507                       ":  [%s] has bad IHDR (libpng longjmp)\n", filename);
508                     break;
509                 case 4:
510                     fprintf(stderr, PROGNAME ":  insufficient memory\n");
511                     break;
512                 default:
513                     fprintf(stderr, PROGNAME
514                       ":  unknown readpng2_init() error\n");
515                     break;
516             }
517             ++error;
518         } else {
519             Trace((stderr, "about to call XOpenDisplay()\n"))
520             display = XOpenDisplay(displayname);
521             if (!display) {
522                 readpng2_cleanup(&rpng2_info);
523                 fprintf(stderr, PROGNAME ":  can't open X display [%s]\n",
524                   displayname? displayname : "default");
525                 ++error;
526             }
527         }
528         if (error)
529             fclose(infile);
530     }
531
532
533     if (error) {
534         fprintf(stderr, PROGNAME ":  aborting.\n");
535         exit(2);
536     }
537
538
539     /* set the title-bar string, but make sure buffer doesn't overflow */
540
541     alen = strlen(appname);
542     flen = strlen(filename);
543     if (alen + flen + 3 > 1023)
544         sprintf(titlebar, "%s:  ...%s", appname, filename+(alen+flen+6-1023));
545     else
546         sprintf(titlebar, "%s:  %s", appname, filename);
547
548
549     /* set some final rpng2_info variables before entering main data loop */
550
551     if (have_bg) {
552         unsigned r, g, b;   /* this approach quiets compiler warnings */
553
554         sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
555         rpng2_info.bg_red   = (uch)r;
556         rpng2_info.bg_green = (uch)g;
557         rpng2_info.bg_blue  = (uch)b;
558     } else
559         rpng2_info.need_bgcolor = TRUE;
560
561     rpng2_info.state = kPreInit;
562     rpng2_info.mainprog_init = rpng2_x_init;
563     rpng2_info.mainprog_display_row = rpng2_x_display_row;
564     rpng2_info.mainprog_finish_display = rpng2_x_finish_display;
565
566
567     /* OK, this is the fun part:  call readpng2_decode_data() at the start of
568      * the loop to deal with our first buffer of data (read in above to verify
569      * that the file is a PNG image), then loop through the file and continue
570      * calling the same routine to handle each chunk of data.  It in turn
571      * passes the data to libpng, which will invoke one or more of our call-
572      * backs as decoded data become available.  We optionally call sleep() for
573      * one second per iteration to simulate downloading the image via an analog
574      * modem. */
575
576     for (;;) {
577         Trace((stderr, "about to call readpng2_decode_data()\n"))
578         if (readpng2_decode_data(&rpng2_info, inbuf, incount))
579             ++error;
580         Trace((stderr, "done with readpng2_decode_data()\n"))
581
582         if (error || incount != INBUFSIZE || rpng2_info.state == kDone) {
583             if (rpng2_info.state == kDone) {
584                 Trace((stderr, "done decoding PNG image\n"))
585             } else if (ferror(infile)) {
586                 fprintf(stderr, PROGNAME
587                   ":  error while reading PNG image file\n");
588                 exit(3);
589             } else if (feof(infile)) {
590                 fprintf(stderr, PROGNAME ":  end of file reached "
591                   "(unexpectedly) while reading PNG image file\n");
592                 exit(3);
593             } else /* if (error) */ {
594                 /* will print error message below */
595             }
596             break;
597         }
598
599         if (timing)
600             sleep(1);
601
602         incount = fread(inbuf, 1, INBUFSIZE, infile);
603     }
604
605
606     /* clean up PNG stuff and report any decoding errors */
607
608     fclose(infile);
609     Trace((stderr, "about to call readpng2_cleanup()\n"))
610     readpng2_cleanup(&rpng2_info);
611
612     if (error) {
613         fprintf(stderr, PROGNAME ":  libpng error while decoding PNG image\n");
614         exit(3);
615     }
616
617
618 #ifdef FEATURE_LOOP
619
620     if (loop && bg_image) {
621         Trace((stderr, "entering -loop loop (FEATURE_LOOP)\n"))
622         for (;;) {
623             int i, use_sleep;
624             struct timeval now, then;
625
626             /* get current time and add loop_interval to get target time */
627             if (gettimeofday(&then, NULL) == 0) {
628                 then.tv_sec += loop_interval;
629                 use_sleep = FALSE;
630             } else
631                 use_sleep = TRUE;
632
633             /* do quick check for a quit event but don't wait for it */
634             /* GRR BUG:  should also check for Expose events and redraw... */
635             if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, &e))
636                 if (QUIT(e,k))
637                     break;
638
639             /* generate next background image */
640             if (++pat >= num_bgpat)
641                 pat = 0;
642             rpng2_x_reload_bg_image();
643
644             /* wait for timeout, using whatever means are available */
645             if (use_sleep || gettimeofday(&now, NULL) != 0) {
646                 for (i = loop_interval;  i > 0;  --i) {
647                     sleep(1);
648                     /* GRR BUG:  also need to check for Expose (and redraw!) */
649                     if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask,
650                         &e) && QUIT(e,k))
651                         break;
652                 }
653             } else {
654                 /* Y2038 BUG! */
655                 if (now.tv_sec < then.tv_sec ||
656                     (now.tv_sec == then.tv_sec && now.tv_usec < then.tv_usec))
657                 {
658                     int quit = FALSE;
659                     long seconds_to_go = then.tv_sec - now.tv_sec;
660                     long usleep_usec;
661
662                     /* basically chew up most of remaining loop-interval with
663                      *  calls to sleep(1) interleaved with checks for quit
664                      *  events, but also recalc time-to-go periodically; when
665                      *  done, clean up any remaining time with usleep() call
666                      *  (could also use SIGALRM, but signals are a pain...) */
667                     while (seconds_to_go-- > 1) {
668                         int seconds_done = 0;
669
670                         for (i = seconds_to_go;  i > 0 && !quit;  --i) {
671                             sleep(1);
672                             /* GRR BUG:  need to check for Expose and redraw */
673                             if (XCheckMaskEvent(display, KeyPressMask |
674                                 ButtonPressMask, &e) && QUIT(e,k))
675                                 quit = TRUE;
676                             if (++seconds_done > 1000)
677                                 break;   /* time to redo seconds_to_go meas. */
678                         }
679                         if (quit)
680                             break;
681
682                         /* OK, more than 1000 seconds since last check:
683                          *  correct the time-to-go measurement for drift */
684                         if (gettimeofday(&now, NULL) == 0) {
685                             if (now.tv_sec >= then.tv_sec)
686                                 break;
687                             seconds_to_go = then.tv_sec - now.tv_sec;
688                         } else
689                             ++seconds_to_go;  /* restore what we subtracted */
690                     }
691                     if (quit)
692                         break;   /* breaks outer do-loop, skips redisplay */
693
694                     /* since difference between "now" and "then" is already
695                      *  eaten up to within a couple of seconds, don't need to
696                      *  worry about overflow--but might have overshot (neg.) */
697                     if (gettimeofday(&now, NULL) == 0) {
698                         usleep_usec = 1000000L*(then.tv_sec - now.tv_sec) +
699                           then.tv_usec - now.tv_usec;
700                         if (usleep_usec > 0)
701                             usleep((ulg)usleep_usec);
702                     }
703                 }
704             }
705
706             /* composite image against new background and display (note that
707              *  we do not take into account the time spent doing this...) */
708             rpng2_x_redisplay_image (0, 0, rpng2_info.width, rpng2_info.height);
709         }
710
711     } else /* FALL THROUGH and do the normal thing */
712
713 #endif /* FEATURE_LOOP */
714
715     /* wait for the user to tell us when to quit */
716
717     if (rpng2_info.state >= kWindowInit) {
718         Trace((stderr, "entering final wait-for-quit-event loop\n"))
719         do {
720             XNextEvent(display, &e);
721             if (e.type == Expose) {
722                 XExposeEvent *ex = (XExposeEvent *)&e;
723                 rpng2_x_redisplay_image (ex->x, ex->y, ex->width, ex->height);
724             }
725         } while (!QUIT(e,k));
726     } else {
727         fprintf(stderr, PROGNAME ":  init callback never called:  probable "
728           "libpng error while decoding PNG metadata\n");
729         exit(4);
730     }
731
732
733     /* we're done:  clean up all image and X resources and go away */
734
735     Trace((stderr, "about to call rpng2_x_cleanup()\n"))
736     rpng2_x_cleanup();
737
738     return 0;
739 }
740
741
742
743
744
745 /* this function is called by readpng2_info_callback() in readpng2.c, which
746  * in turn is called by libpng after all of the pre-IDAT chunks have been
747  * read and processed--i.e., we now have enough info to finish initializing */
748
749 static void rpng2_x_init(void)
750 {
751     ulg i;
752     ulg rowbytes = rpng2_info.rowbytes;
753
754     Trace((stderr, "beginning rpng2_x_init()\n"))
755     Trace((stderr, "  rowbytes = %d\n", rpng2_info.rowbytes))
756     Trace((stderr, "  width  = %ld\n", rpng2_info.width))
757     Trace((stderr, "  height = %ld\n", rpng2_info.height))
758
759     rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
760     if (!rpng2_info.image_data) {
761         readpng2_cleanup(&rpng2_info);
762         return;
763     }
764
765     rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
766     if (!rpng2_info.row_pointers) {
767         free(rpng2_info.image_data);
768         rpng2_info.image_data = NULL;
769         readpng2_cleanup(&rpng2_info);
770         return;
771     }
772
773     for (i = 0;  i < rpng2_info.height;  ++i)
774         rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
775
776
777     /* do the basic X initialization stuff, make the window, and fill it with
778      * the user-specified, file-specified or default background color or
779      * pattern */
780
781     if (rpng2_x_create_window()) {
782
783         /* GRR TEMPORARY HACK:  this is fundamentally no different from cases
784          * above; libpng should call our error handler to longjmp() back to us
785          * when png_ptr goes away.  If we/it segfault instead, seems like a
786          * libpng bug... */
787
788         /* we're here via libpng callback, so if window fails, clean and bail */
789         readpng2_cleanup(&rpng2_info);
790         rpng2_x_cleanup();
791         exit(2);
792     }
793
794     rpng2_info.state = kWindowInit;
795 }
796
797
798
799
800
801 static int rpng2_x_create_window(void)
802 {
803     ulg bg_red   = rpng2_info.bg_red;
804     ulg bg_green = rpng2_info.bg_green;
805     ulg bg_blue  = rpng2_info.bg_blue;
806     ulg bg_pixel = 0L;
807     ulg attrmask;
808     int need_colormap = FALSE;
809     int screen, pad;
810     uch *xdata;
811     Window root;
812     XEvent e;
813     XGCValues gcvalues;
814     XSetWindowAttributes attr;
815     XTextProperty windowName, *pWindowName = &windowName;
816     XTextProperty iconName, *pIconName = &iconName;
817     XVisualInfo visual_info;
818     XSizeHints *size_hints;
819     XWMHints *wm_hints;
820     XClassHint *class_hints;
821
822
823     Trace((stderr, "beginning rpng2_x_create_window()\n"))
824
825     screen = DefaultScreen(display);
826     depth = DisplayPlanes(display, screen);
827     root = RootWindow(display, screen);
828
829 #ifdef DEBUG
830     XSynchronize(display, True);
831 #endif
832
833     if (depth != 16 && depth != 24 && depth != 32) {
834         int visuals_matched = 0;
835
836         Trace((stderr, "default depth is %d:  checking other visuals\n",
837           depth))
838
839         /* 24-bit first */
840         visual_info.screen = screen;
841         visual_info.depth = 24;
842         visual_list = XGetVisualInfo(display,
843           VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
844         if (visuals_matched == 0) {
845 /* GRR:  add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
846             fprintf(stderr, "default screen depth %d not supported, and no"
847               " 24-bit visuals found\n", depth);
848             return 2;
849         }
850         Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
851           visuals_matched))
852         visual = visual_list[0].visual;
853         depth = visual_list[0].depth;
854 /*
855         colormap_size = visual_list[0].colormap_size;
856         visual_class = visual->class;
857         visualID = XVisualIDFromVisual(visual);
858  */
859         have_nondefault_visual = TRUE;
860         need_colormap = TRUE;
861     } else {
862         XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
863         visual = visual_info.visual;
864     }
865
866     RMask = visual->red_mask;
867     GMask = visual->green_mask;
868     BMask = visual->blue_mask;
869
870 /* GRR:  add/check 8-bit support */
871     if (depth == 8 || need_colormap) {
872         colormap = XCreateColormap(display, root, visual, AllocNone);
873         if (!colormap) {
874             fprintf(stderr, "XCreateColormap() failed\n");
875             return 2;
876         }
877         have_colormap = TRUE;
878         if (depth == 8)
879             bg_image = FALSE;   /* gradient just wastes palette entries */
880     }
881     if (depth == 15 || depth == 16) {
882         RShift = 15 - rpng2_x_msb(RMask);    /* these are right-shifts */
883         GShift = 15 - rpng2_x_msb(GMask);
884         BShift = 15 - rpng2_x_msb(BMask);
885     } else if (depth > 16) {
886         RShift = rpng2_x_msb(RMask) - 7;     /* these are left-shifts */
887         GShift = rpng2_x_msb(GMask) - 7;
888         BShift = rpng2_x_msb(BMask) - 7;
889     }
890     if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
891         fprintf(stderr, "rpng2 internal logic error:  negative X shift(s)!\n");
892         return 2;
893     }
894
895 /*---------------------------------------------------------------------------
896     Finally, create the window.
897   ---------------------------------------------------------------------------*/
898
899     attr.backing_store = Always;
900     attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
901     attrmask = CWBackingStore | CWEventMask;
902     if (have_nondefault_visual) {
903         attr.colormap = colormap;
904         attr.background_pixel = 0;
905         attr.border_pixel = 1;
906         attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
907     }
908
909     window = XCreateWindow(display, root, 0, 0, rpng2_info.width,
910       rpng2_info.height, 0, depth, InputOutput, visual, attrmask, &attr);
911
912     if (window == None) {
913         fprintf(stderr, "XCreateWindow() failed\n");
914         return 2;
915     } else
916         have_window = TRUE;
917
918     if (depth == 8)
919         XSetWindowColormap(display, window, colormap);
920
921     if (!XStringListToTextProperty(&window_name, 1, pWindowName))
922         pWindowName = NULL;
923     if (!XStringListToTextProperty(&icon_name, 1, pIconName))
924         pIconName = NULL;
925
926     /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */
927
928     if ((size_hints = XAllocSizeHints()) != NULL) {
929         /* window will not be resizable */
930         size_hints->flags = PMinSize | PMaxSize;
931         size_hints->min_width = size_hints->max_width = (int)rpng2_info.width;
932         size_hints->min_height = size_hints->max_height =
933           (int)rpng2_info.height;
934     }
935
936     if ((wm_hints = XAllocWMHints()) != NULL) {
937         wm_hints->initial_state = NormalState;
938         wm_hints->input = True;
939      /* wm_hints->icon_pixmap = icon_pixmap; */
940         wm_hints->flags = StateHint | InputHint  /* | IconPixmapHint */ ;
941     }
942
943     if ((class_hints = XAllocClassHint()) != NULL) {
944         class_hints->res_name = res_name;
945         class_hints->res_class = res_class;
946     }
947
948     XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
949       size_hints, wm_hints, class_hints);
950
951     /* various properties and hints no longer needed; free memory */
952     if (pWindowName)
953        XFree(pWindowName->value);
954     if (pIconName)
955        XFree(pIconName->value);
956     if (size_hints)
957         XFree(size_hints);
958     if (wm_hints)
959        XFree(wm_hints);
960     if (class_hints)
961        XFree(class_hints);
962
963     XMapWindow(display, window);
964
965     gc = XCreateGC(display, window, 0, &gcvalues);
966     have_gc = TRUE;
967
968 /*---------------------------------------------------------------------------
969     Allocate memory for the X- and display-specific version of the image.
970   ---------------------------------------------------------------------------*/
971
972     if (depth == 24 || depth == 32) {
973         xdata = (uch *)malloc(4*rpng2_info.width*rpng2_info.height);
974         pad = 32;
975     } else if (depth == 16) {
976         xdata = (uch *)malloc(2*rpng2_info.width*rpng2_info.height);
977         pad = 16;
978     } else /* depth == 8 */ {
979         xdata = (uch *)malloc(rpng2_info.width*rpng2_info.height);
980         pad = 8;
981     }
982
983     if (!xdata) {
984         fprintf(stderr, PROGNAME ":  unable to allocate image memory\n");
985         return 4;
986     }
987
988     ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
989       (char *)xdata, rpng2_info.width, rpng2_info.height, pad, 0);
990
991     if (!ximage) {
992         fprintf(stderr, PROGNAME ":  XCreateImage() failed\n");
993         free(xdata);
994         return 3;
995     }
996
997     /* to avoid testing the byte order every pixel (or doubling the size of
998      * the drawing routine with a giant if-test), we arbitrarily set the byte
999      * order to MSBFirst and let Xlib worry about inverting things on little-
1000      * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the
1001      * most efficient approach (the giant if-test would be better), but in
1002      * the interest of clarity, we'll take the easy way out... */
1003
1004     ximage->byte_order = MSBFirst;
1005
1006 /*---------------------------------------------------------------------------
1007     Fill window with the specified background color (default is black) or
1008     faked "background image" (but latter is disabled if 8-bit; gradients
1009     just waste palette entries).
1010   ---------------------------------------------------------------------------*/
1011
1012     if (bg_image)
1013         rpng2_x_load_bg_image();    /* resets bg_image if fails */
1014
1015     if (!bg_image) {
1016         if (depth == 24 || depth == 32) {
1017             bg_pixel = (bg_red   << RShift) |
1018                        (bg_green << GShift) |
1019                        (bg_blue  << BShift);
1020         } else if (depth == 16) {
1021             bg_pixel = (((bg_red   << 8) >> RShift) & RMask) |
1022                        (((bg_green << 8) >> GShift) & GMask) |
1023                        (((bg_blue  << 8) >> BShift) & BMask);
1024         } else /* depth == 8 */ {
1025
1026             /* GRR:  add 8-bit support */
1027
1028         }
1029         XSetForeground(display, gc, bg_pixel);
1030         XFillRectangle(display, window, gc, 0, 0, rpng2_info.width,
1031           rpng2_info.height);
1032     }
1033
1034 /*---------------------------------------------------------------------------
1035     Wait for first Expose event to do any drawing, then flush and return.
1036   ---------------------------------------------------------------------------*/
1037
1038     do
1039         XNextEvent(display, &e);
1040     while (e.type != Expose || e.xexpose.count);
1041
1042     XFlush(display);
1043
1044     return 0;
1045
1046 } /* end function rpng2_x_create_window() */
1047
1048
1049
1050
1051
1052 static int rpng2_x_load_bg_image(void)
1053 {
1054     uch *src;
1055     char *dest;
1056     uch r1, r2, g1, g2, b1, b2;
1057     uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
1058     int k, hmax, max;
1059     int xidx, yidx, yidx_max;
1060     int even_odd_vert, even_odd_horiz, even_odd;
1061     int invert_gradient2 = (bg[pat].type & 0x08);
1062     int invert_column;
1063     int ximage_rowbytes = ximage->bytes_per_line;
1064     ulg i, row;
1065     ulg pixel;
1066
1067 /*---------------------------------------------------------------------------
1068     Allocate buffer for fake background image to be used with transparent
1069     images; if this fails, revert to plain background color.
1070   ---------------------------------------------------------------------------*/
1071
1072     bg_rowbytes = 3 * rpng2_info.width;
1073     bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
1074     if (!bg_data) {
1075         fprintf(stderr, PROGNAME
1076           ":  unable to allocate memory for background image\n");
1077         bg_image = 0;
1078         return 1;
1079     }
1080
1081     bgscale = (pat == 0)? 8 : bgscale_default;
1082     yidx_max = bgscale - 1;
1083
1084 /*---------------------------------------------------------------------------
1085     Vertical gradients (ramps) in NxN squares, alternating direction and
1086     colors (N == bgscale).
1087   ---------------------------------------------------------------------------*/
1088
1089     if ((bg[pat].type & 0x07) == 0) {
1090         uch r1_min  = rgb[bg[pat].rgb1_min].r;
1091         uch g1_min  = rgb[bg[pat].rgb1_min].g;
1092         uch b1_min  = rgb[bg[pat].rgb1_min].b;
1093         uch r2_min  = rgb[bg[pat].rgb2_min].r;
1094         uch g2_min  = rgb[bg[pat].rgb2_min].g;
1095         uch b2_min  = rgb[bg[pat].rgb2_min].b;
1096         int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
1097         int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
1098         int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
1099         int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
1100         int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
1101         int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
1102
1103         for (row = 0;  row < rpng2_info.height;  ++row) {
1104             yidx = (int)(row % bgscale);
1105             even_odd_vert = (int)((row / bgscale) & 1);
1106
1107             r1 = r1_min + (r1_diff * yidx) / yidx_max;
1108             g1 = g1_min + (g1_diff * yidx) / yidx_max;
1109             b1 = b1_min + (b1_diff * yidx) / yidx_max;
1110             r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
1111             g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
1112             b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
1113
1114             r2 = r2_min + (r2_diff * yidx) / yidx_max;
1115             g2 = g2_min + (g2_diff * yidx) / yidx_max;
1116             b2 = b2_min + (b2_diff * yidx) / yidx_max;
1117             r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
1118             g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
1119             b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
1120
1121             dest = (char *)bg_data + row*bg_rowbytes;
1122             for (i = 0;  i < rpng2_info.width;  ++i) {
1123                 even_odd_horiz = (int)((i / bgscale) & 1);
1124                 even_odd = even_odd_vert ^ even_odd_horiz;
1125                 invert_column =
1126                   (even_odd_horiz && (bg[pat].type & 0x10));
1127                 if (even_odd == 0) {        /* gradient #1 */
1128                     if (invert_column) {
1129                         *dest++ = r1_inv;
1130                         *dest++ = g1_inv;
1131                         *dest++ = b1_inv;
1132                     } else {
1133                         *dest++ = r1;
1134                         *dest++ = g1;
1135                         *dest++ = b1;
1136                     }
1137                 } else {                    /* gradient #2 */
1138                     if ((invert_column && invert_gradient2) ||
1139                         (!invert_column && !invert_gradient2))
1140                     {
1141                         *dest++ = r2;       /* not inverted or */
1142                         *dest++ = g2;       /*  doubly inverted */
1143                         *dest++ = b2;
1144                     } else {
1145                         *dest++ = r2_inv;
1146                         *dest++ = g2_inv;   /* singly inverted */
1147                         *dest++ = b2_inv;
1148                     }
1149                 }
1150             }
1151         }
1152
1153 /*---------------------------------------------------------------------------
1154     Soft gradient-diamonds with scale = bgscale.  Code contributed by Adam
1155     M. Costello.
1156   ---------------------------------------------------------------------------*/
1157
1158     } else if ((bg[pat].type & 0x07) == 1) {
1159
1160         hmax = (bgscale-1)/2;   /* half the max weight of a color */
1161         max = 2*hmax;           /* the max weight of a color */
1162
1163         r1 = rgb[bg[pat].rgb1_max].r;
1164         g1 = rgb[bg[pat].rgb1_max].g;
1165         b1 = rgb[bg[pat].rgb1_max].b;
1166         r2 = rgb[bg[pat].rgb2_max].r;
1167         g2 = rgb[bg[pat].rgb2_max].g;
1168         b2 = rgb[bg[pat].rgb2_max].b;
1169
1170         for (row = 0;  row < rpng2_info.height;  ++row) {
1171             yidx = (int)(row % bgscale);
1172             if (yidx > hmax)
1173                 yidx = bgscale-1 - yidx;
1174             dest = (char *)bg_data + row*bg_rowbytes;
1175             for (i = 0;  i < rpng2_info.width;  ++i) {
1176                 xidx = (int)(i % bgscale);
1177                 if (xidx > hmax)
1178                     xidx = bgscale-1 - xidx;
1179                 k = xidx + yidx;
1180                 *dest++ = (k*r1 + (max-k)*r2) / max;
1181                 *dest++ = (k*g1 + (max-k)*g2) / max;
1182                 *dest++ = (k*b1 + (max-k)*b2) / max;
1183             }
1184         }
1185
1186 /*---------------------------------------------------------------------------
1187     Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1188     soids will equal bgscale?].  This one is slow but very cool.  Code con-
1189     tributed by Pieter S. van der Meulen (originally in Smalltalk).
1190   ---------------------------------------------------------------------------*/
1191
1192     } else if ((bg[pat].type & 0x07) == 2) {
1193         uch ch;
1194         int ii, x, y, hw, hh, grayspot;
1195         double freq, rotate, saturate, gray, intensity;
1196         double angle=0.0, aoffset=0.0, maxDist, dist;
1197         double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
1198
1199         fprintf(stderr, "%s:  computing radial background...",
1200           PROGNAME);
1201         fflush(stderr);
1202
1203         hh = (int)(rpng2_info.height / 2);
1204         hw = (int)(rpng2_info.width / 2);
1205
1206         /* variables for radial waves:
1207          *   aoffset:  number of degrees to rotate hue [CURRENTLY NOT USED]
1208          *   freq:  number of color beams originating from the center
1209          *   grayspot:  size of the graying center area (anti-alias)
1210          *   rotate:  rotation of the beams as a function of radius
1211          *   saturate:  saturation of beams' shape azimuthally
1212          */
1213         angle = CLIP(angle, 0.0, 360.0);
1214         grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
1215         freq = MAX((double)bg[pat].bg_freq, 0.0);
1216         saturate = (double)bg[pat].bg_bsat * 0.1;
1217         rotate = (double)bg[pat].bg_brot * 0.1;
1218         gray = 0.0;
1219         intensity = 0.0;
1220         maxDist = (double)((hw*hw) + (hh*hh));
1221
1222         for (row = 0;  row < rpng2_info.height;  ++row) {
1223             y = (int)(row - hh);
1224             dest = (char *)bg_data + row*bg_rowbytes;
1225             for (i = 0;  i < rpng2_info.width;  ++i) {
1226                 x = (int)(i - hw);
1227                 angle = (x == 0)? PI_2 : atan((double)y / (double)x);
1228                 gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
1229                 gray = MIN(1.0, gray);
1230                 dist = (double)((x*x) + (y*y)) / maxDist;
1231                 intensity = cos((angle+(rotate*dist*PI)) * freq) *
1232                   gray * saturate;
1233                 intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
1234                 hue = (angle + PI) * INV_PI_360 + aoffset;
1235                 s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
1236                 s = MIN(MAX(s,0.0), 1.0);
1237                 v = MIN(MAX(intensity,0.0), 1.0);
1238
1239                 if (s == 0.0) {
1240                     ch = (uch)(v * 255.0);
1241                     *dest++ = ch;
1242                     *dest++ = ch;
1243                     *dest++ = ch;
1244                 } else {
1245                     if ((hue < 0.0) || (hue >= 360.0))
1246                         hue -= (((int)(hue / 360.0)) * 360.0);
1247                     hue /= 60.0;
1248                     ii = (int)hue;
1249                     f = hue - (double)ii;
1250                     p = (1.0 - s) * v;
1251                     q = (1.0 - (s * f)) * v;
1252                     t = (1.0 - (s * (1.0 - f))) * v;
1253                     if      (ii == 0) { red = v; green = t; blue = p; }
1254                     else if (ii == 1) { red = q; green = v; blue = p; }
1255                     else if (ii == 2) { red = p; green = v; blue = t; }
1256                     else if (ii == 3) { red = p; green = q; blue = v; }
1257                     else if (ii == 4) { red = t; green = p; blue = v; }
1258                     else if (ii == 5) { red = v; green = p; blue = q; }
1259                     *dest++ = (uch)(red * 255.0);
1260                     *dest++ = (uch)(green * 255.0);
1261                     *dest++ = (uch)(blue * 255.0);
1262                 }
1263             }
1264         }
1265         fprintf(stderr, "done.\n");
1266         fflush(stderr);
1267     }
1268
1269 /*---------------------------------------------------------------------------
1270     Blast background image to display buffer before beginning PNG decode.
1271   ---------------------------------------------------------------------------*/
1272
1273     if (depth == 24 || depth == 32) {
1274         ulg red, green, blue;
1275         int bpp = ximage->bits_per_pixel;
1276
1277         for (row = 0;  row < rpng2_info.height;  ++row) {
1278             src = bg_data + row*bg_rowbytes;
1279             dest = ximage->data + row*ximage_rowbytes;
1280             if (bpp == 32) {    /* slightly optimized version */
1281                 for (i = rpng2_info.width;  i > 0;  --i) {
1282                     red   = *src++;
1283                     green = *src++;
1284                     blue  = *src++;
1285                     pixel = (red   << RShift) |
1286                             (green << GShift) |
1287                             (blue  << BShift);
1288                     /* recall that we set ximage->byte_order = MSBFirst above */
1289                     *dest++ = (char)((pixel >> 24) & 0xff);
1290                     *dest++ = (char)((pixel >> 16) & 0xff);
1291                     *dest++ = (char)((pixel >>  8) & 0xff);
1292                     *dest++ = (char)( pixel        & 0xff);
1293                 }
1294             } else {
1295                 for (i = rpng2_info.width;  i > 0;  --i) {
1296                     red   = *src++;
1297                     green = *src++;
1298                     blue  = *src++;
1299                     pixel = (red   << RShift) |
1300                             (green << GShift) |
1301                             (blue  << BShift);
1302                     /* recall that we set ximage->byte_order = MSBFirst above */
1303                     /* GRR BUG?  this assumes bpp == 24 & bits are packed low */
1304                     /*           (probably need to use RShift, RMask, etc.) */
1305                     *dest++ = (char)((pixel >> 16) & 0xff);
1306                     *dest++ = (char)((pixel >>  8) & 0xff);
1307                     *dest++ = (char)( pixel        & 0xff);
1308                 }
1309             }
1310         }
1311
1312     } else if (depth == 16) {
1313         ush red, green, blue;
1314
1315         for (row = 0;  row < rpng2_info.height;  ++row) {
1316             src = bg_data + row*bg_rowbytes;
1317             dest = ximage->data + row*ximage_rowbytes;
1318             for (i = rpng2_info.width;  i > 0;  --i) {
1319                 red   = ((ush)(*src) << 8);  ++src;
1320                 green = ((ush)(*src) << 8);  ++src;
1321                 blue  = ((ush)(*src) << 8);  ++src;
1322                 pixel = ((red   >> RShift) & RMask) |
1323                         ((green >> GShift) & GMask) |
1324                         ((blue  >> BShift) & BMask);
1325                 /* recall that we set ximage->byte_order = MSBFirst above */
1326                 *dest++ = (char)((pixel >>  8) & 0xff);
1327                 *dest++ = (char)( pixel        & 0xff);
1328             }
1329         }
1330
1331     } else /* depth == 8 */ {
1332
1333         /* GRR:  add 8-bit support */
1334
1335     }
1336
1337     XPutImage(display, window, gc, ximage, 0, 0, 0, 0, rpng2_info.width,
1338       rpng2_info.height);
1339
1340     return 0;
1341
1342 } /* end function rpng2_x_load_bg_image() */
1343
1344
1345
1346
1347
1348 static void rpng2_x_display_row(ulg row)
1349 {
1350     uch bg_red   = rpng2_info.bg_red;
1351     uch bg_green = rpng2_info.bg_green;
1352     uch bg_blue  = rpng2_info.bg_blue;
1353     uch *src, *src2=NULL;
1354     char *dest;
1355     uch r, g, b, a;
1356     int ximage_rowbytes = ximage->bytes_per_line;
1357     ulg i, pixel;
1358     static int rows=0, prevpass=(-1);
1359     static ulg firstrow;
1360
1361 /*---------------------------------------------------------------------------
1362     rows and firstrow simply track how many rows (and which ones) have not
1363     yet been displayed; alternatively, we could call XPutImage() for every
1364     row and not bother with the records-keeping.
1365   ---------------------------------------------------------------------------*/
1366
1367     Trace((stderr, "beginning rpng2_x_display_row()\n"))
1368
1369     if (rpng2_info.pass != prevpass) {
1370         if (pause_after_pass && rpng2_info.pass > 0) {
1371             XEvent e;
1372             KeySym k;
1373
1374             fprintf(stderr,
1375               "%s:  end of pass %d of 7; click in image window to continue\n",
1376               PROGNAME, prevpass + 1);
1377             do
1378                 XNextEvent(display, &e);
1379             while (!QUIT(e,k));
1380         }
1381         fprintf(stderr, "%s:  pass %d of 7\r", PROGNAME, rpng2_info.pass + 1);
1382         fflush(stderr);
1383         prevpass = rpng2_info.pass;
1384     }
1385
1386     if (rows == 0)
1387         firstrow = row;   /* first row that is not yet displayed */
1388
1389     ++rows;   /* count of rows received but not yet displayed */
1390
1391 /*---------------------------------------------------------------------------
1392     Aside from the use of the rpng2_info struct, the lack of an outer loop
1393     (over rows) and moving the XPutImage() call outside the "if (depth)"
1394     tests, this routine is identical to rpng_x_display_image() in the non-
1395     progressive version of the program.
1396   ---------------------------------------------------------------------------*/
1397
1398     if (depth == 24 || depth == 32) {
1399         ulg red, green, blue;
1400         int bpp = ximage->bits_per_pixel;
1401
1402         src = rpng2_info.image_data + row*rpng2_info.rowbytes;
1403         if (bg_image)
1404             src2 = bg_data + row*bg_rowbytes;
1405         dest = ximage->data + row*ximage_rowbytes;
1406         if (rpng2_info.channels == 3) {
1407             for (i = rpng2_info.width;  i > 0;  --i) {
1408                 red   = *src++;
1409                 green = *src++;
1410                 blue  = *src++;
1411                 pixel = (red   << RShift) |
1412                         (green << GShift) |
1413                         (blue  << BShift);
1414                 /* recall that we set ximage->byte_order = MSBFirst above */
1415                 if (bpp == 32) {
1416                     *dest++ = (char)((pixel >> 24) & 0xff);
1417                     *dest++ = (char)((pixel >> 16) & 0xff);
1418                     *dest++ = (char)((pixel >>  8) & 0xff);
1419                     *dest++ = (char)( pixel        & 0xff);
1420                 } else {
1421                     /* GRR BUG?  this assumes bpp == 24 & bits are packed low */
1422                     /*           (probably need to use RShift, RMask, etc.) */
1423                     *dest++ = (char)((pixel >> 16) & 0xff);
1424                     *dest++ = (char)((pixel >>  8) & 0xff);
1425                     *dest++ = (char)( pixel        & 0xff);
1426                 }
1427             }
1428         } else /* if (rpng2_info.channels == 4) */ {
1429             for (i = rpng2_info.width;  i > 0;  --i) {
1430                 r = *src++;
1431                 g = *src++;
1432                 b = *src++;
1433                 a = *src++;
1434                 if (bg_image) {
1435                     bg_red   = *src2++;
1436                     bg_green = *src2++;
1437                     bg_blue  = *src2++;
1438                 }
1439                 if (a == 255) {
1440                     red   = r;
1441                     green = g;
1442                     blue  = b;
1443                 } else if (a == 0) {
1444                     red   = bg_red;
1445                     green = bg_green;
1446                     blue  = bg_blue;
1447                 } else {
1448                     /* this macro (from png.h) composites the foreground
1449                      * and background values and puts the result into the
1450                      * first argument */
1451                     alpha_composite(red,   r, a, bg_red);
1452                     alpha_composite(green, g, a, bg_green);
1453                     alpha_composite(blue,  b, a, bg_blue);
1454                 }
1455                 pixel = (red   << RShift) |
1456                         (green << GShift) |
1457                         (blue  << BShift);
1458                 /* recall that we set ximage->byte_order = MSBFirst above */
1459                 if (bpp == 32) {
1460                     *dest++ = (char)((pixel >> 24) & 0xff);
1461                     *dest++ = (char)((pixel >> 16) & 0xff);
1462                     *dest++ = (char)((pixel >>  8) & 0xff);
1463                     *dest++ = (char)( pixel        & 0xff);
1464                 } else {
1465                     /* GRR BUG?  this assumes bpp == 24 & bits are packed low */
1466                     /*           (probably need to use RShift, RMask, etc.) */
1467                     *dest++ = (char)((pixel >> 16) & 0xff);
1468                     *dest++ = (char)((pixel >>  8) & 0xff);
1469                     *dest++ = (char)( pixel        & 0xff);
1470                 }
1471             }
1472         }
1473
1474     } else if (depth == 16) {
1475         ush red, green, blue;
1476
1477         src = rpng2_info.row_pointers[row];
1478         if (bg_image)
1479             src2 = bg_data + row*bg_rowbytes;
1480         dest = ximage->data + row*ximage_rowbytes;
1481         if (rpng2_info.channels == 3) {
1482             for (i = rpng2_info.width;  i > 0;  --i) {
1483                 red   = ((ush)(*src) << 8);
1484                 ++src;
1485                 green = ((ush)(*src) << 8);
1486                 ++src;
1487                 blue  = ((ush)(*src) << 8);
1488                 ++src;
1489                 pixel = ((red   >> RShift) & RMask) |
1490                         ((green >> GShift) & GMask) |
1491                         ((blue  >> BShift) & BMask);
1492                 /* recall that we set ximage->byte_order = MSBFirst above */
1493                 *dest++ = (char)((pixel >>  8) & 0xff);
1494                 *dest++ = (char)( pixel        & 0xff);
1495             }
1496         } else /* if (rpng2_info.channels == 4) */ {
1497             for (i = rpng2_info.width;  i > 0;  --i) {
1498                 r = *src++;
1499                 g = *src++;
1500                 b = *src++;
1501                 a = *src++;
1502                 if (bg_image) {
1503                     bg_red   = *src2++;
1504                     bg_green = *src2++;
1505                     bg_blue  = *src2++;
1506                 }
1507                 if (a == 255) {
1508                     red   = ((ush)r << 8);
1509                     green = ((ush)g << 8);
1510                     blue  = ((ush)b << 8);
1511                 } else if (a == 0) {
1512                     red   = ((ush)bg_red   << 8);
1513                     green = ((ush)bg_green << 8);
1514                     blue  = ((ush)bg_blue  << 8);
1515                 } else {
1516                     /* this macro (from png.h) composites the foreground
1517                      * and background values and puts the result back into
1518                      * the first argument (== fg byte here:  safe) */
1519                     alpha_composite(r, r, a, bg_red);
1520                     alpha_composite(g, g, a, bg_green);
1521                     alpha_composite(b, b, a, bg_blue);
1522                     red   = ((ush)r << 8);
1523                     green = ((ush)g << 8);
1524                     blue  = ((ush)b << 8);
1525                 }
1526                 pixel = ((red   >> RShift) & RMask) |
1527                         ((green >> GShift) & GMask) |
1528                         ((blue  >> BShift) & BMask);
1529                 /* recall that we set ximage->byte_order = MSBFirst above */
1530                 *dest++ = (char)((pixel >>  8) & 0xff);
1531                 *dest++ = (char)( pixel        & 0xff);
1532             }
1533         }
1534
1535     } else /* depth == 8 */ {
1536
1537         /* GRR:  add 8-bit support */
1538
1539     }
1540
1541
1542 /*---------------------------------------------------------------------------
1543     Display after every 16 rows or when on one of last two rows.  (Region
1544     may include previously displayed lines due to interlacing--i.e., not
1545     contiguous.  Also, second-to-last row is final one in interlaced images
1546     with odd number of rows.)  For demos, flush (and delay) after every 16th
1547     row so "sparse" passes don't go twice as fast.
1548   ---------------------------------------------------------------------------*/
1549
1550     if (demo_timing && (row - firstrow >= 16 || row >= rpng2_info.height-2)) {
1551         XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
1552           (int)firstrow, rpng2_info.width, row - firstrow + 1);
1553         XFlush(display);
1554         rows = 0;
1555         usleep(usleep_duration);
1556     } else
1557     if (!demo_timing && ((rows & 0xf) == 0 || row >= rpng2_info.height-2)) {
1558         XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
1559           (int)firstrow, rpng2_info.width, row - firstrow + 1);
1560         XFlush(display);
1561         rows = 0;
1562     }
1563
1564 }
1565
1566
1567
1568
1569
1570 static void rpng2_x_finish_display(void)
1571 {
1572     Trace((stderr, "beginning rpng2_x_finish_display()\n"))
1573
1574     /* last row has already been displayed by rpng2_x_display_row(), so we
1575      * have nothing to do here except set a flag and let the user know that
1576      * the image is done */
1577
1578     rpng2_info.state = kDone;
1579     printf(
1580       "Done.  Press Q, Esc or mouse button 1 (within image window) to quit.\n");
1581     fflush(stdout);
1582 }
1583
1584
1585
1586
1587
1588 static void rpng2_x_redisplay_image(ulg startcol, ulg startrow,
1589                                     ulg width, ulg height)
1590 {
1591     uch bg_red   = rpng2_info.bg_red;
1592     uch bg_green = rpng2_info.bg_green;
1593     uch bg_blue  = rpng2_info.bg_blue;
1594     uch *src, *src2=NULL;
1595     char *dest;
1596     uch r, g, b, a;
1597     ulg i, row, lastrow = 0;
1598     ulg pixel;
1599     int ximage_rowbytes = ximage->bytes_per_line;
1600
1601
1602     Trace((stderr, "beginning display loop (image_channels == %d)\n",
1603       rpng2_info.channels))
1604     Trace((stderr, "   (width = %ld, rowbytes = %d, ximage_rowbytes = %d)\n",
1605       rpng2_info.width, rpng2_info.rowbytes, ximage_rowbytes))
1606     Trace((stderr, "   (bpp = %d)\n", ximage->bits_per_pixel))
1607     Trace((stderr, "   (byte_order = %s)\n", ximage->byte_order == MSBFirst?
1608       "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown")))
1609
1610 /*---------------------------------------------------------------------------
1611     Aside from the use of the rpng2_info struct and of src2 (for background
1612     image), this routine is identical to rpng_x_display_image() in the non-
1613     progressive version of the program--for the simple reason that redisplay
1614     of the image against a new background happens after the image is fully
1615     decoded and therefore is, by definition, non-progressive.
1616   ---------------------------------------------------------------------------*/
1617
1618     if (depth == 24 || depth == 32) {
1619         ulg red, green, blue;
1620         int bpp = ximage->bits_per_pixel;
1621
1622         for (lastrow = row = startrow;  row < startrow+height;  ++row) {
1623             src = rpng2_info.image_data + row*rpng2_info.rowbytes;
1624             if (bg_image)
1625                 src2 = bg_data + row*bg_rowbytes;
1626             dest = ximage->data + row*ximage_rowbytes;
1627             if (rpng2_info.channels == 3) {
1628                 for (i = rpng2_info.width;  i > 0;  --i) {
1629                     red   = *src++;
1630                     green = *src++;
1631                     blue  = *src++;
1632 #ifdef NO_24BIT_MASKS
1633                     pixel = (red   << RShift) |
1634                             (green << GShift) |
1635                             (blue  << BShift);
1636                     /* recall that we set ximage->byte_order = MSBFirst above */
1637                     if (bpp == 32) {
1638                         *dest++ = (char)((pixel >> 24) & 0xff);
1639                         *dest++ = (char)((pixel >> 16) & 0xff);
1640                         *dest++ = (char)((pixel >>  8) & 0xff);
1641                         *dest++ = (char)( pixel        & 0xff);
1642                     } else {
1643                         /* this assumes bpp == 24 & bits are packed low */
1644                         /* (probably need to use RShift, RMask, etc.) */
1645                         *dest++ = (char)((pixel >> 16) & 0xff);
1646                         *dest++ = (char)((pixel >>  8) & 0xff);
1647                         *dest++ = (char)( pixel        & 0xff);
1648                     }
1649 #else
1650                     red   = (RShift < 0)? red   << (-RShift) : red   >> RShift;
1651                     green = (GShift < 0)? green << (-GShift) : green >> GShift;
1652                     blue  = (BShift < 0)? blue  << (-BShift) : blue  >> BShift;
1653                     pixel = (red & RMask) | (green & GMask) | (blue & BMask);
1654                     /* recall that we set ximage->byte_order = MSBFirst above */
1655                     if (bpp == 32) {
1656                         *dest++ = (char)((pixel >> 24) & 0xff);
1657                         *dest++ = (char)((pixel >> 16) & 0xff);
1658                         *dest++ = (char)((pixel >>  8) & 0xff);
1659                         *dest++ = (char)( pixel        & 0xff);
1660                     } else {
1661                         /* GRR BUG */
1662                         /* this assumes bpp == 24 & bits are packed low */
1663                         /* (probably need to use RShift/RMask/etc. here, too) */
1664                         *dest++ = (char)((pixel >> 16) & 0xff);
1665                         *dest++ = (char)((pixel >>  8) & 0xff);
1666                         *dest++ = (char)( pixel        & 0xff);
1667                     }
1668 #endif
1669                 }
1670
1671             } else /* if (rpng2_info.channels == 4) */ {
1672                 for (i = rpng2_info.width;  i > 0;  --i) {
1673                     r = *src++;
1674                     g = *src++;
1675                     b = *src++;
1676                     a = *src++;
1677                     if (bg_image) {
1678                         bg_red   = *src2++;
1679                         bg_green = *src2++;
1680                         bg_blue  = *src2++;
1681                     }
1682                     if (a == 255) {
1683                         red   = r;
1684                         green = g;
1685                         blue  = b;
1686                     } else if (a == 0) {
1687                         red   = bg_red;
1688                         green = bg_green;
1689                         blue  = bg_blue;
1690                     } else {
1691                         /* this macro (from png.h) composites the foreground
1692                          * and background values and puts the result into the
1693                          * first argument */
1694                         alpha_composite(red,   r, a, bg_red);
1695                         alpha_composite(green, g, a, bg_green);
1696                         alpha_composite(blue,  b, a, bg_blue);
1697                     }
1698 #ifdef NO_24BIT_MASKS
1699                     pixel = (red   << RShift) |
1700                             (green << GShift) |
1701                             (blue  << BShift);
1702                     /* recall that we set ximage->byte_order = MSBFirst above */
1703                     if (bpp == 32) {
1704                         *dest++ = (char)((pixel >> 24) & 0xff);
1705                         *dest++ = (char)((pixel >> 16) & 0xff);
1706                         *dest++ = (char)((pixel >>  8) & 0xff);
1707                         *dest++ = (char)( pixel        & 0xff);
1708                     } else {
1709                         /* this assumes bpp == 24 & bits are packed low */
1710                         /* (probably need to use RShift, RMask, etc.) */
1711                         *dest++ = (char)((pixel >> 16) & 0xff);
1712                         *dest++ = (char)((pixel >>  8) & 0xff);
1713                         *dest++ = (char)( pixel        & 0xff);
1714                     }
1715 #else
1716                     red   = (RShift < 0)? red   << (-RShift) : red   >> RShift;
1717                     green = (GShift < 0)? green << (-GShift) : green >> GShift;
1718                     blue  = (BShift < 0)? blue  << (-BShift) : blue  >> BShift;
1719                     pixel = (red & RMask) | (green & GMask) | (blue & BMask);
1720                     /* recall that we set ximage->byte_order = MSBFirst above */
1721                     if (bpp == 32) {
1722                         *dest++ = (char)((pixel >> 24) & 0xff);
1723                         *dest++ = (char)((pixel >> 16) & 0xff);
1724                         *dest++ = (char)((pixel >>  8) & 0xff);
1725                         *dest++ = (char)( pixel        & 0xff);
1726                     } else {
1727                         /* GRR BUG */
1728                         /* this assumes bpp == 24 & bits are packed low */
1729                         /* (probably need to use RShift/RMask/etc. here, too) */
1730                         *dest++ = (char)((pixel >> 16) & 0xff);
1731                         *dest++ = (char)((pixel >>  8) & 0xff);
1732                         *dest++ = (char)( pixel        & 0xff);
1733                     }
1734 #endif
1735                 }
1736             }
1737             /* display after every 16 lines */
1738             if (((row+1) & 0xf) == 0) {
1739                 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1740                   (int)lastrow, rpng2_info.width, 16);
1741                 XFlush(display);
1742                 lastrow = row + 1;
1743             }
1744         }
1745
1746     } else if (depth == 16) {
1747         ush red, green, blue;
1748
1749         for (lastrow = row = startrow;  row < startrow+height;  ++row) {
1750             src = rpng2_info.row_pointers[row];
1751             if (bg_image)
1752                 src2 = bg_data + row*bg_rowbytes;
1753             dest = ximage->data + row*ximage_rowbytes;
1754             if (rpng2_info.channels == 3) {
1755                 for (i = rpng2_info.width;  i > 0;  --i) {
1756                     red   = ((ush)(*src) << 8);
1757                     ++src;
1758                     green = ((ush)(*src) << 8);
1759                     ++src;
1760                     blue  = ((ush)(*src) << 8);
1761                     ++src;
1762                     pixel = ((red   >> RShift) & RMask) |
1763                             ((green >> GShift) & GMask) |
1764                             ((blue  >> BShift) & BMask);
1765                     /* recall that we set ximage->byte_order = MSBFirst above */
1766                     *dest++ = (char)((pixel >>  8) & 0xff);
1767                     *dest++ = (char)( pixel        & 0xff);
1768                 }
1769             } else /* if (rpng2_info.channels == 4) */ {
1770                 for (i = rpng2_info.width;  i > 0;  --i) {
1771                     r = *src++;
1772                     g = *src++;
1773                     b = *src++;
1774                     a = *src++;
1775                     if (bg_image) {
1776                         bg_red   = *src2++;
1777                         bg_green = *src2++;
1778                         bg_blue  = *src2++;
1779                     }
1780                     if (a == 255) {
1781                         red   = ((ush)r << 8);
1782                         green = ((ush)g << 8);
1783                         blue  = ((ush)b << 8);
1784                     } else if (a == 0) {
1785                         red   = ((ush)bg_red   << 8);
1786                         green = ((ush)bg_green << 8);
1787                         blue  = ((ush)bg_blue  << 8);
1788                     } else {
1789                         /* this macro (from png.h) composites the foreground
1790                          * and background values and puts the result back into
1791                          * the first argument (== fg byte here:  safe) */
1792                         alpha_composite(r, r, a, bg_red);
1793                         alpha_composite(g, g, a, bg_green);
1794                         alpha_composite(b, b, a, bg_blue);
1795                         red   = ((ush)r << 8);
1796                         green = ((ush)g << 8);
1797                         blue  = ((ush)b << 8);
1798                     }
1799                     pixel = ((red   >> RShift) & RMask) |
1800                             ((green >> GShift) & GMask) |
1801                             ((blue  >> BShift) & BMask);
1802                     /* recall that we set ximage->byte_order = MSBFirst above */
1803                     *dest++ = (char)((pixel >>  8) & 0xff);
1804                     *dest++ = (char)( pixel        & 0xff);
1805                 }
1806             }
1807             /* display after every 16 lines */
1808             if (((row+1) & 0xf) == 0) {
1809                 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1810                   (int)lastrow, rpng2_info.width, 16);
1811                 XFlush(display);
1812                 lastrow = row + 1;
1813             }
1814         }
1815
1816     } else /* depth == 8 */ {
1817
1818         /* GRR:  add 8-bit support */
1819
1820     }
1821
1822     Trace((stderr, "calling final XPutImage()\n"))
1823     if (lastrow < startrow+height) {
1824         XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1825           (int)lastrow, rpng2_info.width, rpng2_info.height-lastrow);
1826         XFlush(display);
1827     }
1828
1829 } /* end function rpng2_x_redisplay_image() */
1830
1831
1832
1833
1834
1835 #ifdef FEATURE_LOOP
1836
1837 static void rpng2_x_reload_bg_image(void)
1838 {
1839     char *dest;
1840     uch r1, r2, g1, g2, b1, b2;
1841     uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
1842     int k, hmax, max;
1843     int xidx, yidx, yidx_max;
1844     int even_odd_vert, even_odd_horiz, even_odd;
1845     int invert_gradient2 = (bg[pat].type & 0x08);
1846     int invert_column;
1847     ulg i, row;
1848
1849
1850     bgscale = (pat == 0)? 8 : bgscale_default;
1851     yidx_max = bgscale - 1;
1852
1853 /*---------------------------------------------------------------------------
1854     Vertical gradients (ramps) in NxN squares, alternating direction and
1855     colors (N == bgscale).
1856   ---------------------------------------------------------------------------*/
1857
1858     if ((bg[pat].type & 0x07) == 0) {
1859         uch r1_min  = rgb[bg[pat].rgb1_min].r;
1860         uch g1_min  = rgb[bg[pat].rgb1_min].g;
1861         uch b1_min  = rgb[bg[pat].rgb1_min].b;
1862         uch r2_min  = rgb[bg[pat].rgb2_min].r;
1863         uch g2_min  = rgb[bg[pat].rgb2_min].g;
1864         uch b2_min  = rgb[bg[pat].rgb2_min].b;
1865         int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
1866         int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
1867         int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
1868         int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
1869         int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
1870         int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
1871
1872         for (row = 0;  row < rpng2_info.height;  ++row) {
1873             yidx = (int)(row % bgscale);
1874             even_odd_vert = (int)((row / bgscale) & 1);
1875
1876             r1 = r1_min + (r1_diff * yidx) / yidx_max;
1877             g1 = g1_min + (g1_diff * yidx) / yidx_max;
1878             b1 = b1_min + (b1_diff * yidx) / yidx_max;
1879             r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
1880             g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
1881             b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
1882
1883             r2 = r2_min + (r2_diff * yidx) / yidx_max;
1884             g2 = g2_min + (g2_diff * yidx) / yidx_max;
1885             b2 = b2_min + (b2_diff * yidx) / yidx_max;
1886             r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
1887             g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
1888             b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
1889
1890             dest = (char *)bg_data + row*bg_rowbytes;
1891             for (i = 0;  i < rpng2_info.width;  ++i) {
1892                 even_odd_horiz = (int)((i / bgscale) & 1);
1893                 even_odd = even_odd_vert ^ even_odd_horiz;
1894                 invert_column =
1895                   (even_odd_horiz && (bg[pat].type & 0x10));
1896                 if (even_odd == 0) {        /* gradient #1 */
1897                     if (invert_column) {
1898                         *dest++ = r1_inv;
1899                         *dest++ = g1_inv;
1900                         *dest++ = b1_inv;
1901                     } else {
1902                         *dest++ = r1;
1903                         *dest++ = g1;
1904                         *dest++ = b1;
1905                     }
1906                 } else {                    /* gradient #2 */
1907                     if ((invert_column && invert_gradient2) ||
1908                         (!invert_column && !invert_gradient2))
1909                     {
1910                         *dest++ = r2;       /* not inverted or */
1911                         *dest++ = g2;       /*  doubly inverted */
1912                         *dest++ = b2;
1913                     } else {
1914                         *dest++ = r2_inv;
1915                         *dest++ = g2_inv;   /* singly inverted */
1916                         *dest++ = b2_inv;
1917                     }
1918                 }
1919             }
1920         }
1921
1922 /*---------------------------------------------------------------------------
1923     Soft gradient-diamonds with scale = bgscale.  Code contributed by Adam
1924     M. Costello.
1925   ---------------------------------------------------------------------------*/
1926
1927     } else if ((bg[pat].type & 0x07) == 1) {
1928
1929         hmax = (bgscale-1)/2;   /* half the max weight of a color */
1930         max = 2*hmax;           /* the max weight of a color */
1931
1932         r1 = rgb[bg[pat].rgb1_max].r;
1933         g1 = rgb[bg[pat].rgb1_max].g;
1934         b1 = rgb[bg[pat].rgb1_max].b;
1935         r2 = rgb[bg[pat].rgb2_max].r;
1936         g2 = rgb[bg[pat].rgb2_max].g;
1937         b2 = rgb[bg[pat].rgb2_max].b;
1938
1939         for (row = 0;  row < rpng2_info.height;  ++row) {
1940             yidx = (int)(row % bgscale);
1941             if (yidx > hmax)
1942                 yidx = bgscale-1 - yidx;
1943             dest = (char *)bg_data + row*bg_rowbytes;
1944             for (i = 0;  i < rpng2_info.width;  ++i) {
1945                 xidx = (int)(i % bgscale);
1946                 if (xidx > hmax)
1947                     xidx = bgscale-1 - xidx;
1948                 k = xidx + yidx;
1949                 *dest++ = (k*r1 + (max-k)*r2) / max;
1950                 *dest++ = (k*g1 + (max-k)*g2) / max;
1951                 *dest++ = (k*b1 + (max-k)*b2) / max;
1952             }
1953         }
1954
1955 /*---------------------------------------------------------------------------
1956     Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1957     soids will equal bgscale?].  This one is slow but very cool.  Code con-
1958     tributed by Pieter S. van der Meulen (originally in Smalltalk).
1959   ---------------------------------------------------------------------------*/
1960
1961     } else if ((bg[pat].type & 0x07) == 2) {
1962         uch ch;
1963         int ii, x, y, hw, hh, grayspot;
1964         double freq, rotate, saturate, gray, intensity;
1965         double angle=0.0, aoffset=0.0, maxDist, dist;
1966         double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
1967
1968         hh = (int)(rpng2_info.height / 2);
1969         hw = (int)(rpng2_info.width / 2);
1970
1971         /* variables for radial waves:
1972          *   aoffset:  number of degrees to rotate hue [CURRENTLY NOT USED]
1973          *   freq:  number of color beams originating from the center
1974          *   grayspot:  size of the graying center area (anti-alias)
1975          *   rotate:  rotation of the beams as a function of radius
1976          *   saturate:  saturation of beams' shape azimuthally
1977          */
1978         angle = CLIP(angle, 0.0, 360.0);
1979         grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
1980         freq = MAX((double)bg[pat].bg_freq, 0.0);
1981         saturate = (double)bg[pat].bg_bsat * 0.1;
1982         rotate = (double)bg[pat].bg_brot * 0.1;
1983         gray = 0.0;
1984         intensity = 0.0;
1985         maxDist = (double)((hw*hw) + (hh*hh));
1986
1987         for (row = 0;  row < rpng2_info.height;  ++row) {
1988             y = (int)(row - hh);
1989             dest = (char *)bg_data + row*bg_rowbytes;
1990             for (i = 0;  i < rpng2_info.width;  ++i) {
1991                 x = (int)(i - hw);
1992                 angle = (x == 0)? PI_2 : atan((double)y / (double)x);
1993                 gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
1994                 gray = MIN(1.0, gray);
1995                 dist = (double)((x*x) + (y*y)) / maxDist;
1996                 intensity = cos((angle+(rotate*dist*PI)) * freq) *
1997                   gray * saturate;
1998                 intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
1999                 hue = (angle + PI) * INV_PI_360 + aoffset;
2000                 s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
2001                 s = MIN(MAX(s,0.0), 1.0);
2002                 v = MIN(MAX(intensity,0.0), 1.0);
2003
2004                 if (s == 0.0) {
2005                     ch = (uch)(v * 255.0);
2006                     *dest++ = ch;
2007                     *dest++ = ch;
2008                     *dest++ = ch;
2009                 } else {
2010                     if ((hue < 0.0) || (hue >= 360.0))
2011                         hue -= (((int)(hue / 360.0)) * 360.0);
2012                     hue /= 60.0;
2013                     ii = (int)hue;
2014                     f = hue - (double)ii;
2015                     p = (1.0 - s) * v;
2016                     q = (1.0 - (s * f)) * v;
2017                     t = (1.0 - (s * (1.0 - f))) * v;
2018                     if      (ii == 0) { red = v; green = t; blue = p; }
2019                     else if (ii == 1) { red = q; green = v; blue = p; }
2020                     else if (ii == 2) { red = p; green = v; blue = t; }
2021                     else if (ii == 3) { red = p; green = q; blue = v; }
2022                     else if (ii == 4) { red = t; green = p; blue = v; }
2023                     else if (ii == 5) { red = v; green = p; blue = q; }
2024                     *dest++ = (uch)(red * 255.0);
2025                     *dest++ = (uch)(green * 255.0);
2026                     *dest++ = (uch)(blue * 255.0);
2027                 }
2028             }
2029         }
2030     }
2031
2032 } /* end function rpng2_x_reload_bg_image() */
2033
2034
2035
2036
2037
2038 static int is_number(char *p)
2039 {
2040     while (*p) {
2041         if (!isdigit(*p))
2042             return FALSE;
2043         ++p;
2044     }
2045     return TRUE;
2046 }
2047
2048 #endif /* FEATURE_LOOP */
2049
2050
2051
2052
2053
2054 static void rpng2_x_cleanup(void)
2055 {
2056     if (bg_image && bg_data) {
2057         free(bg_data);
2058         bg_data = NULL;
2059     }
2060
2061     if (rpng2_info.image_data) {
2062         free(rpng2_info.image_data);
2063         rpng2_info.image_data = NULL;
2064     }
2065
2066     if (rpng2_info.row_pointers) {
2067         free(rpng2_info.row_pointers);
2068         rpng2_info.row_pointers = NULL;
2069     }
2070
2071     if (ximage) {
2072         if (ximage->data) {
2073             free(ximage->data);           /* we allocated it, so we free it */
2074             ximage->data = (char *)NULL;  /*  instead of XDestroyImage() */
2075         }
2076         XDestroyImage(ximage);
2077         ximage = NULL;
2078     }
2079
2080     if (have_gc)
2081         XFreeGC(display, gc);
2082
2083     if (have_window)
2084         XDestroyWindow(display, window);
2085
2086     if (have_colormap)
2087         XFreeColormap(display, colormap);
2088
2089     if (have_nondefault_visual)
2090         XFree(visual_list);
2091 }
2092
2093
2094
2095
2096
2097 static int rpng2_x_msb(ulg u32val)
2098 {
2099     int i;
2100
2101     for (i = 31;  i >= 0;  --i) {
2102         if (u32val & 0x80000000L)
2103             break;
2104         u32val <<= 1;
2105     }
2106     return i;
2107 }