/*************************************************************************
  *                                                                      *
  *                            Preliminary                               *
  *                        Amiga AppShell (tm)                           *
  *                                                                      *
  *  Copyright (c) 1990,1991 Commodore-Amiga, Inc. All Rights Reserved.  *
  *                                                                      *
  *   This software and information is proprietary, preliminary, and     *
  *   subject to change without notice.                                  *
  *                                                                      *
  *                            DISCLAIMER                                *
  *                                                                      *
  *   THIS SOFTWARE IS PROVIDED "AS IS".                                 *
  *   NO REPRESENTATIONS OR WARRANTIES ARE MADE WITH RESPECT TO THE      *
  *   ACCURACY, RELIABILITY, PERFORMANCE, CURRENTNESS, OR OPERATION      *
  *   OF THIS SOFTWARE, AND ALL USE IS AT YOUR OWN RISK.                 *
  *   NEITHER COMMODORE NOR THE AUTHORS ASSUME ANY RESPONSIBILITY OR     *
  *   LIABILITY WHATSOEVER WITH RESPECT TO YOUR USE OF THIS SOFTWARE.    *
  *                                                                      *
  *                          Non-Disclosure                              *
  *                                                                      *
  *   This information is not to be disclosed to any other company,      *
  *   individual or party.  Discussion is to be restricted to CBM        *
  *   approved discussion areas, such as the closed conferences on bix;  *
  *   amiga.cert, amiga.com, amiga.beta/appshell.                        *
  *                                                                      *
  ************************************************************************
  * Copyright (C) 1990 Commodore-Amiga, Inc.
  * written by David N. Junod
  */

/* ilbm.c --- read an IFF ILBM file into a record.
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <iff/ilbm.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfx.h>
#include <graphics/displayinfo.h>
#include <graphics/view.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/iffparse.h>
#include <libraries/prefs.h>
#include <utility/tagitem.h>
#include <workbench/workbench.h>
#include <clib/macros.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/dos_protos.h>
#include <clib/utility_protos.h>
#include <clib/iffparse_protos.h>
#include <clib/icon_protos.h>
#include <pragmas/exec.h>
#include <pragmas/dos.h>
#include <pragmas/intuition.h>
#include <pragmas/graphics.h>
#include <pragmas/utility.h>
#include <pragmas/iffparse.h>
#include <pragmas/icon.h>
#include <string.h>

#define VANILLA_COPY	0xC0
#define NO_MASK		0xFF

extern struct Library *DOSBase, *SysBase, *IFFParseBase;
extern struct Library *GfxBase, *IntuitionBase, *IconBase;
extern struct DiskObject brush_icon;

/* ilbm.c */
ILBM *ReadILBM (BPTR drawer, STRPTR name, struct TagItem * attrs);
BOOL WriteILBM (BPTR drawer, STRPTR name, ILBM *ir, BOOL);
VOID FreeILBM (ILBM * ilbm);
ILBM *GetILBM (struct IFFHandle * iff);
BOOL GetBMHD (struct IFFHandle * iff, struct BitMapHeader * bmhd);
BOOL PutBMHD (struct IFFHandle * iff, struct BitMapHeader * bmhd, ILBM *ir);
BOOL PutILBM (struct IFFHandle * iff, ILBM * ilbm);
WORD GetColors (struct IFFHandle * iff, struct ColorRegister * cmap);
BOOL PutColors (struct IFFHandle * iff, struct BitMapHeader * bmhd, struct ColorRegister * cmap);
void GetHotSpot (struct IFFHandle * iff, struct Point2D * grab, WORD, WORD);
BOOL PutHotSpot (struct IFFHandle * iff, struct Point2D * grab);
BOOL GetBody (struct IFFHandle * iff, struct BitMapHeader * bmhd, struct BitMap * bm);
LONG loadbody(struct IFFHandle * iff, struct BitMap *bitmap, struct BitMapHeader *bmhd);
BOOL GetLine (struct IFFHandle * iff, UBYTE * buf, WORD wide, WORD deep, UBYTE cmptype);
BOOL PutBody (struct IFFHandle * iff, struct BitMapHeader * bmhd, struct BitMap * bitmap);
BOOL AllocBMRast (struct BitMap * bm, BYTE depth, WORD width, WORD height);

