
/* JIFF.H */

/************ I usually put these in a file called format.h ****/

#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/gfx.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>

#define XMAX 640
#define LOXMAX 320
#define YMAX 200
#define XASPECT 5
#define YASPECT 11
#define BMDEPTH         5               /* Depth of our bitmap */
#define MAXCOL (1<<BMDEPTH)     /* Maximum number of colors */

/* EA handy make a long from 4 chars macros redone to work with Aztec*/
#define MAKE_ID(a, b, c, d)\
( ((long)(a)<<24) | ((long)(b)<<16) | ((long)(c)<<8) | (long)(d) )

/* These are the IFF types I deal with */
#define FORM MAKE_ID('F', 'O', 'R', 'M')
#define ILBM MAKE_ID('I', 'L', 'B', 'M')
#define BMHD MAKE_ID('B', 'M', 'H', 'D')
#define CMAP MAKE_ID('C', 'M', 'A', 'P')
#define BODY MAKE_ID('B', 'O', 'D', 'Y')

/* And these are the IFF types I ignore but don't squawk about */
#define GRAB MAKE_ID('G', 'R', 'A', 'B')
#define DEST MAKE_ID('D', 'E', 'S', 'T')
#define SPRT MAKE_ID('S', 'P', 'R', 'T')
#define CAMG MAKE_ID('C', 'A', 'M', 'G')
#define CRNG MAKE_ID('C', 'R', 'N', 'G')
#define CCRT MAKE_ID('C', 'C', 'R', 'T')

#define EVEN(x) (((x) + 1) & ~1)

/* Some macros for raster memory allocation ... redefine if you're
   sensible and manage memory locally */

extern void *AllocMem();

        /* ralloc - raster alloc */
# define ralloc(amount)  (PLANEPTR)AllocMem((long)(amount), MEMF_CHIP)
        /* rfree - raster free */
# define rfree(pt, amount)      FreeMem( (pt), (long)(amount) )

/* line_bytes = the number of words * 2 (for bytes) a raster line takes up */
#define line_bytes(width)       (((width + 15) >> 3) & ~0x0001)

/* psize - plane size in bytes (an even number) of a raster given
   width and height */
#define psize(width, height) ( line_bytes(width)*height)

/* The place to throw excess bits */
#define bit_bucket(file, length) fseek(file, (long)EVEN(length), 1)


union bytes4
{
        char b4_name[4];
        long b4_type;
};

struct iff_chunk
{
        union bytes4 iff_type;
        long iff_length;
};

struct form_chunk
{
        union bytes4 fc_type; /* == FORM */
        long fc_length;
        union bytes4 fc_subtype;
};

struct BitMapHeader
{
        UWORD w, h;
        UWORD x, y;
        UBYTE nPlanes;
        UBYTE masking;
        UBYTE compression;
        UBYTE pad1;
        UWORD transparentColor;
        UBYTE xAspect, yAspect;
        WORD pageWidth, pageHeight;
};

/* ILBM_info is the structure read_iff returns, and is hopefully all
   you need to deal with out of the iff reader routines below */
struct ILBM_info
{
        struct BitMapHeader header;
        UBYTE cmap[MAXCOL*3];
        struct BitMap bitmap;
};

/* I sure wish C function "prototypes" were real and not just ANSI
 * extern struct ILBM_info *read_iff();
 * read_iff( char *filename, short just_colors, int ExtraSize,
 *      APTR ExtraInfo );
 * extern void free_planes();  free_planes( struct BitMap *bitmap);
 * extern int write_iff();
 * write_iff(char *name, unsigned char *colors, struct BitMap *bits,
 *      short xoff, short yoff, short width, short compressed);
 */

/* Anyone know where some useful minterms are defined? */
#define COPY_MINTERM            0x0C0L

/***

                A meditation for the guru from the Diamond Sutra -

                So shall you think of all this fleeting world:
                A star at dawn, a bubble in a stream;
                A flash of lightning in a summer cloud,
                A flickering lamp, a phantom, and a dream.

***/


