/*  SpriteWiz support routines  */

#include <stdio.h>
#include <ctype.h>
#include <exec/types.h>
#include <graphics/sprite.h>
#include <intuition/intuition.h>

#include "SW_Menu.def"

/*  Color registers  */
#define COLOR00  0
#define COLOR01  1
#define COLOR02  2
#define COLOR03  3
#define COLOR04  4

/*  Packed UWORDS for default sprite colors  */
#define RED    0xf00
#define GREEN  0x0f0
#define BLUE   0x00f

/*  maximum and minimum bit definitions  */
#define HIGH_BIT     (1 << 15)
#define LOW_BIT      (1 << 0)

/*  Sprite number defines  */
#define LOW_SPRITE    0
#define HIGH_SPRITE   25
#define MAX_SPRITES   26

/*  Various other defines  */
#define MAX_INT      32767           /*  Used for random numbers  */
#define MAX_DEPTH    3
#define SPRITE_SIZE  36      /*  In words  */

/*  External declares  */
extern UBYTE *AllocRaster();
extern UWORD GetRGB4();
extern UWORD PackRGB();
extern BOOL CheckSequence();
extern unsigned int rand();
extern unsigned int GetRand();

/*  The world renowned Sprite structure  */
struct Sprite
 {
 UWORD SpriteData [SPRITE_SIZE];
 UWORD SprColor1,SprColor2,SprColor3;
 UWORD SpriteNumber;
 };

#define SPR_STRUCT_SIZE   sizeof(struct Sprite)

/*  Again, the world famous points structure  */
struct Points
 {
 UWORD X1,Y1;
 UWORD X2,Y2;
 UWORD X3,Y3;
 UWORD X4,Y4;
 UWORD X5,Y5;
 };


/*  Initialize all sprites  */
InitSprites(SpritePtr)
struct Sprite *SpritePtr;                /*  Pointer to first sprite  */
{
struct Sprite *FirstSprPtr;
ULONG Mode;
int i;

FirstSprPtr = SpritePtr;      /*  Save pointer to first sprite  */

/*  Assign sprite numbers  */
for ( i = 0; i < MAX_SPRITES; i++ )
    {
    SpritePtr->SpriteNumber = i;
    SpritePtr++;
    }

Mode = ALL;
ClearSprite(FirstSprPtr,Mode);          /*  Clear sprite imagry   */
ClearColor(FirstSprPtr,Mode);           /*  Reset sprite colors   */
}


/*  Initialzation code for buffer sprite  */
InitTempSprite(SpritePtr)
struct Sprite *SpritePtr;
{
ULONG Mode;

/*  Clear imagry and set colors of buffer sprite to default colors  */
SpritePtr->SpriteNumber = 0;          /*  For KLUDGE purposes  */
Mode = CURRENT;
ClearSprite(SpritePtr,Mode);          /*  Clear sprite imagry   */
ClearColor(SpritePtr,Mode);           /*  Reset sprite colors   */
}


/*  Dynamically allocate rastport for grid scroll and rotate routines  */
InitTempRast(RastPtr,BitMapPtr,Width,Height)
struct RastPort *RastPtr;
struct BitMap *BitMapPtr;
LONG Width,Height;
{
int i;

InitBitMap(BitMapPtr,MAX_DEPTH,Width,Height);
for ( i = 0; i < MAX_DEPTH; i++ )
    {
    BitMapPtr->Planes[i] = AllocRaster(Width,Height);
    if ( BitMapPtr->Planes[i] == NULL )
       {
       printf("Could not allocate space for Temporary BitMap! \n");
       exit(1);
       };
     };

InitRastPort(RastPtr);
RastPtr->BitMap = BitMapPtr;
}


/*  Free dynamically created BitMap  */
FreeTempRast(RastPtr,BitMapPtr,Width,Height)
struct RastPort *RastPtr;
struct BitMap *BitMapPtr;
{
int i;

for ( i = 0; i < MAX_DEPTH; i++ )
    FreeRaster(BitMapPtr->Planes[i],Width,Height);
}


