
/* fundamental custom window opening program */
/* based upon the program in "INSIDE Amiga Graphics" */

#include <exec/types.h>  		/* All the standard garbage */
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <functions.h>

struct IntuitionBase *IntuitionBase;	/* And our wonderful libraries */
struct GfxBase *GfxBase;
struct IntuiMessage *message;

struct Screen *Scr;			/* Our very own custom Screen 	*/
struct Window *Wdw;			/*  and Window 			*/
struct ViewPort *WVP;			/*  and ViewPort structures	*/

ULONG MessageClass;			/* If we want messages from Intuition*/
USHORT code;				/*  these will be handy		*/	

#define Rp   Wdw->RPort			/* And this will save some typing */

long multi, divis;	/* These will specify our pixel coverage ratios  */
int polycolor = 15;	/* This will specify our polygon Pen color 	 */

PLANEPTR workspace;	/* We'll need a workspace and TmpRas for filling */
struct TmpRas myTmpRas;	/*  the Amiga's standard circles */

static USHORT colormap [16] =
{
   0x000,0x110,0x220,0x330,0x440,0x550,0x660,0x770,0x880,
   0x990,0xAA0,0xBB0,0xCC0,0xDD0,0xEE0,0xFF0   
};	/* This is our range of colors from black to full yellow */

struct TextAttr StdFont =	/* Font structure */
   {
	"topaz.font",
	TOPAZ_EIGHTY,
	FS_NORMAL,
	FPF_ROMFONT,
   };


struct NewScreen NewScr =	/* for our custom screen - 4 bit planes */
   {
	0,0,		/* Left Edge, Top Edge */
	320,200,
	4,
	1,0,
	NULL,
	CUSTOMSCREEN,
	&StdFont,
	"Test Screen",
	NULL,
	NULL
   };

struct NewWindow NewWdw =	/* full screen window for drawing in */
   {
	0,0,		/* Left Edge, Top Edge */
	320,200,	/* Width, Height */
	0,5,     	/* Block Pen, Detail Pen */
	CLOSEWINDOW ,	/* IDCMP Flags */
	SMART_REFRESH | ACTIVATE | WINDOWCLOSE,  /* Flags */
	NULL,		/* Pointer to First Gadget */
	NULL,		/* Pointer to Checkmark image */
	"Anti-Aliasing Demo by Miles Kurland",	 /* Title */
	NULL,		/* Pointer to Screen structure (Dummy) */
	NULL,		/* Pointer to custom Bitmap */
	10,10,		/* Minimum Width, Height */
	320,200,		/* Maximum Width, Height */
	CUSTOMSCREEN
     };



main()		/* Here we go, action kids! */
{

/* open the intuition and graphics libraries.
   get pointer to Writable Control Store routines (ROM for all intents),
   if = 0, libraries aren't available */

IntuitionBase = (struct IntuitionBase *)
	OpenLibrary("intuition.library",LIBRARY_VERSION);
if (IntuitionBase == NULL) exit (FALSE);

GfxBase = (struct GfxBase *)
	OpenLibrary("graphics.library",LIBRARY_VERSION);
if (GfxBase == NULL) 
    {
     CloseLibrary(IntuitionBase); 	/* end of the line, get some memory!*/
     exit (FALSE);
    }

/* Open screen and window .  if they return 0, it didn't work! */

 if (( NewWdw.Screen = Scr = (struct Screen *)OpenScreen(&NewScr)) == NULL)
    {
     CloseLibrary(GfxBase);	
     CloseLibrary(IntuitionBase);	/* go home early */
     exit (FALSE);
    }

 if (( Wdw = (struct Window *)OpenWindow(&NewWdw)) == NULL)
    {
	CloseScreen(Scr);
	CloseLibrary(GfxBase);		/* be nice, and clean up your room */
	CloseLibrary(IntuitionBase);
	exit(FALSE);  
     }

 WVP = (struct ViewPort *)ViewPortAddress(Wdw);   /* Specify our View Port */

 workspace = AllocRaster(320,200);	/* Try to grab a workspace for Flood */
 if (workspace == 0)
 {
	CloseWindow(Wdw);
	CloseScreen(Scr);		/* If failure, close shop */
	CloseLibrary(GfxBase);
	CloseLibrary(IntuitionBase);
	exit(FALSE);  
 }
  
 InitTmpRas(&myTmpRas,workspace,RASSIZE(320,200));  /* Do this so Intuition */
 Rp->TmpRas = &myTmpRas;		/* will be able to use Flood */

 LoadRGB4(WVP,&colormap,16); 	/* Set up the colormap with our values */


 SetAPen(Rp,15); 		/* Draw a few concentric filled Ellipses */
 DrawEllipse(Rp,230,100,60,60);
 Flood(Rp,1,(short)230,(short)100);

 SetAPen(Rp,0); 
 DrawEllipse(Rp,230,100,45,45);
 Flood(Rp,1,(short)230,(short)100);

 SetAPen(Rp,15); 
 DrawEllipse(Rp,230,100,30,30);
 Flood(Rp,1,(short)230,(short)100);

 SetAPen(Rp,0); 
 DrawEllipse(Rp,230,100,15,15);
 Flood(Rp,1,(short)230,(short)100);

 polycolor = 15;		/* Draw some ANTIALIASED FILLED CIRCLES!! */
 SetAPen(Rp,15);
 aacircle(90,100,60); 

 polycolor = 0; 
 SetAPen(Rp,0);
 aacircle(90,100,45);

 polycolor = 15;
 SetAPen(Rp,15);
 aacircle(90,100,30); 

 polycolor = 0; 
 SetAPen(Rp,0);
 aacircle(90,100,15); 

 
 for (;;)	/* wait until user closes his window */
  {
  
   if (message = (struct IntuiMessage *)GetMsg(Wdw->UserPort))
    {
        MessageClass = message->Class;
        code = message->Code;
        ReplyMsg(message);
        if (MessageClass == CLOSEWINDOW)
        {
		FreeRaster(workspace,320,200);
                CloseWindow(Wdw);
		CloseScreen(Scr);
		CloseLibrary(GfxBase);
		CloseLibrary(IntuitionBase);
                return;
        }
    }
  }
}





