// This is material.cc CVS version: $Id: material.cc,v 1.2 2000/02/28 18:06:24 andreaha Exp $
#include "eng.h"

/************************************************************************/
/* Material                                                             */
/************************************************************************/

/* import data from picture file */
int World::Material::importFile(char *filen) {
  dpush2("World::Material::importFile(\"%s\")", filen);

  unsigned char *resized, *res;
  char *pal;
  char *c;

  p = new PixFile(myworld, filen);
  if (p->loaded == ERROR) {
    delete p;
    return ERROR;    
  }

  strcpy(filename, filen);                          /* Insert filename */

  res = resized = (unsigned char *)p->sizeTo(256, 256);    /* resize to 256x256 */
  pal = (char *)p->palette;
  c = (char *)txt;

  switch (myworld->endian) {
  case LITTLE:                                      /* littleendian systems */
    for (int i = 0; i < (256 * 256); i++) {         
      *c++ = (char )255;                            /* alpha is set to 255 */
      *c++ = pal[(*res++)*3 + 2];                   /* extract blue component */
      *c++ = pal[(*res)*3 + 1];                     /* extract green component */
      *c++ = pal[(*res)*3 + 0];                     /* extract red component */
    } break;
  case BIG:                                         /* bigendian systems */
    for (int i = 0; i < (256 * 256); i++) {
      *c++ = pal[(*res)*3 + 0];                     /* extract red component */
      *c++ = pal[(*res)*3 + 1];                     /* extract green component */
      *c++ = pal[(*res++)*3 + 2];                   /* extract blue component */
      *c++ = (char )255;                            /* alpha is set to 255 */    }
  }

  myworld->antiFlip(txt, txtm1, 128, 128);          /* create mip 128x128 */
  myworld->antiFlip(txtm1, txtm2, 64, 64);          /* create mip 64x64 */
  myworld->antiFlip(txtm2, txtm3, 32, 32);          /* create mip 32x32 */
  myworld->antiFlip(txtm3, txtm4, 16, 16);          /* create mip 16x16 */

  myworld->freeMem(resized);
  delete p;
  dpop();
  return OK;
}

/* constructor  */
World::Material::Material(World *myw) {
  dpush1("World::Material::Material()");

  myworld = myw;
  next = NULL;
  strcpy(name, "unnamed texture");

  dpop();
}

/* destructor */
World::Material::~Material() {
  dpush1("World::Material::~Material()");

  dpop();
}

void World::Material::printOut() {
  dpush1("World::Material::printOut()");

  print2("Material [%#010x] printout:\n", (int)this);
  print2("  Name:     [%s]\n", name);
  print2("  Filename: [%s]\n", filename);
  print4("  Ambient:  r = %6.2f, g = %6.2f, b = %6.2f\n", ambient.r, ambient.g, ambient.b);
  print4("  Diffuse:  r = %6.2f, g = %6.2f, b = %6.2f\n", diffuse.r, diffuse.g, diffuse.b);
  print4("  Specular: r = %6.2f, g = %6.2f, b = %6.2f\n", specular.r, specular.g, specular.b);
  print2("  Shininess:    %f\n", shininess);
  print2("  Transparency: %f\n", transparency);
  print2("  Twosided:     %s\n", twosided ? myworld->util.charptr("Yes") : myworld->util.charptr("No"));
  print2("  Wireframe:    %s\n", wire ? myworld->util.charptr("Yes") : myworld->util.charptr("No"));
  print2("  Shading:      %i\n", shading);
  dpop();
}


/******************************

  char *strapp(char *a, char *b);

  Returns a string representation of
  a + b.

*******************************/

char *World::Material::PixFile::strapp(char *a, char *b) {
  dpush3("strapp(%s, %s)", a, b);

  char *c;
  int  alength = 0, blength = 0;
  int  i;

  while (a[alength] != '\0') alength++;
  while (b[blength] != '\0') blength++;

  c = (char *)myworld->getMem(alength + blength + 1);

  i = 0;
  while (i <= (alength + blength)) {
    if (i < alength) c[i] = a[i++];
    else c[i] = b[i++ - alength];
  }

  dpop();
  return c;
}

int World::Material::PixFile::isSignature(char *signature) {
  dpush1("PixFile::isSignature(<###>)");

  int sizeOfSign = 0;
  char *a = signature;

  while (a[sizeOfSign] != '\0') {
    if (a[sizeOfSign] != fileDump[sizeOfSign]) { dpop(); return FALSE; }
    sizeOfSign++;
  }
  dpop();
  return TRUE;
}

