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

/* ABSTRACT */
/*------------------------------------------------------------------*/
/*                                                                  */
/*                    XPR - XBox Packed Resource                    */
/*                                                                  */
/*                    by FrANK G. Barchard, EAC                     */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Version Date   SE History:                                       */
/* ------- ----   -- --------                                       */
/*    1.00 061127 FB base on HSI, xprconvert, unbundler             */
/*    1.01 061205 FB AL88                                           */
/*    1.02 070131 FB short swap for bigendian machines              */
/*    1.03 070605 FB untile/short swap allow padded dxt sizes       */
/*    1.04 070615 FB swizzle subtype                                */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Module Notes:                                                    */
/* -------------                                                    */
/* 32 bit                                                           */
/* Reentrant                                                        */
/* Line buffered                                                    */
/* Files: xprread.cpp xprwrite.cpp xprgimex.h                       */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Format Notes:                                                    */
/* -------------                                                    */
/* XPR files where are generated by Xbox360 bundler tool            */
/* Structure of file                                                */
/*   xpr header 16 bytes. id, headersize, texture size, count       */
/*   resource array 16 bytes per entry.                             */
/*      type ('TX2D'), offset, size (0x34), name *                  */
/*      add 12 to all resource offset/pointers                      */
/*      offset points to d3d texture                                */
/*                                                                  */
/* d3dtexture is 34 bytes                                           */
/*     resource   6 dwords                                          */
/*     mipflush   1 dword                                           */
/*     gputexture 6 dwords (more important info here)               */
/*                                                                  */
/* texels begin after 'headersize'. gputexture offsets are from     */
/* from here. each texture is on 4k boundary                        */
/* textures can be swizzled                                         */
/*   swizzle uses 32x32 tiles with out of order content             */
/*   for swizzle info, see these by Andy Eakins                     */
/*   http://globaltechdocs.ea.com/MediaWiki/index.php?title=RWGraphics:Data_Containers_Coordinate_Generators) */
//   EARenderWare/packages/datacontainer_base/dev/modules/coordinategenerator */
/* LIN textures are row padded to 256 bytes                         */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/*------------------------------------------------------------------*/
/* END ABSTRACT */

#define SUB_SWIZZLE 8192
/*       8192    0x2000 Swizzle (aka swizzle)                       */

#if 0
/*
bundler AL88
C:\env\egami\gx\dev\test>xd john.xpr -h
00020: 00000003 00000001 00000000 00000000
       00000000 ffff0000 ffff0000 02000002
	   0000004a 001fe0ff 00000400 00000000
	   00000a00

gx AL88
C:\env\egami\gx\dev>xd john.xpr -h
00020: 00000003 00000001 00000000 00000000  ................
00030: 00000000 ffff0000 ffff0000 02000002  ................
00040: 0000008a 001fe0ff 00000c14 00000000  ......`.........
00050: 00000a00
*/
#endif

#include <string.h>
#include "gimex.h"
#include "xprgimex.h"
#include "codex.h"
#include "dxtcodex.h"

