home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / c / rflic2 / readflic.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-01  |  11.9 KB  |  521 lines

  1. /* readflic.c - This module contains the routines to read and decompress
  2.  * a flic.  They assume Intel byte ordering,  but otherwise should be
  3.  * fairly portable.  They call machine specific stuff in pcclone.c.
  4.  * This file starts with the low level decompression routines - first
  5.  * for colors and then for pixels.  Then it goes to the higher level
  6.  * exported flic_xxxx routines as prototyped in readflic.h.
  7.  *
  8.  * Copyright (c) 1992 Jim Kent.  This file may be freely used, modified,
  9.  * copied and distributed.  This file was first published as part of
  10.  * an article for Dr. Dobb's Journal March 1993 issue.
  11.  */
  12.  
  13. #include <errno.h>
  14. #include <string.h>
  15. #ifdef _MSC_VER
  16. #include <stdio.h>
  17. #endif
  18. #include <io.h>
  19. #include "types.h"
  20. #include "pcclone.h"
  21. #include "flic.h"
  22. #include "readflic.h"
  23.  
  24.  
  25.  
  26. typedef void ColorOut(Screen *s, int start, Color far *colors, int count);
  27.     /* This is the type of output parameter to our decode_color below.
  28.      * Not coincedently screen_put_color is of this type. */
  29.  
  30. static void decode_color(Uchar huge *data
  31. , Flic *flic, Screen *s, ColorOut *output)
  32.     /* Decode color map.  Put results into output.  The two color
  33.      * compressions are identical except for whether the RGB values
  34.      * are 0-63 or 0-255.  Passing in an output that does the appropriate
  35.      * shifting on the way to the real pallete lets us use the same
  36.      * code for both COLOR_64 and COLOR_256 compression.
  37.      */
  38. {
  39. int start = 0;
  40. Uchar far *cbuf = (Uchar far *)data;
  41. Short far *wp = (Short far *)cbuf;
  42. Short ops;
  43. int count;
  44.  
  45. ops = *wp;
  46. cbuf += sizeof(*wp);
  47. while (--ops >= 0)
  48.     {
  49.     start += *cbuf++;
  50.     if ((count = *cbuf++) == 0)
  51.         count = 256;
  52.     (*output)(s, start, (Color far *)cbuf, count);
  53.     cbuf += 3*count;
  54.     start += count;
  55.     }
  56. }
  57.  
  58. static void decode_color_256(Uchar huge *data, Flic *flic, Screen *s)
  59.     /* Decode COLOR_256 chunk. */
  60. {
  61. decode_color(data, flic, s, screen_put_colors);
  62. }
  63.  
  64. static void decode_color_64(Uchar huge *data, Flic *flic, Screen *s)
  65.     /* Decode COLOR_64 chunk. */
  66. {
  67. decode_color(data, flic, s, screen_put_colors_64);
  68. }
  69.  
  70.  
  71. static void decode_byte_run(Uchar huge *data, Flic *flic, Screen *s)
  72.     /* Byte-run-length decompression. */
  73. {
  74. int x,y;
  75. int width = flic->head.width;
  76. int height = flic->head.height;
  77. Char psize;
  78. Char huge *cpt = data;
  79. int end;
  80.  
  81. y = flic->yoff;
  82. end = flic->xoff + width;
  83. while (--height >= 0)
  84.     {
  85.     x = flic->xoff;
  86.     cpt += 1;    /* skip over obsolete opcount byte */
  87.     psize = 0;
  88.     while ((x+=psize) < end)
  89.         {
  90.         psize = *cpt++;
  91.         if (psize >= 0)
  92.             {
  93.             screen_repeat_one(s, x, y, *cpt++, psize);
  94.             }
  95.         else
  96.             {
  97.             psize = -psize;
  98.             screen_copy_seg(s, x, y, (Pixel far *)cpt, psize);
  99.             cpt += psize;
  100.             }
  101.         }
  102.     y++;
  103.     }
  104. }
  105.  
  106. static void decode_delta_fli(Uchar huge *data, Flic *flic, Screen *s)
  107.     /* Fli style delta decompression. */
  108. {
  109. int xorg = flic->xoff;
  110. int yorg = flic->yoff;
  111. Short huge *wpt = (Short huge *)data;
  112. Uchar huge *cpt = (Uchar huge *)(wpt + 2);
  113. int x,y;
  114. Short lines;
  115. Uchar opcount;
  116. Char psize;
  117.  
  118. y = yorg + *wpt++;
  119. lines = *wpt;
  120. while (--lines >= 0)
  121.     {
  122.     x = xorg;
  123.     opcount = *cpt++;
  124.     while (opcount > 0)
  125.         {
  126.         x += *cpt++;
  127.         psize = *cpt++;
  128.         if (psize < 0)
  129.             {
  130.             psize = -psize;
  131.             screen_repeat_one(s, x, y, *cpt++, psize);
  132.             x += psize;
  133.             opcount-=1;
  134.             }
  135.         else
  136.             {
  137.             screen_copy_seg(s, x, y, (Pixel far *)cpt, psize);
  138.             cpt += psize;
  139.             x += psize;
  140.             opcount -= 1;
  141.             }
  142.         }
  143.     y++;
  144.     }
  145. }
  146.  
  147.  
  148. static void decode_delta_flc(Uchar huge *data, Flic *flic, Screen *s)
  149.     /* Flc-style delta decompression.  The data is word oriented though
  150.      * a lot of the control info (how far to skip, how many words to
  151.      * copy) are byte oriented still to save space. */
  152. {
  153. int xorg = flic->xoff;
  154. int yorg = flic->yoff;
  155. int width = flic->head.width;
  156. int x,y;
  157. Short lp_count;
  158. Short opcount;
  159. int psize;
  160. union {Short huge *w; Uchar huge *ub; Char huge *b; Pixels2 huge *p2;} wpt;
  161. int lastx;
  162.  
  163.  
  164.     lastx = xorg + width - 1;
  165.     wpt.ub = data;
  166.     lp_count = *wpt.w++;
  167.     y = yorg;
  168.     goto LPACK;
  169.  
  170. SKIPLINES:    /* Advance over some lines. */
  171.     y -= opcount;
  172.  
  173. LPACK:        /* do next line */
  174.     if ((opcount = *wpt.w++) >= 0)
  175.         goto DO_SS2OPS;
  176.     if( ((Ushort)opcount) & 0x4000) /* skip lines */
  177.         goto SKIPLINES;
  178.     screen_put_dot(s,(int)opcount,lastx,(Pixel)y); /* put dot at eol with low byte */
  179. //    screen_put_dot(s,(Uchar)opcount,lastx,y); /* put dot at eol with low byte */
  180.     if((opcount = *wpt.w++) == 0)
  181.     {
  182.         ++y;
  183.         if (--lp_count > 0)
  184.             goto LPACK;
  185.         goto OUT;
  186.     }
  187. DO_SS2OPS:
  188.     x = xorg;
  189.  
  190. PPACK:                /* do next packet */
  191.     x += *wpt.ub++;
  192.     psize = *wpt.b++;
  193.     if ((psize += psize) >= 0)
  194.     {
  195.         screen_copy_seg(s, x, y, (Pixel far *)wpt.ub, psize);
  196.         x += psize;
  197.         wpt.ub += psize;
  198.         if (--opcount != 0)
  199.             goto PPACK;
  200.         ++y;
  201.         if (--lp_count > 0)
  202.             goto LPACK;
  203.     }
  204.     else
  205.     {
  206.         psize = -psize;
  207.         screen_repeat_two(s, x, y, *wpt.p2++, psize>>1);
  208.         x += psize;
  209.         if (--opcount != 0)
  210.             goto PPACK;
  211.         ++y;
  212.         if (--lp_count > 0)
  213.             goto LPACK;
  214.     }
  215. OUT:
  216.     return;
  217. }
  218.  
  219. static void decode_black(Uchar huge *data, Flic *flic, Screen *s)
  220.     /* Decode a BLACK chunk.  Set frame to solid color 0 one
  221.      * line at a time. */
  222. {
  223. Pixels2 black;
  224. int i;
  225. int height = flic->head.height;
  226. int width = flic->head.width;
  227. int x = flic->xoff;
  228. int y = flic->yoff;
  229.  
  230. black.pixels[0] = black.pixels[1] = 0;
  231. for (i=0; i<height; ++i)
  232.     {
  233.     screen_repeat_two(s, x, y+i, black, width/2);
  234.     if (width & 1)    /* if odd set last pixel */
  235.         screen_put_dot(s, x+width-1, y+i, 0);
  236.     }
  237. }
  238.  
  239. static void decode_literal(Uchar huge *data, Flic *flic, Screen *s)
  240.     /* Decode a LITERAL chunk.  Just copy data to screen one line at
  241.      * a time. */
  242. {
  243. int i;
  244. int height = flic->head.height;
  245. int width = flic->head.width;
  246. int x = flic->xoff;
  247. int y = flic->yoff;
  248.  
  249. for (i=0; i<height; ++i)
  250.     {
  251.     screen_copy_seg(s, x, y+i, (Pixel far *)data, width);
  252.     data += width;
  253.     }
  254. }
  255.  
  256.  
  257. ErrCode flic_open(Flic *flic, char *name)
  258.     /* Open flic file.  Read header and verify it's a flic.
  259.      * Seek to first frame. */
  260. {
  261. ErrCode err;
  262.  
  263. ClearStruct(flic);        /* Start at a known state. */
  264. if ((err = file_open_to_read(&flic->handle, name)) >= Success)
  265.     {
  266.     if ((err = file_read_block(flic->handle, &flic->head, sizeof(flic->head)))
  267.     >= Success)
  268.         {
  269.         flic->name = name;        /* Save name for future use. */
  270.         if (flic->head.type == FLC_TYPE)
  271.             {
  272.             /* Seek frame 1. */
  273. #ifdef _MSC_VER
  274.             _lseek(flic->handle,flic->head.oframe1,SEEK_SET);
  275. #else
  276.             lseek(flic->handle,flic->head.oframe1,SEEK_SET);
  277. #endif
  278.             return Success;
  279.             }
  280.         if (flic->head.type == FLI_TYPE)
  281.             {
  282.             /* Do some conversion work here. */
  283.             flic->head.oframe1 = sizeof(flic->head);
  284.             flic->head.speed = flic->head.speed * 1000L / 70L;
  285.             return Success;
  286.             }
  287.         else
  288.             {
  289.             err = ErrBadFlic;
  290.             }
  291.         }
  292.     flic_close(flic);        /* Close down and scrub partially opened flic. */
  293.     }
  294. return err;
  295. }
  296.  
  297.  
  298. void flic_close(Flic *flic)
  299.     /* Close flic file and scrub flic. */
  300. {
  301. #ifdef _MSC_VER
  302. _close(flic->handle);
  303. #else
  304. close(flic->handle);
  305. #endif
  306. ClearStruct(flic);        /* Discourage use after close. */
  307. }
  308.  
  309. static ErrCode decode_frame(Flic *flic
  310. , FrameHead *frame, Uchar huge *data, Screen *s)
  311.     /* Decode a frame that is in memory already into screen.
  312.      * Here we just loop through each chunk calling appropriate
  313.      * chunk decoder.
  314.      */
  315. {
  316. int i;
  317. ChunkHead huge *chunk;
  318.  
  319. for (i=0; i<frame->chunks; ++i)
  320.     {
  321.     chunk = (ChunkHead huge *)data;
  322.     data += chunk->size;
  323.     switch (chunk->type)
  324.         {
  325.         case COLOR_256:
  326.             decode_color_256((Uchar huge *)(chunk+1), flic, s);
  327.             break;
  328.         case DELTA_FLC:
  329.             decode_delta_flc((Uchar huge *)(chunk+1), flic, s);
  330.             break;
  331.         case COLOR_64:
  332.             decode_color_64((Uchar huge *)(chunk+1), flic, s);
  333.             break;
  334.         case DELTA_FLI:
  335.             decode_delta_fli((Uchar huge *)(chunk+1), flic, s);
  336.             break;
  337.         case BLACK:
  338.             decode_black((Uchar huge *)(chunk+1), flic, s);
  339.             break;
  340.         case BYTE_RUN:
  341.             decode_byte_run((Uchar huge *)(chunk+1), flic, s);
  342.             break;
  343.         case LITERAL:
  344.             decode_literal((Uchar huge *)(chunk+1), flic, s);
  345.             break;
  346.         default:
  347.             break;
  348.         }
  349.     }
  350. return Success;
  351. }
  352.  
  353. ErrCode flic_next_frame(Flic *flic, Screen *screen)
  354.     /* Advance to next frame of flic. */
  355. {
  356. FrameHead head;
  357. ErrCode err;
  358. BigBlock bb;
  359. long size;
  360.  
  361. if ((err = file_read_block(flic->handle, &head, sizeof(head))) >= Success)
  362.     {
  363.     if (head.type == FRAME_TYPE)
  364.         {
  365.         size = head.size - sizeof(head);    /* Don't include head. */
  366.         if (size > 0)
  367.             {
  368.             if ((err = big_alloc(&bb, size)) >= Success)
  369.                 {
  370.                 if ((err = file_read_big_block(flic->handle, &bb, size)) 
  371.                 >= Success)
  372.                     {
  373.                     err = decode_frame(flic, &head, bb.hpt, screen);
  374.                     }
  375.                 big_free(&bb);
  376.                 }
  377.             }
  378.         }
  379.     else
  380.         {
  381.         err = ErrBadFrame;
  382.         }
  383.     }
  384. return err;
  385. }
  386.  
  387.  
  388. static Ulong calc_end_time(Ulong millis, Clock *clock)
  389.     /* Little helper subroutine to find out when to start on next
  390.      * frame. */
  391. {
  392. return clock_ticks(clock) + millis * clock->speed / 1000l;
  393. }
  394.  
  395. static ErrCode wait_til(Ulong end_time, Machine *machine)
  396.     /* This waits until key is hit or end_time arrives.
  397.      * Return Success if timed out,  ErrCancel if key hit.
  398.      * Insures keyboard will be polled at least once.
  399.      */
  400. {
  401.     do
  402.         {
  403.         if (key_ready(&machine->key))
  404.             {
  405.             key_read(&machine->key);
  406.             return ErrCancel;
  407.             }
  408.         }
  409.     while (clock_ticks(&machine->clock) < end_time);
  410.     return Success;
  411. }
  412.  
  413. ErrCode flic_play_once(Flic *flic, Machine *machine)
  414.     /* Play a flic through once. */
  415. {
  416. ErrCode err;
  417. int i;
  418. Ulong end_time;
  419.  
  420. //for (i=0; i<flic->head.frames; ++i)
  421. for (i=0; i<(int)flic->head.frames; ++i)
  422.     {
  423.     end_time = calc_end_time(flic->head.speed, &machine->clock);
  424.     if ((err = flic_next_frame(flic, &machine->screen)) < Success)
  425.         break;
  426.     if ((err = wait_til(end_time, machine)) < Success)
  427.         break;
  428.     }
  429. return err;
  430. }
  431.  
  432. static ErrCode fill_in_frame2(Flic *flic)
  433.     /* This figures out where the second frame of the flic is
  434.      * (useful for playing in a loop).  */
  435. {
  436. FrameHead head;
  437. ErrCode err;
  438.  
  439. #ifdef _MSC_VER
  440. _lseek(flic->handle, flic->head.oframe1, SEEK_SET);
  441. #else
  442. lseek(flic->handle, flic->head.oframe1, SEEK_SET);
  443. #endif
  444. if ((err = file_read_block(flic->handle, &head, sizeof(head))) < Success)
  445.     return err;
  446. flic->head.oframe2 = flic->head.oframe1 + head.size;
  447. return Success;
  448. }
  449.  
  450. ErrCode flic_play_loop(Flic *flic, Machine *machine)
  451.     /* Play a flic until key is pressed. */
  452. {
  453. int i;
  454. Ulong end_time;
  455. ErrCode err;
  456.  
  457. if (flic->head.oframe2 == 0)
  458.     {
  459.     fill_in_frame2(flic);
  460.     }
  461.     /* Seek to first frame. */
  462. #ifdef _MSC_VER
  463. _lseek(flic->handle, flic->head.oframe1, SEEK_SET);
  464. #else
  465. lseek(flic->handle, flic->head.oframe1, SEEK_SET);
  466. #endif
  467.     /* Save time to move on. */
  468. end_time = calc_end_time(flic->head.speed, &machine->clock);
  469.     /* Display first frame. */
  470. if ((err = flic_next_frame(flic, &machine->screen)) < Success)
  471.     return err;
  472. for (;;)
  473.     {
  474.         /* Seek to second frame */
  475. #ifdef _MSC_VER
  476.     _lseek(flic->handle, flic->head.oframe2, SEEK_SET);
  477. #else
  478.     lseek(flic->handle, flic->head.oframe2, SEEK_SET);
  479. #endif
  480.         /* Loop from 2nd frame thru ring frame*/
  481. //    for (i=0; i<flic->head.frames; ++i)
  482.     for (i=0; (Ushort)i < flic->head.frames; ++i)
  483.         {
  484.         if (wait_til(end_time, machine) < Success)
  485.             return Success;        /* Time out is a success here. */
  486.         if ((err = flic_next_frame(flic, &machine->screen)) < Success)
  487.             return err;
  488.         end_time = calc_end_time(flic->head.speed, &machine->clock);
  489.         }
  490.     }
  491. }
  492.  
  493.  
  494. static char *err_strings[] = 
  495.     {
  496.     "Unspecified error",
  497.     "Not enough memory",
  498.     "Not a flic file",
  499.     "Bad frame in flic",
  500.     NULL,
  501.     NULL,
  502.     "Couldn't open display",
  503.     "Couldn't open keyboard",
  504.     "User canceled action",
  505.     };
  506.  
  507. char *flic_err_string(ErrCode err)
  508.     /* Return a string that describes an error. */
  509. {
  510.     if (err >= Success)
  511.         return "Success";        /* Shouldn't happen really... */
  512.     if (err == ErrOpen || err == ErrRead)
  513.         return strerror(errno);    /* Get Disk IO error from DOS. */
  514.     err = -err;
  515.     err -= 1;
  516.     if (err > ArrayEls(err_strings))
  517.         return "Unknown error";
  518.     return err_strings[err];
  519. }
  520.  
  521.