#define	BPR(w)		((w) + 15 >> 4 << 1)	/* Bytes per row */

/* Properties that we can deal with */
LONG ilbmprops[] =
{
    ID_ILBM, ID_BMHD,
    ID_ILBM, ID_CMAP,
    ID_ILBM, ID_GRAB,
    ID_ILBM, ID_CAMG
};

ILBM *ReadILBM (BPTR drawer, STRPTR name, struct TagItem * attrs)
{
    struct Process *proc = (struct Process *) FindTask (NULL);
    struct IFFHandle *iff;
    ILBM *ilbm = NULL;
    BPTR lock = NULL;

    /* Clear the error field */
    proc->pr_Result2 = NULL;

    /* Did they give a directory lock? */
    if (drawer)
    {
	/* Go to the required directory */
	lock = CurrentDir (drawer);
    }

    /* Allocate an IFF handle */
    if (iff = AllocIFF ())
    {
	/* Open the preference file */
	if (iff->iff_Stream = Open (name, MODE_OLDFILE))
	{
	    /* Indicate that the IFF handle is for a file */
	    InitIFFasDOS (iff);

	    if (ilbm = GetILBM (iff))
	    {
	    }

	    /* Close the file */
	    Close (iff->iff_Stream);
	}
	else
	{
	    /* Couldn't open file, Result2 already set by Open */
	}

	/* Free the IFF handle */
	FreeIFF (iff);
    }
    else
    {
	/* Not enough memory */
	proc->pr_Result2 = ERROR_NO_FREE_STORE;
    }

    if (lock)
    {
	CurrentDir (lock);
    }

    return (ilbm);
}

BOOL WriteILBM (BPTR drawer, STRPTR name, ILBM *ir, BOOL icon)
{
    struct Process *proc = (struct Process *) FindTask (NULL);
    struct IFFHandle *iff;
    BOOL retval = FALSE;
    BPTR lock = NULL;

    /* Clear the error field */
    proc->pr_Result2 = NULL;

    /* Did they give a directory lock? */
    if (drawer)
    {
	/* Go to the required directory */
	lock = CurrentDir (drawer);
    }

    /* Allocate an IFF handle */
    if (iff = AllocIFF ())
    {
	/* Open the preference file */
	if (iff->iff_Stream = Open (name, MODE_NEWFILE))
	{
	    /* Indicate that the IFF handle is for a file */
	    InitIFFasDOS (iff);

	    /* Open the IFF handle for writing */
	    if (OpenIFF (iff, IFFF_WRITE) == 0L)
	    {
		/* Place it in the clipboard */
		if (PutILBM (iff, ir))
		{
		    /* wrote ilbm to file */
		    retval = TRUE;
		}
		else
		{
		    /* Couldn't write ilbm */
		}

		/* Close the IFF handle */
		CloseIFF (iff);
	    }
	    else
	    {
		/* Couldn't open IFF for writing */
	    }

	    /* Close the file */
	    Close (iff->iff_Stream);

	    /* Able to write ILBM? */
	    if (retval)
	    {
		/* Clear the execute file attribute */
		SetProtection (name, FIBF_EXECUTE);

		/* Do they want icons? */
		if (icon && IconBase)
		{
		    /* Write an icon for the brush */
		    PutDiskObject (name, &brush_icon);
		}
	    }
	    else
	    {
		/* Delete the partial file */
		DeleteFile (name);
	    }
	}
	else
	{
	    /* Couldn't open file, Result2 already set by Open */
	}

	/* Free the IFF handle */
	FreeIFF (iff);
    }
    else
    {
	/* Not enough memory */
	proc->pr_Result2 = ERROR_NO_FREE_STORE;
    }

    if (lock)
    {
	CurrentDir (lock);
    }

    return (retval);
}