/**********************************************************************
*
*                       jiff.c   Jim Kent's iff - ilbm  reader
*
* This is the (sortof) short (sortof) simple no-frills IFF reader
* to get something out of DPaint, Images, or the Animator.  It
* works well with the Aztec C compiler.  It should work with Lattice
* but you never know until you try it.  I haven't.
*
* I've included a simple main program.  This is just to make it
* stand alone.  Since amiga screen initializations are massive, all
* it does as is is read it into a BitMap, and then free up the BitMap.
* Should crash it if it's gonna crash though.
*
* The main interface to this is through the routine read_iff(filename).
* This returns a ILBM_info structure-pointer on success, and NULL on
* failure.  It cleans up after itself on failure.
*
* I hope you will find this useful and easy to use.  Please forgive
* my funky indentation style?  Well at least I'm consistent!
* (* Run through the C-Beautifier by Olaf Seibert !! *)
*
* To demonstrate what a nice guy I am even though I'm far from wild
* about the IFF standard I'm placing this in the public domain.  When
* you remove the DEBUG and PARANOID definitions the code is only
* 1536 bytes long.
*
*               -Jim Kent  April 22, 1986
************************************************************************/


/* This is an all too common state of software development.  Get rid
   of this define as soon as it runs. */
#undef DEBUG

/* This is the normal state of software development.  Seriously undefine
   this to make it shut up about errors and reduce code size half way
   through beta testing... */
#undef PARANOID

/* This is nice if you want to use a debugger on the STATIC data and
   routines in this file. Redefine only if you don't need a debugger. */
/* #undef STATIC */
/* #define STATIC */

STATIC struct ILBM_info *read_ilbm(), *read_body();

/* OK this code is almost re-entrant.  Pass this guy from above to
   make it really re-entrant.  (Why do you need a reentrant ILBM
   reader though??  Maybe for Dale ... )
   Well, look in the IFF specs for instance... [Olaf Seibert, KosmoSoft] */
STATIC struct ILBM_info root_info;  /* static so get initialized to zero */

void free_planes(bmap)
register struct BitMap *bmap;
{
        PLANEPTR plane;
        long length;
        short i;

        length = bmap->BytesPerRow * bmap->Rows;

        for (i=0; i<8; i++)
                if ( (plane = bmap->Planes[i]) != NULL)
                        rfree(plane, length);
}

#ifdef PARANOID
/* a little paranoid routine that say's where we got before EOF */
STATIC void iff_truncated(where)
int where;
{
        printf("ILBM truncated %d\n", where);
        free_planes(&root_info.bitmap);
}
#endif PARANOID


struct ILBM_info *read_iff(name, just_colors, ExtraSize, ExtraPointer)
char *name;
short just_colors;
int ExtraSize;
APTR ExtraPointer;
{
        struct ILBM_info *info = &root_info;
        FILE *file;
        struct form_chunk chunk;

        if ((file = fopen(name, "r") ) == 0) {
#ifdef PARANOID
                printf("couldn't Open %s to read\n", name);
#endif PARANOID
                return NULL;
        }

        if ( fread(&chunk, sizeof(struct form_chunk), 1, file) != 1) {
#ifdef PARANOID
                iff_truncated(0);
#endif PARANOID
                fclose(file);
                return NULL;
        }

        if (chunk.fc_type.b4_type != FORM) {
#ifdef PARANOID
                printf("not a FORM - %s\n", name);
#endif PARANOID
                fclose(file);
                return NULL;
        }

        if (chunk.fc_subtype.b4_type != ILBM) {
#ifdef PARANOID
                printf("FORM not an ILBM - %s\n", name);
#endif PARANOID
                fclose(file);
                return NULL;
        }

#ifdef DEBUG
        printf("FORM %ld ILBM\n", chunk.fc_length);
#endif DEBUG

        info = read_ilbm(file, info, chunk.fc_length - sizeof(chunk), just_colors);
#ifdef DEBUG
        printf("info = %lx\n", info);
#endif DEBUG

        fclose(file);

        return info;
}

