/*  I/O routines for SpriteWiz  --->  By David A. Visage  */

#include <stdio.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include "SW_Menu.def"

#define SW_FILE         0xffffffff    /*  Signifies SpriteWiz file  */

#define SPRITE_SIZE     36            /*  In UWORD units  */
#define WORDS_PER_LINE  9

/*  Defines for sprite limits  */
#define LOW_SPRITE   0
#define HIGH_SPRITE  25
#define MAX_SPRITES  26               /*  Maximum number of sprites  */

/*  Defines for minimum and maximum colors allowed  */
#define  MIN_COLOR   0x0000
#define  MAX_COLOR   0x0fff

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

/*  Format masks for save as assembler source  */
#define EquMask    "NUM_SPRITES    equ          %02d \n"
#define ColorMask  "SPR%02dCOL       dc.w      $%03x,$%03x,$%03x \n"
#define DataMask1  "SPR%02dDAT       dc.w      $%04x,$%04x,$%04x,$%04x \n"
#define DataMask2  "               dc.w      $%04x,$%04x,$%04x,$%04x \n"

/*  Standard header for C programs  */
char *CHeader [] = {
 "/*  SpriteWiz created data  -->  By David A. Visage  */ \n",
 "\n",
 "#ifndef _STDIO_H \n",
 "#include <stdio.h> \n",
 "#endif \n \n",
 "#ifndef EXEC_TYPES_H \n",
 "#include <exec/types.h> \n",
 "#endif \n \n",
 "#define NUM_SPRITES  (sizeof(MySprInfo) / sizeof(struct SprInfo)) \n", 
 "#define SPRITE_SIZE  36 \n \n",
 "struct SprInfo \n",
 " { \n"
 " UWORD SprColor1,SprColor2,SprColor3; \n",
 " UWORD SpriteData [SPRITE_SIZE]; \n",
 " }; \n \n",
 NULL
 };

/*  Header for 68000 programs.  Second element holds equ for NUM_SPRITES  */
char *AsmHeader [] = {
 "*  SpriteWiz created data  -->  By David A. Visage \n",
 "* \n",
 "               IFND EXEC_TYPES_I \n",
 "               include      'exec/types.i' \n",
 "               ENDC \n",
 "* \n",
 NULL,
 "SPRITE_SIZE    equ          72           ; (36 * sizeof(UWORD)) \n",
 "* \n",
 "               STRUCTURE    SprInfo,0 \n",
 "               UWORD        si_SprColor1 \n",
 "               UWORD        si_SprColor2 \n",
 "               UWORD        si_SprColor3 \n",
 "               STRUCT       si_SprData,SPRITE_SIZE \n",
 "               LABEL        si_SizeOf              \n",
 "* \n",
 NULL               /*  EOA - End of array  */
 };

/*  Memory size definitions  */
#define WORD_SIZE            sizeof(UWORD)
#define LONG_SIZE            sizeof(ULONG)
#define SPR_STRUCT_SIZE      sizeof(struct Sprite)

/*  Declare retun values of functions used  */
extern struct FileHandle *Open();
extern ULONG Read();
extern ULONG Write();
extern BOOL LoadBinary();
extern BOOL SaveBinary();
extern BOOL SaveCSource();
extern BOOL SaveAsmSource();

