~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to source/Irrlicht/libpng/contrib/gregbook/rpng2-win.c

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*---------------------------------------------------------------------------
 
2
 
 
3
   rpng2 - progressive-model PNG display program                rpng2-win.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 32-bit Windows; it may compile under 16-bit Windows with a little
 
10
   tweaking (or maybe not).  Thanks to Adam Costello and Pieter S. van der
 
11
   Meulen for the "diamond" and "radial waves" patterns, respectively.
 
12
 
 
13
   to do (someday, maybe):
 
14
    - handle quoted command-line args (especially filenames with spaces)
 
15
    - finish resizable checkerboard-gradient (sizes 4-128?)
 
16
    - use %.1023s to simplify truncation of title-bar string?
 
17
    - have minimum window width:  oh well
 
18
 
 
19
  ---------------------------------------------------------------------------
 
20
 
 
21
   Changelog:
 
22
    - 1.01:  initial public release
 
23
    - 1.02:  fixed cut-and-paste error in usage screen (oops...)
 
24
    - 1.03:  modified to allow abbreviated options
 
25
    - 1.04:  removed bogus extra argument from usage fprintf() [Glenn R-P?];
 
26
              fixed command-line parsing bug
 
27
    - 1.10:  enabled "message window"/console (thanks to David Geldreich)
 
28
    - 1.20:  added runtime MMX-enabling/disabling and new -mmx* options
 
29
    - 1.21:  made minor tweak to usage screen to fit within 25-line console
 
30
    - 1.22:  added AMD64/EM64T support (__x86_64__)
 
31
    - 2.00:  dual-licensed (added GNU GPL)
 
32
    - 2.01:  fixed 64-bit typo in readpng2.c
 
33
    - 2.02:  fixed improper display of usage screen on PNG error(s); fixed
 
34
              unexpected-EOF and file-read-error cases
 
35
    - 2.03:  removed runtime MMX-enabling/disabling and obsolete -mmx* options
 
36
 
 
37
  ---------------------------------------------------------------------------
 
38
 
 
39
      Copyright (c) 1998-2008 Greg Roelofs.  All rights reserved.
 
40
 
 
41
      This software is provided "as is," without warranty of any kind,
 
42
      express or implied.  In no event shall the author or contributors
 
43
      be held liable for any damages arising in any way from the use of
 
44
      this software.
 
45
 
 
46
      The contents of this file are DUAL-LICENSED.  You may modify and/or
 
47
      redistribute this software according to the terms of one of the
 
48
      following two licenses (at your option):
 
49
 
 
50
 
 
51
      LICENSE 1 ("BSD-like with advertising clause"):
 
52
 
 
53
      Permission is granted to anyone to use this software for any purpose,
 
54
      including commercial applications, and to alter it and redistribute
 
55
      it freely, subject to the following restrictions:
 
56
 
 
57
      1. Redistributions of source code must retain the above copyright
 
58
         notice, disclaimer, and this list of conditions.
 
59
      2. Redistributions in binary form must reproduce the above copyright
 
60
         notice, disclaimer, and this list of conditions in the documenta-
 
61
         tion and/or other materials provided with the distribution.
 
62
      3. All advertising materials mentioning features or use of this
 
63
         software must display the following acknowledgment:
 
64
 
 
65
            This product includes software developed by Greg Roelofs
 
66
            and contributors for the book, "PNG: The Definitive Guide,"
 
67
            published by O'Reilly and Associates.
 
68
 
 
69
 
 
70
      LICENSE 2 (GNU GPL v2 or later):
 
71
 
 
72
      This program is free software; you can redistribute it and/or modify
 
73
      it under the terms of the GNU General Public License as published by
 
74
      the Free Software Foundation; either version 2 of the License, or
 
75
      (at your option) any later version.
 
76
 
 
77
      This program is distributed in the hope that it will be useful,
 
78
      but WITHOUT ANY WARRANTY; without even the implied warranty of
 
79
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
80
      GNU General Public License for more details.
 
81
 
 
82
      You should have received a copy of the GNU General Public License
 
83
      along with this program; if not, write to the Free Software Foundation,
 
84
      Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
85
 
 
86
  ---------------------------------------------------------------------------*/
 
87
 
 
88
#define PROGNAME  "rpng2-win"
 
89
#define LONGNAME  "Progressive PNG Viewer for Windows"
 
90
#define VERSION   "2.02 of 16 March 2008"
 
91
 
 
92
#include <stdio.h>
 
93
#include <stdlib.h>
 
94
#include <string.h>
 
95
#include <setjmp.h>    /* for jmpbuf declaration in readpng2.h */
 
96
#include <time.h>
 
97
#include <math.h>      /* only for PvdM background code */
 
98
#include <windows.h>
 
99
#ifdef __CYGWIN__
 
100
/* getch replacement. Turns out, we don't really need this,
 
101
 * but leave it here if we ever enable any of the uses of
 
102
 * _getch in the main code
 
103
 */
 
104
#include <unistd.h>
 
105
#include <termio.h>
 
106
#include <sys/ioctl.h>
 
107
int repl_getch( void )
 
108
{
 
109
  char ch;
 
110
  int fd = fileno(stdin);
 
111
  struct termio old_tty, new_tty;
 
112
 
 
113
  ioctl(fd, TCGETA, &old_tty);
 
114
  new_tty = old_tty;
 
115
  new_tty.c_lflag &= ~(ICANON | ECHO | ISIG);
 
116
  ioctl(fd, TCSETA, &new_tty);
 
117
  fread(&ch, 1, sizeof(ch), stdin);
 
118
  ioctl(fd, TCSETA, &old_tty);
 
119
 
 
120
  return ch;
 
121
}
 
122
#define _getch repl_getch
 
123
#else
 
124
#include <conio.h>     /* only for _getch() */
 
125
#endif
 
126
 
 
127
/* all for PvdM background code: */
 
128
#ifndef PI
 
129
#  define PI             3.141592653589793238
 
130
#endif
 
131
#define PI_2             (PI*0.5)
 
132
#define INV_PI_360       (360.0 / PI)
 
133
#define MAX(a,b)         (a>b?a:b)
 
134
#define MIN(a,b)         (a<b?a:b)
 
135
#define CLIP(a,min,max)  MAX(min,MIN((a),max))
 
136
#define ABS(a)           ((a)<0?-(a):(a))
 
137
#define CLIP8P(c)        MAX(0,(MIN((c),255)))   /* 8-bit pos. integer (uch) */
 
138
#define ROUNDF(f)        ((int)(f + 0.5))
 
139
 
 
140
#define rgb1_max   bg_freq
 
141
#define rgb1_min   bg_gray
 
142
#define rgb2_max   bg_bsat
 
143
#define rgb2_min   bg_brot
 
144
 
 
145
/* #define DEBUG */     /* this enables the Trace() macros */
 
146
 
 
147
#include "readpng2.h"   /* typedefs, common macros, readpng2 prototypes */
 
148
 
 
149
 
 
150
/* could just include png.h, but this macro is the only thing we need
 
151
 * (name and typedefs changed to local versions); note that side effects
 
152
 * only happen with alpha (which could easily be avoided with
 
153
 * "ush acopy = (alpha);") */
 