STATIC struct ILBM_info *read_ilbm(file, info, length, just_colors)
FILE *file;
struct ILBM_info *info;
long length;
short just_colors;
{
        struct iff_chunk chunk;
        int i;
        long read_in = 0;
        int got_header = FALSE;  /* To make sure gots the header first */
        int got_cmap = FALSE;    /* Make sure get cmap before "BODY" */

/* Make sure the Planes are all NULL so can free up memory easily
   on error abort */
        for (i=0; i<8; i++)
                info->bitmap.Planes[i] = NULL;

        while (read_in < length) {
                if (fread(&chunk, sizeof(chunk), 1, file) != 1) {
#ifdef PARANOID
                        iff_truncated(1);
#endif PARANOID
                        return NULL;
                }
                switch (chunk.iff_type.b4_type) {
                case BMHD:
#ifdef DEBUG
                        printf("\tBMHD %ld\n", chunk.iff_length);
#endif DEBUG
                        if (fread(&info->header, sizeof(info->header), 1, file) != 1) {
#ifdef PARANOID
                                iff_truncated(2);
#endif PARANOID
                                return NULL;
                        }
                        got_header = TRUE;
                        break;
                case CMAP:
#ifdef DEBUG
                        printf("\tCMAP %ld\n", chunk.iff_length);
#endif DEBUG
                        if (!got_header) {
#ifdef PARANOID
                                printf("CMAP befor BMHD\n");
#endif PARANOID
                                return NULL;
                        }
                        if (chunk.iff_length <= 3*MAXCOL ) {
                                if (fread(info->cmap, (int)chunk.iff_length, 1, file) != 1) {
#ifdef PARANOID
                                        iff_truncated(3);
#endif PARANOID
                                        return NULL;
                                }
                        } else {
#ifdef PARANOID
                                printf("warning, more than %d colors in ILBM CMAP\n",
                                        MAXCOL);
#endif PARANOID
                                if (fread(info->cmap, (int) 3*MAXCOL, 1, file) != 1) {
#ifdef PARANOID
                                        iff_truncated(4);
#endif PARANOID
                                        return NULL;
                                }
                                bit_bucket(file, chunk.iff_length - 3*MAXCOL);
                        }
                        got_cmap = TRUE;
                        if (just_colors)
                                return info;
                        break;
                case BODY:
                        if (!got_cmap) {
#ifdef PARANOID
                                printf("BODY before CMAP\n");
#endif PARANOID
                                return NULL;
                        }
#ifdef DEBUG
                        printf("\tBODY %ld\n", chunk.iff_length);
#endif DEBUG
                        return read_body(file, info, chunk.iff_length);

                default:        /* Squawk about unknown types if PARANOID */
#ifdef PARANOID
                        printf("\t unknown type %lx of b4_type\n", chunk.iff_type.b4_type);
                case GRAB:  /* Ignore documented but unwanted types */
                case DEST:
                case SPRT:
                case CAMG:
                case CRNG:
                case CCRT:
#endif PARANOID
                        bit_bucket(file, chunk.iff_length);
                        break;
                }
                read_in += EVEN(chunk.iff_length) + sizeof(chunk);
        }
#ifdef PARANOID
        printf("no BODY in ILBM\n");
#endif PARANOID
        return NULL;
}