// for dxt
static void XPRunorderblocks(int width, int height, int padwidth, int padheight, int rowbytes, const void *source, void *dest, int Tiled, int DataFormat)
{
    int bx,by;
    const unsigned char *s = (const unsigned char *)source;

    if (Tiled)  // tiled DXT1
    {
        if (DataFormat==GPUTEXTUREFORMAT_DXT1)
        {
            int t=0;
            for (int yy1=0; yy1<padheight; yy1+=128)
            {
                for (int xx1=0; xx1<padwidth; xx1+=128)
                {
                    int c=0;
                    for (int yy2=0; yy2<128; yy2+=4)
                    {
                        for (int xx2=0; xx2<128; xx2+=4)
                        {
                            int x0=(c   )&1;
                            int y0=(c>>1)&1;
                            int x1=(c>>2)&1;
                            int x3=(c>>3)&1;
                            int x4=((c>>4)&1) ^ ((c>>9)&1);
                            int x2=(c>>5)&1;
                            int y1=(c>>6)&1;
                            int y2=(c>>7)&1;
                            int y4=(c>>8)&1;
                            int y3=(c>>9)&1;

                            int x=xx1+((x4<<4)|(x3<<3)|(x2<<2)|(x1<<1)|(x0))*4;
                            int y=yy1+((y4<<4)|(y3<<3)|(y2<<2)|(y1<<1)|(y0))*4;

                            if (y<height && x<width)
                            {
                                for (by=0; by<4; ++by) // rows of block
                                {
                                    for (bx=0; bx<4; ++bx) // columns of block
                                    {
                                        if ((y+by)<height && (x+bx)<width)
                                            *(int *) ((char *)dest + (y+by)*rowbytes + (x+bx)*4) = *(int *) (s + by*16 + bx*4);
                                    }
                                }
                            }
                            s += 64;
                            ++c;
                        }
                    }
                }
            }
        }
        else // dxt3/5
        {
            int t=0;
            for (int yy1=0; yy1<padheight; yy1+=128)
            {
                for (int xx1=0; xx1<padwidth; xx1+=128)
                {
                    int c=0;
                    for (int yy2=0; yy2<128; yy2+=4)
                    {
                        for (int xx2=0; xx2<128; xx2+=4)
                        {
                            int y0=(c   )&1;
                            int x0=(c>>1)&1;
                            int x3=(c>>2)&1;
                            int x4=((c>>3)&1) ^ ((c>>9)&1);
                            int x1=(c>>4)&1;
                            int x2=(c>>5)&1;
                            int y1=(c>>6)&1;
                            int y4=(c>>7)&1;
                            int y2=(c>>8)&1;
                            int y3=(c>>9)&1;

                            int x=xx1+((x4<<4)|(x3<<3)|(x2<<2)|(x1<<1)|(x0))*4;
                            int y=yy1+((y4<<4)|(y3<<3)|(y2<<2)|(y1<<1)|(y0))*4;

                            if (y<height && x<width)
                            {
                                for (by=0; by<4; ++by) // rows of block
                                {
                                    for (bx=0; bx<4; ++bx) // columns of block
                                    {
                                        if ((y+by)<height && (x+bx)<width)
                                            *(int *) ((char *)dest + (y+by)*rowbytes + (x+bx)*4) = *(int *) (s + by*16 + bx*4);
                                    }
                                }
                            }
                            s += 64;
                            ++c;
                        }
                    }
                }
            }
        }
    }
    else // LIN_DXT
    {
        for (int y=0; y<height; y+=4)
        {
            for (int x=0; x<width; x+=4)
            {
                for (by=0; by<4; ++by) // rows of block
                {
                    for (bx=0; bx<4; ++bx) // columns of block
                    {
                        if ((y+by)<height && (x+bx)<width)
                            *(int *) ((char *)dest + (y+by)*rowbytes + (x+bx)*4) = *(int *) (s + by*16 + bx*4);
                    }
                }
                s += 64;
            }
        }
    }
}

#ifndef TYPE3PR
// dxt needs all shorts swapped first
static void ShortSwap(unsigned char *framebuf, int framesize)
{
    for (int i=0; i<framesize; i+=2)
    {
        gputi(framebuf, ggetm(framebuf,2), 2);
        framebuf += 2;
    }
}
#endif

static void XPRuntile(int width, int height, int destrowbytes, const void *source, void *dest)
{
    const unsigned char *s = (const unsigned char *)source;
    destrowbytes = width*4; // fudge

    for (int ty=0; ty<height; ty+=32)       // 32x32 tiles
    {
        for (int tx=0; tx<width; tx+=32)
        {
            for (int by=0; by<32; by+=2)    // 8x2 blocks
            {
                for (int bx=0; bx<32; bx+=8)
                {
                    int bx2=bx^((by&8)/8)*16; // 16x8 swap

                    for (int y=0; y<2; y+=1)    // 4x1
                    {
                        for (int x=0; x<8; x+=1)
                        {
                            int y2=x/4;
                            int x2=(x&3)+y*4;
                            *(int *) ((char *)dest + (ty+by+y2)*destrowbytes + (tx+bx2+x2)*4) = *(int *) s;
                            s += 4;
                        }
                    }
                }
            }
        }
    }
}

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

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

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

        info->size            = sizeof(GABOUT);
        info->version         = GIMEX_VERSION;
        info->canimport       = 1;    /* supports importing */
        info->canexport       = 1;    /* supports exporting */
        info->importpacked    = 1;    /* supports importing packed */
        info->exportpacked    = 1;    /* 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       = 1;    /* 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    = XPR_MAXFRAMENAME-1;   /* max frame name to help with exporter size calc */
        info->defaultquality  = 70;   /* default pack quality (for dxt) */
        info->movie           = 0;    /* movie file format */
        info->file64          = 0;    /* this format supports 64 bit file sizes */
        strcpy(info->authorstr,     "FrANK G. Barchard");   /* author */
        strcpy(info->versionstr,    "1.04");                /* version # */