/*  aacircle draws an antialiased, filled circle */

aacircle(xcent, ycent, rad)
int xcent, ycent, rad;   /* center of circle, and radius (in pixels) */
{
  int x,y;   	/* current x, y  position in quadrant */
  int r;     	/* remainder žo factor division out of the loop*/

  y = 0;   	/* start on the x-axis */
  x = rad;	/* with x=radius */
  r = x;	/* initialize remainder for round off. */
		/* the left and right edges, the top and bottom are assumed */
		/* to exactly cover a whole pixel, I fill those in first */

  fill(xcent-rad,ycent,xcent+rad);	/* draw middle line in */
  wdot(xcent,ycent+rad,polycolor);	/* the top dot, */
  wdot(xcent,ycent-rad,polycolor);	/* and bottom dot */
  while (y++ < x)	/* loop for all scan lines in 1/2 quadrant */
  { 
	r = r-y;	/* do next step in iterative division */
	if (r<0)	/* when underflow occurs, it's time to */
	{
		x=x-1;	/* subtract a whole pixel from x */
		r=r+x;	/* and push the remainder back up */
				/* fill in a line in the top and bottom */
		fill(xcent-y+1,ycent+x,xcent+y-1);	/* sections of the */	
		fill(xcent-y+1,ycent-x,xcent+y-1);	/* circle */
	}
 
	fill(xcent-x+1,ycent+y,xcent+x-1);	/* always fill a line across */
	fill(xcent-x+1,ycent-y,xcent+x-1);	/* the center of the circle */
	multi = r;	/* set the globals that specify the color */
	divis = x;	/* coverage ratio for this edge pixel */

	adot(xcent-x,ycent+y);	/* replicate this dot in all four quadrants */
	adot(xcent+x,ycent+y);
	adot(xcent-x,ycent-y);
	adot(xcent+x,ycent-y);
	adot(xcent-y,ycent-x); 	/* and use xy symmetry to generate the upper */
	adot(xcent+y,ycent-x);	/* half of each quadrant */
	adot(xcent-y,ycent+x);
	adot(xcent+y,ycent+x);
   }
   return;
 
}

wdot(x,y,color)		/* writes a dot of 'color' to screen */ 
int x,y,color;
{
    SetAPen(Rp,color);
    WritePixel(Rp,x,y);
    return;
}


fill(x1,y1,x2)		/* fills in pixels between two points in "polycolor" */
int x1,y1,x2;
{
   SetAPen(Rp,polycolor);
   Move(Rp,x1,y1);
   Draw(Rp,x2,y1);
   return;
}



adot(x,y)	/* routine to write one anti-aliased polygon edge dot */
int x,y;	
{
    int color;	/* storage for calculated color */
    int v;	/* color of pixel to be written over */
    int d;	/* distance between pixel and polycolor */

    v = ReadPixel(Rp,x,y);	/* read present color of pixel */
    d = v - polycolor;		/* calculate difference of pixels */
    d = d*multi/divis;		/* and interpolate new distances between */
				/* these two colors */
    color = (v-d);  /* calculate the new color, between two original colors*/

    wdot(x,y,color);	/* write the pixel out */
    return;		/* th-th-that's all folks */
}


/* Acknowledgement to Mike Higgens, who provided this algorithm, as well as
   example programs, which I liberally adapted to my own nefarious purposes */