ILBM *GetILBM (struct IFFHandle * iff)
{
    ILBM *ilbm = NULL;
    LONG msize = sizeof (ILBM);

    /* Open the IFF handle for reading */
    if (!(OpenIFF (iff, IFFF_READ)))
    {
	/* Register collection chunks */
	PropChunks (iff, ilbmprops, 4);

	/* Register where we want to stop */
	StopChunk (iff, ID_ILBM, ID_BODY);

	/* Parse the file, stopping at the body */
	if (ParseIFF (iff, IFFPARSE_SCAN) == 0L)
	{
	    /* Allocate an ILBM record */
	    if (ilbm = (ILBM *) AllocVec (msize, MEMF_CLEAR))
	    {
		struct BitMapHeader bmhd;

		/* See if we collected a bitmap header */
		if (GetBMHD (iff, &bmhd))
		{
		    struct BitMap *bm = &(ilbm->ir_BMap);

		    /* Get the size information */
		    ilbm->ir_Width = bmhd.w;
		    ilbm->ir_Height = bmhd.h;
		    ilbm->ir_Depth = bmhd.nplanes;

		    /* Allocate a bitmap w/rasters to hold the image */
		    if (AllocBMRast (bm, ilbm->ir_Depth, ilbm->ir_Width, ilbm->ir_Height))
		    {
			struct ColorRegister pp_Colors[MAXCOLORS];
			struct StoredProperty *sp;
			ULONG mode = NULL;

			/* Initialize the rastport */
			InitRastPort (&(ilbm->ir_RPort));
			ilbm->ir_RPort.BitMap = bm;
			SetRast (&(ilbm->ir_RPort), 0);

			/* See if we have a CAMG chunk */
			if (sp = FindProp (iff, ID_ILBM, ID_CAMG))
			{
			    /* Get the mode ID */
			    mode  = *((ULONG *) sp->sp_Data);
			}

			/* See if we have a valid ModeID */
			if (((mode & (0xffff0000)) && (!(mode & 0x00001000))) ||
			    (mode == NULL))
			{
			    /* We have to fabricate a correct ModeID */
			    mode = LORES_KEY;
			    if (ilbm->ir_Width >= 640)
				mode = HIRES;
			    if (ilbm->ir_Height >= 400)
				mode |= LACE;
			    if (ilbm->ir_Depth == 6)
				mode |= HAM;
			}

			/* Remember the ModeID */
			ilbm->ir_ModeID = mode;

			/* Get the color map */
			if (ilbm->ir_NumColors = GetColors (iff, &(pp_Colors[0])))
			{
			    WORD i, r, g, b;

			    for (i = 0; i < ilbm->ir_NumColors; i++)
			    {
				r = (pp_Colors[i].red >> 4);
				g = (pp_Colors[i].green >> 4);
				b = (pp_Colors[i].blue >> 4);

				ilbm->ir_CRegs[i] = (r << 8) | (g << 4) | (b);
			    }
			}
			else
			{
			    /* Couldn't get colors */
			}

			/* Get the hot spot */
			GetHotSpot (iff, &(ilbm->ir_Grab), ilbm->ir_Width, ilbm->ir_Height);

			/* Get the image data itself */
			if (GetBody (iff, &bmhd, bm))
			{
			    /* Close the IFF handle!!! */
			    CloseIFF (iff);

			    return (ilbm);

			}	/* End of get body */
			else
			{
			    /* couldn't get body */
			}
		    }		/* End of allocate BM */
		    else
		    {
			/* couldn't allocate bitmap */
		    }
		}		/* End of get bitmap header */
		else
		{
		    /* no bitmap header */
		}

		/* Free the ilbm buffer */
		FreeILBM (ilbm);
	    }
	    else
	    {
		/* not enough memory */
	    }
	}
	else
	{
	    /* scan error */
	}

	/* Close the IFF handle */
	CloseIFF (iff);
    }
    else
    {
	/* couldn't open stream */
    }

    return (NULL);
}