154
 
 
155
#define alpha_composite(composite, fg, alpha, bg) {               \
 
156
    ush temp = ((ush)(fg)*(ush)(alpha) +                          \
 
157
                (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128);  \
 
158
    (composite) = (uch)((temp + (temp >> 8)) >> 8);               \
 
159
}
 
160
 
 
161
 
 
162
#define INBUFSIZE 4096   /* with pseudo-timing on (1 sec delay/block), this
 
163
                          *  block size corresponds roughly to a download
 
164
                          *  speed 10% faster than theoretical 33.6K maximum
 
165
                          *  (assuming 8 data bits, 1 stop bit and no other
 
166
                          *  overhead) */
 
167
 
 
168
/* local prototypes */
 
169
static void       rpng2_win_init(void);
 
170
static int        rpng2_win_create_window(void);
 
171
static int        rpng2_win_load_bg_image(void);
 
172
static void       rpng2_win_display_row(ulg row);
 
173
static void       rpng2_win_finish_display(void);
 
174
static void       rpng2_win_cleanup(void);
 
175
LRESULT CALLBACK  rpng2_win_wndproc(HWND, UINT, WPARAM, LPARAM);
 
176
 
 
177
 
 
178
static char titlebar[1024];
 
179
static char *progname = PROGNAME;
 
180
static char *appname = LONGNAME;
 
181
static char *filename;
 
182
static FILE *infile;
 
183
 
 
184
static mainprog_info rpng2_info;
 
185
 
 
186
static uch inbuf[INBUFSIZE];
 
187
static int incount;
 
188
 
 
189
static int pat = 6;         /* must be less than num_bgpat */
 
190
static int bg_image = 0;
 
191
static int bgscale = 16;
 
192
static ulg bg_rowbytes;
 
193
static uch *bg_data;
 
194
 
 
195
static struct rgb_color {
 
196
    uch r, g, b;
 
197
} rgb[] = {
 
198
    {  0,   0,   0},    /*  0:  black */
 
199
    {255, 255, 255},    /*  1:  white */
 
200
    {173, 132,  57},    /*  2:  tan */
 
201
    { 64, 132,   0},    /*  3:  medium green */
 
202
    {189, 117,   1},    /*  4:  gold */
 
203
    {253, 249,   1},    /*  5:  yellow */
 
204
    {  0,   0, 255},    /*  6:  blue */
 
205
    {  0,   0, 120},    /*  7:  medium blue */
 
206
    {255,   0, 255},    /*  8:  magenta */
 
207
    { 64,   0,  64},    /*  9:  dark magenta */
 
208
    {255,   0,   0},    /* 10:  red */
 
209
    { 64,   0,   0},    /* 11:  dark red */
 
210
    {255, 127,   0},    /* 12:  orange */
 
211
    {192,  96,   0},    /* 13:  darker orange */
 
212
    { 24,  60,   0},    /* 14:  dark green-yellow */
 
213
    { 85, 125, 200}     /* 15:  ice blue */
 
214
};
 
215
/* not used for now, but should be for error-checking:
 
216
static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
 
217
 */
 
218
 
 
219
/*
 
220
    This whole struct is a fairly cheesy way to keep the number of
 
221
    command-line options to a minimum.  The radial-waves background
 
222
    type is a particularly poor fit to the integer elements of the
 
223
    struct...but a few macros and a little fixed-point math will do
 
224
    wonders for ya.
 
225
 
 
226
    type bits:
 
227
       F E D C B A 9 8 7 6 5 4 3 2 1 0
 
228
                             | | | | |
 
229
                             | | +-+-+-- 0 = sharp-edged checkerboard
 
230
                             | |         1 = soft diamonds
 
231
                             | |         2 = radial waves
 
232
                             | |       3-7 = undefined
 
233
                             | +-- gradient #2 inverted?
 
234
                             +-- alternating columns inverted?
 
235
 */
 
236
static struct background_pattern {
 
237
    ush type;
 
238
    int rgb1_max, rgb1_min;     /* or bg_freq, bg_gray */
 
239
    int rgb2_max, rgb2_min;     /* or bg_bsat, bg_brot (both scaled by 10)*/
 
240
} bg[] = {
 
241
    {0+8,   2,0,  1,15},        /* checkered:  tan/black vs. white/ice blue */
 
242
    {0+24,  2,0,  1,0},         /* checkered:  tan/black vs. white/black */
 
243
    {0+8,   4,5,  0,2},         /* checkered:  gold/yellow vs. black/tan */
 
244
    {0+8,   4,5,  0,6},         /* checkered:  gold/yellow vs. black/blue */
 
245
    {0,     7,0,  8,9},         /* checkered:  deep blue/black vs. magenta */
 
246
    {0+8,  13,0,  5,14},        /* checkered:  orange/black vs. yellow */
 
247
    {0+8,  12,0, 10,11},        /* checkered:  orange/black vs. red */
 
248
    {1,     7,0,  8,0},         /* diamonds:  deep blue/black vs. magenta */
 
249
    {1,    12,0, 11,0},         /* diamonds:  orange vs. dark red */
 
250
    {1,    10,0,  7,0},         /* diamonds:  red vs. medium blue */
 
251
    {1,     4,0,  5,0},         /* diamonds:  gold vs. yellow */
 
252
    {1,     3,0,  0,0},         /* diamonds:  medium green vs. black */
 
253
    {2,    16, 100,  20,   0},  /* radial:  ~hard radial color-beams */
 
254
    {2,    18, 100,  10,   2},  /* radial:  soft, curved radial color-beams */
 
255
    {2,    16, 256, 100, 250},  /* radial:  very tight spiral */
 
256
    {2, 10000, 256,  11,   0}   /* radial:  dipole-moire' (almost fractal) */
 
257
};
 
258
static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern);
 
259
 
 
260
 
 
261
/* Windows-specific global variables (could go in struct, but messy...) */
 
262
static ulg wimage_rowbytes;
 
263
static uch *dib;
 
264
static uch *wimage_data;
 
265
static BITMAPINFOHEADER *bmih;
 
266
 
 
267
static HWND global_hwnd;
 
268
static HINSTANCE global_hInst;
 
269
static int global_showmode;
 
270
 
 
271
 
 
272
 
 
273
 
 
274
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode)
 
