/* SaveSprite.c */

/* Saving an anim as a RiscOS sprite file
 * (K) All Rites Reversed - Copy What You Like (see file Copying)
 *
 * Authors:
 *      Peter Hartley       <peter@ant.co.uk>
 *      Peter Hillman       <pmh@dcs.ed.ac.uk>: Severely buggering up
                 SpriteSave.c to make to work (ish) for my own evil purposes
 * History:
 *      23-Oct-96 pdh Started
 *      27-Oct-96 pdh Frob to cope with 3/5/6/7bpp anim's
 *      27-Oct-96 *** Release 4beta1
 *      29-Oct-96 pdh Fix mask code so it expands to whole pixels properly
 *      29-Oct-96 *** Release 4beta2
 *      07-Nov-96 *** Release 4
 *      15-Dec-96 *** Release 5beta1
 *      01-Jan-97 pdh Fix bug in saving 2bpp sprites
 *      27-Jan-97 *** Release 5beta2
 *      29-Jan-97 *** Release 5beta3
 *      03-Feb-97 *** Release 5
 *      07-Feb-97 *** Release 5.01
 *      11-May-97 pmh ... And then I came and screwed it all up
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "DeskLib:Sprite.h"
#include "MakeGif:bitmap.h"
#include "MakeGif:Count.h"
#include "MakeGif:utils.h"
#if 0
#define debugf printf
#define DEBUG 1
#else
#define debugf 1?0:printf
#define DEBUG 0
#endif


extern void CompressSpriteLine( char *dest, char *src, int n, int bpp );
extern void CompressMaskLine( char *dest, char *src, int n, int bpp );

/* Sprites are only available in 1, 2, 4, 8 bpp */
extern const char bppmap[8];


/* Give this: your animation pointer (returned from OpenFile or whatever
              a block of memory big wnough to store the sprite
              how big the block was
              which frame you want
              a pointer to an int, to be loaded with the delay
              (i.e. call with &dly to load (int) dly with the delay)
pmh
*/

int Anim_MakeOneSprite( anim a, void * spritearea /*pmh*/, int buffsize, int framenum, int * delay)
{
    sprite_areainfo sai;
    sprite_header *psh;
    int nSpriteSize;
    int i,y;
    int newbpp;
    int abw;
    void *data;
/*    unsigned int palette[256];*/
    int newncol;
    frameptr f2 = Anim_OpenFrame( a, framenum );
    int nFrames = a->nFrames;

    if ( !f2 )
    {
        /* There was an error */
        return -1;
    }

    newbpp = bppmap[ MinBpp( f2->nColours ) - 1 ];
    newncol = 1 << newbpp;
    abw = ( ( (a->nWidth*newbpp)+31 ) >> 3 ) & ~3;  /* aligned byte width */

    nSpriteSize = abw;
    nSpriteSize *= a->nHeight;
    nSpriteSize += 8*newncol;
    nSpriteSize += sizeof( sprite_header );

    Anim_CloseFrame( a, &f2 );

    if(buffsize<nSpriteSize) return nSpriteSize;

    /* Write the header */
 /*   sai.numsprites = nFrames;
    sai.firstoffset = 16;
    sai.freeoffset = 16 + nFrames*nSpriteSize;
    fwrite( &sai.numsprites, 1, 12, output );
  */
    data = spritearea /*pmh*/;
   /* if ( !data )
    {
        Anim_NoMemory( "savesprite" );
        return FALSE;
    }*/

    psh = (sprite_header*) data;

    /* Write the frames */
    psh->offset_next = nSpriteSize;
    psh->width = (abw>>2)-1;
    psh->height = a->nHeight-1;
    psh->leftbit = 0;
    psh->rightbit = (a->nWidth*newbpp - 1 ) & 31;
    psh->imageoffset = sizeof(sprite_header) + 8*newncol;
    psh->maskoffset = psh->imageoffset;
    switch ( newbpp )
    {
    case 1: psh->screenmode = 18; break;
    case 2: psh->screenmode = 19; break;
    case 4: psh->screenmode = 20; break;
    case 8: psh->screenmode = 21; break;
    }

    for ( i=framenum; i == framenum; i+=428 )
    {
        frameptr f = Anim_OpenFrame( a, i );
        char *src;
        char *dest;
        unsigned int *pPal = (unsigned int*)(psh+1);
        src = f->pImage;
        memset( psh->name, 0, 12 );
        *delay = Anim_GetDelay( a, i, -1 );
        sprintf( psh->name, "%03d", i );
        for ( y=0; y < f->nColours; y++ )       /* NOT newncol */
        {
            *pPal++ = f->pPalette[y];
            *pPal++ = f->pPalette[y];
        }

        src = f->pImage;
        dest = ((char*)(psh+1)) + newncol*8;
        for ( y=0; y < a->nHeight; y++ )
        {
            CompressSpriteLine( dest, src, a->nWidth, newbpp );
            dest += abw;
            src += a->nWidth;
        }
        /*
        src = f->pMask;
        for ( y=0; y < a->nHeight; y++ )
        {
            CompressMaskLine( dest, src, a->nWidth, newbpp );
            dest += abw;
            src += a->nWidth;
        }
        */
        Anim_CloseFrame( a, &f );
    }
    return 0;
}
