#include <string.h>
#include "sprite.h"
#include "objgfx30.h"

TogSprite::TogSprite(void) {
  image     = NULL;
  pal       = NULL;
  imagesize = 0;
  width     = 0;
  height    = 0;
  bitdepth  = 0;
  RFP       = 0;
  GFP       = 0;
  BFP       = 0;
  AFP       = 0;
  RShift    = 0;
  GShift    = 0;
  BShift    = 0;
  AShift    = 0;
  return;
} // TogSprite

void
TogSprite::get(TGfx0& SrcObject, Int32 x1, Int32 y1, Int32 x2, Int32 y2) {
  TPixelFmt pixfmt;
  uInt32 xx,yy,xOfs,yOfs;
  uInt32 rx1, ry1, rx2, ry2;
  uInt32 xCount, yCount;
  void *p;
  uInt32 bm; // bit multiplier
  uInt32 MaxX, MaxY;

  if ((SrcObject.Buffer==NULL) || (SrcObject.LineOfs==NULL)) return;
  if (image!=NULL) free(image);

  MaxX = SrcObject.ogGetMaxX();
  MaxY = SrcObject.ogGetMaxY();

  SrcObject.ogGetPixFmt(pixfmt);

  bitdepth = pixfmt.BPP;
  RFP = pixfmt.RedFieldPosition;
  GFP = pixfmt.GreenFieldPosition;
  BFP = pixfmt.BlueFieldPosition;
  AFP = pixfmt.AlphaFieldPosition;
  RShift = 8-pixfmt.RedMaskSize;
  GShift = 8-pixfmt.GreenMaskSize;
  BShift = 8-pixfmt.BlueMaskSize;
  AShift = 8-pixfmt.AlphaMaskSize;

  if (bitdepth==8) {
    if (pal==NULL) new TRGBA[256];
    if (pal==NULL) return;
    memcpy(pal, SrcObject.pal, sizeof(TRGBA)*256);
  } // if

  bm = ((bitdepth+7) >> 3);

  if (x1>x2) {
    xx = x1;
    x1 = x2;
    x2 = xx;
  } // if

  if (y1>y2) {
    yy = y1;
    y1 = y2;
    y2 = yy;
  } // if

  xCount = abs(x2-x1)+1;
  yCount = abs(y2-y1)+1;
  width = xCount;
  height = yCount;
  imagesize = xCount*yCount*bm;
  image = malloc(imagesize);

  p = image;
  
  if ( ((uInt32)x1>MaxX) || ((uInt32)y1>MaxY) ||
       ((uInt32)x2>MaxX) || ((uInt32)y2>MaxY) ) {
    memset(p,0,imagesize);
  } // if

  xOfs = 0;
  yOfs = 0;

  if (y1<0) {
    yCount += y1;
    ry1 = 0;
    yOfs = xCount*abs(y1);
  } else ry1 = y1;

  if (x1<0) {
    xCount += x1;
    rx1 = 0;
    xOfs = abs(x1);
  } else rx1 = x1;

  if (x2>(Int32)MaxX) {
    xCount -= MaxX-x2+1;
    rx2 = MaxX;
  } else rx2 = x2;

  if (y2>(Int32)MaxY) {
    yCount -= MaxY-y2+1;
    ry2=MaxY;
  } else ry2 = y2;

  xCount *= bm;
  for (yy=0; yy<yCount; yy++) {
    ( (uInt8 *)p ) += xCount;
    memcpy(p,(uInt8 *)SrcObject.Buffer+SrcObject.LineOfs[ry1+yy]+rx1,xCount);
    ( (uInt8 *)p ) += xCount;
  }
  return;
} // TogSprite::get

uInt32
TogSprite::getPixel(void * p) {
  uInt32 result;
  switch (bitdepth) {
  case 8:
    return *(uInt8 *)p;
    break;
  case 15:
  case 16:
    return *(uInt16 *)p;
    break;
  case 24:
    asm(
       "  xor  %%eax, %%eax   \n"  // xor     eax, eax
       "  mov  2(%%edi),%%al  \n"  // mov     al, [edi+2]
       "  shl  $16, %%eax     \n"  // shl     eax, 16
       "  mov  (%%edi), %%ax  \n"  // mov     ax, [edi]
       "  mov  %%eax, %1      \n"  // mov     result, eax
       :
       : "D" (p), "m" (result)
       );
     return result;
     break;
  case 32:
    return *(uInt32 *)p;
    break;
  default:
    return 0;
    break;
  } // switch
} // TogSprite::getPixel