/*  This routine will load sprite binary data  */
BOOL LoadBinary(FirstSprPtr,FileName,ErrMsg)
struct Sprite *FirstSprPtr;
char *FileName;
char *ErrMsg;
{
struct Sprite *NextSprPtr;
struct Sprite TempSprite;
struct FileHandle *InFile;
UBYTE *SrcPtr,*DestPtr;
ULONG HeaderHunk,NumBytes;
UWORD SprNum;
BOOL  Test1,Test2,Test3;
UWORD SprColor1,SprColor2,SprColor3;

/*  Try to open input file  */
if ( ( InFile = Open(FileName,MODE_OLDFILE) ) == NULL )
   {
   sprintf(ErrMsg,"Could not open requested file!");
   return(FALSE);
   };

/*  Read first ULONG of data file   --->  Header Chunk  */
if ( Read(InFile,&HeaderHunk,LONG_SIZE) != LONG_SIZE )
   {
   sprintf(ErrMsg,"Error reading requested file!");
   Close(InFile);
   return(FALSE);
   };

/*  Is this a SpriteWiz file?  */
if ( HeaderHunk != SW_FILE )
   {
   sprintf(ErrMsg,"Requested file not created by SpriteWiz!");
   Close(InFile);
   return(FALSE);
   };

/*  Read sprites in till end of file reached  */
while ( TRUE )
  {
  NumBytes = Read(InFile,&TempSprite,SPR_STRUCT_SIZE);   /*  0 when EOF  */
  if ( NumBytes != SPR_STRUCT_SIZE )
     {
     if ( NumBytes == 0 )
        {
        Close(InFile);
        return(TRUE);
        }
     else
        {
        sprintf(ErrMsg,"Error reading requested file!");
        Close(InFile);
        return(FALSE);
        };
     };

  Convert(&TempSprite);                /*  Decode encoded data  */

  /*  Is sprite number within bounds?  */
  SprNum = TempSprite.SpriteNumber;
  if ( SprNum < LOW_SPRITE || SprNum > HIGH_SPRITE )
     {
     sprintf(ErrMsg,"Illegal sprite number found!");
     Close(InFile);
     return(FALSE);
     };

  /*  Get sprite colors  */
  SprColor1 = TempSprite.SprColor1;
  SprColor2 = TempSprite.SprColor2;
  SprColor3 = TempSprite.SprColor3;

  /*   Check sprite colors  */
  Test1 = (SprColor1 < MIN_COLOR || SprColor1 > MAX_COLOR );
  Test2 = (SprColor2 < MIN_COLOR || SprColor2 > MAX_COLOR );
  Test3 = (SprColor3 < MIN_COLOR || SprColor3 > MAX_COLOR );

  /*  Are sprite colors out of bounds?  */
  if ( Test1 | Test2 | Test3 )
     {
     sprintf(ErrMsg,"Illegal sprite color found!");
     Close(InFile);
     return(FALSE);
     };

  /*  Copy last read sprite to area it was saved from  */
  NextSprPtr = FirstSprPtr + SprNum;
  CopySprite(&TempSprite,NextSprPtr);
  };
}


/*  This routine will save sprite binary data  */
BOOL SaveBinary(SpritePtr,FileName,Mode,ErrMsg)
struct Sprite *SpritePtr;                           /*  Current Sprite  */
char *FileName;
ULONG Mode;
char *ErrMsg;
{
struct Sprite *FirstSprPtr;                /*  Points to first sprite  */
struct Sprite *NextSprPtr;
struct Sprite TempSprite;
struct FileHandle *OutFile;
ULONG HeaderHunk,LowRange,HighRange;
UWORD SprNum;
UBYTE *SrcPtr,*DestPtr;
int i;

/*  Try to open output file  */
if ( ( OutFile = Open(FileName,MODE_NEWFILE) ) == NULL )
   {
   sprintf(ErrMsg,"Could not create requested file!");
   return(FALSE);
   };

/*  Write first ULONG of data file  --->  Header Chunk  */
HeaderHunk = SW_FILE; 
if ( Write(OutFile,&HeaderHunk,LONG_SIZE) != LONG_SIZE )
   {
   sprintf(ErrMsg,"Error writing requested file!");
   Close(OutFile);
   return(FALSE);
   };

/*  Determine loop counter values  */
SprNum = SpritePtr->SpriteNumber;
FirstSprPtr = SpritePtr - SprNum;         /*  scaled by argument size  */
switch(Mode)
  {
  case CURRENT :
       LowRange = 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;

  default :
       sprintf(ErrMsg,"Illegal save mode requested!");
       Close(OutFile);
       return(FALSE);
  break;
  };

/*  Write all selected sprites  */
for ( i = LowRange; i <= HighRange; i++ )
    {
    if ( Mode == EXCEPT && i == SprNum )
       {
       NextSprPtr++;             /*  Skip current sprite  */
       continue;
       };

    /*  Copy current sprite to temporary before encoding  */
    CopySprite(NextSprPtr,&TempSprite);
    Convert(&TempSprite);                      /*  Encode that puppy!  */

    /*  Write next Sprite  */
    if ( Write(OutFile,&TempSprite,SPR_STRUCT_SIZE) != SPR_STRUCT_SIZE )
       {
       sprintf(ErrMsg,"Error writing requested file!");
       Close(OutFile);
       return(FALSE);
       };

    NextSprPtr++;           /*  Get pointer to next sprite  */
    };

Close(OutFile);
return(TRUE);
}


