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
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 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[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
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 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