#include "qtools.h"

/*
 * MIP-tools
 */

struct palpic *GetMipMap(FILE *file, unsigned char MipLevel) {
  struct mipmap MipMap;
  int MipMapSize, MipMapOffset;
  struct palpic *Picture = 0;

  fread(&MipMap, 1, sizeof(struct mipmap), file);
  MipMapSize = LittleLong(MipMap.width) * LittleLong(MipMap.height);
  if ((Picture = pmalloc(LittleLong(MipMap.width), LittleLong(MipMap.height), 0, MipMap.name))) {
    switch (MipLevel) {
      case 3:
	MipMapSize /= (8 * 8);
	MipMapOffset = LittleLong(MipMap.mip3);
	break;
      case 2:
	MipMapSize /= (4 * 4);
	MipMapOffset = LittleLong(MipMap.mip2);
	break;
      case 1:
	MipMapSize /= (2 * 2);
	MipMapOffset = LittleLong(MipMap.mip1);
	break;
      case 0:
      default:
	MipMapOffset = LittleLong(MipMap.mip0);
	break;
    }
    MipMapOffset -= sizeof(struct mipmap);

    fseek(file, MipMapOffset, SEEK_CUR);
    fread(Picture->rawdata, 1, MipMapSize, file);
  }

  return Picture;
}

struct palpic *ParseMipMap(struct mipmap *MipMap, unsigned char MipLevel) {
  int MipMapSize, MipMapOffset;
  struct palpic *Picture = 0;

  MipMapSize = LittleLong(MipMap->width) * LittleLong(MipMap->height);
  if ((Picture = pmalloc(LittleLong(MipMap->width), LittleLong(MipMap->height), 0, MipMap->name))) {
    switch (MipLevel) {
      case 3:
	MipMapSize /= (8 * 8);
	MipMapOffset = LittleLong(MipMap->mip3);
	break;
      case 2:
	MipMapSize /= (4 * 4);
	MipMapOffset = LittleLong(MipMap->mip2);
	break;
      case 1:
	MipMapSize /= (2 * 2);
	MipMapOffset = LittleLong(MipMap->mip1);
	break;
      case 0:
      default:
	MipMapOffset = LittleLong(MipMap->mip0);
	break;
    }
    memcpy(Picture->rawdata, ((char *)MipMap) + MipMapOffset, MipMapSize);
  }

  return Picture;
}

/*
 * returns the offset or -1 for fail 
 */
bool PutMipMap(FILE *file, struct palpic *Picture) {
  struct mipmap MipMap;
  int MipMapSize;
  unsigned char *MipBody;
  bool retval = FALSE;

  /*
   * fix!!! OP_UPDATE offsets ??? 
   */
  MipMapSize = Picture->width * Picture->height;
  if ((MipBody = (unsigned char *)tmalloc(MipMapSize))) {
    short int x, y, num, dwidth = 1, dheight = 1, dshift = 1;
    unsigned char *bodySrc, *bodyDst;
    struct rgb *Palette = Picture->palette;

    strncpy(MipMap.name, Picture->name, NAMELEN_MIP);
    MipMap.height = LittleLong(Picture->height);
    MipMap.width = LittleLong(Picture->width);
    MipMap.mip0 = LittleLong(sizeof(struct mipmap));
    MipMap.mip1 = LittleLong(LittleLong(MipMap.mip0) + (MipMapSize / (1 * 1)));
    MipMap.mip2 = LittleLong(LittleLong(MipMap.mip1) + (MipMapSize / (2 * 2)));
    MipMap.mip3 = LittleLong(LittleLong(MipMap.mip2) + (MipMapSize / (4 * 4)));

    fwrite(&MipMap, 1, sizeof(struct mipmap), file);
    fwrite(bodySrc = Picture->rawdata, 1, MipMapSize, file);

    for (num = 0; num < 3; num++) {
      bodyDst = MipBody;
      dwidth *= 2;
      dheight *= 2;
      dshift++;
      for (y = 0; y < Picture->height; y += dheight) {
	for (x = 0; x < Picture->width; x += dwidth) {
	  short int dx, dy;
	  short int R = 0, G = 0, B = 0;
	  struct rgb rawpix;

	  for (dy = 0; dy < dheight; dy++) {
	    for (dx = 0; dx < dheight; dx++) {
	      short int palpix = (short int)bodySrc[((y + dy) * Picture->width) + x + dx];

	      R += (short int)Palette[palpix].r;
	      G += (short int)Palette[palpix].g;
	      B += (short int)Palette[palpix].b;
	    }
	  }
	  rawpix.r = (unsigned char)(R >> dshift);
	  rawpix.g = (unsigned char)(G >> dshift);
	  rawpix.b = (unsigned char)(B >> dshift);
	  *bodyDst++ = Match(&rawpix, Palette);
	}
      }
      fwrite(MipBody, 1, MipMapSize / (dheight * dwidth), file);
    }
    tfree(MipBody);
    retval = TRUE;
  }
  else
    eprintf("cannot tmalloc %d bytes-body\n", MipMapSize);

  return retval;
}

