File: common\gifview.c
1 /*
2 *
3 * This GIF decoder is designed for use with the FRACTINT program.
4 * This decoder code lacks full generality in the following respects:
5 * supports non-interlaced GIF files only, and calmly ignores any
6 * local color maps and non-Fractint-specific extension blocks.
7 *
8 * GIF and 'Graphics Interchange Format' are trademarks (tm) of
9 * Compuserve, Incorporated, an H&R Block Company.
10 *
11 * Tim Wegner
12 */
13
14 #include <string.h>
15 /* see Fractint.c for a description of the "include" hierarchy */
16 #include "port.h"
17 #include "prototyp.h"
18
19 static void close_file(void);
20
21 #define MAXCOLORS 256
22
23 static FILE *fpin = NULL; /* FILE pointer */
24 unsigned int height;
25 unsigned numcolors;
26 int bad_code_count = 0; /* needed by decoder module */
27
28 static int out_line_dither(BYTE *, int);
29 static int out_line_migs(BYTE *, int);
30 static int out_line_too_wide(BYTE *, int);
31 static int colcount; /* keeps track of current column for wide images */
32
33 static unsigned int gifview_image_top; /* (for migs) */
34 static unsigned int gifview_image_left; /* (for migs) */
35 static unsigned int gifview_image_twidth; /* (for migs) */
36
37 int get_byte()
38 {
39 return (getc(fpin)); /* EOF is -1, as desired */
40 }
41
42 int get_bytes(BYTE *where,int how_many)
43 {
44 return (fread((char *)where,1,how_many,fpin)); /* EOF is -1, as desired */
45 }
46
47 /*
48 * DECODERLINEWIDTH is the width of the pixel buffer used by the decoder. A
49 * larger buffer gives better performance. However, this buffer does not
50 * have to be a whole line width, although historically in Fractint it has
51 * been: images were decoded line by line and a whole line written to the
52 * screen at once. The requirement to have a whole line buffered at once
53 * has now been relaxed in order to support larger images. The one exception
54 * to this is in the case where the image is being decoded to a smaller size.
55 * The skipxdots and skipydots logic assumes that the buffer holds one line.
56 */
57
58 #ifdef XFRACT
61 #else
62 #define DECODERLINE_WIDTH 2048 /* width of decoderline, can be smaller */
63 #endif
64
65 BYTE *decoderline1;
66 static char far *ditherbuf = NULL;
67
68 /* Main entry decoder */
69
70 int gifview()
71 {
72 BYTE buffer[16];
73 unsigned top, left, width, finished;
74 char temp1[FILE_MAX_DIR];
75 BYTE byte_buf[257]; /* for decoder */
76 int status;
77 int i, j, k, planes;
78 BYTE linebuf[DECODERLINE_WIDTH];
79 decoderline1 = linebuf;
80
81 #if 0
87 #endif
88
89 /* using stack for decoder byte buf rather than static mem */
90 set_byte_buff(byte_buf);
91
92 status = 0;
93
94 /* initialize the col and row count for write-lines */
95 colcount = rowcount = 0;
96
97 /* Open the file */
98 if(outln == outline_stereo)
99 strcpy(temp1,stereomapname);
100 else
101 strcpy(temp1,readname);
102 if (has_ext(temp1) == NULL) {
103 strcat(temp1,DEFAULTFRACTALTYPE);
104 if ((fpin = fopen(temp1,"rb")) != NULL) {
105 fclose(fpin);
106 }
107 else {
108 if(outln == outline_stereo)
109 strcpy(temp1,stereomapname);
110 else
111 strcpy(temp1,readname);
112 strcat(temp1,ALTERNATEFRACTALTYPE);
113 }
114 }
115 if ((fpin = fopen(temp1, "rb")) == NULL) {
116 return (-1);
117 }
118
119 /* Get the screen description */
120 for (i = 0; i < 13; i++)
121 {
122 int tmp;
123
124 buffer[i] = (BYTE)(tmp = get_byte());
125 if (tmp < 0)
126 {
127 close_file();
128 return(-1);
129 }
130 }
131
132 if(strncmp((char *)buffer,"GIF87a",3) || /* use updated GIF specs */
133 buffer[3] < '0' || buffer[3] > '9' ||
134 buffer[4] < '0' || buffer[4] > '9' ||
135 buffer[5] < 'A' || buffer[5] > 'z' )
136 {
137 close_file();
138 return(-1);
139 }
140
141 width = buffer[6] | (buffer[7] << 8);
142 height = buffer[8] | (buffer[9] << 8);
143 planes = (buffer[10] & 0x0F) + 1;
144 gifview_image_twidth = width;
145
146 if((buffer[10] & 0x80)==0) /* color map (better be!) */
147 {
148 close_file();
149 return(-1);
150 }
151 numcolors = 1 << planes;
152
153 if (dither_flag && numcolors>2 && colors==2 && outln==out_line) {
154 outln = out_line_dither;
155 }
156
157 for (i = 0; i < (int)numcolors; i++)
158 {
159 for (j = 0; j < 3; j++) {
160 if ((k = get_byte()) < 0)
161 {
162 close_file();
163 return(-1);
164 }
165 if((!display3d || (glassestype != 1 && glassestype != 2))
166 && !dontreadcolor)
167 dacbox[i][j] = (BYTE)(k >> 2);
168 }
169 }
170 colorstate = 1; /* colors aren't default and not a known .map file */
171
172 /* don't read if glasses */
173 if (display3d && mapset && glassestype!=1 && glassestype != 2)
174 {
175 ValidateLuts(MAP_name); /* read the palette file */
176 spindac(0,1); /* load it, but don't spin */
177 }
178 if (dacbox[0][0] != 255)
179 spindac(0,1); /* update the DAC */
180 if (dotmode == 11){ /* disk-video */
181 char fname[FILE_MAX_FNAME];
182 char ext[FILE_MAX_EXT];
183 char tmpname[15];
184 char msg[40];
185 splitpath(temp1,NULL,NULL,fname,ext);
186 makepath(tmpname,NULL,NULL,fname,ext);
187 sprintf(msg,"restoring %s",tmpname);
188 dvid_status(1,msg);
189 }
190 dontreadcolor = 0;
191
192 /* Now display one or more GIF objects */
193 finished = 0;
194 while (!finished)
195 {
196 switch (get_byte())
197 {
198 case ';':
199 /* End of the GIF dataset */
200
201 finished = 1;
202 status = 0;
203 break;
204
205 case '!': /* GIF Extension Block */
206 get_byte(); /* read (and ignore) the ID */
207 while ((i = get_byte()) > 0) /* get the data length */
208 for (j = 0; j < i; j++)
209 get_byte(); /* flush the data */
210 break;
211 case ',':
212 /*
213 * Start of an image object. Read the image description.
214 */
215
216 for (i = 0; i < 9; i++)
217 {
218 int tmp;
219
220 buffer[i] = (BYTE)(tmp = get_byte());
221 if (tmp < 0)
222 {
223 status = -1;
224 break;
225 }
226 }
227 if(status < 0)
228 {
229 finished = 1;
230 break;
231 }
232
233 left = buffer[0] | (buffer[1] << 8);
234 top = buffer[2] | (buffer[3] << 8);
235 width = buffer[4] | (buffer[5] << 8);
236 height = buffer[6] | (buffer[7] << 8);
237
238 /* adjustments for handling MIGs */
239 gifview_image_top = top;
240 if (skipxdots > 0)
241 gifview_image_top /= (skipydots+1);
242 gifview_image_left = left;
243 if (skipydots > 0)
244 gifview_image_left /= (skipxdots+1);
245 if (outln==out_line)
246 {
247 /* what about continuous potential???? */
248 if(width != gifview_image_twidth || top != 0)
249 { /* we're using normal decoding and we have a MIG */
250 outln = out_line_migs;
251 }
252 else if(width > DECODERLINE_WIDTH && skipxdots == 0)
253 {
254 outln = out_line_too_wide;
255 }
256 }
257
258 if (pot16bit) width >>= 1;
259
260 /* Skip local color palette */
261 if((buffer[8] & 0x80)==0x80) { /* local map? */
262 int numcolors; /* make this local */
263 planes = (buffer[8] & 0x0F) + 1;
264 numcolors = 1 << planes;
265 /* skip local map */
266 for (i = 0; i < numcolors; i++) {
267 for (j = 0; j < 3; j++) {
268 if ((k = get_byte()) < 0) {
269 close_file();
270 return(-1);
271 }
272 }
273 }
274 }
275
276 /* initialize the row count for write-lines */
277 rowcount = 0;
278
279 if (calc_status == 1) /* should never be so, but make sure */
280 calc_status = 0;
281 busy = 1; /* for slideshow CALCWAIT */
282 /*
283 * Call decoder(width) via timer.
284 * Width is limited to DECODERLINE_WIDTH.
285 */
286 if(skipxdots == 0)
287 width = min(width,DECODERLINE_WIDTH);
288 status = timer(1,NULL,width);
289 busy = 0; /* for slideshow CALCWAIT */
290 if (calc_status == 1) /* e.g., set by line3d */
291 {
292 calctime = timer_interval; /* note how long it took */
293 if (keypressed() != 0) {
294 calc_status = 3; /* interrupted, not resumable */
295 finished = 1;
296 }
297 else
298 calc_status = 4; /* complete */
299 }
300 /* Hey! the decoder doesn't read the last (0-length) block!! */
301 if (get_byte() != 0) {
302 status = -1;
303 finished = 1;
304 }
305 break;
306 default:
307 status = -1;
308 finished = 1;
309 break;
310 }
311 }
312 close_file();
313 if (dotmode == 11) { /* disk-video */
314 static FCODE o_msg[] = {"Restore completed"};
315 char msg[sizeof(o_msg)];
316 far_strcpy(msg,o_msg);
317 dvid_status(0,msg);
318 dvid_status(1,"");
319 }
320
321 if (ditherbuf != NULL) { /* we're done, free dither memory */
322 farmemfree(ditherbuf);
323 ditherbuf = NULL;
324 }
325
326 return(status);
327 }
328
329 static void close_file()
330 {
331 fclose(fpin);
332 fpin = NULL;
333 }
334
335 /* routine for MIGS that generates partial output lines */
336
337 static int out_line_migs(BYTE *pixels, int linelen)
338 {
339 int row, startcol, stopcol;
340
341 row = gifview_image_top + rowcount;
342 startcol = gifview_image_left;
343 stopcol = startcol+linelen-1;
344 put_line(row, startcol, stopcol, pixels);
345 rowcount++;
346
347 return(0);
348 }
349
350 static int out_line_dither(BYTE *pixels, int linelen)
351 {
352 int i,nexterr,brt,err;
353 if(ditherbuf == NULL)
354 ditherbuf = (char far *)farmemalloc(linelen+1);
355 far_memset( ditherbuf, 0, linelen+1);
356
357 nexterr = (rand()&0x1f)-16;
358 for (i=0;i<linelen;i++) {
359 #ifdef __SVR4
362 #else
363 brt = (dacbox[pixels[i]][0]*5+dacbox[pixels[i]][1]*9 +
364 dacbox[pixels[i]][2]*2)>>4; /* brightness from 0 to 63 */
365 #endif
366 brt += nexterr;
367 if (brt>32) {
368 pixels[i] = 1;
369 err = brt-63;
370 } else {
371 pixels[i] = 0;
372 err = brt;
373 }
374 nexterr = ditherbuf[i+1]+err/3;
375 ditherbuf[i] = (char)(err/3);
376 ditherbuf[i+1] = (char)(err/3);
377 }
378 return out_line(pixels, linelen);
379 }
380
381 /* routine for images wider than the row buffer */
382
383 static int out_line_too_wide(BYTE *pixels, int linelen)
384 {
385 /* int twidth = gifview_image_twidth;*/
386 int twidth = xdots;
387 int extra;
388 while(linelen > 0)
389 {
390 extra = colcount+linelen-twidth;
391 if(extra > 0) /* line wraps */
392 {
393 put_line(rowcount, colcount, twidth-1, pixels);
394 pixels += twidth-colcount;
395 linelen -= twidth-colcount;
396 colcount = twidth;
397 }
398 else
399 {
400 put_line(rowcount, colcount, colcount+linelen-1, pixels);
401 colcount += linelen;
402 linelen = 0;
403 }
404 if(colcount >= twidth)
405 {
406 colcount = 0;
407 rowcount++;
408 }
409 }
410 return(0);
411 }
412
413 static int put_sound_line(int row, int colstart, int colstop, BYTE *pixels)
414 {
415 int col;
416 for(col=colstart;col<=colstop;col++)
417 {
418 putcolor(col,row,*pixels);
419 if(orbit_delay > 0)
420 sleepms(orbit_delay);
421 w_snd((int)((int)(*pixels++)*3000/colors+basehertz));
422 if(keypressed())
423 {
424 mute();
425 return(-1);
426 }
427 }
428 return(0);
429 }
430
431 int sound_line(BYTE *pixels, int linelen)
432 {
433 /* int twidth = gifview_image_twidth;*/
434 int twidth = xdots;
435 int extra;
436 int ret=0;
437 while(linelen > 0)
438 {
439 extra = colcount+linelen-twidth;
440 if(extra > 0) /* line wraps */
441 {
442 if(put_sound_line(rowcount, colcount, twidth-1, pixels))
443 break;
444 pixels += twidth-colcount;
445 linelen -= twidth-colcount;
446 colcount = twidth;
447 }
448 else
449 {
450 if(put_sound_line(rowcount, colcount, colcount+linelen-1, pixels))
451 break;
452 colcount += linelen;
453 linelen = 0;
454 }
455 if(colcount >= twidth)
456 {
457 colcount = 0;
458 rowcount++;
459 }
460 }
461 mute();
462 if(keypressed())
463 ret = -1;
464 return(ret);
465 }
466
467 int pot_line(BYTE *pixels, int linelen)
468 {
469 int row,col,saverowcount;
470 if (rowcount == 0)
471 if (pot_startdisk() < 0)
472 return -1;
473 saverowcount = rowcount;
474 row = (rowcount >>= 1);
475 if ((saverowcount & 1) != 0) /* odd line */
476 row += ydots;
477 else if (dotmode != 11) /* even line - display the line too */
478 out_line(pixels,linelen);
479 for (col = 0; col < xdots; ++col)
480 writedisk(col+sxoffs,row+syoffs,*(pixels+col));
481 rowcount = saverowcount + 1;
482 return(0);
483 }
484