#ifdef TYPE3PR
        info->signature       = GMAKEID('.','3','P','R');
		info->mactype[0]      = GMAKEID('.','3','P','R');   /* mac file system types used */
        strcpy(info->extensions[0], ".3pr");                /* extensions */
        strcpy(info->shorttypestr,  "3PR");                 /* type */
        strcpy(info->wordtypestr,   "3PR");                 /* wordtype */
        strcpy(info->longtypestr,   "PS3 Packed Resource"); /* longtype */
#else
		info->signature       = GMAKEID('.','X','P','R');
		info->mactype[0]      = GMAKEID('.','X','P','R');   /* mac file system types used */
        strcpy(info->extensions[0], ".xpr");                /* extensions */
        strcpy(info->shorttypestr,  "XPR");                 /* type */
        strcpy(info->wordtypestr,   "XPR");                 /* wordtype */
        strcpy(info->longtypestr,   "XBox Packed Resource");/* longtype */
#endif

    }
    return(info);
}

/* check for reasonable header: */
/* has 4 byte id */

// C:\env\egami\gx\dev\test>xd ie.xpr -h
//00000: 58505232 00000800 000f8000 00000003  XPR2............

int GCALL XPR_is(GSTREAM *g)
{
    unsigned char xprheader[4];
    int ok=0;

    gseek(g,(GPOS)0);
    if (gread(g,xprheader,4))
    {
#ifdef TYPE3PR
		if (xprheader[0]==0x33
#else
		if (xprheader[0]==0x58
#endif
	     && xprheader[1]==0x50
         && xprheader[2]==0x52
         && xprheader[3]==0x32)
            ok = 100;
    }
    return(ok);
}

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

int GCALL XPR_open(GINSTANCE **gxptr, GSTREAM *g, const char *pathname,bool framecountflag)
{
    GINSTANCE *gx;
    int ok=0;
    unsigned char xprheader[16];

    gx = (GINSTANCE *) galloc(sizeof(GINSTANCE));
    if (gx)
    {
        memset(gx, 0, sizeof(GINSTANCE));
        *gxptr = gx;
#ifdef TYPE3PR
		gx->signature=GMAKEID('.','3','P','R');
#else
		gx->signature=GMAKEID('.','X','P','R');
#endif
        gx->size=sizeof(GINSTANCE);
        gx->gstream = g;

        gseek(g,(GPOS)0);
        if (gread(g,xprheader,16))
        {
            gx->frames = ggetm(xprheader+12,4);
            int headersize = ggetm(xprheader+4,4); // typically 2048

            gx->gref = galloc(headersize);
            if (gx->gref)
            {
                gseek(gx->gstream,(GPOS)0);
                if (gread(gx->gstream,gx->gref,headersize))
                {
                    ok = gx->frames;
                }
            }
        }
        if (gx->gref && !ok)
            gfree(gx->gref);
    }
    return(ok);
}

/*
typedef struct _XGTEXTURE_DESC
{
    D3DRESOURCETYPE     ResourceType;
        DWORD Common;
        DWORD ReferenceCount;
        DWORD Fence;
        DWORD ReadFence;
        DWORD Identifier;
        DWORD BaseFlush;
        mipflush?
    UINT                Width;
    UINT                Height;
    UINT                Depth;
    D3DFORMAT           Format;
    UINT                RowPitch;
    UINT                SlicePitch;
    UINT                BitsPerPixel;
    UINT                WidthInBlocks;
    UINT                HeightInBlocks;
    UINT                DepthInBlocks;
    UINT                BytesPerBlock;
    INT                 ExpBias;
    DWORD               Flags;
    D3DMULTISAMPLE_TYPE MultiSampleType;
} XGTEXTURE_DESC;
*/

#if 0
typedef struct
{
    DWORD Width                         : 13;   // DWORD
    DWORD Height                        : 13;   // DWORD
    DWORD                               : 6;
} GPUTEXTURESIZE_2D;

typedef union {
    struct {
        // DWORD 0:

        DWORD Type                      : 2;    // GPUCONSTANTTYPE
        DWORD SignX                     : 2;    // GPUSIGN
        DWORD SignY                     : 2;    // GPUSIGN
        DWORD SignZ                     : 2;    // GPUSIGN
        DWORD SignW                     : 2;    // GPUSIGN
        DWORD ClampX                    : 3;    // GPUCLAMP
        DWORD ClampY                    : 3;    // GPUCLAMP
        DWORD ClampZ                    : 3;    // GPUCLAMP
        DWORD                           : 2;
        DWORD                           : 1;
        DWORD Pitch                     : 9;    // DWORD
        DWORD Tiled                     : 1;    // BOOL

        // DWORD 1:

        DWORD DataFormat                : 6;    // GPUTEXTUREFORMAT
        DWORD Endian                    : 2;    // GPUENDIAN
        DWORD RequestSize               : 2;    // GPUREQUESTSIZE
        DWORD Stacked                   : 1;    // BOOL
        DWORD ClampPolicy               : 1;    // GPUCLAMPPOLICY
        DWORD BaseAddress               : 20;   // DWORD

        // DWORD 2:

        union
        {
            GPUTEXTURESIZE_1D OneD;
            GPUTEXTURESIZE_2D TwoD;
            GPUTEXTURESIZE_3D ThreeD;
            GPUTEXTURESIZE_STACK Stack;
        } Size;

        // DWORD 3:

        DWORD NumFormat                 : 1;    // GPUNUMFORMAT
        DWORD SwizzleX                  : 3;    // GPUSWIZZLE
        DWORD SwizzleY                  : 3;    // GPUSWIZZLE
        DWORD SwizzleZ                  : 3;    // GPUSWIZZLE
        DWORD SwizzleW                  : 3;    // GPUSWIZZLE
        INT   ExpAdjust                 : 6;    // int
        DWORD MagFilter                 : 2;    // GPUMINMAGFILTER
        DWORD MinFilter                 : 2;    // GPUMINMAGFILTER
        DWORD MipFilter                 : 2;    // GPUMIPFILTER
        DWORD AnisoFilter               : 3;    // GPUANISOFILTER
        DWORD                           : 3;
        DWORD BorderSize                : 1;    // DWORD

        // DWORD 4:

        DWORD VolMagFilter              : 1;    // GPUMINMAGFILTER
        DWORD VolMinFilter              : 1;    // GPUMINMAGFILTER
        DWORD MinMipLevel               : 4;    // DWORD
        DWORD MaxMipLevel               : 4;    // DWORD
        DWORD MagAnisoWalk              : 1;    // BOOL
        DWORD MinAnisoWalk              : 1;    // BOOL
        INT   LODBias                   : 10;   // int
        INT   GradExpAdjustH            : 5;    // int
        INT   GradExpAdjustV            : 5;    // int

        // DWORD 5:

        DWORD BorderColor               : 2;    // GPUBORDERCOLOR
        DWORD ForceBCWToMax             : 1;    // BOOL
        DWORD TriClamp                  : 2;    // GPUTRICLAMP
        INT   AnisoBias                 : 4;    // int
        DWORD Dimension                 : 2;    // GPUDIMENSION
        DWORD PackedMips                : 1;    // BOOL
        DWORD MipAddress                : 20;   // DWORD
    };
    DWORD dword[6];
} GPUTEXTURE_FETCH_CONSTANT;
#endif


GINFO * GCALL XPR_info(GINSTANCE *gx, int framenum)
{
    unsigned char *xprheader;
    GINFO *ginfo=0;

    xprheader = (unsigned char*)gx->gref;

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

        /* template for ginfo */

#ifdef TYPE3PR
        ginfo->signature        = GMAKEID('.','3','P','R');   /* Gimex type */
#else
		ginfo->signature        = GMAKEID('.','X','P','R');   /* Gimex type */
#endif
	    ginfo->size             = sizeof(GINFO);            /* Length of GINFO */
        ginfo->version          = GIMEX_VERSION;
        ginfo->framenum         = framenum;    /* Current frame */
        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        = 0;    /* 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 */

        unsigned char *resource = xprheader+16+framenum*16;
        char *resourcename = (char *)xprheader+12+ggetm(resource+12,4);
        strcpy(ginfo->framename,resourcename);
        unsigned char *texture = xprheader+12+ggetm(resource+4,4);
        unsigned char *gputexture = texture+6*4+1*4; // d3dtexture is 6 dwords. then 1 mipflush dword.  gputexture is 6 dwords
        unsigned int TextureSizeTwoD = ggetm(gputexture+8,4);
        ginfo->width = (TextureSizeTwoD&8191)+1;
        ginfo->height = ((TextureSizeTwoD>>13)&8191)+1;

        unsigned int Tiled = ggetm(gputexture+0,4)>>31;
        ginfo->subtype = Tiled?SUB_SWIZZLE:0;

        ginfo->bpp              = 32;   /* Bits per pixel (8 or 32) */
        ginfo->originalbpp      = 32;   /* Bits per pixel in original image (1 to 32) */
        ginfo->numcolours       = 0;    /* Number of colours in original indexed palette */

        unsigned int DataFormat = ggetm(gputexture+4,4)&63;
        switch (DataFormat)
        {
            case GPUTEXTUREFORMAT_5_6_5:
                ginfo->alphabits = 0;
                ginfo->redbits = 5;
                ginfo->greenbits = 6;
                ginfo->bluebits = 5;
                ginfo->originalbpp = 16;
                break;

            case GPUTEXTUREFORMAT_1_5_5_5:
                ginfo->alphabits = 1;
                ginfo->redbits = 5;
                ginfo->greenbits = 5;
                ginfo->bluebits = 5;
                ginfo->originalbpp = 16;
                break;

            case GPUTEXTUREFORMAT_8_8_8_8:
                ginfo->alphabits = 8;
                ginfo->redbits = 8;
                ginfo->greenbits = 8;
                ginfo->bluebits = 8;
                ginfo->originalbpp = 32;
                break;

            case GPUTEXTUREFORMAT_8_8:
                ginfo->alphabits = 8;
                ginfo->redbits = 8;
                ginfo->greenbits = 0;
                ginfo->bluebits = 0;
                ginfo->originalbpp = 16;
                break;

            case GPUTEXTUREFORMAT_4_4_4_4:
                ginfo->alphabits = 4;
                ginfo->redbits = 4;
                ginfo->greenbits = 4;
                ginfo->bluebits = 4;
                ginfo->originalbpp = 16;
                break;

            case GPUTEXTUREFORMAT_DXT1:
                ginfo->alphabits = 1;
                ginfo->redbits = 5;
                ginfo->greenbits = 6;
                ginfo->bluebits = 5;
                ginfo->originalbpp = 17;
                ginfo->packed = 3;             // 3 is DXT
                break;

            case GPUTEXTUREFORMAT_DXT2_3:
                ginfo->alphabits = 4;
                ginfo->redbits = 5;
                ginfo->greenbits = 6;
                ginfo->bluebits = 5;
                ginfo->originalbpp = 20;
                ginfo->packed = 3;             // 3 is DXT
                break;

            case GPUTEXTUREFORMAT_DXT4_5:
                ginfo->alphabits = 3;
                ginfo->redbits = 5;
                ginfo->greenbits = 6;
                ginfo->bluebits = 5;
                ginfo->originalbpp = 19;
                ginfo->packed = 3;             // 3 is DXT
                break;
        }

    }

    return(ginfo);
}