bool PutMipMap0(FILE *file, struct palpic *Picture) {
  struct mipmap MipMap;

  strncpy(MipMap.name, Picture->name, NAMELEN_MIP);
  MipMap.height = LittleLong(Picture->height);
  MipMap.width = LittleLong(Picture->width);
  MipMap.mip0 = LittleLong(sizeof(struct mipmap));
  MipMap.mip1 = 0;
  MipMap.mip2 = 0;
  MipMap.mip3 = 0;
  fwrite(&MipMap, 1, sizeof(struct mipmap), file);
  fwrite(Picture->rawdata, 1, Picture->width * Picture->height, file);

  return TRUE;
}

bool PasteMipMap(struct mipmap *MipMap, struct palpic *Picture) {
  int MipMapSize;
  unsigned char *MipBody;
  bool retval = FALSE;

  /*
   * fix!!! OP_UPDATE offsets ??? 
   */
  MipMapSize = Picture->width * Picture->height;
  if ((MipBody = (unsigned char *)tmalloc(MipMapSize))) {
    short int x, y, num, dwidth = 1, dheight = 1, dshift = 1, pos;
    unsigned char *bodySrc, *bodyDst;
    struct rgb *Palette = Picture->palette;

    strncpy(MipMap->name, Picture->name, NAMELEN_MIP);
    MipMap->height = LittleLong(Picture->height);
    MipMap->width = LittleLong(Picture->width);
    MipMap->mip0 = LittleLong(sizeof(struct mipmap));
    MipMap->mip1 = LittleLong(LittleLong(MipMap->mip0) + (MipMapSize / (1 * 1)));
    MipMap->mip2 = LittleLong(LittleLong(MipMap->mip1) + (MipMapSize / (2 * 2)));
    MipMap->mip3 = LittleLong(LittleLong(MipMap->mip2) + (MipMapSize / (4 * 4)));
    
    pos = sizeof(struct mipmap);

    memcpy(((char *)MipMap) + pos, bodySrc = Picture->rawdata, MipMapSize);
    pos += MipMapSize;

    for (num = 0; num < 3; num++) {
      bodyDst = MipBody;
      dwidth *= 2;
      dheight *= 2;
      dshift++;
      for (y = 0; y < Picture->height; y += dheight) {
	for (x = 0; x < Picture->width; x += dwidth) {
	  short int dx, dy;
	  short int R = 0, G = 0, B = 0;
	  struct rgb rawpix;

	  for (dy = 0; dy < dheight; dy++) {
	    for (dx = 0; dx < dheight; dx++) {
	      short int palpix = (short int)bodySrc[((y + dy) * Picture->width) + x + dx];

	      R += (short int)Palette[palpix].r;
	      G += (short int)Palette[palpix].g;
	      B += (short int)Palette[palpix].b;
	    }
	  }
	  rawpix.r = (unsigned char)(R >> dshift);
	  rawpix.g = (unsigned char)(G >> dshift);
	  rawpix.b = (unsigned char)(B >> dshift);
	  *bodyDst++ = Match(&rawpix, Palette);
	}
      }
      memcpy(((char *)MipMap) + pos, MipBody, MipMapSize / (dheight * dwidth));
      pos += MipMapSize / (dheight * dwidth);
    }
    tfree(MipBody);
    retval = TRUE;
  }
  else
    eprintf("cannot tmalloc %d bytes-body\n", MipMapSize);

  return retval;
}

bool PasteMipMap0(struct mipmap *MipMap, struct palpic *Picture) {
  strncpy(MipMap->name, Picture->name, NAMELEN_MIP);
  MipMap->height = LittleLong(Picture->height);
  MipMap->width = LittleLong(Picture->width);
  MipMap->mip0 = LittleLong(sizeof(struct mipmap));
  MipMap->mip1 = 0;
  MipMap->mip2 = 0;
  MipMap->mip3 = 0;
  memcpy(((char *)MipMap) + sizeof(struct mipmap), Picture->rawdata, Picture->width * Picture->height);

  return TRUE;
}