/*  This routine will save sprite data as C source code  */
BOOL SaveCSource(SpritePtr,FileName,Mode,ErrMsg)
struct Sprite *SpritePtr;                           /*  Current Sprite  */
char *FileName;
ULONG Mode;
char *ErrMsg;
{
struct Sprite *FirstSprPtr;                /*  Points to first sprite  */
struct Sprite *NextSprPtr;
struct FileHandle *OutFile;
ULONG LowRange,HighRange;
ULONG Len,NextSprite;
UWORD SprNum,NumSprites;
UWORD *SpriteDataPtr,NextWord;
UWORD SprColor1,SprColor2,SprColor3;
UWORD TempSprite [SPRITE_SIZE];
char OutStr [80];
char *StrPtr;
BOOL Finished;
int i,j,cntr;

/*  Try to open output file  */
if ( ( OutFile = Open(FileName,MODE_NEWFILE) ) == NULL )
   {
   sprintf(ErrMsg,"Could not create requested file!");
   return(FALSE);
   };

/*  Determine loop counter values and number of sprites  */
SprNum = SpritePtr->SpriteNumber;
FirstSprPtr = SpritePtr - SprNum;          /*  Scaled by argument size  */
switch(Mode)
  {
  case CURRENT :
       LowRange = HighRange = SprNum;
       NumSprites = 1;
       NextSprPtr = SpritePtr;
  break;

  case ALL :
       LowRange = LOW_SPRITE;
       HighRange = HIGH_SPRITE;
       NumSprites = MAX_SPRITES;
       NextSprPtr = FirstSprPtr;
  break;

  case FROM :
       LowRange = SprNum;
       HighRange = HIGH_SPRITE;
       NumSprites = MAX_SPRITES - SprNum;
       NextSprPtr = SpritePtr;
  break;

  case UP_TO :
       LowRange = LOW_SPRITE;
       HighRange = SprNum;
       NumSprites = SprNum + 1;
       NextSprPtr = FirstSprPtr;
  break;

  case EXCEPT :
       LowRange = LOW_SPRITE;
       HighRange = HIGH_SPRITE;
       NumSprites = MAX_SPRITES - 1;
       NextSprPtr = FirstSprPtr;
  break;

  default :
       sprintf(ErrMsg,"Illegal save mode requested!");
       Close(OutFile);
       return(FALSE);
  break;
  };

/*  Write sprite header info  */
Finished = FALSE;
cntr = 0;
while ( ! Finished )
  {
  StrPtr = CHeader[cntr];
  if ( *StrPtr == NULL )
     Finished = TRUE;
  else
     {
     Len = (ULONG) strlen(StrPtr);
     if ( Write(OutFile,StrPtr,Len) != Len )
        {
        sprintf(ErrMsg,"Error writing requested file!");
        Close(OutFile);
        return(FALSE);
        };
     cntr++;          /*  Get next CHeader string  */
     };
  };                   /*  End while  */

/*  Write sprite declare info  */
sprintf(OutStr,"struct SprInfo MySprInfo [] = { \n",NULL);
Len = (ULONG) strlen(OutStr);
if ( Write(OutFile,OutStr,Len) != Len )
   {
   sprintf(ErrMsg,"Error writing requested file!");
   Close(OutFile);
   return(FALSE);
   };

/*  Write each selected sprite  */
NextSprite = 0;
for ( i = LowRange; i <= HighRange; i++ )
    {
    if ( Mode == EXCEPT && i == SprNum )
       {
       NextSprPtr++;       /*  Skip current sprite  */
       continue;
       };

    /*  Get next sprite colors  */
    SprColor1 = NextSprPtr->SprColor1;
    SprColor2 = NextSprPtr->SprColor2;
    SprColor3 = NextSprPtr->SprColor3;

    /*  Write sprite colors comments  */
    sprintf(OutStr,"\n /*  Colors for sprite %02d  */ \n",NextSprite);
    Len = (ULONG) strlen(OutStr);
    if ( Write(OutFile,OutStr,Len) != Len )
       {
       sprintf(ErrMsg,"Error writing requested file!");
       Close(OutFile);
       return(FALSE);
       };
 
    /*  Write actual sprite colors  */
    sprintf(OutStr,"0x%03x,0x%03x,0x%03x, \n",SprColor1,SprColor2,SprColor3);
    Len = (ULONG) strlen(OutStr);
    if ( Write(OutFile,OutStr,Len) != Len )
       {
       sprintf(ErrMsg,"Error writing requested file!");
       Close(OutFile);
       return(FALSE);
       };

    /*  Clear sprite PosCtl and attached data  */
    SpriteDataPtr = &NextSprPtr->SpriteData[0];
    CopySprData(SpriteDataPtr,&TempSprite[0]);
    ClearPosCtl(&TempSprite);

    /*  Write sprite data comments  */
    sprintf(OutStr,"/*  Data for sprite %02d  */ \n",NextSprite);
    Len = (ULONG) strlen(OutStr);
    if ( Write(OutFile,OutStr,Len) != Len )
       {
       sprintf(ErrMsg,"Error writing requested file!");
       Close(OutFile);
       return(FALSE);
       };

    /*  Write sprite data  */
    cntr = 0;
    for ( j = 0; j < SPRITE_SIZE; j++ )
        {
        /*  Is this the last word of the last sprite?  */
        NextWord = TempSprite [j];
        if ( i == HighRange && j == (SPRITE_SIZE - 1) )
           sprintf(OutStr,"0x%04x }; \n \n",NextWord);
        else
           {
           /*  Time to write a return?  */
           if ( cntr == (WORDS_PER_LINE - 1) )
              {
              cntr = 0;
              sprintf(OutStr,"0x%04x, \n",NextWord);
              }
           else
              {
              cntr++;
              sprintf(OutStr,"0x%04x,",NextWord);
              };
           };

        /*  Write data line of current sprite  */
        Len = (ULONG) strlen(OutStr);
        if ( Write(OutFile,OutStr,Len) != Len )
           {
           sprintf(ErrMsg,"Error writing requested file!");
           Close(OutFile);
           return(FALSE);
           };
        };                  /*  End j  */

    /*  Get next sprite pointer and number  */
    NextSprPtr++;           
    NextSprite++;
    };                      /*  End i  */

Close(OutFile);
return(TRUE);
}


