/* blot Library */

#include <exec/memory.h>
#include <exec/execbase.h>
#include <libraries/iffparse.h>
#include <utility/tagitem.h>
#include <graphics/gfxbase.h>
#include <intuition/intuitionbase.h>

#include <clib/macros.h>

#define __USE_SYSBASE 42

#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/utility.h>

#include <math.h>

#include <BTD.h>

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *UtilityBase;

/* #define DEBUG YES */

#ifdef DEBUG 

void KPrintF(char *,...);

#define DEBUG_PRINTF(a,b)  KPrintF(a,b);
#define DEBUG_PRINT(a)     KPrintF(a)
#else
#define DEBUG_PRINTF(a,b)
#define DEBUG_PRINT(a)
#endif


#define QTAG(o) (BTD_Client+(o))

#define BP_Seconds QTAG(0)
#define BP_Colors  QTAG(2)
#define BP_Zoom    QTAG(3)

#define MAX_SECONDS 2048L /* seconds until a new graphic is plotted */
#define DEF_SECONDS 10L

#define DEF_COLORS 8L
#define MAX_COLORS 255L

#define DEF_ZOOM 7L
#define MAX_ZOOM 20L

struct BTDInteger blotIntParams[] =
 {
  BP_Seconds,"Patternchange",BTDPT_INTEGER,DEF_SECONDS,1L,MAX_SECONDS,TRUE,
  BP_Colors,"Colors",BTDPT_INTEGER,DEF_COLORS,4L,MAX_COLORS,TRUE,
  BP_Zoom,"Grow leafs",BTDPT_INTEGER,DEF_ZOOM,4L,MAX_ZOOM,TRUE
 };

struct BTDNode *blotParams[] = 
 {
  &blotIntParams[0].BI_Node,
  &blotIntParams[1].BI_Node,
  &blotIntParams[2].BI_Node,NULL
 };

struct BTDInfo blotInfo =
 {
  BTDI_Revision,MAKE_ID('B','L','O','T'),
  "The Blots","The return of the Blots\nYet another standard modul","Markus Illenseer 1995",
  blotParams
 };

char MyBlankerName[] = "blot.btd";
char MyBlankerID[]   = "blot Fun Blanker V" VERSION "." REVISION " for BTD";


LONG MyBlankerLibInit(void)

{
 if (GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37L))
  {
   if (IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37L))
    {
     if (UtilityBase=OpenLibrary("utility.library",37L)) return TRUE;

     CloseLibrary (&IntuitionBase->LibNode);
    }
   CloseLibrary (&GfxBase->LibNode);
  }
 return FALSE;
}

void MyBlankerLibFree(void)

{
 CloseLibrary (UtilityBase);
 CloseLibrary (&IntuitionBase->LibNode);
 CloseLibrary (&GfxBase->LibNode);
}


typedef struct {
  LONG  x,y;
} XPoint;

#define MAXPOINTS 99
#define MAX_DELTA 3
#define MAX_blotS 2048

#define blot_THRESH 5

struct blotStruct
{
  struct BTDDrawInfo *BTDDrawInfo;
  LONG   hs_RandN,hs_RandF,hs_RandI;
  int width;
  int height;
  int xmid, ymid;
  int offset;
  int xsym, ysym;
  int size;
  int pix;
  long startTime;
  XPoint *pointBuffer;
  int pointBufferSize;
  int ncolors;
  int seconds;
  int zoom;
};


struct BTDInfo *QueryMyBlanker(void)

{
 return &blotInfo;
}


void __regargs InitRandom(struct blotStruct *BP,ULONG Instance)

{
 ULONG Time[2];

 CurrentTime (&Time[0],&Time[1]);
 BP->hs_RandN=(LONG)Time[0];
 if (Time[1]<1024L) Time[1]|=1;
 else Time[1]>>=10;
 Time[1]^=Instance;

 BP->hs_RandF=4*Time[1]+1;
 BP->hs_RandI=2*Time[1]+1;
}

WORD __regargs Random(struct blotStruct *BP,WORD Max)

