diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/libpng/contrib/gregbook/rpng2-win.c | 1253 |
1 files changed, 1253 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/libpng/contrib/gregbook/rpng2-win.c b/libraries/irrlicht-1.8/source/Irrlicht/libpng/contrib/gregbook/rpng2-win.c new file mode 100644 index 0000000..2303b58 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/libpng/contrib/gregbook/rpng2-win.c | |||
@@ -0,0 +1,1253 @@ | |||
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 | } | ||