home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff218.lzh / Mandel / src / Jiff.c < prev    next >
C/C++ Source or Header  |  1989-06-04  |  28KB  |  1,203 lines

  1.  
  2. /*
  3.  * JIFF.H
  4.  */
  5.  
  6. #define XMAX 640
  7. #define LOXMAX 320
  8. #define YMAX 200
  9. #define XASPECT 5
  10. #define YASPECT 11
  11.  
  12. /*
  13.  * EA handy make a long from 4 chars macros redone to work with Aztec
  14.  */
  15. #define MAKE_ID(a, b, c, d)\
  16. ( ((long)(a)<<24) | ((long)(b)<<16) | ((long)(c)<<8) | (long)(d) )
  17.  
  18. /*
  19.  * These are the IFF types I deal with
  20.  */
  21. #define FORM MAKE_ID('F', 'O', 'R', 'M')
  22. #define ILBM MAKE_ID('I', 'L', 'B', 'M')
  23. #define BMHD MAKE_ID('B', 'M', 'H', 'D')
  24. #define CMAP MAKE_ID('C', 'M', 'A', 'P')
  25. #define BODY MAKE_ID('B', 'O', 'D', 'Y')
  26.  
  27. /*
  28.  * And these are the IFF types I ignore but don't squawk about
  29.  */
  30. #define GRAB MAKE_ID('G', 'R', 'A', 'B')
  31. #define DEST MAKE_ID('D', 'E', 'S', 'T')
  32. #define SPRT MAKE_ID('S', 'P', 'R', 'T')
  33. #define CAMG MAKE_ID('C', 'A', 'M', 'G')
  34. #define CRNG MAKE_ID('C', 'R', 'N', 'G')
  35. #define CCRT MAKE_ID('C', 'C', 'R', 'T')
  36.  
  37. #define EVEN(x) (((x) + 1) & ~1)
  38. #define MANDEL
  39.  
  40. /*
  41.  * Some macros for raster memory allocation ... redefine if you're
  42.  * sensible and manage memory locally
  43.  */
  44.  
  45. #ifndef MANDEL
  46.  
  47. /*
  48.  * ralloc - raster alloc
  49.  */
  50. # define ralloc(amount)  (PLANEPTR)AllocMem((long)(amount), MEMF_CHIP)
  51. /*
  52.  * rfree - raster free
  53.  */
  54. # define rfree(pt, amount)  FreeMem( (pt), (long)(amount) )
  55.  
  56. #else                /* MANDEL */
  57.  
  58. # include <mandel.h>
  59.  
  60. /*
  61.  * We don't want to allocate a complete raster for the picture, since we
  62.  * already have a screen with a window where we want to have it.
  63.  * Therefore, we allocate some small buffers, which get blitted into our
  64.  * window as soon as they fill up.
  65.  */
  66. # define MAXPLANESIZE    1040L
  67. /*
  68.  * ralloc - raster alloc
  69.  */
  70. # define ralloc(amount) (PLANEPTR)AllocMem(MAXPLANESIZE, MEMF_CHIP | MEMF_CLEAR)
  71. /*
  72.  * rfree - raster free
  73.  */
  74. # define rfree(pt, amount)  FreeMem( (pt), MAXPLANESIZE )
  75.  
  76. #endif                /* !MANDEL */
  77.  
  78. /*
  79.  * line_bytes = the number of words * 2 (for bytes) a raster line takes up
  80.  */
  81. #define line_bytes(width)   ((((width) + 15) >> 3) & ~0x0001)
  82.  
  83. /*
  84.  * psize - plane size in bytes (an even number) of a raster given width
  85.  * and height
  86.  */
  87. #define psize(width, height) ( line_bytes(width)*height)
  88.  
  89. /*
  90.  * The place to throw excess bits
  91.  */
  92. #define bit_bucket(file, length) fseek(file, (long)EVEN(length), 1)
  93.  
  94.  
  95. union bytes4 {
  96.     char        b4_name[4];
  97.     LONG        b4_type;
  98. };
  99.  
  100. struct iff_chunk {
  101.     union bytes4    iff_type;
  102.     LONG        iff_length;
  103. };
  104.  
  105. struct form_chunk {
  106.     union bytes4    fc_type;    /* == FORM */
  107.     LONG        fc_length;
  108.     union bytes4    fc_subtype;
  109. };
  110.  
  111. struct CommodoreAmiga {
  112.     struct iff_chunk camg_iffc; /* == CAMG */
  113.     LONG        camg_data;
  114. };
  115.  
  116. #ifndef MANDEL            /* We have this already in Mandel.h */
  117. struct BitMapHeader {
  118.     UWORD        w,
  119.             h;
  120.     UWORD        x,
  121.             y;
  122.     UBYTE        nPlanes;
  123.     UBYTE        masking;
  124.     UBYTE        compression;
  125.     UBYTE        pad1;
  126.     UWORD        transparentColor;
  127.     UBYTE        xAspect,
  128.             yAspect;
  129.     WORD        pageWidth,
  130.             pageHeight;
  131. };
  132.  
  133. /*
  134.  * ILBM_info is the structure win_read_iff returns, and is hopefully all
  135.  * you need to deal with out of the iff reader routines below
  136.  */
  137. struct ILBM_info {
  138.     struct BitMapHeader header;
  139.     UBYTE        cmap[MAXCOL * 3];
  140.     struct BitMap   bitmap;
  141. #ifdef MANDEL
  142.     struct Mand    *mand;
  143.     long        mandsize;
  144. #endif
  145. };
  146.  
  147. #endif                /* !MANDEL */
  148.  
  149. /*-
  150.  * I sure wish C function "prototypes" were real and not just ANSI
  151.  *
  152.  * extern struct ILBM_info *win_read_iff();
  153.  * win_read_iff( char *filename, short just_colors, int MandSize,
  154.  *          APTR MandPointer );
  155.  * extern void free_planes();  free_planes( struct BitMap *bitmap);
  156.  * extern int write_iff();
  157.  * write_iff(char *name, unsigned char *colors, struct Window *window,
  158.  *  short xoff, short yoff, short compressed);
  159.  */
  160.  
  161. /*
  162.  * Anyone know where some useful minterms are defined?
  163.  */
  164. #define COPY_MINTERM        0x0C0L
  165.  
  166. /***
  167.  
  168.     A meditation for the guru from the Diamond Sutra -
  169.  
  170.     So shall you think of all this fleeting world:
  171.     A star at dawn, a bubble in a stream;
  172.     A flash of lightning in a summer cloud,
  173.     A flickering lamp, a phantom, and a dream.
  174.  
  175. ***/
  176.  
  177.  
  178. /*
  179.  * jiff.c   Jim Kent's iff - ilbm  reader
  180.  *
  181.  * This is the (sortof) short (sortof) simple no-frills IFF reader to get
  182.  * something out of DPaint, Images, or the Animator.  It works well with
  183.  * the Aztec C compiler.  It should work with Lattice but you never know
  184.  * until you try it.    I haven't.
  185.  *
  186.  * I've included a simple main program.  This is just to make it stand alone.
  187.  * Since amiga screen initializations are massive, all it does as is is
  188.  * read it into a BitMap, and then free up the BitMap. Should crash it if
  189.  * it's gonna crash though.
  190.  *
  191.  * The main interface to this is through the routine win_read_iff(filename).
  192.  * This returns a ILBM_info structure-pointer on success, and NULL on
  193.  * failure.  It cleans up after itself on failure.
  194.  *
  195.  * I hope you will find this useful and easy to use.  Please forgive my funky
  196.  * indentation style?  Well at least I'm consistent! (* Run through the
  197.  * C-Beautifier by Olaf Seibert !! *)
  198.  *
  199.  * To demonstrate what a nice guy I am even though I'm far from wild about
  200.  * the IFF standard I'm placing this in the public domain.  When you
  201.  * remove the DEBUG and PARANOID definitions the code is only 1536 bytes
  202.  * long.
  203.  *
  204.  * -Jim Kent  April 22, 1986
  205.  */
  206.  
  207.  
  208. #include <stdio.h>
  209. #include <exec/types.h>
  210. #include <exec/memory.h>
  211. #include <graphics/gfx.h>
  212. #include <libraries/dos.h>
  213. #include <intuition/intuition.h>
  214. /* #include "jiff.h"    */
  215.  
  216.  
  217. /*
  218.  * This is an all too common state of software development.  Get rid of
  219.  * this define as soon as it runs.
  220.  */
  221. #undef DEBUG
  222. /* #define DEBUG/* */
  223.  
  224. /*
  225.  * This is the normal state of software development.  Seriously undefine
  226.  * this to make it shut up about errors and reduce code size half way
  227.  * through beta testing...
  228.  */
  229. #undef PARANOID
  230.  
  231. /*
  232.  * This is nice if you want to use a debugger on the STATIC data and
  233.  * routines in this file. Redefine only if you don't need a debugger.
  234.  */
  235.  
  236. #ifdef DEBUG
  237. # undef STATIC
  238. # define STATIC
  239. #endif
  240.  
  241. STATIC struct ILBM_info *win_read_ilbm();
  242. STATIC struct ILBM_info *win_read_body();
  243.  
  244. /*
  245.  * OK this code is almost re-entrant.  Pass this guy from above to make it
  246.  * really re-entrant.  (Why do you need a reentrant ILBM reader though??
  247.  * Maybe for Dale ... ) Well, look in the IFF specs for instance... [Olaf
  248.  * Seibert, KosmoSoft]
  249.  */
  250. STATIC struct ILBM_info root_info;    /* static so get initialized to
  251.                      * zero */
  252.  
  253.  
  254. #ifdef PARANOID
  255. /*
  256.  * a little paranoid routine that say's where we got before EOF
  257.  */
  258. STATIC void
  259. iff_truncated(where)
  260. int        where;
  261. {
  262.     printf("ILBM truncated %d\n", where);
  263.     free_planes(&root_info.bitmap);
  264. }
  265.  
  266. #endif PARANOID
  267.  
  268.  
  269. struct ILBM_info *
  270. win_read_iff(name, just_colors, window, MandSize, MandPointer)
  271. char           *name;
  272. short        just_colors;
  273. struct Window  *window;
  274. int        MandSize;
  275. APTR        MandPointer;
  276. {
  277.     struct ILBM_info *info = &root_info;
  278.     FILE       *file;
  279.     struct form_chunk chunk;
  280.  
  281.     if ((file = fopen(name, "r")) == 0) {
  282. #ifdef PARANOID
  283.     printf("couldn't fopen %s to read\n", name);
  284. #endif PARANOID
  285.     return NULL;
  286.     }
  287.     if (fread(&chunk, sizeof (struct form_chunk), 1, file) != 1) {
  288. #ifdef PARANOID
  289.     iff_truncated(0);
  290. #endif PARANOID
  291.     fclose(file);
  292.     return NULL;
  293.     }
  294.     if (chunk.fc_type.b4_type != FORM) {
  295. #ifdef PARANOID
  296.     printf("not a FORM - %s\n", name);
  297. #endif PARANOID
  298.     fclose(file);
  299.     return NULL;
  300.     }
  301.     if (chunk.fc_subtype.b4_type != ILBM) {
  302. #ifdef PARANOID
  303.     printf("FORM not an ILBM - %s\n", name);
  304. #endif PARANOID
  305.     fclose(file);
  306.     return NULL;
  307.     }
  308. #ifdef DEBUG
  309.     printf("FORM %ld ILBM\n", chunk.fc_length);
  310. #endif DEBUG
  311.  
  312. #ifdef MANDEL
  313.     info->mand = (struct Mand *) MandPointer;
  314.     info->mandsize = MandSize;
  315.     info->mand->MandID = 0;    /* we have not yet read it */
  316. #endif
  317.  
  318.     info = win_read_ilbm(file, info, chunk.fc_length - sizeof (chunk),
  319.              just_colors, window);
  320. #ifdef DEBUG
  321.     printf("info = %lx\n", info);
  322. #endif DEBUG
  323.  
  324. #ifdef MANDEL
  325.     /*
  326.      * Backward compatibility with non-standard code: We may want to read
  327.      * the extra MAND if we have not read it by now.
  328.      */
  329.     if (info && MandSize && info->mand->MandID != MAND) {
  330.     fread(MandPointer, 1, MandSize, file);
  331.     info->mand->Size -= 2 * sizeof (long);  /* patch bug */
  332.     }
  333. #endif MANDEL
  334.  
  335.     fclose(file);
  336.  
  337.     return info;
  338. }
  339.  
  340. STATIC struct ILBM_info *
  341. win_read_ilbm(file, info, length, just_colors, window)
  342. FILE           *file;
  343. struct ILBM_info *info;
  344. long        length;
  345. short        just_colors;
  346. struct Window  *window;
  347. {
  348.     struct iff_chunk chunk;
  349.     int         i;
  350.     long        read_in = 0;
  351.     int         got_header = FALSE; /* To make sure gots the header
  352.                      * first */
  353.     int         got_cmap = FALSE;    /* Make sure get cmap before
  354.                      * "BODY" */
  355.  
  356.     /*
  357.      * Make sure the Planes are all NULL so can free up memory easily on
  358.      * error abort
  359.      */
  360.     for (i = 0; i < 8; i++)
  361.     info->bitmap.Planes[i] = NULL;
  362.  
  363.     while (read_in < length) {
  364.     if (fread(&chunk, sizeof (chunk), 1, file) != 1) {
  365. #ifdef PARANOID
  366.         iff_truncated(1);
  367. #endif PARANOID
  368.         return NULL;
  369.     }
  370.     switch (chunk.iff_type.b4_type) {
  371.     case BMHD:
  372. #ifdef DEBUG
  373.         printf("\tBMHD %ld\n", chunk.iff_length);
  374. #endif DEBUG
  375.         if (fread(&info->header, sizeof (info->header), 1, file) != 1) {
  376. #ifdef PARANOID
  377.         iff_truncated(2);
  378. #endif PARANOID
  379.         return NULL;
  380.         }
  381.         got_header = TRUE;
  382.         break;
  383.     case CMAP:
  384. #ifdef DEBUG
  385.         printf("\tCMAP %ld\n", chunk.iff_length);
  386. #endif DEBUG
  387.         if (!got_header) {
  388. #ifdef PARANOID
  389.         printf("CMAP before BMHD\n");
  390. #endif PARANOID
  391.         return NULL;
  392.         }
  393.         if (chunk.iff_length <= 3 * MAXCOL) {
  394.         if (fread(info->cmap, (int) chunk.iff_length, 1, file) != 1) {
  395. #ifdef PARANOID
  396.             iff_truncated(3);
  397. #endif PARANOID
  398.             return NULL;
  399.         }
  400.         } else {
  401. #ifdef PARANOID
  402.         printf("warning, more than %d colors in ILBM CMAP\n",
  403.                MAXCOL);
  404. #endif PARANOID
  405.         if (fread(info->cmap, (int) 3 * MAXCOL, 1, file) != 1) {
  406. #ifdef PARANOID
  407.             iff_truncated(4);
  408. #endif PARANOID
  409.             return NULL;
  410.         }
  411.         bit_bucket(file, chunk.iff_length - 3 * MAXCOL);
  412.         }
  413.         got_cmap = TRUE;
  414.         if (just_colors)
  415.         return info;
  416.         break;
  417.     case MAND:
  418. #ifdef DEBUG
  419.         printf("\tMAND %ld\n", chunk.iff_length);
  420. #endif DEBUG
  421.         if (chunk.iff_length + sizeof (chunk) <= info->mandsize) {
  422.         if (fread((char *) info->mand + sizeof (chunk),
  423.               (int) chunk.iff_length, 1, file) != 1) {
  424. #ifdef DEBUG
  425.             printf("fread MAND fails; filepos %ld ferror %d\n",
  426.                (long) ftell(file), (int) ferror(file));
  427. #endif
  428.             return NULL;
  429.         }
  430.         *(struct iff_chunk *) info->mand = chunk;
  431.  
  432.         /*
  433.          * skip padding byte
  434.          */
  435.         if (chunk.iff_length & 1)
  436.             getc(file);
  437.         } else {
  438. #ifdef DEBUG
  439.         printf("skipping MAND; too large for buffer (%ld)\n",
  440.                (long) info->mandsize);
  441. #endif
  442.         bit_bucket(file, chunk.iff_length);
  443.         }
  444.         break;
  445.     case BODY:
  446.         if (!got_cmap) {
  447. #ifdef PARANOID
  448.         printf("BODY before CMAP\n");
  449. #endif PARANOID
  450.         return NULL;
  451.         }
  452. #ifdef DEBUG
  453.         printf("\tBODY %ld\n", chunk.iff_length);
  454. #endif DEBUG
  455.         return win_read_body(file, info, chunk.iff_length, window);
  456.  
  457.     default:        /* Squawk about unknown types if PARANOID */
  458. #ifdef PARANOID
  459.         printf("\t unknown type %lx of b4_type\n", chunk.iff_type.b4_type);
  460.     case GRAB:        /* Ignore documented but unwanted types */
  461.     case DEST:
  462.     case SPRT:
  463.     case CAMG:
  464.     case CRNG:
  465.     case CCRT:
  466. #endif PARANOID
  467.         bit_bucket(file, chunk.iff_length);
  468.         break;
  469.     }
  470.     read_in += EVEN(chunk.iff_length) + sizeof (chunk);
  471.     }
  472. #ifdef PARANOID
  473.     printf("no BODY in ILBM\n");
  474. #endif PARANOID
  475.     return NULL;
  476. }
  477.  
  478.  
  479.  
  480. STATIC struct ILBM_info *
  481. win_read_body(file, info, length, window)
  482. FILE           *file;
  483. register struct ILBM_info *info;
  484. long        length;
  485. struct Window  *window;
  486. {
  487.     struct ILBM_header *header;
  488.     struct BitMap  *bm;
  489.     int         i,
  490.             j;
  491.     int         rlength;
  492.     int         plane_offset;
  493.     ULONG        YSize,
  494.             DestX,
  495.             DestY;
  496.  
  497. #ifdef DEBUG
  498.     printf("win_read_body( %lx %lx %ld)\n", file, info, length);
  499. #endif DEBUG
  500.  
  501. #ifdef PARANOID
  502.     /*
  503.      * When paranoid do a little error checking first ... fail fast!
  504.      */
  505.     if (info->header.nPlanes > 8) {
  506.     printf("Whoa, woe  Dale only speaks 8 planes boy, not %d\n",
  507.            info->header.nPlanes);
  508.     return NULL;
  509.     }
  510. #endif PARANOID
  511.  
  512.     /*
  513.      * Ok a little more error checking
  514.      */
  515.     if (info->header.compression != 0 && info->header.compression != 1) {
  516. #ifdef PARANOID
  517.     printf("unrecognized compression type %d\n", info->header.compression);
  518. #endif PARANOID
  519.     return NULL;
  520.     }
  521.     /*
  522.      * Set up the bitmap part that doesn't involve memory allocation first
  523.      * - hey this part does get done, and let's be optimistic...
  524.      */
  525.     info->bitmap.BytesPerRow = line_bytes(info->header.w);
  526.     info->bitmap.Rows = info->header.h;
  527.     info->bitmap.Depth = info->header.nPlanes;
  528.     info->bitmap.Flags = info->bitmap.pad = 0;
  529.  
  530.     rlength = info->bitmap.Rows * info->bitmap.BytesPerRow;
  531.  
  532.     for (i = 0; i < info->header.nPlanes; i++) {
  533.     if ((info->bitmap.Planes[i] = ralloc(rlength)) == NULL) {
  534. #ifdef PARANOID
  535.         printf("couldn't alloc plane %d in win_read_body\n", i);
  536. #endif PARANOID
  537.         free_planes(&info->bitmap);
  538.         return NULL;
  539.     }
  540.     }
  541.  
  542.     plane_offset = 0;
  543.     YSize = (MAXPLANESIZE / info->bitmap.BytesPerRow);
  544.     if (window->Flags & GIMMEZEROZERO) {
  545.     DestX = 0;
  546.     DestY = 0;
  547.     } else {
  548.     DestX = window->BorderLeft;
  549.     DestY = window->BorderTop;
  550.     }
  551.  
  552.     for (i = 0; i < info->bitmap.Rows; i++) {
  553.     /*
  554.      * This test should be in the inner loop for shortest code, in the
  555.      * outer loop for greatest speed, so sue me I compromised
  556.      */
  557.     if (info->header.compression == 0) {
  558.         for (j = 0; j < info->bitmap.Depth; j++) {
  559.         if (fread(info->bitmap.Planes[j] + plane_offset,
  560.               info->bitmap.BytesPerRow, 1, file) != 1) {
  561. #ifdef PARANOID
  562.             iff_truncated(6);
  563. #endif PARANOID
  564.             free_planes(&info->bitmap);
  565.             return NULL;
  566.         }
  567.         }
  568.     } else {
  569.         register char  *dest,
  570.                 value;
  571.         register int    so_far,
  572.                 count;    /* How much have unpacked so far */
  573.  
  574.         for (j = 0; j < info->bitmap.Depth; j++) {
  575.         so_far = info->bitmap.BytesPerRow;
  576.         dest = (char *) info->bitmap.Planes[j] + plane_offset;
  577.         while (so_far > 0) {
  578.             if ((value = getc(file)) == 128) {
  579. #ifdef DEBUG
  580.             printf("NOP\n");
  581. #endif DEBUG
  582.             } else if (value > 0) {
  583.             count = (int) value + 1;
  584.             so_far -= count;
  585.             if (fread(dest, count, 1, file) != 1) {
  586. #ifdef PARANOID
  587.                 iff_truncated(7);
  588. #endif PARANOID
  589.                 free_planes(&info->bitmap);
  590.                 return NULL;
  591.             }
  592.             dest += count;
  593.             } else {
  594.             count = (int) -value + 1;
  595.             so_far -= count;
  596.             value = getc(file);
  597.             while (--count >= 0)    /* This is fastest loop on
  598.                          * the 68000 */
  599.                 *dest++ = value;
  600.             }
  601.         }
  602.         if (so_far != 0) {
  603. #ifdef PARANOID
  604.             printf("compression quite screwed up, aborting %d\n", so_far);
  605. #endif PARANOID
  606.             free_planes(&info->bitmap);
  607.             return NULL;
  608.         }
  609.         }
  610.     }
  611.     plane_offset += info->bitmap.BytesPerRow;
  612.  
  613.     if (plane_offset > MAXPLANESIZE - info->bitmap.BytesPerRow) {
  614.         BltBitMapRastPort(&info->bitmap, 0L, 0L,
  615.                   window->RPort, DestX, DestY,
  616.                   info->bitmap.BytesPerRow * 8L, YSize,
  617.                   COPY_MINTERM);
  618.         plane_offset = 0;
  619.         DestY += YSize;
  620.     }
  621.     }
  622.  
  623.     if (plane_offset) {
  624.     BltBitMapRastPort(&info->bitmap, 0L, 0L,
  625.               window->RPort, DestX, DestY,
  626.               info->bitmap.BytesPerRow * 8L,
  627.               (long) plane_offset / info->bitmap.BytesPerRow,
  628.               COPY_MINTERM);
  629.     }
  630.     if (length & 1) {
  631.     /*
  632.      * Skip padding byte
  633.      */
  634.     getc(file);
  635.     }
  636.     free_planes(&info->bitmap);
  637.     return info;
  638. }
  639.  
  640.  
  641. void
  642. free_planes(bmap)
  643. register struct BitMap *bmap;
  644. {
  645.     PLANEPTR        plane;
  646.     long        length;
  647.     short        i;
  648.  
  649.     length = bmap->BytesPerRow * bmap->Rows;
  650.  
  651.     for (i = bmap->Depth; --i >= 0;) {
  652.     if ((plane = bmap->Planes[i]) != NULL) {
  653.         rfree(plane, length);
  654.         bmap->Planes[i] = NULL;
  655.     }
  656.     }
  657. }
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664. #undef DEBUG
  665. /* #define DEBUG/* */
  666. #undef PARANOID
  667.  
  668. /*----------------------------------------------------------------------*
  669.  * jpacker.c Convert data to "cmpByteRun1" run compression.
  670.  *
  671.  * pack_row() is an adaptation of PackRow()
  672.  * by Jerry Morrison and Steve Shaw, Electronic Arts,
  673.  * modified and tweaked by Jim Kent, Dancing Flame 05/02/86
  674.  *
  675.  *  control bytes:
  676.  *   [0..127]    : followed by n+1 bytes of data.
  677.  *   [-1..-127] : followed by byte to be repeated(-n)+1 times.
  678.  *   -128    : NOOP.
  679.  *
  680.  *
  681.  * write_iff() is the only function you can access in this module.
  682.  *----------------------------------------------------------------------*/
  683.  
  684. /*-
  685. #include <exec/types.h>
  686. #include <graphics/gfx.h>
  687. #include <stdio.h>
  688. #include "jiff.h"
  689. */
  690.  
  691. #define DUMP    0
  692. #define RUN 1
  693.  
  694. #define MINRUN 3
  695. #define MAXRUN 128
  696. #define MAXDAT 128
  697.  
  698. /*
  699.  * pack_row - pass source line pointer, length of line, and file. Returns
  700.  * # of bytes after compression.  Returns 0 on write error. Pass file =
  701.  * NULL to just find out length, otherwise will write compressed row to
  702.  * file.
  703.  */
  704.  
  705. STATIC unsigned int
  706. pack_row(file, source, size)
  707. FILE           *file;
  708. char           *source;
  709. int        size;
  710. {
  711.     char        c,
  712.             lastc = '\0';
  713.     short        mode = DUMP;
  714.     short        nbuf = 0;    /* Number of chars in buffer */
  715.     short        rstart = 0; /* Buffer index current run starts */
  716.     unsigned short  putsize;
  717.  
  718. #if OLD
  719.     char        buf[MAXDAT * 3 / 2];    /* I think MAXDAT+1 would
  720.                          * suffice */
  721.  
  722. #else
  723.     /*
  724.      * And I think that buf can be changed into a pointer to the source
  725.      * line, to the beginning of a dump. Saves stack space and copying.
  726.      */
  727.     char       *buf;
  728.  
  729. #endif
  730.  
  731.     putsize = 0;
  732. #if OLD
  733.     buf[0] = lastc = *source++; /* So have valid lastc */
  734. #else
  735.     buf = source;
  736.     lastc = *source++;        /* So have valid lastc */
  737. #endif
  738.     nbuf = 1;
  739.     size--;            /* Since one byte eaten */
  740.  
  741.  
  742.     for (; size; --size) {
  743. #if OLD
  744.     buf[nbuf++] = c = *source++;
  745. #else
  746.     nbuf++;
  747.     c = *source++;
  748. #endif
  749.     switch (mode) {
  750.     case DUMP:
  751.         /*
  752.          * If the buffer is full, write the length byte, then the data
  753.          */
  754.         if (nbuf > MAXDAT) {
  755.         if (file != NULL) {
  756.             if (putc(nbuf - 2, file) == EOF)
  757.             return 0;
  758.             if (fwrite(buf, nbuf - 1, 1, file) != 1)
  759.             return 0;
  760.         }
  761.         putsize += nbuf;
  762. #if OLD
  763.         buf[0] = c;
  764. #else
  765.         buf = source - 1;    /* Undo the previous source++ */
  766. #endif
  767.         nbuf = 1;
  768.         rstart = 0;
  769.         break;
  770.         }
  771.         if (c == lastc) {
  772.         if (nbuf - rstart >= MINRUN) {
  773.             if (rstart > 0) {
  774.             if (file != NULL) {
  775.                 if (putc(rstart - 1, file) == EOF)
  776.                 return 0;
  777.                 if (fwrite(buf, rstart, 1, file) != 1)
  778.                 return 0;
  779.             }
  780.             putsize += rstart + 1;
  781.             }
  782.             mode = RUN;
  783.         } else if (rstart == 0)
  784.             mode = RUN;
  785.         /*
  786.          * No dump in progress, so can't lose by making these 2 a
  787.          * run.
  788.          */
  789.         } else
  790.         rstart = nbuf - 1;    /* First of run */
  791.         break;
  792.  
  793.     case RUN:
  794.         if ((c != lastc) || (nbuf - rstart > MAXRUN)) {
  795.         /*
  796.          * Output run
  797.          */
  798.         if (file != NULL) {
  799.             if (putc(-(nbuf - rstart - 2), file) == EOF)
  800.             return 0;
  801.             if (putc(lastc, file) == EOF)
  802.             return 0;
  803.         }
  804.         putsize += 2;
  805. #if OLD
  806.         buf[0] = c;
  807. #else
  808.         buf = source - 1;    /* Undo the previous source++ */
  809. #endif
  810.         nbuf = 1;
  811.         rstart = 0;
  812.         mode = DUMP;
  813.         }
  814.         break;
  815.     }
  816.  
  817.     lastc = c;
  818.     }
  819.  
  820.     switch (mode) {
  821.     case DUMP:
  822.     if (file != NULL) {
  823.         if (putc(nbuf - 1, file) == EOF)
  824.         return 0;
  825.         if (fwrite(buf, nbuf, 1, file) != 1)
  826.         return 0;
  827.     }
  828.     putsize += nbuf + 1;
  829.     break;
  830.     case RUN:
  831.     if (file != NULL) {
  832.         if (putc(-(nbuf - rstart - 1), file) == EOF)
  833.         return 0;
  834.         if (putc(lastc, file) == EOF)
  835.         return 0;
  836.     }
  837.     putsize += 2;
  838.     break;
  839.     }
  840.     return putsize;
  841. }
  842.  
  843. /*
  844.  * write_row - pass source line pointer, length of line, and file. Returns
  845.  * # of bytes after not compressing.  Returns 0 on write error. Pass file
  846.  * = NULL to just find out length, otherwise will write non-compressed row
  847.  * to file.
  848.  */
  849.  
  850. STATIC unsigned int
  851. write_row(file, source, size)
  852. FILE           *file;
  853. char           *source;
  854. int        size;
  855. {
  856.     if (file) {
  857.     if (fwrite(source, size, 1, file) != 1)
  858.         return 0;
  859.     }
  860.     return size;
  861. }
  862.  
  863.  
  864. STATIC unsigned long
  865. pack_window(file, window, writer)
  866. FILE           *file;
  867. register struct Window *window;
  868. register unsigned int (*writer) ();
  869.  
  870. {
  871.     unsigned short  i,
  872.             j;
  873.     unsigned        row_length;
  874.     unsigned long   compressed_length;
  875.     unsigned        plane_offset;
  876.     int         BytesPerRow;
  877.     int         YSize;
  878.     ULONG        SrcX,
  879.             SrcY;
  880.     struct RastPort Rp;
  881.     struct BitMap   Bitmap;
  882.  
  883. #ifdef DEBUG
  884.     printf("pack_window( %lx %lx)\n", file, window);
  885. #endif DEBUG
  886.  
  887.     compressed_length = 0;
  888.     plane_offset = 0;
  889.  
  890.     BytesPerRow = line_bytes(window->GZZWidth);
  891.     Bitmap.Depth = window->WScreen->BitMap.Depth;
  892.     if (window->Flags & GIMMEZEROZERO) {
  893.     SrcX = 0;
  894.     SrcY = 0;
  895.     } else {
  896.     SrcX = window->BorderLeft;
  897.     SrcY = window->BorderTop;
  898.     }
  899.     YSize = MAXPLANESIZE / BytesPerRow;
  900.     InitBitMap(&Bitmap, (ULONG) Bitmap.Depth,
  901.            (ULONG) (8 * BytesPerRow), (ULONG) YSize);
  902.  
  903.     /*
  904.      * Make sure the Planes are all NULL so can free up memory easily on
  905.      * error abort
  906.      */
  907.     for (i = 0; i < 8; i++)
  908.     Bitmap.Planes[i] = NULL;
  909.  
  910.     for (i = 0; i < Bitmap.Depth; i++) {
  911.     if ((Bitmap.Planes[i] = ralloc(MAXPLANESIZE)) == NULL) {
  912. #ifdef DEBUG
  913.         printf("couldn't alloc plane %d in pack_window\n", i);
  914.         printf("pack_window: aborting; free_planes\n");
  915. #endif
  916.         free_planes(&Bitmap);
  917.         return 0;
  918.     }
  919.     }
  920.     InitRastPort(&Rp);
  921.     Rp.BitMap = &Bitmap;
  922. #ifdef DEBUG
  923.     printf("pack_window BytesPerRow=%ld Depth=%ld\n", (long) BytesPerRow,
  924.        (long) Bitmap.Depth);
  925. #endif
  926.  
  927.     for (i = 0; i < window->GZZHeight; i++) {
  928.     if (plane_offset == 0) {
  929. #ifdef DEBUG
  930.         printf("pack_window ClipBlit SrcX=%ld SrcY=%ld YSize=%ld\n",
  931.            SrcX, SrcY, (ULONG) YSize);
  932. #endif
  933. #define DestX    0L
  934. #define DestY    0L
  935.         ClipBlit(window->RPort, SrcX, SrcY,
  936.              &Rp, DestX, DestY,
  937.              (ULONG) window->GZZWidth, (ULONG) YSize,
  938.              COPY_MINTERM);
  939. #undef DestX
  940. #undef DestY
  941.         SrcY += YSize;
  942.     }
  943.     for (j = 0; j < Bitmap.Depth; j++) {
  944.         if ((row_length = (*writer) (file, Bitmap.Planes[j] + plane_offset,
  945.                      BytesPerRow)) == 0) {
  946. #ifdef DEBUG
  947.         printf("error packing row %d plane %d\n", i, j);
  948.         printf("pack_window: aborting; free_planes\n");
  949. #endif
  950.         free_planes(&Bitmap);
  951.         return 0;
  952.         }
  953.         compressed_length += row_length;
  954.     }
  955.  
  956.     plane_offset += BytesPerRow;
  957.     if (plane_offset > MAXPLANESIZE - BytesPerRow)
  958.         plane_offset = 0;
  959.     }
  960.  
  961. #ifdef DEBUG
  962.     printf("pack_window: free_planes\n");
  963. #endif
  964.     free_planes(&Bitmap);
  965.  
  966.     if (compressed_length & 1) {/* Check to see odd length */
  967.     if (file != NULL) {
  968.         if (putc(0, file) == EOF) {
  969.         return 0;
  970.         }
  971.     }
  972.     /*
  973.      * compressed_length++; Deleted!!! Padding should NOT be included
  974.      * in the chunk size !!!
  975.      */
  976.     }
  977.     return compressed_length;
  978. }
  979.  
  980. int
  981. write_iff(name, colors, window, xoff, yoff, compressed, MandSize, MandPointer)
  982. char           *name;
  983. unsigned char  *colors;
  984. register struct Window *window;
  985. short        xoff,
  986.         yoff;
  987. short        compressed;
  988. int        MandSize;
  989. APTR        MandPointer;
  990. {
  991.     FILE       *file;
  992.     struct form_chunk chunk;
  993.     struct iff_chunk ichunk;
  994.     struct BitMapHeader header;
  995.     long        bits_size;
  996.     short        i;
  997.     int         width = 0;
  998.     int         Depth;
  999.     int         BytesPerRow;
  1000.  
  1001. #ifdef DEBUG
  1002.     printf("write_iff\n");
  1003. #endif
  1004.  
  1005.     if ((file = fopen(name, "w")) == 0) {
  1006. #ifdef PARANOID
  1007.     printf("couldn't fopen %s to write\n", name);
  1008. #endif PARANOID
  1009.     goto abort;
  1010.     }
  1011.     /*
  1012.      * Say its a FORM ILBM
  1013.      */
  1014.     chunk.fc_type.b4_type = FORM;
  1015.     chunk.fc_subtype.b4_type = ILBM;
  1016. #ifdef MANDEL
  1017.     chunk.fc_length = 4 + 3 * sizeof (struct iff_chunk) + MAXCOL * 3 +
  1018.     sizeof (struct BitMapHeader) + sizeof (struct CommodoreAmiga) + MandSize;
  1019. #else
  1020.     chunk.fc_length = 4 + 3 * sizeof (struct iff_chunk) + MAXCOL * 3 +
  1021.     sizeof (struct BitMapHeader) + sizeof (struct CommodoreAmiga);
  1022. #endif MANDEL
  1023.     if (window) {
  1024.     width = window->GZZWidth;
  1025.     BytesPerRow = line_bytes(width);
  1026.     Depth = window->WScreen->BitMap.Depth;
  1027.     if (compressed) {
  1028. #ifdef DEBUG
  1029.         printf("write_iff: call pack_window for sizing\n");
  1030. #endif
  1031.         if ((bits_size = pack_window(NULL, window, pack_row)) == 0)
  1032.         goto abort;
  1033.     } else {
  1034.         bits_size = BytesPerRow * window->GZZHeight * Depth;
  1035.     }
  1036.     chunk.fc_length += bits_size;
  1037.     if (bits_size & 1)
  1038.         chunk.fc_length++;
  1039.     }
  1040.     if (fwrite(&chunk, sizeof (chunk), 1, file) != 1)
  1041.     goto abort;
  1042.  
  1043.     /*
  1044.      * Here comes a BitMapHeader
  1045.      */
  1046.     {
  1047.     struct iff_chunk ichunk;
  1048.  
  1049.     ichunk.iff_type.b4_type = BMHD;
  1050.     ichunk.iff_length = sizeof (header);
  1051.     if (fwrite(&ichunk, sizeof (ichunk), 1, file) != 1)
  1052.         goto abort;
  1053.     }
  1054.  
  1055.     /*
  1056.      * Initialize the BitMapHeader to normal values
  1057.      */
  1058.     header.masking = 0;
  1059.     header.pad1 = 0;
  1060.     header.transparentColor = 0;
  1061.     if (compressed)
  1062.     header.compression = 1;
  1063.     else
  1064.     header.compression = 0;
  1065.     header.pageWidth = width;
  1066.     header.pageHeight = window ? window->GZZHeight : YMAX;
  1067.     header.xAspect = width > LOXMAX ? XASPECT : XASPECT * 2;
  1068.     header.yAspect = YASPECT;
  1069.     /*
  1070.      * If it's not just a color map give the dimensions of rasters
  1071.      */
  1072.     if (window) {
  1073.     header.w = width;
  1074.     header.h = window->GZZHeight;
  1075.     header.nPlanes = Depth;
  1076.     header.x = xoff;
  1077.     header.y = yoff;
  1078.     }
  1079.     if (fwrite(&header, sizeof (header), 1, file) != 1)
  1080.     goto abort;
  1081.  
  1082.     /*
  1083.      * Squirt out the color map
  1084.      */
  1085.     {
  1086.     struct iff_chunk ichunk;
  1087.  
  1088.     ichunk.iff_type.b4_type = CMAP;
  1089.     ichunk.iff_length = MAXCOL * 3;
  1090.     if (fwrite(&ichunk, sizeof (ichunk), 1, file) != 1)
  1091.         goto abort;
  1092.     if (fwrite(colors, (int) 3 * MAXCOL, 1, file) != 1)
  1093.         goto abort;
  1094.     }
  1095.  
  1096.     /*
  1097.      * Write a CAMG chunk with ViewPort modes
  1098.      */
  1099.     {
  1100.     struct CommodoreAmiga camg;
  1101.  
  1102.     camg.camg_iffc.iff_type.b4_type = CAMG;
  1103.     camg.camg_iffc.iff_length = sizeof (camg) - sizeof (camg.camg_iffc);
  1104.     camg.camg_data = window->WScreen->ViewPort.Modes;
  1105.     if (fwrite(&camg, sizeof (camg), 1, file) != 1)
  1106.         goto abort;
  1107.     }
  1108.  
  1109. #ifdef MANDEL
  1110.     /*
  1111.      * We want to write our own private MAND chunk
  1112.      */
  1113.     if (MandSize) {
  1114.     if (fwrite(MandPointer, MandSize, 1, file) != 1)
  1115.         goto abort;
  1116.     }
  1117. #endif MANDEL
  1118.  
  1119.     /*
  1120.      * If they be bits then squirt out the bits
  1121.      */
  1122.     if (window) {
  1123.     struct iff_chunk ichunk;
  1124.  
  1125.     ichunk.iff_type.b4_type = BODY;
  1126.     ichunk.iff_length = bits_size;
  1127.     if (fwrite(&ichunk, sizeof (ichunk), 1, file) != 1)
  1128.         goto abort;
  1129. #ifdef DEBUG
  1130.     printf("write_iff: call pack_window for real\n");
  1131. #endif
  1132.     if (compressed) {
  1133.         if (pack_window(file, window, pack_row) == 0)
  1134.         goto abort;
  1135.     } else {
  1136.         if (pack_window(file, window, write_row) == 0)
  1137.         goto abort;
  1138.     }
  1139.     }
  1140.     fclose(file);
  1141.  
  1142.     return 1;
  1143. abort:
  1144. #ifdef DEBUG
  1145.     printf("write_iff: aborting !!!\n");
  1146. #endif
  1147.     fclose(file);
  1148.     return 0;
  1149. }
  1150.  
  1151.  
  1152. /*
  1153.  * put_ea_cmap given an ea-type color map:
  1154.  *
  1155.  * an array of unsigned chars of form ea_cmap[] = {r, g, b, r, g, b...}
  1156.  *
  1157.  * turn it into an amiga-type color map:
  1158.  *
  1159.  * an array of unsigned short of form amiga_cmap = {0xrgb, 0xrgb, ...}
  1160.  *
  1161.  * and then tell Dale this is the colors we want for our viewport
  1162.  */
  1163.  
  1164. void
  1165. put_ea_cmap(ea_cmap, colors, Screen)
  1166. unsigned char  *ea_cmap;
  1167. int        colors;
  1168. struct Screen  *Screen;
  1169. {
  1170.     unsigned short  amy_cmap[MAXCOL];
  1171.     register int    i;
  1172.     register short  color;
  1173.  
  1174.     if (colors > MAXCOL)        /* Color clipping */
  1175.     colors = MAXCOL;
  1176.     for (i = 0; i < colors; i++) {
  1177.     color = (*ea_cmap++ & 0xF0) << 4;
  1178.     color |= *ea_cmap++ & 0xF0;
  1179.     color |= (*ea_cmap++ & 0xF0) >> 4;
  1180.     amy_cmap[i] = color;
  1181.     }
  1182.     LoadRGB4(&Screen->ViewPort, amy_cmap, (long) colors);
  1183. }
  1184.  
  1185. void
  1186. get_ea_cmap(ea_cmap, colors, Screen)
  1187. unsigned char  *ea_cmap;
  1188. int        colors;
  1189. struct Screen  *Screen;
  1190. {
  1191.     register long   i;
  1192.     register unsigned short rgb;
  1193.  
  1194.     if (colors > MAXCOL)        /* Color clipping */
  1195.     colors = MAXCOL;
  1196.     for (i = 0; i < colors; i++) {
  1197.     rgb = GetRGB4(Screen->ViewPort.ColorMap, i);
  1198.     *ea_cmap++ = (rgb & 0xF00) >> 4;
  1199.     *ea_cmap++ = (rgb & 0x0F0);
  1200.     *ea_cmap++ = (rgb & 0x00F) << 4;
  1201.     }
  1202. }
  1203.