{
 BP->hs_RandN=BP->hs_RandF*BP->hs_RandN+BP->hs_RandI;
 if (BP->hs_RandN<0L) BP->hs_RandN=-BP->hs_RandN;

 return (WORD)(BP->hs_RandN%Max);
}


#define FindTagData(l,t,d) GetTagData((t),(d),(l))
/* rainbow colors */

#define NUM_RAINBOW_COLORS 6

UBYTE RBRed[NUM_RAINBOW_COLORS+1]   = {0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF};
UBYTE RBGreen[NUM_RAINBOW_COLORS+1] = {0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00};
UBYTE RBBlue[NUM_RAINBOW_COLORS+1]  = {0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00};

/* blot routine. */

struct blotStruct *InitMyBlanker(struct TagItem *TagList)
{
 struct blotStruct *BP;
 struct BTDDrawInfo *BTDDrawInfo;
 ULONG *Error,Dummy,Index,Instance;
 ULONG Time[2];

 if ((BTDDrawInfo=(struct BTDDrawInfo *)
                   FindTagData(TagList,BTD_DrawInfo,NULL))==NULL) return NULL;
 Error=(LONG *)FindTagData(TagList,BTD_Error,(ULONG)&Dummy);
 if ((BP=AllocVec(sizeof(struct blotStruct),MEMF_PUBLIC|MEMF_CLEAR))==NULL)
  {
   *Error=BTDERR_Memory;
   return NULL;
  }

 BP->BTDDrawInfo=BTDDrawInfo;

 BP->seconds=FindTagData(TagList,BP_Seconds,DEF_SECONDS);
 BP->ncolors=FindTagData(TagList,BP_Colors,DEF_COLORS);
 BP->zoom=FindTagData(TagList,BP_Zoom,DEF_ZOOM);
 Instance=FindTagData(TagList,BTD_Instance,0L);

 InitRandom(BP,Instance);

 BP->width = BTDDrawInfo->BDI_Width-1;
 BP->height = BTDDrawInfo->BDI_Height-1;
 BP->xmid = BP->width / 2;
 BP->ymid = BP->height / 2;

 BP->offset = 4;
 BP->ysym = Random(BP,2);
 BP->xsym = (BP->ysym) ? Random(BP,2) : 1;
 BP->pix = Random(BP,BP->ncolors);
 if (BP->offset <= 0) BP->offset = 3;
 BP->size = BP->zoom * BP->width * BP->height / 1024;

 BP->pointBuffer = (XPoint *) AllocVec(BP->size * sizeof(XPoint),MEMF_PUBLIC|MEMF_CLEAR);
 BP->pointBufferSize = BP->size * sizeof(XPoint);

 CurrentTime (&Time[0],&Time[1]);
 BP->startTime = Time[0];

 if (BP->ncolors>NUM_RAINBOW_COLORS)
  {
   LONG ColNum,Col,RBCol;
   UBYTE *Red,*Green,*Blue,*Changed;

   Red=BTDDrawInfo->BDI_Red;
   Green=BTDDrawInfo->BDI_Green;
   Blue=BTDDrawInfo->BDI_Blue;
   Changed=BTDDrawInfo->BDI_Changed;
   ColNum=BP->ncolors/NUM_RAINBOW_COLORS+1L;
   Index=0L;
   for (RBCol=0L; RBCol<NUM_RAINBOW_COLORS; RBCol++)
    {
     if (RBCol==(BP->ncolors%NUM_RAINBOW_COLORS)) ColNum--;

     for (Col=0L; Col<ColNum; Col++)
      {
       Red[BTDDrawInfo->BDI_Pens[Index]]=RBRed[RBCol]+((RBRed[RBCol+1]-RBRed[RBCol])*Col)/ColNum;
       Green[BTDDrawInfo->BDI_Pens[Index]]=RBGreen[RBCol]+((RBGreen[RBCol+1]-RBGreen[RBCol])*Col)/ColNum;
       Blue[BTDDrawInfo->BDI_Pens[Index]]=RBBlue[RBCol]+((RBBlue[RBCol+1]-RBBlue[RBCol])*Col)/ColNum;
       Changed[BTDDrawInfo->BDI_Pens[Index++]]=TRUE;
      }
    }
  }
 else
  for (Index=0L; Index<BP->ncolors; Index++)
   {
    BTDDrawInfo->BDI_Red[BTDDrawInfo->BDI_Pens[Index]]=RBRed[Index];
    BTDDrawInfo->BDI_Green[BTDDrawInfo->BDI_Pens[Index]]=RBGreen[Index];
    BTDDrawInfo->BDI_Blue[BTDDrawInfo->BDI_Pens[Index]]=RBBlue[Index];
    BTDDrawInfo->BDI_Changed[BTDDrawInfo->BDI_Pens[Index]]=TRUE;
   }

DEBUG_PRINT("blot: Init ready\n");

