/* Hop Library */

#include <exec/memory.h>
#include <exec/execbase.h>
#include <graphics/gfxbase.h>
#include <intuition/intuitionbase.h>
#include <libraries/iffparse.h>
#include <utility/tagitem.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 <stdio.h>

#include <btd.h>

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *UtilityBase,*MathIeeeDoubBasBase,*MathIeeeDoubTransBase;

#define HOPTAG(o) (BTD_Client+(o))

#define HOP_Seconds HOPTAG(0)

#define MAX_SECONDS 360L /* seconds until a new graphic is plotted */
#define DEF_SECONDS 20L

#define DEG45 (-0.707106781)

struct BTDInteger HopIntParams[] =
 {
  HOP_Seconds,"Seconds",BTDPT_INTEGER,DEF_SECONDS,1L,MAX_SECONDS,TRUE
 };

struct BTDNode *HopParams[] = {&HopIntParams[0].BI_Node,NULL};

struct BTDInfo HopInfo =
 {
  BTDI_Revision,MAKE_ID('H','O','P',' '),
  "Hop a long","based on Hop","Matthias Scheler",
  HopParams
 };

struct HopStruct
 {
  struct BTDDrawInfo *hs_BTDDrawInfo;
  WORD   hs_Left,hs_Top,hs_MidX,hs_MidY;
  LONG   hs_Seconds;
  LONG   hs_Time;
  DOUBLE hs_a,hs_b, hs_c, hs_mag; /* Pattern Points */
  DOUBLE hs_x,hs_y;               /* Running Point */
  DOUBLE hs_sx,hs_sy;
  LONG   hs_RandN,hs_RandF,hs_RandI;
 };

/* catch FP errors */

int _FPERR=0;

void __stdargs _CXFERR(int Code)

{
 _FPERR=Code;
}

/* library stuff */

char MyBlankerName[] = "hop.btd";
char MyBlankerID[]   = "Hop 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))
      {
       if (MathIeeeDoubBasBase=OpenLibrary("mathieeedoubbas.library",37L))
        {
         if (MathIeeeDoubTransBase=OpenLibrary("mathieeedoubtrans.library",37L)) return TRUE;

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

void MyBlankerLibFree(void)

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

/* random generator */

void __regargs InitRandom(struct HopStruct *HopStruct,ULONG Instance)

{
 ULONG Time[2];

 CurrentTime (&Time[0],&Time[1]);
 HopStruct->hs_RandN=(LONG)Time[0];

 if (Time[1]<1024L) Time[1]|=1;
 else Time[1]>>=10;
 Time[1]^=Instance;

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

WORD __regargs Random(struct HopStruct *HopStruct,WORD Max)

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

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

/* implementation of library functions */

struct BTDInfo *QueryMyBlanker(void)

{
 return &HopInfo;
}

struct HopStruct *InitMyBlanker(struct TagItem *TagList)

{
 struct BTDDrawInfo *BTDDrawInfo;
 struct HopStruct *HopStruct;
 ULONG *Error,Dummy,Instance;

 if ((BTDDrawInfo=(struct BTDDrawInfo *)
                   GetTagData(BTD_DrawInfo,NULL,TagList))==NULL) return NULL;
 Error=(ULONG *)GetTagData(BTD_Error,(ULONG)&Dummy,TagList);
 if ((HopStruct=AllocVec(sizeof(struct HopStruct),MEMF_PUBLIC|MEMF_CLEAR))==NULL)
  {
   *Error=BTDERR_Memory;
   return NULL;
  }
 Instance=GetTagData(BTD_Instance,0L,TagList);

 HopStruct->hs_BTDDrawInfo=BTDDrawInfo;
 HopStruct->hs_Left=HopStruct->hs_BTDDrawInfo->BDI_Left;
 HopStruct->hs_Top=HopStruct->hs_BTDDrawInfo->BDI_Top;
 HopStruct->hs_MidX=HopStruct->hs_BTDDrawInfo->BDI_Width/2;
 HopStruct->hs_MidY=HopStruct->hs_BTDDrawInfo->BDI_Height/2;
 HopStruct->hs_Seconds=GetTagData(HOP_Seconds,DEF_SECONDS,TagList);
 InitRandom (HopStruct,Instance);

 BTDDrawInfo->BDI_Red[BTDDrawInfo->BDI_Pens[0]]=255;
 BTDDrawInfo->BDI_Green[BTDDrawInfo->BDI_Pens[0]]=255;
 BTDDrawInfo->BDI_Blue[BTDDrawInfo->BDI_Pens[0]]=255;
 BTDDrawInfo->BDI_Changed[BTDDrawInfo->BDI_Pens[0]]=TRUE;
 SetAPen (BTDDrawInfo->BDI_RPort,BTDDrawInfo->BDI_Pens[0]);

 return HopStruct;
}

void EndMyBlanker(struct HopStruct *HopStruct)

{
 FreeVec (HopStruct);
}

void AnimMyBlanker(struct HopStruct *HopStruct)

{
 DOUBLE Help,NewY;
 ULONG Seconds,Micros;
 LONG X,Y;

 CurrentTime (&Seconds,&Micros);
 if (Seconds>=HopStruct->hs_Time)
  {
   HopStruct->hs_Time=Seconds+HopStruct->hs_Seconds;
   HopStruct->hs_a=Random(HopStruct,300)/100.0;
   HopStruct->hs_b=Random(HopStruct,100)/100.0;
   HopStruct->hs_c=Random(HopStruct,50)/100.0;
   HopStruct->hs_mag=(1<<(Random(HopStruct,4)+5))*DEG45;
   HopStruct->hs_x=0.0;
   HopStruct->hs_y=0.0;
   HopStruct->hs_sx=0.0;
   HopStruct->hs_sy=0.0;

   EraseRect (HopStruct->hs_BTDDrawInfo->BDI_RPort,
              HopStruct->hs_BTDDrawInfo->BDI_Left,
              HopStruct->hs_BTDDrawInfo->BDI_Top,
              HopStruct->hs_BTDDrawInfo->BDI_Left+HopStruct->hs_BTDDrawInfo->BDI_Width-1,
              HopStruct->hs_BTDDrawInfo->BDI_Top+HopStruct->hs_BTDDrawInfo->BDI_Height-1);
  }

 NewY=HopStruct->hs_a-HopStruct->hs_x;

 Help=fabs(HopStruct->hs_b*HopStruct->hs_x-HopStruct->hs_c);

 if (HopStruct->hs_x<0.0L) HopStruct->hs_x=HopStruct->hs_y+sqrt(Help);
 else HopStruct->hs_x=HopStruct->hs_y-sqrt(Help);

 HopStruct->hs_y=NewY;

 HopStruct->hs_sx=HopStruct->hs_mag*(HopStruct->hs_x+HopStruct->hs_y);
 HopStruct->hs_sy=HopStruct->hs_mag*(HopStruct->hs_y-HopStruct->hs_x);

 X=(LONG)HopStruct->hs_sx+HopStruct->hs_MidX;
 Y=(LONG)HopStruct->hs_sy+HopStruct->hs_MidY;
 if ((X>=0L)&&(X<HopStruct->hs_BTDDrawInfo->BDI_Width)&&
     (Y>=0L)&&(Y<HopStruct->hs_BTDDrawInfo->BDI_Height))
  WritePixel (HopStruct->hs_BTDDrawInfo->BDI_RPort,
              HopStruct->hs_Left+X,HopStruct->hs_Top+Y);
}

ULONG PenCountMyBlanker(struct TagItem *TagList)

{
 return 1L;
}