BOOL PutILBM (struct IFFHandle * iff, ILBM * ilbm)
{
    BOOL status = FALSE;
    LONG retval;

    if (iff && ilbm)
    {
	/* Open the IFF handle for reading */
	if (!(OpenIFF (iff, IFFF_WRITE)))
	{
	    /* Start writing the text ... */
	    if ((retval = PushChunk (iff, ID_ILBM, ID_FORM, -1L)) == 0)
	    {
		struct BitMapHeader *bmhd;
		LONG msize = sizeof (struct BitMapHeader);

		if (bmhd = AllocMem (msize, MEMF_CLEAR))
		{
		    if (PutBMHD (iff, bmhd, ilbm))
		    {
			/* Do they have a color table to output */
			if (ilbm->ir_NumColors > 0L)
			{
			    struct ColorRegister pp_Colors[MAXCOLORS];
			    WORD i, r, g, b;

			    for (i = 0; i < (ilbm->ir_NumColors); i++)
			    {
				r = (ilbm->ir_CRegs[i] & 0xF00) >> 4;
				g = (ilbm->ir_CRegs[i] & 0xF0);
				b = (ilbm->ir_CRegs[i] << 4);

				pp_Colors[i].red = r;
				pp_Colors[i].green = g;
				pp_Colors[i].blue = b;
			    }

			    /* Write the colors */
			    PutColors (iff, bmhd, pp_Colors);
			}

			if (PutBody (iff, bmhd, &(ilbm->ir_BMap)))
			{
			    status = TRUE;
			}
		    }

		    FreeMem (bmhd, msize);
		}
		else
		{
		    /* couldn't allocate room for bitmap header */
		}

		/* Finish out the entire write */
		PopChunk (iff);
	    }
	    else
	    {
		/* Couldn't start clip */
	    }

	    /* Close the IFF handle */
	    CloseIFF (iff);
	}
	else
	{
	    /* couldn't open for writing */
	}
    }

    return (status);
}

BOOL GetBMHD (struct IFFHandle *iff, struct BitMapHeader *bmhd)
{
    struct StoredProperty *sp;

    if (sp = FindProp (iff, ID_ILBM, ID_BMHD))
    {
	*bmhd = *((struct BitMapHeader *) sp->sp_Data);
	return (TRUE);
    }

    return (FALSE);
}

BOOL PutBMHD (struct IFFHandle *iff, struct BitMapHeader *bmhd, ILBM *ir)
{
    struct BitMap *bm = &(ir->ir_BMap);

    bmhd->w = bm->BytesPerRow * 8;
    bmhd->h = bm->Rows;
    bmhd->x = 0;
    bmhd->y = 0;
    bmhd->nplanes = bm->Depth;
    bmhd->Masking = mskHasTransparentColor;
    bmhd->Compression = cmpNone;

/*     bmhd->Compression = cmpByteRun1; */

    bmhd->pad1 = 0;
    bmhd->TransparentColor = 0;
    bmhd->XAspect = 10;
    bmhd->YAspect = 11;
    bmhd->PageWidth = ir->ir_Width;
    bmhd->PageHeight = ir->ir_Height;

    if ((PushChunk (iff, 0, ID_BMHD, sizeof (struct BitMapHeader))) == 0L)
    {
	if ((WriteChunkBytes (iff, bmhd, sizeof (struct BitMapHeader))) ==
	    sizeof (struct BitMapHeader))
	{
	    if ((PopChunk (iff)) == 0L)
	    {
		return (TRUE);
	    }
	}
    }

    return (FALSE);
}

WORD
GetColors (struct IFFHandle * iff, struct ColorRegister * cmap)
{
    struct ColorRegister *rgb;
    struct StoredProperty *sp;
    WORD i, ncolors = 0;

    if (sp = FindProp (iff, ID_ILBM, ID_CMAP))
    {
	/* Compute the actual number of colors we need to convert. */
	i = ncolors = MIN (MAXCOLORS, (sp->sp_Size / 3L));

	rgb = (struct ColorRegister *) sp->sp_Data;
	while (i--)
	{
	    *cmap = *rgb;
	    cmap++;
	    rgb++;
	}
    }

    return (ncolors);
}