STATIC struct ILBM_info *read_body(file, info, length)
FILE *file;
register struct ILBM_info *info;
long length;
{
        struct ILBM_header *header;
        struct BitMap *bm;
        int i, j;
        int rlength;
        int plane_offset;

#ifdef DEBUG
        printf("read_body( %lx %lx %ld)\n", file, info, length);
#endif DEBUG

#ifdef PARANOID
/* When paranoid do a little error checking first ... fail fast! */
        if (info->header.nPlanes > 8) {
                printf("Whoa, woe  Dale only speaks 8 planes boy, not %d\n",
                info->header.nPlanes);
                return NULL;
        }
#endif PARANOID

/* Ok a little more error checking */
        if (info->header.compression != 0 && info->header.compression != 1) {
#ifdef PARANOID
                printf("unrecognized compression type %d\n", info->header.compression);
#endif PARANOID
                return NULL;
        }

/* Set up the bitmap part that doesn't involve memory allocation first -
   hey this part does get done, and let's be optimistic...*/
        info->bitmap.BytesPerRow = line_bytes(info->header.w);
        info->bitmap.Rows = info->header.h;
        info->bitmap.Depth = info->header.nPlanes;
        info->bitmap.Flags = info->bitmap.pad = 0;

        rlength = info->bitmap.Rows * info->bitmap.BytesPerRow;

        for (i=0; i<info->header.nPlanes; i++) {
                if ((info->bitmap.Planes[i] = ralloc(rlength)) == NULL) {
#ifdef PARANOID
                        printf("couldn't alloc plane %d in read_body\n",i);
#endif PARANOID
                        free_planes( &info->bitmap );
                        return NULL;
                }
        }

        plane_offset = 0;
        for (i=0; i<info->bitmap.Rows; i++) {
        /* This test should be in the inner loop for shortest code,                     */
        /* in the outer loop for greatest speed, so sue me I compromised        */
                if (info->header.compression == 0) {
                        for (j = 0; j < info->bitmap.Depth; j++) {
                                if ( fread(info->bitmap.Planes[j] + plane_offset,
                                        info->bitmap.BytesPerRow, 1, file) != 1) {
#ifdef PARANOID
                                        iff_truncated(6);
#endif PARANOID
                                        free_planes( &info->bitmap);
                                        return NULL;
                                }
                        }
                } else {
                        register char *dest, value;
                        register int so_far, count;  /* How much have unpacked so far */

                        for (j = 0; j < info->bitmap.Depth; j++) {
                                so_far = info->bitmap.BytesPerRow;
                                dest = (char *)info->bitmap.Planes[j] + plane_offset;
                                while (so_far > 0) {
                                        if ( (value = getc(file)) == 128) {
#ifdef DEBUG
                                                printf("NOP\n");
#endif DEBUG
                                        } else if (value > 0) {
                                                count = (int)value + 1;
                                                so_far -= count;
                                                if ( fread(dest, count, 1, file) != 1) {
#ifdef PARANOID
                                                        iff_truncated(7);
#endif PARANOID
                                                        free_planes( &info->bitmap);
                                                        return NULL;
                                                }
                                                dest += count;
                                        } else  {
                                                count = (int)-value + 1;
                                                so_far -= count;
                                                value = getc(file);
                                                while (--count >= 0)  /* This is fastest loop on the 68000 */
                                                        *dest++ = value;
                                        }
                                }
                                if (so_far != 0) {
#ifdef PARANOID
                                        printf("compression quite screwed up, aborting %d\n", so_far);
#endif PARANOID
                                        free_planes( &info->bitmap);
                                        return NULL;
                                }
                        }
                }
                plane_offset += info->bitmap.BytesPerRow;
        }
        if (length & 1) {
                /* Skip padding byte */
                getc(file);
        }

        return info;
}



#undef DEBUG
#undef PARANOID

/*----------------------------------------------------------------------*
 * jpacker.c Convert data to "cmpByteRun1" run compression.
 *
 * pack_row() is an adaptation of PackRow()
 * by Jerry Morrison and Steve Shaw, Electronic Arts,
 * modified and tweaked by Jim Kent, Dancing Flame 05/02/86
 *
 *      control bytes:
 *       [0..127]   : followed by n+1 bytes of data.
 *       [-1..-127] : followed by byte to be repeated(-n)+1 times.
 *       -128       : NOOP.
 *
 *
 * write_iff() is the only function you can access in this module.
 *----------------------------------------------------------------------*/

/*
        #include <exec/types.h>
        #include <graphics/gfx.h>
        #include <stdio.h>
        #include "jiff.h"
*/

#define DUMP    0
#define RUN     1

#define MINRUN 3
#define MAXRUN 128
#define MAXDAT 128

/* pack_row - pass source line pointer, length of line, and file.
   Returns # of bytes after compression.  Returns 0 on write error.
   Pass file = NULL to just find out length,
   otherwise will write compressed row to file. */
