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 
get_byte()37 int get_byte()
38 {
39    return (getc(fpin)); /* EOF is -1, as desired */
40 }
41 
get_bytes(BYTE * where,int how_many)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
59 BYTE decoderline[MAXPIXELS+1]; /* write-line routines use this */
60 #define DECODERLINE_WIDTH MAXPIXELS
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 
gifview()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
82    {
83       char msg[100];
84       sprintf(msg,"Stack free in gifview: %d",stackavail());
85       stopmsg(0,msg);
86    }
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[MAX_NAME];
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 
close_file()329 static void close_file()
330 {
331    fclose(fpin);
332    fpin = NULL;
333 }
334 
335 /* routine for MIGS that generates partial output lines */
336 
out_line_migs(BYTE * pixels,int linelen)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 
out_line_dither(BYTE * pixels,int linelen)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
360         brt = (int)((dacbox[pixels[i]][0]*5+dacbox[pixels[i]][1]*9 +
361             dacbox[pixels[i]][2]*2))>>4; /* brightness from 0 to 63 */
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 
out_line_too_wide(BYTE * pixels,int linelen)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 
put_sound_line(int row,int colstart,int colstop,BYTE * pixels)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 
sound_line(BYTE * pixels,int linelen)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 
pot_line(BYTE * pixels,int linelen)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