/*  Draw sprite image onto grid  */
CalcSprite(Rp,SpritePtr,BoxPtr)
struct RastPort *Rp;
struct Sprite *SpritePtr;
struct Rectangle *BoxPtr;
{
struct Rectangle *RectPtr;
UWORD *SpriteDataPtr;
UWORD HighWord,LowWord;
UWORD HighBit,LowBit;
LONG Row,BoxIndex,WordIndex;
LONG MinX,MinY,MaxX,MaxY;
int i;

SpriteDataPtr = &SpritePtr->SpriteData[0];

for ( Row = 0; Row <= 15; Row++ )
    {
    /*  Get HighWord and LowWord of each sprite line  */
    WordIndex = 2 + (2 * Row);
    HighWord = *(SpriteDataPtr + WordIndex);
    LowWord = *(SpriteDataPtr + WordIndex + 1);

    for ( i = 0; i <= 15; i++ )
        {
        /*  Check each bit position in HighWord amd LowWord  */
        HighBit = HighWord & (1 << (15 - i));
        LowBit =  LowWord & (1 << (15 - i));

        /*  Set Rp color depending on bit combination  */
        if ( HighBit == 0 && LowBit == 0 )
           SetAPen(Rp,COLOR00);
        else if ( HighBit != 0 && LowBit == 0 )
           SetAPen(Rp,COLOR01);
        else if ( HighBit == 0 && LowBit != 0 )
           SetAPen(Rp,COLOR02);
        else if ( HighBit != 0 && LowBit != 0 )
           SetAPen(Rp,COLOR03);

        /*  Get MinX, MinY, MaxX, MaxY for current box  */
        BoxIndex = (Row * 16) + i;
        RectPtr = BoxPtr + BoxIndex;
        MinX = RectPtr->MinX;
        MinY = RectPtr->MinY;
        MaxX = RectPtr->MaxX;
        MaxY = RectPtr->MaxY;

        /*  Do RectFill() to current box  */
        RectFill(Rp,MinX + 1,MinY + 1,MaxX - 1,MaxY - 1);
        };
    };                               /*  Next row  */
}


ClearSprite(SpritePtr,Mode)
struct Sprite *SpritePtr;         /*  Points to current sprite  */
ULONG Mode;
{
UWORD *SpriteDataPtr;
UWORD SprNum;
int i,LowRange,HighRange;
struct Sprite *FirstSprPtr,*NextSprPtr;

SprNum = SpritePtr->SpriteNumber;
FirstSprPtr = SpritePtr - SprNum;    /*  Get pointer to first sprite  */

switch(Mode)
  {
  case CURRENT :
       LowRange = SprNum;
       HighRange = SprNum;
       NextSprPtr = SpritePtr;
  break;
  case ALL :
       LowRange = LOW_SPRITE;
       HighRange = HIGH_SPRITE;
       NextSprPtr = FirstSprPtr;
  break;
  case FROM :
       LowRange = SprNum;
       HighRange = HIGH_SPRITE;
       NextSprPtr = SpritePtr;
  break;
  case UP_TO :
       LowRange = LOW_SPRITE;
       HighRange = SprNum;
       NextSprPtr = FirstSprPtr;
  break;
  case EXCEPT :
       LowRange = LOW_SPRITE;
       HighRange = HIGH_SPRITE;
       NextSprPtr = FirstSprPtr;
  break;
  };

/*  Clear specified range of sprites  */
for ( i = LowRange; i <= HighRange; i++ )
    {
    if ( Mode == EXCEPT && i == SprNum )
       {
       NextSprPtr++;
       continue;
       };

       /*  Clear next sprite image  */
       SpriteDataPtr = &NextSprPtr->SpriteData[0];
       ClearSprData(SpriteDataPtr);
       NextSprPtr++;
    };
}


ClearColor(SpritePtr,Mode)
struct Sprite *SpritePtr;         /*  Points to current sprite  */
ULONG Mode;
{
UWORD SprNum;
int i,LowRange,HighRange;
struct Sprite *FirstSprPtr,*NextSprPtr;

SprNum = SpritePtr->SpriteNumber;
FirstSprPtr = SpritePtr - SprNum;    /*  Get pointer to first sprite  */

switch(Mode)
  {
  case CURRENT :
      LowRange = SprNum;
      HighRange = SprNum;
      NextSprPtr = SpritePtr;
  break;
  case ALL :
       LowRange = LOW_SPRITE;
       HighRange = HIGH_SPRITE;
       NextSprPtr = FirstSprPtr;
  break;
  case FROM :
       LowRange = SprNum;
       HighRange = HIGH_SPRITE;
       NextSprPtr = SpritePtr;
  break;
  case UP_TO :
       LowRange = LOW_SPRITE;
       HighRange = SprNum;
       NextSprPtr = FirstSprPtr;
  break;
  case EXCEPT :
       LowRange = LOW_SPRITE;
       HighRange = HIGH_SPRITE;
       NextSprPtr = FirstSprPtr;
  break;
  };

/*  Reset colors of specified range to default colors  */
for ( i = LowRange; i <= HighRange; i++ )
    {
    if ( Mode == EXCEPT && i == SprNum )
       {
       NextSprPtr++;
       continue;
       };

       /*  Reset colors of next sprite to default colors  */
       NextSprPtr->SprColor1 = RED;
       NextSprPtr->SprColor2 = GREEN;
       NextSprPtr->SprColor3 = BLUE;
       NextSprPtr++;
    };
}