void World::Material::PixFile::transferPalTo(byte *p) {
  dpush2("PixFile::transferPalTo(%#010x)", (int )p);

  for (int i = 0; i < 768; i++)
    p[i] = palette[i];

  dpop();
}

void World::Material::PixFile::dumpIt(char *fileName) {
  dpush2("PixFile::dumpIt(%s)", fileName);

  FILE *fp;

  char *filen;
  char *paletten;

  unsigned int r,g,b;

  if (loaded != OK) {
    dpop();
    return;
  }

  if (strcmp(fileName, "")) {
    filen = strapp(fileName, ".raw");
    paletten = strapp(fileName, ".pal");
  } else {
    filen = "test.raw";
    paletten = "test.pal";
  }

  if ((fp = fopen(filen, "wb"))) {
    fwrite(output, imageSize, 1, fp);
    fclose(fp);
  } else {
  }
  if ((fp = fopen(paletten, "w"))) {
    fprintf(fp, "JASC-PAL\n0100\n256\n");
    for (int i = 0; i < 256; i++) {
      r = (unsigned int)palette[(i*3)+0];
      g = (unsigned int)palette[(i*3)+1];
      b = (unsigned int)palette[(i*3)+2];
      fprintf(fp, "%i %i %i\n", r, g, b);
    }
    fclose(fp);
  } else {
  }

  myworld->freeMem(fileName);
  myworld->freeMem(filen);
  myworld->freeMem(paletten);
  dpop();
  return;
}

byte World::Material::PixFile::getNextByte() {
  dpush1("PixFile::getNextByte()");

  if (offsetPtr > fileSize) {
    dpop();
    return 0;
  }

  dpop();
  return (byte )fileDump[offsetPtr++];
}

int World::Material::PixFile::getNextWord() {
  dpush1("PixFile::getNextWord()");

  char *b;

  int o = offsetPtr;
  offsetPtr += 2;
  if (offsetPtr > fileSize) {
    dpop();
    return 0;
  }
  b = &fileDump[o];

  dpop();
  return WORD(b);
}

void World::Material::PixFile::skipBytes(int n) {
  dpush2("PixFile::skipBytes(%i)", n);
  offsetPtr += n;
  dpop();
}

int World::Material::PixFile::load(char *fileName) {
  dpush2("PixFile::load(%s)", fileName);

  FILE *fp;

  if ((fp = fopen(fileName, "rb"))) {

    offsetPtr = 0;
    fseek(fp, 0, SEEK_END);
    fileSize = ftell(fp);
    rewind(fp);

    if ((fileDump = (char *)myworld->getMem(fileSize)) == NULL) {
      dpop();
      return ERROR;
    }
    
    fread(fileDump, 1, fileSize, fp);
    fclose(fp);

    debug3("  Size: %ik (%i bytes)", fileSize >> 10, fileSize);
    dpop();
    return TRUE;
  } else {
    dpop();
    return ERROR;
  }
  return ERROR;
}

int World::Material::PixFile::load(char *offset, int fSize) {
  dpush3("PixFile::load(%#010x, %i)", (int )offset, fSize);
  debug("[INTERNAL]: ");

  offsetPtr = 0;
  fileSize = fSize;
  fileDump = offset;

  debug2("%ik ", fileSize >> 10);
  dpop();
  return TRUE;
}

byte *World::Material::PixFile::sizeTo(int xOutSize, int yOutSize) {
  dpush3("PixFile::sizeTo(%i, %i)", xOutSize, yOutSize);

  int a, b;

  int *precx;
  int *precy;

  byte *outArea = (byte *)myworld->getMem(xOutSize * yOutSize);
  byte *outA = outArea;

  precx = (int *)myworld->getMem(sizeof(int) * xOutSize);
  precy = (int *)myworld->getMem(sizeof(int) * yOutSize);

  for (int i = 0; i < xOutSize; i++)
    precx[i] = (i * xSize) / xOutSize;

  for (int i = 0; i < yOutSize; i++)
    precy[i] = ((i * ySize) / yOutSize) * xSize;

  for (int y = 0; y < yOutSize; y++) {
    b = precy[y];
    for (int x = 0; x < xOutSize; x++) {
      a = precx[x] + b;
      *outA++ = output[a];
    }
  }

  myworld->freeMem(precx);
  myworld->freeMem(precy);

  dpop();
  return outArea;
}