275
{
 
276
    char *args[1024];                 /* arbitrary limit, but should suffice */
 
277
    char **argv = args;
 
278
    char *p, *q, *bgstr = NULL;
 
279
    int argc = 0;
 
280
    int rc, alen, flen;
 
281
    int error = 0;
 
282
    int timing = FALSE;
 
283
    int have_bg = FALSE;
 
284
    double LUT_exponent;              /* just the lookup table */
 
285
    double CRT_exponent = 2.2;        /* just the monitor */
 
286
    double default_display_exponent;  /* whole display system */
 
287
    MSG msg;
 
288
 
 
289
 
 
290
    /* First initialize a few things, just to be sure--memset takes care of
 
291
     * default background color (black), booleans (FALSE), pointers (NULL),
 
292
     * etc. */
 
293
 
 
294
    global_hInst = hInst;
 
295
    global_showmode = showmode;
 
296
    filename = (char *)NULL;
 
297
    memset(&rpng2_info, 0, sizeof(mainprog_info));
 
298
 
 
299
#ifndef __CYGWIN__
 
300
    /* Next reenable console output, which normally goes to the bit bucket
 
301
     * for windowed apps.  Closing the console window will terminate the
 
302
     * app.  Thanks to David.Geldreich@realviz.com for supplying the magical
 
303
     * incantation. */
 
304
 
 
305
    AllocConsole();
 
306
    freopen("CONOUT$", "a", stderr);
 
307
    freopen("CONOUT$", "a", stdout);
 
308
#endif
 
309
 
 
310
    /* Set the default value for our display-system exponent, i.e., the
 
311
     * product of the CRT exponent and the exponent corresponding to
 
312
     * the frame-buffer's lookup table (LUT), if any.  This is not an
 
313
     * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
 
314
     * ones), but it should cover 99% of the current possibilities.  And
 
315
     * yes, these ifdefs are completely wasted in a Windows program... */
 
316
 
 
317
#if defined(NeXT)
 
318
    /* third-party utilities can modify the default LUT exponent */
 
319
    LUT_exponent = 1.0 / 2.2;
 
320
    /*
 
321
    if (some_next_function_that_returns_gamma(&next_gamma))
 
322
        LUT_exponent = 1.0 / next_gamma;
 
323
     */
 
324
#elif defined(sgi)
 
325
    LUT_exponent = 1.0 / 1.7;
 
326
    /* there doesn't seem to be any documented function to
 
327
     * get the "gamma" value, so we do it the hard way */
 
328
    infile = fopen("/etc/config/system.glGammaVal", "r");
 
329
    if (infile) {
 
330
        double sgi_gamma;
 
331
 
 
332
        fgets(tmpline, 80, infile);
 
333
        fclose(infile);
 
334
        sgi_gamma = atof(tmpline);
 
335
        if (sgi_gamma > 0.0)
 
336
            LUT_exponent = 1.0 / sgi_gamma;
 
337
    }
 
338
#elif defined(Macintosh)
 
339
    LUT_exponent = 1.8 / 2.61;
 
340
    /*
 
341
    if (some_mac_function_that_returns_gamma(&mac_gamma))
 
342
        LUT_exponent = mac_gamma / 2.61;
 
343
     */
 
344
#else
 
345
    LUT_exponent = 1.0;   /* assume no LUT:  most PCs */
 
346
#endif
 
347
 
 
348
    /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
 
349
    default_display_exponent = LUT_exponent * CRT_exponent;
 
350
 
 
351
 
 
352
    /* If the user has set the SCREEN_GAMMA environment variable as suggested
 
353
     * (somewhat imprecisely) in the libpng documentation, use that; otherwise
 
354
     * use the default value we just calculated.  Either way, the user may
 
355
     * override this via a command-line option. */
 
356
 
 
357
    if ((p = getenv("SCREEN_GAMMA")) != NULL)
 
358
        rpng2_info.display_exponent = atof(p);
 
359
    else
 
360
        rpng2_info.display_exponent = default_display_exponent;
 
361
 
 
362
 
 
363
    /* Windows really hates command lines, so we have to set up our own argv.
 
364
     * Note that we do NOT bother with quoted arguments here, so don't use
 
365
     * filenames with spaces in 'em! */
 
366
 
 
367
    argv[argc++] = PROGNAME;
 
368
    p = cmd;
 
369
    for (;;) {
 
370
        if (*p == ' ')
 
371
            while (*++p == ' ')
 
372
                ;
 
373
        /* now p points at the first non-space after some spaces */
 
374
        if (*p == '\0')
 
375
            break;    /* nothing after the spaces:  done */
 
376
        argv[argc++] = q = p;
 
377
        while (*q && *q != ' ')
 
378
            ++q;
 
379
        /* now q points at a space or the end of the string */
 
380
        if (*q == '\0')
 
381
            break;    /* last argv already terminated; quit */
 
382
        *q = '\0';    /* change space to terminator */
 
383
        p = q + 1;
 
384
    }
 
385
    argv[argc] = NULL;   /* terminate the argv array itself */
 
386
 
 
387
 
 
388
    /* Now parse the command line for options and the PNG filename. */
 
389
 
 
390
    while (*++argv && !error) {
 
391
        if (!strncmp(*argv, "-gamma", 2)) {
 
392
            if (!*++argv)
 
393
                ++error;
 
394
            else {
 
395
                rpng2_info.display_exponent = atof(*argv);
 
396
                if (rpng2_info.display_exponent <= 0.0)
 
397
                    ++error;
 
398
            }
 
399
        } else if (!strncmp(*argv, "-bgcolor", 4)) {
 
400
            if (!*++argv)
 
401
                ++error;
 
402
            else {
 
403
                bgstr = *argv;
 
404
                if (strlen(bgstr) != 7 || bgstr[0] != '#')
 
405
                    ++error;
 
406
                else {
 
407
                    have_bg = TRUE;
 
408
                    bg_image = FALSE;
 
409
                }
 
410
            }
 
411
        } else if (!strncmp(*argv, "-bgpat", 4)) {
 
412
            if (!*++argv)
 
413
                ++error;
 
414
            else {
 
415
                pat = atoi(*argv) - 1;
 
416
                if (pat < 0 || pat >= num_bgpat)
 
417
                    ++error;
 
418
                else {
 
419
                    bg_image = TRUE;
 
420
                    have_bg = FALSE;
 
421
                }
 
422
            }
 
423
        } else if (!strncmp(*argv, "-timing", 2)) {
 
424
            timing = TRUE;
 
425
        } else {
 
426
            if (**argv != '-') {
 
427
                filename = *argv;
 
428
                if (argv[1])   /* shouldn't be any more args after filename */
 
429
                    ++error;
 
430
            } else
 
431
                ++error;   /* not expecting any other options */
 
432
        }
 
433
    }
 
434
 
 
435
    if (!filename)
 
436
        ++error;
 
437
 
 
438
 
 
439
    /* print usage screen if any errors up to this point */
 
440
 
 
441
    if (error) {
 
442
#ifndef __CYGWIN__
 
443
        int ch;
 
444
#endif
 
445
 
 
446
        fprintf(stderr, "\n%s %s:  %s\n\n", PROGNAME, VERSION, appname);
 
447
        readpng2_version_info();
 
448
        fprintf(stderr, "\n"
 
449
          "Usage:  %s [-gamma exp] [-bgcolor bg | -bgpat pat] [-timing]\n"
 
450
          "        %*s file.png\n\n"
 
451
          "    exp \ttransfer-function exponent (``gamma'') of the display\n"
 
452
          "\t\t  system in floating-point format (e.g., ``%.1f''); equal\n"
 
453
          "\t\t  to the product of the lookup-table exponent (varies)\n"
 
454
          "\t\t  and the CRT exponent (usually 2.2); must be positive\n"
 
455
          "    bg  \tdesired background color in 7-character hex RGB format\n"
 
456
          "\t\t  (e.g., ``#ff7700'' for orange:  same as HTML colors);\n"
 
457
          "\t\t  used with transparent images; overrides -bgpat option\n"
 
458
          "    pat \tdesired background pattern number (1-%d); used with\n"
 
459
          "\t\t  transparent images; overrides -bgcolor option\n"
 
460
          "    -timing\tenables delay for every block read, to simulate modem\n"
 
461
          "\t\t  download of image (~36 Kbps)\n"
 
462
          "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n"
 
463
#ifndef __CYGWIN__
 
464
          "Press Q or Esc to quit this usage screen. ",
 
465
#else
 
466
          ,
 
467
#endif
 
468
          PROGNAME,
 
469
#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \
 
470
    !(defined(__CYGWIN__) || defined(__MINGW32__))
 
471
          (int)strlen(PROGNAME), " ",
 
472
#endif
 
473
          (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat);
 
474
        fflush(stderr);
 
475
#ifndef __CYGWIN__
 
476
        do
 
477
            ch = _getch();
 
478
        while (ch != 'q' && ch != 'Q' && ch != 0x1B);
 
479
#endif
 
480
        exit(1);
 
481
    }
 
482
 
 
483
 
 
484
    if (!(infile = fopen(filename, "rb"))) {
 
485
        fprintf(stderr, PROGNAME ":  can't open PNG file [%s]\n", filename);
 
486
        ++error;
 
487
    } else {
 
488
        incount = fread(inbuf, 1, INBUFSIZE, infile);
 
489
        if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
 
490
            fprintf(stderr, PROGNAME
 
491
              ":  [%s] is not a PNG file: incorrect signature\n",
 
492
              filename);
 
493
            ++error;
 
494
        } else if ((rc = readpng2_init(&rpng2_info)) != 0) {
 
495
            switch (rc) {
 
496
                case 2:
 
497
                    fprintf(stderr, PROGNAME
 
498
                      ":  [%s] has bad IHDR (libpng longjmp)\n", filename);
 
499
                    break;
 
500
                case 4:
 
501
                    fprintf(stderr, PROGNAME ":  insufficient memory\n");
 
502
                    break;
 
503
                default:
 
504
                    fprintf(stderr, PROGNAME
 
505
                      ":  unknown readpng2_init() error\n");
 
506
                    break;
 
507
            }
 
508
            ++error;
 
509
        }
 
510
        if (error)
 
511
            fclose(infile);
 
512
    }
 
513
 
 
514
 
 
515
    if (error) {
 
516
#ifndef __CYGWIN__
 
517
        int ch;
 
518
#endif
 
519
 
 
520
        fprintf(stderr, PROGNAME ":  aborting.\n");
 
521
#ifndef __CYGWIN__
 
522
        do
 
523
            ch = _getch();
 
524
        while (ch != 'q' && ch != 'Q' && ch != 0x1B);
 
525
#endif
 
526
        exit(2);
 
527
    } else {
 
528
        fprintf(stderr, "\n%s %s:  %s\n", PROGNAME, VERSION, appname);
 
529
#ifndef __CYGWIN__
 
530
        fprintf(stderr,
 
531
          "\n   [console window:  closing this window will terminate %s]\n\n",
 
532
          PROGNAME);
 
533
#endif
 
534
        fflush(stderr);
 
535
    }
 
536
 
 
537
 
 
538
    /* set the title-bar string, but make sure buffer doesn't overflow */
 
539
 
 
540
    alen = strlen(appname);
 
541
    flen = strlen(filename);
 
542
    if (alen + flen + 3 > 1023)
 
543
        sprintf(titlebar, "%s:  ...%s", appname, filename+(alen+flen+6-1023));
 
544
    else
 
545
        sprintf(titlebar, "%s:  %s", appname, filename);
 
546
 
 
547
 
 
548
    /* set some final rpng2_info variables before entering main data loop */
 
549
 
 
550
    if (have_bg) {
 
551
        unsigned r, g, b;   /* this approach quiets compiler warnings */
 
552
 
 
553
        sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
 
554
        rpng2_info.bg_red   = (uch)r;
 
555
        rpng2_info.bg_green = (uch)g;
 
556
        rpng2_info.bg_blue  = (uch)b;
 
557
    } else
 
558
        rpng2_info.need_bgcolor = TRUE;
 
559
 
 
560
    rpng2_info.state = kPreInit;
 
561
    rpng2_info.mainprog_init = rpng2_win_init;
 
562
    rpng2_info.mainprog_display_row = rpng2_win_display_row;
 
563
    rpng2_info.mainprog_finish_display = rpng2_win_finish_display;
 
564
 
 
565
 
 
566
    /* OK, this is the fun part:  call readpng2_decode_data() at the start of
 
567
     * the loop to deal with our first buffer of data (read in above to verify
 
568
     * that the file is a PNG image), then loop through the file and continue
 
569
     * calling the same routine to handle each chunk of data.  It in turn
 
570
     * passes the data to libpng, which will invoke one or more of our call-
 
571
     * backs as decoded data become available.  We optionally call Sleep() for
 
572
     * one second per iteration to simulate downloading the image via an analog
 
573
     * modem. */
 
574
 
 
575
    for (;;) {
 
576
        Trace((stderr, "about to call readpng2_decode_data()\n"))
 
577
        if (readpng2_decode_data(&rpng2_info, inbuf, incount))
 
578
            ++error;
 
579
        Trace((stderr, "done with readpng2_decode_data()\n"))
 
580
 
 
581
        if (error || incount != INBUFSIZE || rpng2_info.state == kDone) {
 
582
            if (rpng2_info.state == kDone) {
 
583
                Trace((stderr, "done decoding PNG image\n"))
 
584
            } else if (ferror(infile)) {
 
585
                fprintf(stderr, PROGNAME
 
586
                  ":  error while reading PNG image file\n");
 
587
                exit(3);
 
588
            } else if (feof(infile)) {
 
589
                fprintf(stderr, PROGNAME ":  end of file reached "
 
590
                  "(unexpectedly) while reading PNG image file\n");
 
591
                exit(3);
 
592
            } else /* if (error) */ {
 
593
                // will print error message below
 
594
            }
 
595
            break;
 
596
        }
 
597
 
 
598
        if (timing)
 
599
            Sleep(1000L);
 
600
 
 
601
        incount = fread(inbuf, 1, INBUFSIZE, infile);
 
602
    }
 
603
 
 
604
 
 
605
    /* clean up PNG stuff and report any decoding errors */
 
606
 
 
607
    fclose(infile);
 
608
    Trace((stderr, "about to call readpng2_cleanup()\n"))
 
609
    readpng2_cleanup(&rpng2_info);
 
610
 
 
611
    if (error) {
 
612
        fprintf(stderr, PROGNAME ":  libpng error while decoding PNG image\n");
 
613
        exit(3);
 
614
    }
 
615
 
 
616
 
 
617
    /* wait for the user to tell us when to quit */
 
618
 
 
619
    while (GetMessage(&msg, NULL, 0, 0)) {
 
620
        TranslateMessage(&msg);
 
621
        DispatchMessage(&msg);
 
622
    }
 
623
 
 
624
 
 
625
    /* we're done:  clean up all image and Windows resources and go away */
 
626
 
 
627
    Trace((stderr, "about to call rpng2_win_cleanup()\n"))
 
628
    rpng2_win_cleanup();
 
629
 
 
630
    return msg.wParam;
 
631
}
 