/*  This routine will save sprite data as assembler source code  */
BOOL SaveAsmSource(SpritePtr,FileName,Mode,ErrMsg)
struct Sprite *SpritePtr;                           /*  Current Sprite  */
char *FileName;
ULONG Mode;
char *ErrMsg;
{
struct Sprite *FirstSprPtr;                /*  Points to first sprite  */
struct Sprite *NextSprPtr;
struct FileHandle *OutFile;
ULONG LowRange,HighRange;
ULONG Len,NextSprite;
UWORD SprNum,NumSprites,*SpriteDataPtr;
UWORD Word1,Word2,Word3,Word4;
UWORD SprColor1,SprColor2,SprColor3;
UWORD TempSprite [SPRITE_SIZE];
char OutStr [80];
char *StrPtr;
BOOL Finished;
int i,j,cntr;

/*  Try to open output file  */
if ( ( OutFile = Open(FileName,MODE_NEWFILE) ) == NULL )
   {
   sprintf(ErrMsg,"Could not create requested file!");
   return(FALSE);
   };

/*  Determine loop counter values and number of sprites  */
SprNum = SpritePtr->SpriteNumber;
FirstSprPtr = SpritePtr - SprNum;          /*  Scaled by argument size  */
switch(Mode)
  {
  case CURRENT :
       LowRange = HighRange = SprNum;
       NumSprites = 1;
       NextSprPtr = SpritePtr;
  break;

  case ALL :
       LowRange = LOW_SPRITE;
       HighRange = HIGH_SPRITE;
       NumSprites = MAX_SPRITES;
       NextSprPtr = FirstSprPtr;
  break;

  case FROM :
       LowRange = SprNum;
       HighRange = HIGH_SPRITE;
       NumSprites = MAX_SPRITES - SprNum;
       NextSprPtr = SpritePtr;
  break;

  case UP_TO :
       LowRange = LOW_SPRITE;
       HighRange = SprNum;
       NumSprites = SprNum + 1;
       NextSprPtr = FirstSprPtr;
  break;

  case EXCEPT :
       LowRange = LOW_SPRITE;
       HighRange = HIGH_SPRITE;
       NumSprites = MAX_SPRITES - 1;
       NextSprPtr = FirstSprPtr;
  break;

  default :
       sprintf(ErrMsg,"Illegal save mode requested!");
       Close(OutFile);
       return(FALSE);
  break;
  };

/*  Put EQU for number of sprites in sixth element of AsmHeader  */
sprintf(OutStr,EquMask,NumSprites);
AsmHeader[6] = OutStr;

/*  Write sprite header info  */
Finished = FALSE;
cntr = 0;
while ( ! Finished )
  {
  StrPtr = AsmHeader[cntr];
  if ( *StrPtr == NULL )
     Finished = TRUE;
  else
     {
     Len = (ULONG) strlen(StrPtr);
     if ( Write(OutFile,StrPtr,Len) != Len )
        {
        sprintf(ErrMsg,"Error writing requested file!");
        Close(OutFile);
        return(FALSE);
        };
     cntr++;          /*  Get next AsmHeader string  */
     };
  };                   /*  End while  */

/*  Write each selected sprite as 68000 data  */
NextSprite = 0;
for ( i = LowRange; i <= HighRange; i++ )
    {
    if ( Mode == EXCEPT && i == SprNum )
       {
       NextSprPtr++;       /*  Skip current sprite  */
       continue;
       };

    /*  Get next sprite colors  */
    SprColor1 = NextSprPtr->SprColor1;
    SprColor2 = NextSprPtr->SprColor2;
    SprColor3 = NextSprPtr->SprColor3;

    /*  Write sprite colors  */
    sprintf(OutStr,ColorMask,NextSprite,SprColor1,SprColor2,SprColor3);
    Len = (ULONG) strlen(OutStr);
    if ( Write(OutFile,OutStr,Len) != Len )
       {
       sprintf(ErrMsg,"Error writing requested file!");
       Close(OutFile);
       return(FALSE);
       };

    /*  Clear sprite PosCtl and attached data  */
    SpriteDataPtr = &NextSprPtr->SpriteData[0];
    CopySprData(SpriteDataPtr,&TempSprite[0]);
    ClearPosCtl(&TempSprite);

    /*  Write sprite data  */
    cntr = 0;
    for ( j = 0; j < SPRITE_SIZE; j += 4 )
        {
        /*  Get the next four words of the current sprite  */
        Word1 = TempSprite [j+0]; Word2 = TempSprite [j+1];
        Word3 = TempSprite [j+2]; Word4 = TempSprite [j+3];

        if ( j == 0 )     /*  First line?  */
            sprintf(OutStr,DataMask1,NextSprite,Word1,Word2,Word3,Word4);
        else
            sprintf(OutStr,DataMask2,Word1,Word2,Word3,Word4);
            
        /*  Write data line of current sprite  */
        Len = (ULONG) strlen(OutStr);
        if ( Write(OutFile,OutStr,Len) != Len )
           {
           sprintf(ErrMsg,"Error writing requested file!");
           Close(OutFile);
           return(FALSE);
           };
        };                  /*  End j  */

    /*  Get next sprite pointer and number  */
    NextSprPtr++;           
    NextSprite++;
    };                      /*  End i  */

Close(OutFile);
return(TRUE);
}


/*  This subroutine will encode and decode a Sprite structure  */
Convert(SpritePtr)
struct Sprite *SpritePtr;
{
UWORD *WordPtr,NextWord;
int i;

/*  This code is a increasing XOR encryption scheme  */
WordPtr = (UWORD *) SpritePtr;
for ( i = 0; i < SPR_STRUCT_SIZE; i += WORD_SIZE )
    {
    NextWord = *WordPtr;
    NextWord ^= i;
    *WordPtr = NextWord;
    WordPtr++;                    /*  Get next word of sprite  */
    };
}

    
