#define	DEMO	1

#if DEMO
/* main.c
 * example of transparent images
 * Written by David N. Junod
 *
 * Compiled with SAS/C version 5.10.
 * LC -L -cfist -ms -v -y main
 *
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <workbench/workbench.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/icon_protos.h>
#include <string.h>
#include <stdio.h>

/* main.c */
int main (int argc, char **argv);
BOOL OpenLibraries (VOID);
VOID CloseLibraries (VOID);

/* transparent images prototypes */
VOID DrawTransImage (struct RastPort * rp, struct Image * im, WORD x, WORD y);

struct Library *IntuitionBase, *GfxBase, *IconBase;

/* NewWindow Structures */
struct NewWindow NewWindow1 =
{
    0, 1, 640, 199, -1, -1,
    CLOSEWINDOW | MOUSEBUTTONS,
    WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE
    | SIZEBRIGHT | ACTIVATE | NOCAREREFRESH | RMBTRAP,
    NULL, NULL,
    "Click Left MB for Transparent, Right MB for Normal",
    NULL, NULL, 150, 50, 65535, 65535, WBENCHSCREEN,
};

main (int argc, char **argv)
{

    if (OpenLibraries ())
    {
	STRPTR name = "SYS:Prefs";
	struct DiskObject *dob;

	/* Get a name if one was passed */
	if (argc >= 2)
	    name = argv[1];

	/* Get an image to work with */
	if (dob = GetDiskObject (name))
	{
	    struct Image *image;
	    struct Window *win;

	    image = (struct Image *) dob->do_Gadget.GadgetRender;

	    /* Open the window */
	    if (win = OpenWindow (&NewWindow1))
	    {
		struct RastPort *rp = win->RPort;
		BOOL going = TRUE;

		while (going)
		{
		    struct IntuiMessage *msg;

		    /* Wait for something to happen */
		    Wait (1L << win->UserPort->mp_SigBit);

		    /* Process all outstanding messages */
		    while (msg = (struct IntuiMessage *) GetMsg (win->UserPort))
		    {
			switch (msg->Class)
			{
			    case CLOSEWINDOW:
				going = FALSE;
				break;

			    case MOUSEBUTTONS:
				if (msg->Code == SELECTDOWN)
				{
				    DrawTransImage (rp, image,
						    msg->MouseX, msg->MouseY);
				}
				/* This is not a recommended thing. Just done
				 * to illustrate a point (rectangular draw).
				 */
				else if (msg->Code == MENUDOWN)
				{
				    DrawImage (rp, image,
						    msg->MouseX, msg->MouseY);
				}
				break;

			    default:
				break;
			}

			/* Reply to the message now that we're done with it */
			ReplyMsg ((struct Message *) msg);
		    }
		}

		/* Done with the window, close it */
		CloseWindow (win);
	    }

	    /* Done with the icon, close it */
	    FreeDiskObject (dob);
	}
	else
	{
	    printf ("Couldn't open %s\n", name);
	}

	CloseLibraries ();
    }
}

BOOL
OpenLibraries (VOID)
{

    if (IntuitionBase = OpenLibrary ("intuition.library", 31))
    {
	if (GfxBase = OpenLibrary ("graphics.library", 31))
	{
	    if (IconBase = OpenLibrary ("icon.library", 31))
	    {
		return (TRUE);
	    }
	    CloseLibrary (GfxBase);
	}
	CloseLibrary (IntuitionBase);
    }
    return (FALSE);
}

VOID
CloseLibraries (VOID)
{

    if (IconBase)
	CloseLibrary (IconBase);
    if (IntuitionBase)
	CloseLibrary (IntuitionBase);
    if (GfxBase)
	CloseLibrary (GfxBase);
}

#endif
/*------------------------------------------------------------------------*/
/* transparent.c
 * functions to implement transparent brushes and images
 * Written by David N. Junod
 *
 */
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/sprite.h>
#include <graphics/gels.h>
#include <graphics/clip.h>

/* Structure for transparent images */
struct TransImage
{
    struct Image *ti_IM;	/* The plain image */
    struct BitMap *ti_sBM;	/* Shadow bitmap */
    struct RastPort *ti_sRP;	/* Shadow rastport */
    struct BitMap ti_BM;	/* Image bitmap */
    struct RastPort ti_RP;	/* Image rastport */
};

struct TransImage *AllocTransImage (struct Image * im);
VOID FreeTransImage (struct TransImage * ti);
VOID drawtransimage (struct RastPort * rp, struct TransImage * ti, WORD x, WORD y);
VOID DrawTransImage (struct RastPort * rp, struct Image * im, WORD x, WORD y);

VOID FreeShadowBM (struct BitMap *);
VOID FreeShadowRP (struct RastPort *);
struct BitMap *AllocShadowBM (UWORD, UWORD, UWORD);
struct RastPort *AllocShadowRP (struct BitMap *);
VOID ClipBlitTrans (struct RastPort *, WORD, WORD, struct RastPort *, WORD, WORD, WORD, WORD, struct RastPort *, BOOL);