STATIC unsigned int pack_row(file, source, size)
FILE *file;
char *source;
int size;
{
        char    c,
        lastc = '\0';
        short mode = DUMP;
        short   nbuf = 0;               /* Number of chars in buffer */
        short   rstart = 0;             /* Buffer index current run starts */
        unsigned short putsize;
        char    buf[MAXDAT*3/2];                /* I think MAXDAT+1 would suffice */

        putsize = 0;
        buf[0] = lastc = *source++;/* So have valid lastc */
        nbuf = 1;
        size--;                 /* Since one byte eaten. */


        for (; size; --size) {
                buf[nbuf++] = c = *source++;
                switch (mode) {
                case DUMP:
                        /* If the buffer is full, write the length byte, then the data */
                        if (nbuf > MAXDAT) {
                                if (file != NULL) {
                                        if (putc(nbuf-2, file) == EOF)
                                                return 0;
                                        if (fwrite(buf, nbuf-1, 1, file) != 1)
                                                return 0;
                                }
                                putsize += nbuf;
                                buf[0] = c;
                                nbuf = 1;
                                rstart = 0;
                                break;
                        }

                        if (c == lastc) {
                                if (nbuf - rstart >= MINRUN) {
                                        if (rstart > 0) {
                                                if (file != NULL) {
                                                        if (putc(rstart-1, file) == EOF)
                                                                return 0;
                                                        if (fwrite(buf, rstart, 1, file) != 1)
                                                                return 0;
                                                }
                                                putsize += rstart+1;
                                        }
                                        mode = RUN;
                                }
                                else if (rstart == 0)
                                        mode = RUN;
                        /* No dump in progress, so can't lose by making these 2 a run. */
                        }
                        else
                                rstart = nbuf - 1;/* First of run */
                        break;

                case RUN:
                        if ((c != lastc) ||(nbuf - rstart > MAXRUN)) {
                                /* Output run */
                                if (file != NULL) {
                                        if (putc( -(nbuf - rstart - 2), file) == EOF)
                                                return 0;
                                        if (putc( lastc, file) == EOF)
                                                return 0;
                                }
                                putsize += 2;
                                buf[0] = c;
                                nbuf = 1;
                                rstart = 0;
                                mode = DUMP;
                        }
                        break;
                }

                lastc = c;
        }

        switch (mode) {
        case DUMP:
                if (file != NULL) {
                        if (putc(nbuf-1, file) == EOF)
                                return 0;
                        if (fwrite(buf, nbuf, 1, file) != 1)
                                return 0;
                }
                putsize += nbuf+1;
                break;
        case RUN:
                if (file != NULL) {
                        if (putc( -(nbuf - rstart - 1), file) == EOF)
                                return 0;
                        if (putc( lastc, file) == EOF)
                                return 0;
                }
                putsize += 2;
                break;
        }
        return putsize;
}


STATIC unsigned long pack_bitmap(file, bm)
FILE *file;
struct BitMap *bm;
{
        unsigned short i, j;
        unsigned row_length;
        unsigned long compressed_length;
        unsigned plane_offset;

#ifdef DEBUG
        printf("pack_bitmap( %lx %lx)\n", file, bm);
#endif DEBUG

#ifdef PARANOID
/* When paranoid do a little error checking first ... Fail fast! */
        if (bm->BytesPerRow <= 0 || bm->Rows <= 0 || bm->BytesPerRow > MAXDAT) {
                printf("bitmap %d bytes by %d rows?????\n", bm->BytesPerRow,
                bm->Rows);
                return 0;
        }
        if (bm->Depth <= 0 || bm->Depth > 8) {
                printf("bitmap with %d planes ??????\n", bm->Depth);
                return 0;
        }
#endif PARANOID

        compressed_length = 0;
        plane_offset = 0;
        for (i=0; i<bm->Rows; i++) {
                for (j = 0; j < bm->Depth; j++) {
                        if ( (row_length = pack_row(file, bm->Planes[j] + plane_offset,
                        bm->BytesPerRow)) == 0) {
#ifdef PARANOID
                                printf("error packing row %d plane %d\n", i, j);
#endif PARANOID
                                return 0;
                        }
                        compressed_length += row_length;
                }
                plane_offset += bm->BytesPerRow;
        }
        if ( compressed_length & 1) {  /* Check to see odd length */
                if (file != NULL) {
                        if ( putc( 0, file) == EOF) {
                                return 0;
                        }
                }
                /* compressed_length++; Deleted!!! Padding should NOT be included */
                /* in the chunk size !!! */
        }
        return compressed_length;
}