BOOL
PutColors (struct IFFHandle *iff, struct BitMapHeader *bmhd, struct ColorRegister *cmap)
{

    if (cmap == NULL)
	return (FALSE);

    if ((PushChunk (iff, 0, ID_CMAP, IFFSIZE_UNKNOWN)) == 0L)
    {
	if ((WriteChunkRecords (iff, cmap, sizeof (struct ColorRegister),
				(1 << bmhd->nplanes))) == (1 << bmhd->nplanes))
	{
	    if ((PopChunk (iff)) == 0L)
	    {
		return (TRUE);
	    }
	}
    }

    return (FALSE);
}

VOID
GetHotSpot (struct IFFHandle *iff, struct Point2D *grab, WORD width, WORD height)
{
    struct StoredProperty *sp;

    if (sp = FindProp (iff, ID_ILBM, ID_GRAB))
    {
	*grab = *((struct Point2D *) sp->sp_Data);
    }
    else
    {
	grab->x = 0;
	grab->y = 0;
    }

    if ((grab->x >= width) || (grab->y >= height))
    {
	grab->x = 0;
	grab->y = 0;
    }
}

BOOL PutHotSpot (struct IFFHandle *iff, struct Point2D *grab)
{
    if (grab)
    {
	if ((PushChunk (iff, 0, ID_GRAB, sizeof (struct Point2D))) == 0L)
	{
	    if ((WriteChunkBytes (iff, grab, sizeof (struct Point2D))) ==
		sizeof (struct Point2D))
	    {
		if ((PopChunk (iff)) == 0L)
		{
		    return (TRUE);
		}
	    }
	}
    }

    return (FALSE);
}

BOOL
GetBody (struct IFFHandle *iff, struct BitMapHeader *bmhd, struct BitMap *bm)
{
    BOOL status = FALSE;
    WORD i, n, p;
    UWORD *srcline, *destline;
    struct BitMap mapcopy, *destmap;
    UBYTE *linebuf, *csrcline;
    WORD srcw, destw;		/* src and dest width in BYTES */
    WORD srch, desth;		/* src and dest height (rows) */
    WORD srcd, destd;		/* src and dest depth */
    WORD deep, rows, mod;
    LONG msize;

    /* Check compression type. */
    if ((bmhd->Compression != cmpNone) && (bmhd->Compression != cmpByteRun1))
    {
	return (status);
    }

    /* Copy the bitmap pointer */
    destmap = bm;

    /* Copy the bitmap */
    mapcopy = *destmap;

    /* Set up our size variables */
    srcw = BPR (bmhd->w);
    srch = bmhd->h;
    srcd = bmhd->nplanes;
    destw = mapcopy.BytesPerRow;
    desth = mapcopy.Rows;
    destd = mapcopy.Depth;
    rows = MIN (srch, desth);

    mod = destw - srcw;
    if (mod < 0)
	mod = -mod;

    if (bmhd->Masking == mskHasMask)
	srcd++;

    deep = MIN (srcd, destd);

    /*
     * Allocate a one-line buffer to load imagery in.  The line is then copied
     * into the destination bitmap.  This seeming duplicity makes clipping
     * loaded images easier.
     */

    msize = (LONG) (srcw * srcd);
    if (linebuf = (UBYTE *) AllocVec (msize, MEMF_CLEAR))
    {

	/*
	 * Load the BODY into the allocated line buffer, then copy into the
	 * destination bitmap.
	 */
	for (i = rows; i--;)
	{
	    if (!(status = GetLine (iff, linebuf, srcw, srcd, bmhd->Compression)))
		break;

	    srcline = (UWORD *) linebuf;
	    for (p = 0; p < deep; p++)
	    {
		destline = (UWORD *) mapcopy.Planes[p];
		*destline = 0xffff;
		n = (MIN (srcw, destw)) >> 1;	/* convert #bytes to #words */

		while (n--)
		    *destline++ = *srcline++;

		if (srcw > destw)
		{
		    csrcline = (UBYTE *) srcline;
		    csrcline += mod;
		    srcline = (UWORD *) csrcline;
		}
		mapcopy.Planes[p] += destw;
	    }
	}

	/* Free the temporary line buffer */
	FreeVec ((APTR) linebuf);

	/* Say that it worked */
	status = TRUE;
    }

    return (status);
}