int World::Material::PixFile::loadPcx() {
  dpush1("PixFile::loadPcx()");

  int  index;
  char data;
  char count;
  PcxHeader *pcx;

  skipBytes(PCXHEADERSIZE);
  pcx = (PcxHeader *)fileDump;

  xSize = WORD(pcx->xamax) - WORD(pcx->xamin) + 1;
  ySize = WORD(pcx->yamax) - WORD(pcx->yamin) + 1;

  imageSize  = xSize * ySize;

  output = (byte *)myworld->getMem(imageSize);
  memset(output, 0, imageSize);

  index = 0;

  while (index < imageSize) {
    data = getNextByte();

    if ((data & COUNTER) == COUNTER) {
      count = data & STRIPBYTES;
      data = getNextByte();
    } else {
      count = 1;
    }
    memset(&output[index], data, count);
    index += count;
  }

  memcpy(&palette, &fileDump[fileSize-768], 768);

  debug3("  Dim:  %ix%i", xSize, ySize);

  myworld->freeMem(fileDump);
  dpop();
  return loaded = OK;
}

int World::Material::PixFile::loadGif() {
  dpush1("PixFile::loadGif()");

  int  gctFlag, lctFlag;
  int  colorResolution;
  int  sortFlag;
  int  gctSize;
  int  imageLeft, imageTop;
  int  imageWidth, imageHeight;
  byte packed;
  GifHeader *gif;

  skipBytes(GIFHEADERSIZE);
  gif = (GifHeader *)fileDump;

  xSize = WORD(gif->width);
  ySize = WORD(gif->height);

  gctFlag         = GCTFLAG(gif->packed);
  colorResolution = COLORRES(gif->packed) + 1;
  sortFlag        = GCTSORTFLAG(gif->packed);
  gctSize         = 3 * (int )pow((double )2, (double )GCTSIZE(gif->packed) + 1);

  if (gctFlag == 0)
    gif->bgColorIndex = 0;
  else
    for (int i = 0; i < 768; i++)
      palette[i] = getNextByte();

  /* N… er Global Color Table lest, n… f°lger image data.
   */

  while (getNextByte() != 0x2c);

  imageLeft   = getNextWord();
  imageTop    = getNextWord();
  imageWidth  = getNextWord();
  imageHeight = getNextWord();
  packed      = getNextByte();
  lctFlag = LCTFLAG(packed);

  print2(" lctFlag: %i\n", lctFlag);
  print3(" imageleft,top: %ix%i\n", imageLeft, imageTop);
  print3(" imagesize:     %ix%i\n", imageWidth, imageHeight);

  print3("%ix%i ", xSize, ySize);

  myworld->freeMem(fileDump);
  dpop();
  return loaded = OK;
}

int World::Material::PixFile::identified() {
  dpush1("PixFile::identified()");

  static char PCXSIGNATURE[] = "\12\5\1";
  static char GIFSIGNATURE[] = "GIF";

  if (isSignature(PCXSIGNATURE)) {
    debug("  Type: Z-soft paintbrush (PCX) ");
    dpop();
    return PCXFILE;
  }
  if (isSignature(GIFSIGNATURE)) {
    debug("  Type: Graphics Interchange Format (GIF) ");
    dpop();
    return GIFFILE;
  }

  dpop();
  return UNKNOWN;
}

World::Material::PixFile::PixFile(World *myw, char *fileName) {
  dpush2("PixFile::PixFile(%s)", fileName);

  int result;

  myworld = myw; 
  memAlloc = 0;
  loaded = ERROR;

  if (load(fileName)) {
    switch (identified()) {
    case PCXFILE: result = loadPcx(); break;
    case UNKNOWN: result = UNKNOWN; break;
    default: result = UNKNOWN;
    }
  } else {
    result = ERROR;
  }

  switch (result) {
  case ERROR  : error("Error reading file")
    return;
  case UNKNOWN: error("Unknown file format, not loaded");
    return;
  }

  dpop();
}

World::Material::PixFile::PixFile(World *myw, char *offset, int fSize) {
  dpush3("PixFile::PixFile(%#010x, %i)", (int )offset, fSize);

  int result;

  myworld = myw;
  memAlloc = 0;
  loaded = ERROR;

  if (load(offset, fSize)) {
    switch (identified()) {
    case PCXFILE: result = loadPcx(); break;
    case UNKNOWN: result = UNKNOWN; break;
    default: result = UNKNOWN;
    }
  } else {
    result = ERROR;
  }

  switch (result) {
    case ERROR  : error("Error decoding internal.");
      return;
    case UNKNOWN: error("Internal unknown format, not loaded");
      return;
  }

  dpop();
  debug("ok.\n");
}

World::Material::PixFile::~PixFile() {
  dpush1("PixFile::~PixFile()");
  myworld->freeMem(output);
  dpop();
}