uInt32
TogSprite::getSize(void) {
 /*
  * getSize
  *
  * returns the size of the image as it would take on disk.  This includes
  * all header related information (width/height, bitdepth, pixel format,
  * etc) along with an extra sizeof(uInt32)
  * for storing the complete size. This allows easy indexing of images,
  * since you can figure out exactly how much the image will take up on
  * disk.  This function computes the size in the exact order it is on disk.
  * If the image is 8bpp, then there is a 768 byte palette stored after the
  * image data along with an extra sizeof(uInt32) for the palette size in
  * bytes.  Currently we store the entire palette, but later I expect we
  * will add the ability to optimize the palette so only used entries are
  * stored.
  *
  * If you were to store a single bitmap in a file, getSize would equal the
  * filesize.
  */
  uInt32 tmpsize;
  char header_ident[4];
  tmpsize = sizeof(header_ident)+
            sizeof(uInt32)+               // total size
            sizeof(width)+sizeof(height)+ // width/height
            sizeof(bitdepth)+             // bitDepth
            sizeof(RFP)+sizeof(GFP)+sizeof(BFP)+sizeof(AFP)+ // field positions
            sizeof(RShift)+sizeof(GShift)+sizeof(BShift)+sizeof(AShift)+ // shifters
            sizeof(imagesize)+            // image size in bytes
            imagesize;                    // actual image area in bytes
  if (bitdepth==8) tmpsize += sizeof(uInt32)+sizeof(TRGBA)*256;
  return tmpsize;
} // TogSprite::getSize

bool
TogSprite::load(const char * filename) {
  return loadFrom(filename,0);
} // TogSprite::load

bool
TogSprite::loadFrom(const char * filename, uInt32 offset) {
  return true;
} // TogSprite::loadFrom;

bool
TogSprite::save(const char * filename) {
  return saveTo(filename,0);
} // TogSprite::save

bool
TogSprite::saveTo(const char * filename, Int32 offset) {
  return true;
} // TogSprite::saveTo

void
TogSprite::unpackRGB(uInt32 colour, uInt8& red, uInt8& green, uInt8& blue) {
  switch (bitdepth) {
  case 8:
    if (colour>255) colour&=255;
    if (pal==NULL) return;
    red=pal[colour].red;
    green=pal[colour].green;
    blue=pal[colour].blue;
    break;
  case 15:
  case 16:
    red = (uInt8)(colour >> RFP) << RShift;
    green = (uInt8)(colour >> GFP) << GShift;
    blue = (uInt8)(colour >> BFP) << BShift;
    if ((red!=0) && (RShift!=0)) red+=(1 << RShift)-1;
    if ((green!=0) && (GShift!=0)) green+=(1 << GShift)-1;
    if ((blue!=0) && (BShift!=0)) blue+=(1 << BShift)-1;
    break;
  case 24:
  case 32:
    red = (uInt8)(colour >> RFP);
    green = (uInt8)(colour >> GFP);
    blue = (uInt8)(colour >> BFP);
    break;
  default:
    red = 0;
    green = 0;
    blue = 0;
    break;
  } // switch
  return;
} // TogSprite::unpackRGB

TogSprite::~TogSprite(void) {
  if (image!=NULL) free(image);
  if (pal!=NULL) delete [] pal;
  image     = NULL;
  pal       = NULL;
  imagesize = 0;
  width     = 0;
  height    = 0;
  bitdepth  = 0;
  RFP       = 0;
  GFP       = 0;
  BFP       = 0;
  AFP       = 0;
  RShift    = 0;
  GShift    = 0;
  BShift    = 0;
  AShift    = 0;
  return;
} // TogSprite::~TogSprite