int write_iff(name, colors, bits, xoff, yoff, width, compressed, ExtraSize, ExtraInfo)
char *name;
unsigned char *colors;
register struct BitMap *bits;
short xoff, yoff;
short compressed;
int ExtraSize;
APTR ExtraInfo;
{
        FILE *file;
        struct form_chunk chunk;
        struct iff_chunk ichunk;
        struct BitMapHeader header;
        long bits_size;
        short i;
        register short j;
        register short row_offset;

        if ((file = fopen(name, "w") ) == 0) {
#ifdef PARANOID
                printf("couldn't Open %s to write\n", name);
#endif PARANOID
                goto abort;
        }

        /* Say its a FORM ILBM */
        chunk.fc_type.b4_type = FORM;
        chunk.fc_subtype.b4_type = ILBM;
        chunk.fc_length = 4 + 3*sizeof(struct iff_chunk) + MAXCOL*3 +
            sizeof(struct BitMapHeader);
        if (bits) {
                if (compressed) {
                        if ( (bits_size = pack_bitmap(NULL, bits)) == 0)
                                goto abort;
                } else {
                        bits_size =  bits->BytesPerRow*bits->Rows*bits->Depth;
                }
                chunk.fc_length += bits_size;
                if (bits_size & 1)      chunk.fc_length++;
        }
        if (fwrite(&chunk, sizeof(chunk), 1, file) != 1)
                goto abort;

/* Here comes a BitMapHeader */
        ichunk.iff_type.b4_type = BMHD;
        ichunk.iff_length = sizeof(header);
        if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1)
                goto abort;

/* Initialize the BitMapHeader to normal values */
        header.masking = 0;
        header.pad1 = 0;
        header.transparentColor = 0;
        if (compressed)
                header.compression = 1;
        else
                header.compression = 0;
        header.pageWidth = width;
        header.pageHeight = bits? bits->Rows: YMAX;
        header.xAspect = width > LOXMAX? XASPECT: XASPECT*2;
        header.yAspect = YASPECT;
/* If it's not just a color map give the dimensions of rasters */
        if (bits) {
                header.w = width;
                header.h = bits->Rows;
                header.nPlanes = bits->Depth;
                header.x = xoff;
                header.y = yoff;
        }
        if (fwrite(&header, sizeof(header), 1, file) != 1)
                goto abort;

/* Squirt out the color map */
        ichunk.iff_type.b4_type = CMAP;
        ichunk.iff_length = MAXCOL*3;
        if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1)
                goto abort;
        if (fwrite(colors, (int) 3*MAXCOL, 1, file) != 1)
                goto abort;

/* If they be bits then squirt out the bits */
        if (bits) {
                ichunk.iff_type.b4_type = BODY;
                ichunk.iff_length = bits_size;
                if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1)
                        goto abort;
                if (compressed) {
                        if (pack_bitmap(file, bits) == 0)
                                goto abort;
                } else {
                        i = bits->Rows;
                        row_offset = 0;
                        while (--i >= 0) {
                                for (j=0; j<bits->Depth; j++) {
                                        if (fwrite( bits->Planes[j]+row_offset,
                                                bits->BytesPerRow, 1, file) != 1)
                                                goto abort;
                                }
                                row_offset += bits->BytesPerRow;
                        }
                }
        }

        fclose(file);
        return 1;
abort:
        fclose(file);
        return 0;
}


/***********************************************************************
* put_ea_cmap given an ea-type color map:
* an array of unsigned chars of form ea_cmap[] = {r, g, b, r, g, b...}
* turn it into an amiga-type color map:
* an array of unsigned short of form amiga_cmap = {0xrgb, 0xrgb, ...}
* and then tell Dale this is the colors we want for our viewport
*/
void put_ea_cmap(ea_cmap, colors, Screen)
unsigned char *ea_cmap;
int colors;
struct Screen *Screen;
{
        unsigned short amy_cmap[MAXCOL];
        register int i;
        register short color;

        if (colors > MAXCOL)   /* Color clipping */
                colors = MAXCOL;
        for (i=0; i<colors; i++) {
                color  = (*ea_cmap++ & 0xF0) << 4;
                color |=  *ea_cmap++ & 0xF0;
                color |= (*ea_cmap++ & 0xF0) >> 4;
                amy_cmap[i] = color;
        }
        LoadRGB4( &Screen->ViewPort, amy_cmap, (long)colors);
}

void get_ea_cmap(ea_cmap, colors, Screen)
unsigned char *ea_cmap;
int colors;
struct Screen *Screen;
{
        register long i;
        register unsigned short rgb;

        if (colors > MAXCOL)   /* Color clipping */
                colors = MAXCOL;
        for (i=0; i<colors; i++) {
                rgb = GetRGB4(Screen->ViewPort.ColorMap, i);
                *ea_cmap++ = (rgb & 0xF00) >> 4;
                *ea_cmap++ = (rgb & 0x0F0);
                *ea_cmap++ = (rgb & 0x00F) << 4;
        }
}