/*  Clear sprite data to zero  */
ClearSprData(SpriteDataPtr)
UWORD *SpriteDataPtr;
{
UBYTE *SrcPtr;

SrcPtr = (UBYTE *) SpriteDataPtr;
BltClear(SrcPtr,SPRITE_SIZE * sizeof(UWORD),1);
}


/*  Copy source sprite data to destination sprite data  */
CopySprData(SrcData,DestData)
UWORD *SrcData,*DestData;
{
UBYTE *SrcPtr,*DestPtr;

SrcPtr = (UBYTE *) SrcData;
DestPtr = (UBYTE *) DestData;
CopyMem(SrcPtr,DestPtr,SPRITE_SIZE * sizeof(UWORD));
}


/*  Copy source sprite sprite to destination sprite  */
CopySprite(SrcSprite,DestSprite)
struct Sprite *SrcSprite,*DestSprite;
{
UBYTE *SrcPtr,*DestPtr;

SrcPtr = (UBYTE *) SrcSprite;
DestPtr = (UBYTE *) DestSprite;
CopyMem(SrcPtr,DestPtr,SPR_STRUCT_SIZE);
}


/*  Clear posctldata and attached bits  */
ClearPosCtl(SpriteDataPtr)
UWORD *SpriteDataPtr;
{

*SpriteDataPtr = 0;
*(SpriteDataPtr + 1) = 0;
*(SpriteDataPtr + 34) = 0;
*(SpriteDataPtr + 35) = 0;
}


/*  Shift left for sprite data  */
ShiftLeft(HighWordPtr,LowWordPtr)
UWORD *HighWordPtr,*LowWordPtr;
{
UWORD HighWord,LowWord;
LONG BitVal;

/*  Shift high word to the left by one bit  */
HighWord = *HighWordPtr;
if ( (HighWord & HIGH_BIT) != 0 )
   BitVal = LOW_BIT;
else
   BitVal = 0;
HighWord = (HighWord << 1) | BitVal;
*HighWordPtr = HighWord;

/*  Shift low word to the left by one bit  */
LowWord = *LowWordPtr;
if ( (LowWord & HIGH_BIT) != 0 )
   BitVal = LOW_BIT;
else
   BitVal = 0;
LowWord = (LowWord << 1) | BitVal;
*LowWordPtr = LowWord;
}


/*  Shift right for sprite data  */
ShiftRight(HighWordPtr,LowWordPtr)
UWORD *HighWordPtr,*LowWordPtr;
{
UWORD HighWord,LowWord;
LONG BitVal;

/*  Shift high word to the right by one bit  */
HighWord = *HighWordPtr;
if ( (HighWord & LOW_BIT) != 0 )
   BitVal = HIGH_BIT;
else
   BitVal = 0;
HighWord = (HighWord >> 1) | BitVal;
*HighWordPtr = HighWord;

/*  Shift low word to the right by one bit  */
LowWord = *LowWordPtr;
if ( (LowWord & LOW_BIT) != 0 )
   BitVal = HIGH_BIT;
else
   BitVal = 0;
LowWord = (LowWord >> 1) | BitVal;
*LowWordPtr = LowWord;
}


/*  Allocate edit sprite  */
AllocSprite(SpritePtr,SprNum)
struct SimpleSprite *SpritePtr;
LONG SprNum;
{

if ( GetSprite(SpritePtr,SprNum) != SprNum )
   {
   printf("Could not allocate edit Sprite! \n");
   exit(1);
   };

SpritePtr->height = 16;
SpritePtr->x = 500;
SpritePtr->y = 120;
SpritePtr->num = SprNum;
}


/*  Set a ViewPort color register from a Packed UWORD  */
SetPackedRGB(VPortPtr,ColorVal,ColorReg)
struct ViewPort *VPortPtr;
UWORD ColorVal;
ULONG ColorReg;
{
ULONG RedBits,GreenBits,BlueBits;

UnPackRGB(ColorVal,&RedBits,&GreenBits,&BlueBits);
SetRGB4(VPortPtr,ColorReg,RedBits,GreenBits,BlueBits);
}