632
 
 
633
 
 
634
 
 
635
 
 
636
 
 
637
/* this function is called by readpng2_info_callback() in readpng2.c, which
 
638
 * in turn is called by libpng after all of the pre-IDAT chunks have been
 
639
 * read and processed--i.e., we now have enough info to finish initializing */
 
640
 
 
641
static void rpng2_win_init()
 
642
{
 
643
    ulg i;
 
644
    ulg rowbytes = rpng2_info.rowbytes;
 
645
 
 
646
    Trace((stderr, "beginning rpng2_win_init()\n"))
 
647
    Trace((stderr, "  rowbytes = %d\n", rpng2_info.rowbytes))
 
648
    Trace((stderr, "  width  = %ld\n", rpng2_info.width))
 
649
    Trace((stderr, "  height = %ld\n", rpng2_info.height))
 
650
 
 
651
    rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
 
652
    if (!rpng2_info.image_data) {
 
653
        readpng2_cleanup(&rpng2_info);
 
654
        return;
 
655
    }
 
656
 
 
657
    rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
 
658
    if (!rpng2_info.row_pointers) {
 
659
        free(rpng2_info.image_data);
 
660
        rpng2_info.image_data = NULL;
 
661
        readpng2_cleanup(&rpng2_info);
 
662
        return;
 
663
    }
 
664
 
 
665
    for (i = 0;  i < rpng2_info.height;  ++i)
 
666
        rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
 
667
 
 
668
/*---------------------------------------------------------------------------
 
669
    Do the basic Windows initialization stuff, make the window, and fill it
 
670
    with the user-specified, file-specified or default background color.
 
671
  ---------------------------------------------------------------------------*/
 
672
 
 
673
    if (rpng2_win_create_window()) {
 
674
        readpng2_cleanup(&rpng2_info);
 
675
        return;
 
676
    }
 
677
 
 
678
    rpng2_info.state = kWindowInit;
 
679
}
 