 return BP;
}

void EndMyBlanker(struct blotStruct *BP)

{
DEBUG_PRINT("blot: FreeMem\n");
 if(BP->pointBuffer)
  FreeVec(BP->pointBuffer);
 FreeVec (BP);
}

void XDrawPoints(struct blotStruct *BP,int size)
{
 int i,mx,my;
 mx=BP->BTDDrawInfo->BDI_Width;
 my=BP->BTDDrawInfo->BDI_Height;
 for (i=0; i<size; i++)
  if(BP->pointBuffer[i].x<mx && BP->pointBuffer[i].y<my &&
     BP->pointBuffer[i].x>0  && BP->pointBuffer[i].y>0)
  WritePixel(BP->BTDDrawInfo->BDI_RPort,BP->pointBuffer[i].x,BP->pointBuffer[i].y);
}

void initblot(struct blotStruct *BP)
{

 ULONG Time[2];

 BP->offset = 4;
 BP->ysym = Random(BP,2);
 BP->xsym = (BP->ysym) ? Random(BP,2) : 1;
 BP->pix = Random(BP,BP->ncolors);
 if (BP->offset <= 0) BP->offset = 3;
 BP->size = BP->zoom * BP->width * BP->height / 1024;

 if (!BP->pointBuffer || BP->pointBufferSize < (BP->size * sizeof(XPoint))) 
  {
      if (BP->pointBuffer != NULL)
        FreeVec(BP->pointBuffer);
      BP->pointBuffer = (XPoint *) AllocVec(BP->size * sizeof(XPoint),MEMF_PUBLIC|MEMF_CLEAR);
      BP->pointBufferSize = BP->size * sizeof(XPoint);
  }

 CurrentTime (&Time[0],&Time[1]);
 BP->startTime = Time[0];

 SetRast(BP->BTDDrawInfo->BDI_RPort,0);

}

void AnimMyBlanker(struct blotStruct *BP)
{
  int x, y;
  int         k;
  XPoint     *xp = BP->pointBuffer;
  ULONG Time[2];

  SetAPen(BP->BTDDrawInfo->BDI_RPort,BP->BTDDrawInfo->BDI_Pens[BP->pix]);
  if (++BP->pix>= BP->ncolors)
      BP->pix = 0;

  x = BP->xmid;
  y = BP->ymid;
  k = BP->size;
  while (k >= 4) {
      x += (Random(BP,(1 + (BP->offset << 1))) - BP->offset);
      y += (Random(BP,(1 + (BP->offset << 1))) - BP->offset);
      k--;
      xp->x = x;
      xp->y = y;
      xp++;
      if (BP->xsym)
	{
          k--;
	  xp->x = BP->width - x;
	  xp->y = y;
	  xp++;
	}
      if (BP->ysym)
	{
          k--;
	  xp->x = x;
	  xp->y = BP->height - y;
	  xp++;
	}
      if (BP->xsym && BP->ysym)
	{
          k--;
	  xp->x = BP->width - x;
	  xp->y = BP->height - y;
	  xp++;
	}
    }
    XDrawPoints (BP, BP->size - k);
    CurrentTime (&Time[0],&Time[1]);
    if (Time[0]- BP->startTime > BP->seconds)
	initblot(BP);
}

ULONG PenCountMyBlanker(struct TagItem *TagList)

{
 ULONG colors;
 colors=FindTagData(TagList,BP_Colors,DEF_COLORS);
 return colors;
}