BOOL GetLine (iff, buf, wide, deep, cmptype)
    struct IFFHandle *iff;
    UBYTE *buf;
    WORD wide, deep;
    UBYTE cmptype;
{

    if (cmptype == cmpNone)
    {				/* No compression */
	LONG big = wide * deep;

	if (ReadChunkBytes (iff, buf, big) != big)
	    return (FALSE);
    }
    else
    {
	WORD i, so_far;
	UBYTE *dest = buf;
	BYTE len;

	for (i = deep; i--;)
	{
	    so_far = wide;
	    while (so_far > 0)
	    {
		if (ReadChunkBytes (iff, &len, 1L) != 1)
		    return (FALSE);

		if (len >= 0)
		{		/* Literal byte copy  */
		    if ((so_far -= ++len) < 0)
			break;
		    if (ReadChunkBytes (iff, dest, (LONG) len) != len)
			return (FALSE);
		    dest += len;
		}
		else if ((UBYTE) len == 128)
		     /* NOP  */ ;

		else if (len < 0)
		{		/* Replication count  */
		    UBYTE byte;

		    len = -len + 1;
		    if ((so_far -= len) < 0)
			break;
		    if (ReadChunkBytes (iff, &byte, 1L) != 1)
			return (FALSE);
		    while (--len >= 0)
			*dest++ = byte;
		}
	    }
	    if (so_far)
	    {
		return (FALSE);
	    }
	}
	buf += wide;
    }
    return (TRUE);
}

BOOL PutBody (iff, bmhd, bitmap)
    struct IFFHandle *iff;
    struct BitMapHeader *bmhd;
    struct BitMap *bitmap;
{
    UWORD i;
    UBYTE p, *pptr;

    if ((PushChunk (iff, 0, ID_BODY, IFFSIZE_UNKNOWN)) == 0L)
    {
	for (i = 0; i < bmhd->h; i++)
	{
	    for (p = 0; p < bmhd->nplanes; p++)
	    {
		pptr = (UBYTE *) bitmap->Planes[p];

		WriteChunkBytes (iff, &pptr[i * bitmap->BytesPerRow],
				 2 * ((bmhd->w + 15) / 16));
	    }
	}

	if ((PopChunk (iff)) == 0L)
	{
	    return (TRUE);
	}
    }

    return (FALSE);
}

BOOL AllocBMRast (struct BitMap *bm, BYTE depth, WORD width, WORD height)
{
    WORD i;

    /* Initialize the BitMap */
    InitBitMap (bm, depth, width, height);

    /* Allocate the rasters */
    for (i = 0; i < depth; i++)
    {
	if (!(bm->Planes[i] = (PLANEPTR) AllocRaster (width, height)))
	{
	    return (FALSE);
	}
    }

    return (TRUE);
}

VOID FreeILBM (ILBM * ilbm)
{

    if (ilbm)
    {
	struct BitMap *bm = &(ilbm->ir_BMap);
	WORD i;

	/* Free each plane of the bitmap */
	for (i = 0; i < ilbm->ir_Depth; i++)
	{
	    if (bm->Planes[i])
	    {
		/* Free the raster */
		FreeRaster (bm->Planes[i], ilbm->ir_Width, ilbm->ir_Height);
		bm->Planes[i] = NULL;
	    }
	}

	/* Free the ILBM record */
	FreeVec ((APTR) ilbm);
    }
}

