// (c) 1994-2007 Electronic Arts Inc.

/* ABSTRACT */
/*------------------------------------------------------------------*/
/*                                                                  */
/*                   FLM - Adobe Filmstrip Gimex                    */
/*                                                                  */
/*                    by FrANK G. Barchard, EAC                     */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Version Date   SE History:                                       */
/* ------- ----   -- --------                                       */
/*    1.00 990713 FB Adobe Filmstrip 1.0 based on HSI gimex         */
/*    1.01 990728 FB 1555 format extension                          */
/*    1.02 990805 FB ginfo->fps supported (1..1000)                 */
/*    1.03 000404 FB about->movie                                   */
/*    1.04 001207 FB 16 bpp friendly seek                           */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Module Notes:                                                    */
/* -------------                                                    */
/* 15,32 bit                                                        */
/* Reentrant                                                        */
/* Line buffered                                                    */
/* Files: flmread.cpp flmwrite.cpp flmgimex.h                           */
/*                                                                  */
/* Normal FLM is 32 bpp only.  EAC has extended it in a nonstandard */
/* way to 1555 as well.                                             */
/* 1555 format is intel abbbbbgggggrrrrr                            */
/* 8888 format is motorolla rgba                                    */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Format Notes:                                                    */
/* -------------                                                    */
/* FLM files are generated by Adobe Premiere 2.0.  They are a       */
/* raw movie format with the header at the end.                     */
/* Photoshop imports/exports FLM as a tall image containing all     */
/* the frames                                                       */
/*                                                                  */
/* The image is top/left to bottom/right, no padding, RGBA          */
/*                                                                  */
/*------------------------------------------------------------------*/
/* END ABSTRACT */

#include <string.h>
#include "gimex.h"
#include "flmgimex.h"

/****************************************************************/
/*  Information Functions                                       */
/****************************************************************/

GABOUT * GCALL FLM_about(void)
{
    GABOUT *info;

    info = (GABOUT *) galloc(sizeof(GABOUT));
    if (info)
    {
        memset(info, 0, sizeof(GABOUT));

        info->signature       = GMAKEID('.','F','L','M');
        info->size            = sizeof(GABOUT);
        info->version         = GIMEX_VERSION;
        info->canimport       = 1;    /* supports importing */
        info->canexport       = 1;    /* supports exporting */
        info->importpacked    = 0;    /* supports importing packed */
        info->exportpacked    = 0;    /* supports exporting packed */
        info->import8         = 0;    /* supports importing 8 bit indexed */
        info->export8         = 0;    /* supports exporting 8 bit indexed */
        info->import32        = 1;    /* supports importing 32 bit direct rgb */
        info->export32        = 1;    /* supports exporting 32 bit direct rgb */
        info->multiframe      = 1;    /* supports multiple frames */
        info->multifile       = 0;    /* format requires additional files or resource fork */
        info->multisize       = 0;    /* supports each frame different size */
        info->framebuffer     = 0;    /* module requires memory to buffer entire frame */
        info->external        = 0;    /* module uses external resources */
        info->usesfile        = 1;    /* module is file based */
        info->globalpalette   = 0;    /* one palette per file */
        info->maxframename    = 0;    /* max frame name character */
        info->movie           = 1;    /* movie file format */
        info->file64          = 1;    /* this format supports 64 bit file sizes */
        info->defaultquality  = 100;  /* default pack quality */
        info->mactype[0]      = GMAKEID('.','F','L','M');   /* mac file system types used */
        strcpy(info->extensions[0], ".flm");                /* extensions */
        strcpy(info->authorstr,     "FrANK G. Barchard");   /* author */
        strcpy(info->versionstr,    "1.04");                /* version # */
        strcpy(info->shorttypestr,  "FLM");                 /* type */
        strcpy(info->wordtypestr,   "FilmStrip");           /* wordtype */
        strcpy(info->longtypestr,   "Adobe FilmStrip");     /* longtype */
    }
    return(info);
}

/* check for reasonable header: */
/* id at len-36 is 'Rand' */

int GCALL FLM_is(GSTREAM *g)
{
    FLMHeaderStruct flmheader;
    GPOS framesize;
    int width;
    int height;
    int signature;
    int ok=0;

    framesize = glen(g);
    if (framesize>36)
    {
        gseek(g,framesize-36);
        ok = gread(g, (char *) &flmheader, 36);   /* read header */
        if (ok)
        {
            ok = 0;
            width       = FLMGETFIELD(flmheader.width);                 /* Width of bitmap in pixels */
            height      = FLMGETFIELD(flmheader.height);                /* Height of bitmap in pixels */
            signature   = FLMGETFIELD(flmheader.signature);             /* signature */

            if (signature==GMAKEID('R','a','n','d')
             && width>0 && width<=16384
             && height>0 && height<=16384)
                ok = 100;
        }
    }
    return(ok);
}

/****************************************************************/
/*  Import Functions                                            */
/****************************************************************/

int GCALL FLM_open(GINSTANCE **gxptr, GSTREAM *g, const char *pathname,bool framecountflag)
{
    GINSTANCE *gx;
    GPOS framesize;
    int numframes;
    int signature;
    int ok=0;

    gx = (GINSTANCE *) galloc(sizeof(GINSTANCE));
    if (gx)
    {
        memset(gx, 0, sizeof(GINSTANCE));
        *gxptr = gx;
        gx->frames = 1;
        gx->signature=GMAKEID('.','F','L','M');
        gx->size=sizeof(GINSTANCE);
        gx->gstream = g;

        gx->gref = galloc(sizeof(FLMHeaderStruct));
        if (gx->gref)
        {
            framesize = glen(g);
            if (framesize>36)
            {
                FLMHeaderStruct *flmheader = (FLMHeaderStruct *)gx->gref;
                gseek(g,framesize-36);
                ok = gread(g, (char *) flmheader, 36);   /* read header */
                if (ok)
                {
                    ok = 0;
                    signature   = FLMGETFIELD(flmheader->signature);
                    numframes   = FLMGETFIELD(flmheader->numframes);

                    if (signature==GMAKEID('R','a','n','d'))
                        ok = gx->frames = numframes;
                }
            }
            if (!ok)
                gfree(gx->gref);
        }
    }

    return(ok);
}