680
 
 
681
 
 
682
 
 
683
 
 
684
 
 
685
static int rpng2_win_create_window()
 
686
{
 
687
    uch bg_red   = rpng2_info.bg_red;
 
688
    uch bg_green = rpng2_info.bg_green;
 
689
    uch bg_blue  = rpng2_info.bg_blue;
 
690
    uch *dest;
 
691
    int extra_width, extra_height;
 
692
    ulg i, j;
 
693
    WNDCLASSEX wndclass;
 
694
    RECT rect;
 
695
 
 
696
 
 
697
/*---------------------------------------------------------------------------
 
698
    Allocate memory for the display-specific version of the image (round up
 
699
    to multiple of 4 for Windows DIB).
 
700
  ---------------------------------------------------------------------------*/
 
701
 
 
702
    wimage_rowbytes = ((3*rpng2_info.width + 3L) >> 2) << 2;
 
703
 
 
704
    if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) +
 
705
                              wimage_rowbytes*rpng2_info.height)))
 
706
    {
 
707
        return 4;   /* fail */
 
708
    }
 
709
 
 
710
/*---------------------------------------------------------------------------
 
711
    Initialize the DIB.  Negative height means to use top-down BMP ordering
 
712
    (must be uncompressed, but that's what we want).  Bit count of 1, 4 or 8
 
713
    implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values
 
714
    directly => wimage_data begins immediately after BMP header.
 
715
  ---------------------------------------------------------------------------*/
 
716
 
 
717
    memset(dib, 0, sizeof(BITMAPINFOHEADER));
 
718
    bmih = (BITMAPINFOHEADER *)dib;
 
719
    bmih->biSize = sizeof(BITMAPINFOHEADER);
 
720
    bmih->biWidth = rpng2_info.width;
 
721
    bmih->biHeight = -((long)rpng2_info.height);
 
722
    bmih->biPlanes = 1;
 
723
    bmih->biBitCount = 24;
 
724
    bmih->biCompression = 0;
 
725
    wimage_data = dib + sizeof(BITMAPINFOHEADER);
 
726
 
 
727
/*---------------------------------------------------------------------------
 
728
    Fill window with the specified background color (default is black), but
 
729
    defer loading faked "background image" until window is displayed (may be
 
730
    slow to compute).  Data are in BGR order.
 
731
  ---------------------------------------------------------------------------*/
 
732
 
 
733
    if (bg_image) {   /* just fill with black for now */
 
734
        memset(wimage_data, 0, wimage_rowbytes*rpng2_info.height);
 
735
    } else {
 
736
        for (j = 0;  j < rpng2_info.height;  ++j) {
 
737
            dest = wimage_data + j*wimage_rowbytes;
 
738
            for (i = rpng2_info.width;  i > 0;  --i) {
 
739
                *dest++ = bg_blue;
 
740
                *dest++ = bg_green;
 
741
                *dest++ = bg_red;
 
742
            }
 
743
        }
 
744
    }
 
745
 
 
746
/*---------------------------------------------------------------------------
 
747
    Set the window parameters.
 
748
  ---------------------------------------------------------------------------*/
 
749
 
 
750
    memset(&wndclass, 0, sizeof(wndclass));
 
751
 
 
752
    wndclass.cbSize = sizeof(wndclass);
 
753
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
 
754
    wndclass.lpfnWndProc = rpng2_win_wndproc;
 
755
    wndclass.hInstance = global_hInst;
 
756
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 
757
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
 
758
    wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
 
759
    wndclass.lpszMenuName = NULL;
 
760
    wndclass.lpszClassName = progname;
 
761
    wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
 
762
 
 
763
    RegisterClassEx(&wndclass);
 
764
 
 
765
/*---------------------------------------------------------------------------
 
766
    Finally, create the window.
 
767
  ---------------------------------------------------------------------------*/
 
768
 
 
769
    extra_width  = 2*(GetSystemMetrics(SM_CXBORDER) +
 
770
                      GetSystemMetrics(SM_CXDLGFRAME));
 
771
    extra_height = 2*(GetSystemMetrics(SM_CYBORDER) +
 
772
                      GetSystemMetrics(SM_CYDLGFRAME)) +
 
773
                      GetSystemMetrics(SM_CYCAPTION);
 
774
 
 
775
    global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW,
 
776
      CW_USEDEFAULT, CW_USEDEFAULT, rpng2_info.width+extra_width,
 
777
      rpng2_info.height+extra_height, NULL, NULL, global_hInst, NULL);
 
778
 
 
779
    ShowWindow(global_hwnd, global_showmode);
 
780
    UpdateWindow(global_hwnd);
 
781
 
 
782
/*---------------------------------------------------------------------------
 
783
    Now compute the background image and display it.  If it fails (memory
 
784
    allocation), revert to a plain background color.
 
785
  ---------------------------------------------------------------------------*/
 