UWORD chip brushI1Data[] =
{
/* Plane 0 */
    0x0000,0x0000,0x0000,0x0400,0x0000,0x0000,0x0000,0x0C00,
    0x0000,0x0000,0x0000,0x0C00,0x0067,0xE7F0,0x0000,0x0C00,
    0x0066,0x0600,0x0000,0x0C00,0x0067,0xC7C0,0x0060,0x0C00,
    0x0066,0x0600,0x0180,0x0C00,0x0066,0x0600,0x0600,0x0C00,
    0x0066,0x0600,0x1800,0x0C00,0x0000,0x0000,0x6000,0x0C00,
    0x0000,0x0003,0x8000,0x0C00,0x0000,0x000E,0x0000,0x0C00,
    0x0000,0x0038,0x0000,0x0C00,0x0000,0x00E0,0x0000,0x0C00,
    0x0000,0x0380,0x0000,0x0C00,0x0000,0x0E00,0x0000,0x0C00,
    0x0000,0x7800,0xAA00,0x0C00,0x0003,0xE0AA,0x8000,0x0C00,
    0x00FE,0xAAA0,0x0000,0x0C00,0x0000,0x0000,0x0000,0x0C00,
    0x0000,0x0000,0x0000,0x0C00,0x7FFF,0xFFFF,0xFFFF,0xFC00,
/* Plane 1 */
    0xFFFF,0xFFFF,0xFFFF,0xF800,0xD555,0x5555,0x5555,0x5000,
    0xD555,0x5555,0x5555,0x5000,0xD510,0x1005,0x5555,0x5000,
    0xD511,0x5155,0x5555,0x5000,0xD510,0x1015,0x5515,0x5000,
    0xD511,0x5155,0x5455,0x5000,0xD511,0x5155,0x5155,0x5000,
    0xD511,0x5155,0x4555,0x5000,0xD555,0x5555,0x1555,0x5000,
    0xD555,0x5554,0x5555,0x5000,0xD555,0x5551,0x5555,0x5000,
    0xD555,0x5545,0x5555,0x5000,0xD555,0x5515,0x5555,0x5000,
    0xD555,0x5455,0x5555,0x5000,0xD555,0x5155,0x5555,0x5000,
    0xD555,0x7D55,0xFF55,0x5000,0xD557,0xF5FF,0xD555,0x5000,
    0xD5FF,0xFFF5,0x5555,0x5000,0xD555,0x5555,0x5555,0x5000,
    0xD555,0x5555,0x5555,0x5000,0x8000,0x0000,0x0000,0x0000,
};

struct Image brushI1 =
{
    0, 0,			/* Upper left corner */
    54, 22, 2,			/* Width, Height, Depth */
    brushI1Data,		/* Image data */
    0x0003, 0x0000,		/* PlanePick, PlaneOnOff */
    NULL			/* Next image */
};

struct DiskObject brush_icon =
{
    WB_DISKMAGIC,		/* Magic Number */
    WB_DISKVERSION,		/* Version */
    {				/* Embedded Gadget Structure */
	NULL,			/* Next Gadget Pointer */
	0, 0, 54, 23,		/* Left,Top,Width,Height */
	GADGIMAGE | GADGHCOMP,	/* Flags */
	RELVERIFY,		/* Activation Flags */
	BOOLGADGET,		/* Gadget Type */
	(APTR)&brushI1,		/* Render Image */
	NULL,			/* Select Image */
	NULL,			/* Gadget Text */
	NULL,			/* Mutual Exclude */
	NULL,			/* Special Info */
	0,			/* Gadget ID */
	NULL,			/* User Data */
    },
    WBPROJECT,			/* Icon Type */
    (char *)"SYS:Utilities/Display",/* Default Tool */
    NULL,			/* Tool Type Array */
    NO_ICON_POSITION,		/* Current X */
    NO_ICON_POSITION,		/* Current Y */
    NULL,			/* Drawer Structure */
    NULL,			/* Tool Window */
    0				/* Stack Size */
};