struct TransImage *
AllocTransImage (struct Image * im)
{
    if (im)
    {
	LONG msize = sizeof (struct TransImage);
	struct TransImage *ti;

	if (ti = (struct TransImage *) AllocMem (msize, MEMF_CLEAR))
	{
	    LONG image_data = (LONG) im->ImageData;
	    UWORD depth = im->Depth;
	    UWORD width = im->Width;
	    UWORD height = im->Height;
	    WORD planes = RASSIZE (width, height);
	    WORD i;

	    /* Remember the image */
	    ti->ti_IM = im;

	    /* Initialize the Image bitmap */
	    InitBitMap (&ti->ti_BM, depth, width, height);

	    /* Map the image data to planes */
	    for (i = 0L; i < depth; ++i)
		ti->ti_BM.Planes[i] = (PLANEPTR) (image_data + i * planes);

	    /* Initialize the Image rastport */
	    InitRastPort (&ti->ti_RP);
	    ti->ti_RP.BitMap = &ti->ti_BM;

	    if (ti->ti_sBM = AllocShadowBM (depth, width, height))
	    {
		if (ti->ti_sRP = AllocShadowRP (ti->ti_sBM))
		{
		    return (ti);
		}
		FreeShadowBM (ti->ti_sBM);
	    }
	    FreeMem ((APTR) ti, msize);
	}
    }

    return (NULL);
}

VOID
FreeTransImage (struct TransImage * ti)
{

    if (ti)
    {
	LONG msize = sizeof (struct TransImage);

	/* Free the shadow RastPort */
	FreeShadowRP (ti->ti_sRP);

	/* Free the shadow BitMap */
	FreeShadowBM (ti->ti_sBM);

	/* Free the temporary buffer */
	FreeMem ((APTR) ti, msize);
    }
}

VOID
drawtransimage (struct RastPort * rp, struct TransImage * ti, WORD x, WORD y)
{

    ClipBlitTrans (
		      &(ti->ti_RP),	/* Source RastPort */
		      0, 0,		/* Source LeftEdge, TopEdge */
		      rp,		/* Destination RastPort */
		      x, y,		/* Destination LeftEdge, TopEdge */
		      ti->ti_IM->Width,	/* Width of Image */
		      ti->ti_IM->Height,/* Height of Image */
		      ti->ti_sRP,	/* Shadow RastPort */
		      TRUE);		/* Make a new shadow */
}

/* If your going to be doing a lot with the image, then allocate it in
 * your own app, use the lowercase drawtransimage() as many times as you
 * want, and then free it.
 */
VOID
DrawTransImage (struct RastPort * rp, struct Image * im, WORD x, WORD y)
{
    struct TransImage *ti;

    if (ti = AllocTransImage (im))
    {
	drawtransimage (rp, ti, x, y);

	FreeTransImage (ti);
    }
}

VOID
FreeShadowBM (struct BitMap *sbm)
{

    if (sbm)
    {
	LONG msize;

	msize = RASSIZE (8 * (sbm->BytesPerRow), sbm->Rows);

	if (sbm->Planes[0])
	{
	    FreeMem ((APTR)sbm->Planes[0], msize);
	}

	FreeMem ((APTR)sbm, sizeof (struct BitMap));
    }
}

VOID
FreeShadowRP (struct RastPort *srp)
{

    if (srp)
    {
	FreeMem (srp, sizeof (struct RastPort));
    }
}

struct BitMap *
AllocShadowBM (UWORD depth, UWORD width, UWORD height)
{
    LONG msize = sizeof (struct BitMap);
    struct BitMap *bm;
    WORD i;

    /* Allocate a bitmap */
    if (bm = (struct BitMap *) AllocMem (msize, MEMF_CHIP))
    {
	LONG rsize = RASSIZE (width, height);

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

	/* Allocate one plane */
	if (bm->Planes[0] = (PLANEPTR) AllocMem (rsize, MEMF_CHIP | MEMF_CLEAR))
	{
	    /* All planes point to the first plane */
	    for (i = 1; i < depth; i++)
		bm->Planes[i] = bm->Planes[0];

	    return (bm);
	}

	FreeMem ((APTR) bm, msize);
    }

    return (NULL);
}

struct RastPort *
AllocShadowRP (struct BitMap *bm)
{
    LONG msize = sizeof (struct RastPort);
    struct RastPort *rp;

    /* Allocate a RastPort */
    if (rp = (struct RastPort *) AllocMem (msize, MEMF_CHIP))
    {
	/* Initialize the new RastPort */
	InitRastPort (rp);

	/* Point the RastPort's BitMap... */
	rp->BitMap = bm;
    }

    return (rp);
}

VOID
ClipBlitTrans (
    struct RastPort *rp,	/* source RastPort */
    WORD sx, WORD sy,		/* source top-left edge */
    struct RastPort *drp,	/* destination RastPort */
    WORD dx, WORD dy,		/* destination top-left edge */
    WORD width, WORD height,	/* width & height of image to blit */
    struct RastPort *Srp,	/* shadow RastPort */
    BOOL makeShadow)		/* create new shadow? */
{

    if (makeShadow)
    {
	ClipBlit (rp, sx, sy, Srp, 0, 0, width, height, 0xe0);
    }

    ClipBlit (Srp, 0, 0, drp, dx, dy, width, height, 0x20);
    ClipBlit (rp, sx, sy, drp, dx, dy, width, height, 0xe0);
}