/*  Determine RGB values based on packed UWORD  */
UnPackRGB(ColorVal,RedPtr,GreenPtr,BluePtr)
UWORD ColorVal;
ULONG *RedPtr,*GreenPtr,*BluePtr;
{
*RedPtr = (ColorVal >> 8) & 0xf;
*GreenPtr = (ColorVal >> 4) & 0xf;
*BluePtr = ColorVal & 0xf;
}


/*  Pack RGB Values into a single UWORD  */
UWORD PackRGB(RedBits,GreenBits,BlueBits)
ULONG RedBits,GreenBits,BlueBits;
{
UWORD ColorVal;

RedBits = (RedBits << 8) & 0xf00;
GreenBits = (GreenBits << 4) & 0x0f0;
BlueBits = BlueBits & 0x00f;

ColorVal = RedBits | GreenBits | BlueBits;
return(ColorVal);
}


/*  Initialize borders for gadgets and requesters  */
InitBorder(PointsPtr,BorderPtr,Width,Height)
struct Points *PointsPtr;
struct Border *BorderPtr;
SHORT Width,Height;
{
/*  Define points structure for gadget border  */
PointsPtr->X1 = PointsPtr->X5 = 0;
PointsPtr->Y1 = PointsPtr->Y5 = 0;
PointsPtr->X2 = Width;
PointsPtr->Y2 = 0;
PointsPtr->X3 = Width;
PointsPtr->Y3 = Height;
PointsPtr->X4 = 0;
PointsPtr->Y4 = Height;

/*  Initialize border  */
BorderPtr->LeftEdge = 0;
BorderPtr->TopEdge = 0;
BorderPtr->FrontPen = COLOR04;
BorderPtr->BackPen = COLOR00;
BorderPtr->DrawMode = JAM1;
BorderPtr->Count = 5;
BorderPtr->XY = (SHORT *) PointsPtr;
BorderPtr->NextBorder = NULL;
}

/*  Check if animation sequence is valid  -  Convert to upper case  */
BOOL CheckSequence(StrPtr)
char *StrPtr;
{
char NextChar;

while ( *StrPtr != NULL )
  {
  NextChar = *StrPtr;
  NextChar = ( isupper(NextChar) ? NextChar : toupper(NextChar) );
  if ( NextChar < 'A' || NextChar > 'Z' )
     return(FALSE);
  else
     *StrPtr++ = NextChar;
  };

return(TRUE);
}


/*  Get a random number between 0 and MaxRange  */
unsigned int GetRand(MaxRange)
int MaxRange;
{
int Divisor,Value;

Divisor = MAX_INT/MaxRange;
Value = rand()/Divisor;
return(Value);
}


/*  Seed random number generator based on the current time  */
SetSeed()
{
ULONG Seconds,MicroSeconds;
unsigned int IntSeconds;

CurrentTime(&Seconds,&MicroSeconds);
IntSeconds = (unsigned int) Seconds;
srand(IntSeconds);
}

/*  Refresh sprite number display  */
RefreshSprNum(Rp,SprNum)
struct RastPort *Rp;
UWORD SprNum;
{
char SprNumStr[25];
LONG Len;

sprintf(SprNumStr,"Sprite = %c",SprNum + 65);
Len = (LONG) strlen(SprNumStr);
SetAPen(Rp,COLOR04);
Move(Rp,511,25);
Text(Rp,SprNumStr,Len);
}


/*  Refresh grid (X,Y) coordinates  */
RefreshGridXY(Rp,Row,Column)
struct RastPort *Rp;
LONG Row,Column;
{
char CoordStr[50];
LONG Len;

sprintf(CoordStr,"Row = %02d    Column = %02d",Row,Column);
Len = (LONG) strlen(CoordStr);
SetAPen(Rp,COLOR04);
Move(Rp,300,25);
Text(Rp,CoordStr,Len);
}


/*  Refresh current edit mode  */
RefreshMode(Rp,ModeStr)
struct RastPort *Rp;
char *ModeStr;
{
LONG Len;
char OutStr[80];

sprintf(OutStr,"Mode : %s",ModeStr);
Len = (LONG) strlen(OutStr);
SetAPen(Rp,COLOR04);
Move(Rp,25,193);
Text(Rp,OutStr,Len);
}