786
 
 
787
    if (bg_image) {
 
788
        static const char *msg = "Computing background image...";
 
789
        int x, y, len = strlen(msg);
 
790
        HDC hdc = GetDC(global_hwnd);
 
791
        TEXTMETRIC tm;
 
792
 
 
793
        GetTextMetrics(hdc, &tm);
 
794
        x = (rpng2_info.width - len*tm.tmAveCharWidth)/2;
 
795
        y = (rpng2_info.height - tm.tmHeight)/2;
 
796
        SetBkMode(hdc, TRANSPARENT);
 
797
        SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
 
798
        /* this can still begin out of bounds even if x is positive (???): */
 
799
        TextOut(hdc, ((x < 0)? 0 : x), ((y < 0)? 0 : y), msg, len);
 
800
        ReleaseDC(global_hwnd, hdc);
 
801
 
 
802
        rpng2_win_load_bg_image();   /* resets bg_image if fails */
 
803
    }
 
804
 
 
805
    if (!bg_image) {
 
806
        for (j = 0;  j < rpng2_info.height;  ++j) {
 
807
            dest = wimage_data + j*wimage_rowbytes;
 
808
            for (i = rpng2_info.width;  i > 0;  --i) {
 
809
                *dest++ = bg_blue;
 
810
                *dest++ = bg_green;
 
811
                *dest++ = bg_red;
 
812
            }
 
813
        }
 
814
    }
 
815
 
 
816
    rect.left = 0L;
 
817
    rect.top = 0L;
 
818
    rect.right = (LONG)rpng2_info.width;       /* possibly off by one? */
 
819
    rect.bottom = (LONG)rpng2_info.height;     /* possibly off by one? */
 
820
    InvalidateRect(global_hwnd, &rect, FALSE);
 
821
    UpdateWindow(global_hwnd);                 /* similar to XFlush() */
 
822
 
 
823
    return 0;
 
824
 
 
825
} /* end function rpng2_win_create_window() */
 
826
 
 
827
 
 
828
 
 
829
 
 
830
 
 
831
static int rpng2_win_load_bg_image()
 