GINFO * GCALL FLM_info(GINSTANCE *gx, int framenum)
{
    FLMHeaderStruct *flmheader;
    GINFO *ginfo=0;
    int width;
    int height;
    int eaformat;
    int framespersec;

    if (framenum < gx->frames)
        ginfo = (GINFO *) galloc(sizeof(GINFO));

    if (ginfo)
    {
        memset(ginfo,0,sizeof(GINFO));

        flmheader = (FLMHeaderStruct *) gx->gref;

        width        = FLMGETFIELD(flmheader->width);                 /* Width of bitmap in pixels */
        height       = FLMGETFIELD(flmheader->height);                /* Height of bitmap in pixels */
        eaformat     = FLMGETFIELD(flmheader->eaformat);              /* EA extension. 0xea02=1555 */
        framespersec = FLMGETFIELD(flmheader->framespersec);          /* frames per second */

        ginfo->signature        = GMAKEID('.','F','L','M');   /* Gimex type */
        ginfo->size             = sizeof(GINFO);            /* Length of GINFO */
        ginfo->version          = GIMEX_VERSION;
        ginfo->framenum         = framenum;    /* Current frame */
        ginfo->width            = width;
        ginfo->height           = height;
        ginfo->bpp              = 32;
        ginfo->originalbpp      = 32;
        ginfo->subtype          = 0;    /* Internal format sub-type 0-default */
        ginfo->packed           = 0;    /* Type of packing on original image. 0 none, 1 run, n other */
        ginfo->quality          = 100;  /* Quality of lossy packing 0..100 */
        ginfo->alphabits        = 8;    /* Number of bits in alpha channel */
        ginfo->redbits          = 8;    /* Number of bits in red channel */
        ginfo->greenbits        = 8;    /* Number of bits in grreen channel */
        ginfo->bluebits         = 8;    /* Number of bits in blue channel */
        ginfo->centerx          = 0;    /* Center Point relative to upper left corner */
        ginfo->centery          = 0;
        ginfo->defaultx         = 0;    /* Default Coordinate Point */
        ginfo->defaulty         = 0;
        ginfo->numhotspots      = 0;    /* Number of Hot Spots defined */
        ginfo->fps              = (float) framespersec; /* frames per second */

        if (eaformat==0xea02)
        {
            ginfo->originalbpp      = 16;
            ginfo->alphabits        = 1;    /* Number of bits in alpha channel */
            ginfo->redbits          = 5;    /* Number of bits in red channel */
            ginfo->greenbits        = 5;    /* Number of bits in grreen channel */
            ginfo->bluebits         = 5;    /* Number of bits in blue channel */
        }

    }

    return(ginfo);
}

int GCALL FLM_read(GINSTANCE *gx, GINFO *ginfo, char *dest, int rowbytes)
{
    FLMHeaderStruct *flmheader;
    char *linebuf;
    char *lineptr;
    int bpp;
    int bpl;
    int width;
    int height;
    int leading;
    int eaformat;
    int x;
    int y;
    int ok=0;
    ARGB *d;
    GPOS framesize;

    flmheader = (FLMHeaderStruct *) gx->gref;

    width        = FLMGETFIELD(flmheader->width);                 /* Width of bitmap in pixels */
    height       = FLMGETFIELD(flmheader->height);                /* Height of bitmap in pixels */
    leading      = FLMGETFIELD(flmheader->leading);               /* Rows unused after each frame */
    eaformat     = FLMGETFIELD(flmheader->eaformat);              /* EA extension. 0xea02=1555 */

    bpp = eaformat==0xea02?16:32;
    framesize = width*(height+leading)*bpp/8;
    gseek(gx->gstream,framesize*ginfo->framenum);

    bpl = ginfo->width*bpp/8;

    linebuf = (char *)galloc(bpl);

    if (linebuf)
    {
        ok = 1;

        for (y=0; y<ginfo->height && ok; ++y)
        {
            d = (ARGB *) (dest+rowbytes*y);

            ok = gread(gx->gstream,linebuf,bpl);
            lineptr = linebuf;

            if (bpp==16)
            {
                int aRgb5;

                for (x=0; x<ginfo->width; ++x)
                {
                    aRgb5 = ggeti(lineptr,2);
                    d->a = (unsigned char)((((aRgb5>>15)&1 )*255+0)/1);
                    d->b = (unsigned char)((((aRgb5>>10)&31)*255+16)/31);
                    d->g = (unsigned char)((((aRgb5>>5 )&31)*255+16)/31);
                    d->r = (unsigned char)((((aRgb5>>0 )&31)*255+16)/31);
                    ++d;
                    lineptr += 2;
                }
            }
            else
            {
                for (x=0; x<ginfo->width; ++x)
                {
                    d->r = lineptr[0];
                    d->g = lineptr[1];
                    d->b = lineptr[2];
                    d->a = lineptr[3];
                    ++d;
                    lineptr += 4;
                }
            }
        }
        gfree(linebuf);
    }
    return(ok);
}

int GCALL FLM_close(GINSTANCE *gx)
{
    int ok=0;

    if (gx)
    {
        if (gx->gref)
            gfree(gx->gref);

        ok = gfree((void *) gx);
    }
    return(ok);
}