int GCALL XPR_read(GINSTANCE *gx, GINFO *ginfo, char *dest, int rowbytes)
{
    int ok=0;

    int framenum=ginfo->framenum;
    unsigned char *xprheader = (unsigned char*)gx->gref;
    unsigned char *resource = xprheader+16+framenum*16;
    unsigned char *texture = xprheader+12+ggetm(resource+4,4);
    unsigned char *gputexture = texture+6*4+1*4; // d3dtexture is 6 dwords. then 1 mipflush dword.  gputexture is 6 dwords

    unsigned int HeaderSize = ggetm(xprheader+4,4); // graphics start after header
    unsigned int Pitch = (ggetm(gputexture,4)>>22)&511; // rowbytes
    unsigned int BaseAddress = ggetm(gputexture+4,4)>>12; // offset from header

    unsigned int DataFormat = ggetm(gputexture+4,4)&63;
    int actualbpp = ginfo->originalbpp;
    if (DataFormat==GPUTEXTUREFORMAT_DXT1) actualbpp = 4;
    else if (DataFormat==GPUTEXTUREFORMAT_DXT4_5 || GPUTEXTUREFORMAT_DXT2_3) actualbpp = 8;

    unsigned int Tiled = ggetm(gputexture+0,4)>>31;
    if (DataFormat==GPUTEXTUREFORMAT_DXT1)
    {
        Pitch = ginfo->width/2; // dxt1 is 4 bpp
    }
    else if (DataFormat==GPUTEXTUREFORMAT_DXT2_3 || DataFormat==GPUTEXTUREFORMAT_DXT4_5)
    {
        Pitch = ginfo->width; // dxt3/5 is 8 bpp
    }
    else if (ginfo->originalbpp==16)
    {
        Pitch = ginfo->width*2; // dxt3/5 is 8 bpp
    }
    else
        Pitch = ginfo->width*4; // force 32


#ifdef TYPE3PR
    if (!Tiled) Pitch = (Pitch+3)&~3;   // ps3 make a multiple of 4
#else
    if (!Tiled) Pitch = (Pitch+255)&~255;   // make a multiple of 256
#endif




	unsigned int framesize = Pitch*ginfo->height;
    if (Tiled && (DataFormat==GPUTEXTUREFORMAT_DXT1 || DataFormat==GPUTEXTUREFORMAT_DXT2_3 || DataFormat==GPUTEXTUREFORMAT_DXT4_5))
    {
        int width=ginfo->width;
        int height=ginfo->height;
        if (Tiled)
        {
            width = (width+127)&~127;
            height = (height+127)&~127;
		}
		else
        {
            width = (width+255)&~255;
            height = (height+127)&~127;
		}

        if (DataFormat==GPUTEXTUREFORMAT_DXT1)
    	    framesize = width*height/2;
        else
    	    framesize = width*height;
	}

    unsigned char *framebuf = (unsigned char *) galloc(framesize+sizeof(DXTHEADER));

    if (framebuf)
    {
        unsigned int mipoffset=0;
//        if (ginfo->width<=16)
//            mipoffset = 32*actualbpp/8;
        gseek(gx->gstream,HeaderSize+12+(BaseAddress<<12)+mipoffset);

        if (DataFormat==GPUTEXTUREFORMAT_DXT1 || DataFormat==GPUTEXTUREFORMAT_DXT2_3 || DataFormat==GPUTEXTUREFORMAT_DXT4_5)
        {
            int width=ginfo->width;
            int height=ginfo->height;
            if (Tiled)
            {
                width = (width+127)&~127;
                height = (height+127)&~127;

                if (DataFormat==GPUTEXTUREFORMAT_DXT1)
            	    framesize = width*height/2;
                else
            	    framesize = width*height;
            }

            ok = gread(gx->gstream,framebuf+sizeof(DXTHEADER),framesize); // read dxt source
            DXTHEADER *dxtheader = (DXTHEADER *)framebuf;

            unsigned int code=0;
            if (DataFormat==GPUTEXTUREFORMAT_DXT1)
                code |= DXT_DXT1_CODE;
            else if (DataFormat==GPUTEXTUREFORMAT_DXT2_3)
                code |= DXT_DXT3_CODE;
            else// if (DataFormat==GPUTEXTUREFORMAT_DXT4_5)
                code |= DXT_DXT5_CODE;

            gputm(dxtheader->code, code, sizeof(dxtheader->code));
            gputm(dxtheader->size, ((width+3)/4) * ((height+3)/4) * 64, sizeof(dxtheader->size));
            gputm(dxtheader->mode, 0, sizeof(dxtheader->mode));

#ifndef TYPE3PR
            ShortSwap(framebuf+sizeof(DXTHEADER), framesize);
#endif

            // Decode and reorder the blocks for the destination image
            char *temp = (char *) galloc(DXT_size(dxtheader));
            if (temp)
            {
                int compressedsize;
                memset(temp, 0, DXT_size(dxtheader));
                DXT_decode((void*)temp,dxtheader, &compressedsize);
                XPRunorderblocks(ginfo->width, ginfo->height, width, height, rowbytes, (void*)(temp), dest, Tiled, DataFormat);
                gfree(temp);
                ok = 1;
            }
        }
        else // not dxt
        {
            ok = gread(gx->gstream,framebuf,framesize);

            for (int y=0; y<ginfo->height && ok; ++y)
            {
                ARGB *d = (ARGB *) (dest+rowbytes*y);
                unsigned char *lineptr = framebuf+Pitch*y;

                switch (DataFormat)
                {
                    case GPUTEXTUREFORMAT_4_4_4_4:
                        for (int x=0; x<ginfo->width; ++x)
                        {
                            d->a = (((ggetm(lineptr,2)>>12)&15)*255+8)/15;
                            d->r = (((ggetm(lineptr,2)>> 8)&15)*255+8)/15;
                            d->g = (((ggetm(lineptr,2)>> 4)&15)*255+8)/15;
                            d->b = (((ggetm(lineptr,2)    )&15)*255+8)/15;
                            ++d;
                            lineptr += 2;
                        }
                        break;

                    case GPUTEXTUREFORMAT_1_5_5_5:
                        for (int x=0; x<ginfo->width; ++x)
                        {
                            d->a = (((ggetm(lineptr,2)>>15)&1)*255)/1;
                            d->r = (((ggetm(lineptr,2)>>10)&31)*255+16)/31;
                            d->g = (((ggetm(lineptr,2)>> 5)&31)*255+16)/31;
                            d->b = (((ggetm(lineptr,2)    )&31)*255+16)/31;
                            ++d;
                            lineptr += 2;
                        }
                        break;

                    case GPUTEXTUREFORMAT_5_6_5:
                        for (int x=0; x<ginfo->width; ++x)
                        {
                            d->a = 255;
                            d->r = (((ggetm(lineptr,2)>>11)&31)*255+16)/31;
                            d->g = (((ggetm(lineptr,2)>> 5)&63)*255+32)/63;
                            d->b = (((ggetm(lineptr,2)    )&31)*255+16)/31;
                            ++d;
                            lineptr += 2;
                        }
                        break;

                    case GPUTEXTUREFORMAT_8_8_8_8:
                        for (int x=0; x<ginfo->width; ++x)
                        {
                            d->a = lineptr[0];
                            d->r = lineptr[1];
                            d->g = lineptr[2];
                            d->b = lineptr[3];
                            ++d;
                            lineptr += 4;
                        }
                        break;

                    case GPUTEXTUREFORMAT_8_8:
                        for (int x=0; x<ginfo->width; ++x)
                        {
                            d->a = lineptr[0];
                            d->r = lineptr[1];
                            d->g = lineptr[1];
                            d->b = lineptr[1];
                            ++d;
                            lineptr += 2;
                        }
                        break;
                }
            }

            if (Tiled)
            {
                if (DataFormat==GPUTEXTUREFORMAT_8_8_8_8)
                {
                    void *temp = galloc(ginfo->width*ginfo->height*4);
                    memcpy(temp,dest,ginfo->width*ginfo->height*4);

                    XPRuntile(ginfo->width, ginfo->height, rowbytes, temp, dest);
                }
                else// if (DataFormat==GPUTEXTUREFORMAT_1_5_5_5)
                {
                    void *temp = galloc(ginfo->width*ginfo->height*4);
                    memcpy(temp,dest,ginfo->width*ginfo->height*4);

                    XPRuntile(ginfo->width, ginfo->height, rowbytes, temp, dest);
                }

            }

        }


        gfree(framebuf);
    }
    return(ok);
}

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

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

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