832
{
 
833
    uch *src, *dest;
 
834
    uch r1, r2, g1, g2, b1, b2;
 
835
    uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
 
836
    int k, hmax, max;
 
837
    int xidx, yidx, yidx_max = (bgscale-1);
 
838
    int even_odd_vert, even_odd_horiz, even_odd;
 
839
    int invert_gradient2 = (bg[pat].type & 0x08);
 
840
    int invert_column;
 
841
    ulg i, row;
 
842
 
 
843
/*---------------------------------------------------------------------------
 
844
    Allocate buffer for fake background image to be used with transparent
 
845
    images; if this fails, revert to plain background color.
 
846
  ---------------------------------------------------------------------------*/
 
847
 
 
848
    bg_rowbytes = 3 * rpng2_info.width;
 
849
    bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
 
850
    if (!bg_data) {
 
851
        fprintf(stderr, PROGNAME
 
852
          ":  unable to allocate memory for background image\n");
 
853
        bg_image = 0;
 
854
        return 1;
 
855
    }
 
856
 
 
857
/*---------------------------------------------------------------------------
 
858
    Vertical gradients (ramps) in NxN squares, alternating direction and
 
859
    colors (N == bgscale).
 
860
  ---------------------------------------------------------------------------*/
 
861
 
 
862
    if ((bg[pat].type & 0x07) == 0) {
 
863
        uch r1_min  = rgb[bg[pat].rgb1_min].r;
 
864
        uch g1_min  = rgb[bg[pat].rgb1_min].g;
 
865
        uch b1_min  = rgb[bg[pat].rgb1_min].b;
 
866
        uch r2_min  = rgb[bg[pat].rgb2_min].r;
 
867
        uch g2_min  = rgb[bg[pat].rgb2_min].g;
 
868
        uch b2_min  = rgb[bg[pat].rgb2_min].b;
 
869
        int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
 
870
        int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
 
871
        int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
 
872
        int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
 
873
        int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
 
874
        int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
 
875
 
 
876
        for (row = 0;  row < rpng2_info.height;  ++row) {
 
877
            yidx = row % bgscale;
 
878
            even_odd_vert = (row / bgscale) & 1;
 
879
 
 
880
            r1 = r1_min + (r1_diff * yidx) / yidx_max;
 
881
            g1 = g1_min + (g1_diff * yidx) / yidx_max;
 
882
            b1 = b1_min + (b1_diff * yidx) / yidx_max;
 
883
            r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
 
884
            g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
 
885
            b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
 
886
 
 
887
            r2 = r2_min + (r2_diff * yidx) / yidx_max;
 
888
            g2 = g2_min + (g2_diff * yidx) / yidx_max;
 
889
            b2 = b2_min + (b2_diff * yidx) / yidx_max;
 
890
            r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
 
891
            g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
 
892
            b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
 
893
 
 
894
            dest = bg_data + row*bg_rowbytes;
 
895
            for (i = 0;  i < rpng2_info.width;  ++i) {
 
896
                even_odd_horiz = (i / bgscale) & 1;
 
897
                even_odd = even_odd_vert ^ even_odd_horiz;
 
898
                invert_column =
 
899
                  (even_odd_horiz && (bg[pat].type & 0x10));
 
900
                if (even_odd == 0) {         /* gradient #1 */
 
901
                    if (invert_column) {
 
902
                        *dest++ = r1_inv;
 
903
                        *dest++ = g1_inv;
 
904
                        *dest++ = b1_inv;
 
905
                    } else {
 
906
                        *dest++ = r1;
 
907
                        *dest++ = g1;
 
908
                        *dest++ = b1;
 
909
                    }
 
910
                } else {                     /* gradient #2 */
 
911
                    if ((invert_column && invert_gradient2) ||
 
912
                        (!invert_column && !invert_gradient2))
 
913
                    {
 
914
                        *dest++ = r2;        /* not inverted or */
 
915
                        *dest++ = g2;        /*  doubly inverted */
 
916
                        *dest++ = b2;
 
917
                    } else {
 
918
                        *dest++ = r2_inv;
 
919
                        *dest++ = g2_inv;    /* singly inverted */
 
920
                        *dest++ = b2_inv;
 
921
                    }
 
922
                }
 
923
            }
 
924
        }
 
925
 
 
926
/*---------------------------------------------------------------------------
 
927
    Soft gradient-diamonds with scale = bgscale.  Code contributed by Adam
 
928
    M. Costello.
 
929
  ---------------------------------------------------------------------------*/
 
930
 
 
931
    } else if ((bg[pat].type & 0x07) == 1) {
 
932
 
 
933
        hmax = (bgscale-1)/2;   /* half the max weight of a color */
 
934
        max = 2*hmax;           /* the max weight of a color */
 
935
 
 
936
        r1 = rgb[bg[pat].rgb1_max].r;
 
937
        g1 = rgb[bg[pat].rgb1_max].g;
 
938
        b1 = rgb[bg[pat].rgb1_max].b;
 
939
        r2 = rgb[bg[pat].rgb2_max].r;
 
940
        g2 = rgb[bg[pat].rgb2_max].g;
 
941
        b2 = rgb[bg[pat].rgb2_max].b;
 
942
 
 
943
        for (row = 0;  row < rpng2_info.height;  ++row) {
 
944
            yidx = row % bgscale;
 
945
            if (yidx > hmax)
 
946
                yidx = bgscale-1 - yidx;
 
947
            dest = bg_data + row*bg_rowbytes;
 
948
            for (i = 0;  i < rpng2_info.width;  ++i) {
 
949
                xidx = i % bgscale;
 
950
                if (xidx > hmax)
 
951
                    xidx = bgscale-1 - xidx;
 
952
                k = xidx + yidx;
 
953
                *dest++ = (k*r1 + (max-k)*r2) / max;
 
954
                *dest++ = (k*g1 + (max-k)*g2) / max;
 
955
                *dest++ = (k*b1 + (max-k)*b2) / max;
 
956
            }
 
957
        }
 
958
 
 
959
/*---------------------------------------------------------------------------
 
960
    Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
 
961
    soids will equal bgscale?].  This one is slow but very cool.  Code con-
 
962
    tributed by Pieter S. van der Meulen (originally in Smalltalk).
 
963
  ---------------------------------------------------------------------------*/
 
964
 
 
965
    } else if ((bg[pat].type & 0x07) == 2) {
 
966
        uch ch;
 
967
        int ii, x, y, hw, hh, grayspot;
 
968
        double freq, rotate, saturate, gray, intensity;
 
969
        double angle=0.0, aoffset=0.0, maxDist, dist;
 
970
        double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
 
971
 
 
972
        fprintf(stderr, "%s:  computing radial background...",
 
973
          PROGNAME);
 
974
        fflush(stderr);
 
975
 
 
976
        hh = rpng2_info.height / 2;
 
977
        hw = rpng2_info.width / 2;
 
978
 
 
979
        /* variables for radial waves:
 
980
         *   aoffset:  number of degrees to rotate hue [CURRENTLY NOT USED]
 
981
         *   freq:  number of color beams originating from the center
 
982
         *   grayspot:  size of the graying center area (anti-alias)
 
983
         *   rotate:  rotation of the beams as a function of radius
 
984
         *   saturate:  saturation of beams' shape azimuthally
 
985
         */
 
986
        angle = CLIP(angle, 0.0, 360.0);
 
987
        grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
 
988
        freq = MAX((double)bg[pat].bg_freq, 0.0);
 
989
        saturate = (double)bg[pat].bg_bsat * 0.1;
 
990
        rotate = (double)bg[pat].bg_brot * 0.1;
 
991
        gray = 0.0;
 
992
        intensity = 0.0;
 
993
        maxDist = (double)((hw*hw) + (hh*hh));
 
994
 
 
995
        for (row = 0;  row < rpng2_info.height;  ++row) {
 
996
            y = row - hh;
 
997
            dest = bg_data + row*bg_rowbytes;
 
998
            for (i = 0;  i < rpng2_info.width;  ++i) {
 
999
                x = i - hw;
 
1000
                angle = (x == 0)? PI_2 : atan((double)y / (double)x);
 
1001
                gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
 
1002
                gray = MIN(1.0, gray);
 
1003
                dist = (double)((x*x) + (y*y)) / maxDist;
 
1004
                intensity = cos((angle+(rotate*dist*PI)) * freq) *
 
1005
                  gray * saturate;
 
1006
                intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
 
1007
                hue = (angle + PI) * INV_PI_360 + aoffset;
 
1008
                s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
 
1009
                s = MIN(MAX(s,0.0), 1.0);
 
1010
                v = MIN(MAX(intensity,0.0), 1.0);
 
1011
 
 
1012
                if (s == 0.0) {
 
1013
                    ch = (uch)(v * 255.0);
 
1014
                    *dest++ = ch;
 
1015
                    *dest++ = ch;
 
1016
                    *dest++ = ch;
 
1017
                } else {
 
1018
                    if ((hue < 0.0) || (hue >= 360.0))
 
1019
                        hue -= (((int)(hue / 360.0)) * 360.0);
 
1020
                    hue /= 60.0;
 
1021
                    ii = (int)hue;
 
1022
                    f = hue - (double)ii;
 
1023
                    p = (1.0 - s) * v;
 
1024
                    q = (1.0 - (s * f)) * v;
 
1025
                    t = (1.0 - (s * (1.0 - f))) * v;
 
1026
                    if      (ii == 0) { red = v; green = t; blue = p; }
 
1027
                    else if (ii == 1) { red = q; green = v; blue = p; }
 
1028
                    else if (ii == 2) { red = p; green = v; blue = t; }
 
1029
                    else if (ii == 3) { red = p; green = q; blue = v; }
 
1030
                    else if (ii == 4) { red = t; green = p; blue = v; }
 
1031
                    else if (ii == 5) { red = v; green = p; blue = q; }
 
1032
                    *dest++ = (uch)(red * 255.0);
 
1033
                    *dest++ = (uch)(green * 255.0);
 
1034
                    *dest++ = (uch)(blue * 255.0);
 
1035
                }
 
1036
            }
 
1037
        }
 
1038
        fprintf(stderr, "done.\n");
 
1039
        fflush(stderr);
 
1040
    }
 
1041
 
 
1042
/*---------------------------------------------------------------------------
 
1043
    Blast background image to display buffer before beginning PNG decode;
 
1044
    calling function will handle invalidation and UpdateWindow() call.
 
1045
  ---------------------------------------------------------------------------*/
 
1046
 
 
1047
    for (row = 0;  row < rpng2_info.height;  ++row) {
 
1048
        src = bg_data + row*bg_rowbytes;
 
1049
        dest = wimage_data + row*wimage_rowbytes;
 
1050
        for (i = rpng2_info.width;  i > 0;  --i) {
 
1051
            r1 = *src++;
 
1052
            g1 = *src++;
 
1053
            b1 = *src++;
 
1054
            *dest++ = b1;
 
1055
            *dest++ = g1;   /* note reverse order */
 
1056
            *dest++ = r1;
 
1057
        }
 
1058
    }
 
1059
 
 
1060
    return 0;
 
1061
 
 
1062
} /* end function rpng2_win_load_bg_image() */
 
1063
 
 
1064
 
 
1065
 
 
1066
 
 
1067
 
 
1068
static void rpng2_win_display_row(ulg row)
 
1069
{
 
1070
    uch bg_red   = rpng2_info.bg_red;
 
1071
    uch bg_green = rpng2_info.bg_green;
 
1072
    uch bg_blue  = rpng2_info.bg_blue;
 
1073
    uch *src, *src2=NULL, *dest;
 
1074
    uch r, g, b, a;
 
1075
    ulg i;
 
1076
    static int rows=0;
 
1077
    static ulg firstrow;
 
1078
 
 
1079
/*---------------------------------------------------------------------------
 
1080
    rows and firstrow simply track how many rows (and which ones) have not
 
1081
    yet been displayed; alternatively, we could call InvalidateRect() for
 
1082
    every row and not bother with the records-keeping.
 
1083
  ---------------------------------------------------------------------------*/
 
1084
 
 
1085
    Trace((stderr, "beginning rpng2_win_display_row()\n"))
 
1086
 
 
1087
    if (rows == 0)
 
1088
        firstrow = row;   /* first row not yet displayed */
 
1089
 
 
1090
    ++rows;   /* count of rows received but not yet displayed */
 
1091
 
 
1092
/*---------------------------------------------------------------------------
 
1093
    Aside from the use of the rpng2_info struct and the lack of an outer
 
1094
    loop (over rows), this routine is identical to rpng_win_display_image()
 
1095
    in the non-progressive version of the program.
 
1096
  ---------------------------------------------------------------------------*/
 
1097
 
 
1098
    src = rpng2_info.image_data + row*rpng2_info.rowbytes;
 
1099
    if (bg_image)
 
1100
        src2 = bg_data + row*bg_rowbytes;
 
1101
    dest = wimage_data + row*wimage_rowbytes;
 
1102
 
 
1103
    if (rpng2_info.channels == 3) {
 
1104
        for (i = rpng2_info.width;  i > 0;  --i) {
 
1105
            r = *src++;
 
1106
            g = *src++;
 
1107
            b = *src++;
 
1108
            *dest++ = b;
 
1109
            *dest++ = g;   /* note reverse order */
 
1110
            *dest++ = r;
 
1111
        }
 
1112
    } else /* if (rpng2_info.channels == 4) */ {
 
1113
        for (i = rpng2_info.width;  i > 0;  --i) {
 
1114
            r = *src++;
 
1115
            g = *src++;
 
1116
            b = *src++;
 
1117
            a = *src++;
 
1118
            if (bg_image) {
 
1119
                bg_red   = *src2++;
 
1120
                bg_green = *src2++;
 
1121
                bg_blue  = *src2++;
 
1122
            }
 
1123
            if (a == 255) {
 
1124
                *dest++ = b;
 
1125
                *dest++ = g;
 
1126
                *dest++ = r;
 
1127
            } else if (a == 0) {
 
1128
                *dest++ = bg_blue;
 
1129
                *dest++ = bg_green;
 
1130
                *dest++ = bg_red;
 
1131
            } else {
 
1132
                /* this macro (copied from png.h) composites the
 
1133
                 * foreground and background values and puts the
 
1134
                 * result into the first argument; there are no
 
1135
                 * side effects with the first argument */
 
1136
                alpha_composite(*dest++, b, a, bg_blue);
 
1137
                alpha_composite(*dest++, g, a, bg_green);
 
1138
                alpha_composite(*dest++, r, a, bg_red);
 
1139
            }
 
1140
        }
 
1141
    }
 
1142
 
 
1143
/*---------------------------------------------------------------------------
 
1144
    Display after every 16 rows or when on last row.  (Region may include
 
1145
    previously displayed lines due to interlacing--i.e., not contiguous.)
 
1146
  ---------------------------------------------------------------------------*/
 
1147
 
 
1148
    if ((rows & 0xf) == 0 || row == rpng2_info.height-1) {
 
1149
        RECT rect;
 
1150
 
 
1151
        rect.left = 0L;
 
1152
        rect.top = (LONG)firstrow;
 
1153
        rect.right = (LONG)rpng2_info.width;       /* possibly off by one? */
 
1154
        rect.bottom = (LONG)row + 1L;              /* possibly off by one? */
 
1155
        InvalidateRect(global_hwnd, &rect, FALSE);
 
1156
        UpdateWindow(global_hwnd);                 /* similar to XFlush() */
 
1157
        rows = 0;
 
1158
    }
 
1159
 
 
1160
} /* end function rpng2_win_display_row() */
 
1161
 
 
1162
 
 
1163
 
 
1164
 
 
1165
 
 
1166
static void rpng2_win_finish_display()
 
1167
{
 
1168
    Trace((stderr, "beginning rpng2_win_finish_display()\n"))
 
1169
 
 
1170
    /* last row has already been displayed by rpng2_win_display_row(), so
 
1171
     * we have nothing to do here except set a flag and let the user know
 
1172
     * that the image is done */
 
1173
 
 
1174
    rpng2_info.state = kDone;
 
1175
    printf(
 
1176
#ifndef __CYGWIN__
 
1177
      "Done.  Press Q, Esc or mouse button 1 (within image window) to quit.\n"
 
1178
#else
 
1179
      "Done.  Press mouse button 1 (within image window) to quit.\n"
 
1180
#endif
 
1181
    );
 
1182
    fflush(stdout);
 
1183
}
 
1184
 
 
1185
 
 
1186
 
 
1187
 
 
1188
 
 
1189
static void rpng2_win_cleanup()
 
1190
{
 
1191
    if (bg_image && bg_data) {
 
1192
        free(bg_data);
 
1193
        bg_data = NULL;
 
1194
    }
 
1195
 
 
1196
    if (rpng2_info.image_data) {
 
1197
        free(rpng2_info.image_data);
 
1198
        rpng2_info.image_data = NULL;
 
1199
    }
 
1200
 
 
1201
    if (rpng2_info.row_pointers) {
 
1202
        free(rpng2_info.row_pointers);
 
1203
        rpng2_info.row_pointers = NULL;
 
1204
    }
 
1205
 
 
1206
    if (dib) {
 
1207
        free(dib);
 
1208
        dib = NULL;
 
1209
    }
 
1210
}
 
1211
 
 
1212
 
 
1213
 
 
1214
 
 
1215
 
 
1216
LRESULT CALLBACK rpng2_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP)
 
1217
{
 
1218
    HDC         hdc;
 
1219
    PAINTSTRUCT ps;
 
1220
    int rc;
 
1221
 
 
1222
    switch (iMsg) {
 
1223
        case WM_CREATE:
 
1224
            /* one-time processing here, if any */
 
1225
            return 0;
 
1226
 
 
1227
        case WM_PAINT:
 
1228
            hdc = BeginPaint(hwnd, &ps);
 
1229
            rc = StretchDIBits(hdc, 0, 0, rpng2_info.width, rpng2_info.height,
 
1230
                                    0, 0, rpng2_info.width, rpng2_info.height,
 
1231
                                    wimage_data, (BITMAPINFO *)bmih,
 
1232
                                    0, SRCCOPY);
 
1233
            EndPaint(hwnd, &ps);
 
1234
            return 0;
 
1235
 
 
1236
        /* wait for the user to tell us when to quit */
 
1237
        case WM_CHAR:
 
1238
            switch (wP) {       /* only need one, so ignore repeat count */
 
1239
                case 'q':
 
1240
                case 'Q':
 
1241
                case 0x1B:      /* Esc key */
 
1242
                    PostQuitMessage(0);
 
1243
            }
 
1244
            return 0;
 
1245
 
 
1246
        case WM_LBUTTONDOWN:    /* another way of quitting */
 
1247
        case WM_DESTROY:
 
1248
            PostQuitMessage(0);
 
1249
            return 0;
 
1250
    }
 
1251
 
 
1252
    return DefWindowProc(hwnd, iMsg, wP, lP);
 
1253
}