/*===========================================================================
 *
 * DFIMG.CPP - Dave Humphrey (4 November 2000), uesp@m0use.net
 *
 *=========================================================================*/

	/* Include Files */
#include "dfimg.h"
#include "dfcommon.h"


#undef  __FUNC__
#define __FUNC__ "CDFImgFile::CDFImgFile()"
/*===========================================================================
 *
 * Class CDFImgFile Constructor
 *
 *=========================================================================*/
CDFImgFile::CDFImgFile() {
  pData = NULL;
  Width = 0;
  Height = 0;
  XOffset = 0;
  YOffset = 0;
  Unknown = 0;
  ImageSize = 0;
  CIFGroupIndex = 0;
  HasOffsetList = FALSE;
  HasNoHeader = FALSE;
  HasCIFWeaponHeader = FALSE;
  DestroyOnRead = FALSE;
 }
/*===========================================================================
 *		End of Class CDFImgFile Constructor
 *=========================================================================*/


#undef  __FUNC__
#define __FUNC__ "CDFImgFile::Destroy()"
/*===========================================================================
 *
 * Class CDFImgFile Destructor
 *
 *=========================================================================*/
void CDFImgFile::Destroy (void) {
  DestroyPointer(pData);

  Width = 0;
  Height = 0;
  XOffset = 0;
  YOffset = 0;
  Unknown = 0;
  ImageSize = 0;
  HasOffsetList = FALSE;
  HasNoHeader = FALSE;
  HasCIFWeaponHeader = FALSE;
  CIFGroupIndex = 0;
 }
/*===========================================================================
 *		End of Class CDFImgFile Destructor
 *=========================================================================*/


#undef  __FUNC__
#define __FUNC__ "CDFImgFile::Load()"
/*===========================================================================
 *
 * Class CDFImgFile Method - boolean Load (pFilename);
 *
 * Open and read a IMG file. Returns FALSE on any error.
 *
 *=========================================================================*/
boolean CDFImgFile::Load (const char* pFilename) {
  FILE*   pFileHandle;
  boolean Result;
  long    FileSize;

	/* Attempt to open file for input */
  pFileHandle = openfile (pFilename, "rb");

  if (pFileHandle == NULL) {
    SET_EXT_ERROR3(ERR_FILE, "Failed to open file %s!", pFilename);
    return (FALSE);
   }

	/* Delete the current contents */
  Destroy();

	/* Check special IMG files */
  FileSize = GetFilesize(pFileHandle);

  if (FileSize == 720) {
    HasNoHeader = TRUE;
    Width = 9;
    Height = 80;
    ImageSize = 720;
   }
  else if (FileSize == 990) {
    HasNoHeader = TRUE;
    Width = 45;
    Height = 22;
    ImageSize = 990;
   }
  else if (FileSize == 1720) {
    HasNoHeader = TRUE;
    Width = 43;
    Height = 40;
    ImageSize = 1720;
   }
  else if (FileSize == 2140) {
    HasNoHeader = TRUE;
    Width = 107;
    Height = 20;
    ImageSize = 2140;
   }
  else if (FileSize == 2916) { 
    HasNoHeader = TRUE;
    Width = 81;
    Height = 36;
    ImageSize = 2916;
   }
  else if (FileSize == 3200) { 
    HasNoHeader = TRUE;
    Width = 40;
    Height = 80;
    ImageSize = 3200;
   }
  else if (FileSize == 3938) {
    HasNoHeader = TRUE;
    Width = 179;
    Height = 22;
    ImageSize = 3938;
   }
  else if (FileSize == 4280) {
    HasNoHeader = TRUE;
    Width = 107;
    Height = 40;
    ImageSize = 4280;
   }
  else if (FileSize == 20480) { 
    HasNoHeader = TRUE;
    Width = 320;
    Height = 64;
    ImageSize = 20480;
   }
  else if (FileSize == 26496) { 
    HasNoHeader = TRUE;
    Width = 207;
    Height = 128;
    ImageSize = 26496;
   }
  else if (FileSize == 64000) {
    HasNoHeader = TRUE;
    Width = 320;
    Height = 200;
    ImageSize = 64000;
   }
  else if (FileSize == 64768) {
    HasNoHeader = TRUE;
    Width = 320;
    Height = 200;
    ImageSize = 64000;
   }
  else if (FileSize == 68800) {
    HasNoHeader = TRUE;
    Width = 320;
    Height = 215;
    ImageSize = 68800;
   }
  else if (FileSize == 112128) {
    HasNoHeader = TRUE;
    Width = 512;
    Height = 219;
    ImageSize = 112128;
   }

	/* Read the image file */
  Result = Read(pFileHandle);

  fclose (pFileHandle);
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFImgFile::Load()
 *=========================================================================*/


#undef  __FUNC__
#define __FUNC__ "CDFImgFile::Read()"
/*===========================================================================
 *
 * Class CDFImgFile Method - boolean Read (pFileHandle);
 *
 * Read a IMG file from the current position in the given file stream.
 * Returns FALSE on any error.
 *
 *=========================================================================*/
boolean CDFImgFile::Read (FILE* pFileHandle) {
  int Result;
  
	/* Ensure valid input */
  if (pFileHandle == NULL) {
    SET_EXT_ERROR2(ERR_NULL, "Invalid NULL file handle received!");
    return (FALSE);
   }

	/* Delete the current image data (only for CIF files) */
  if (DestroyOnRead) Destroy();

	/* Read in the image header */
  Result = ReadHeader(pFileHandle);

	/* Skip the weapon CIF offset list, if present */
  if (HasOffsetList) {
    fseek (pFileHandle, DFCIF_OFFSETLIST_SIZE, SEEK_CUR);
   }

  if (Result) {
    if (IsCompressed())
      Result = ReadCompressedData(pFileHandle);
    else
      Result = ReadData(pFileHandle);
   }

  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFImgFile::Read()
 *=========================================================================*/


#undef  __FUNC__
#define __FUNC__ "CDFImgFile::ReadHeader()"
/*===========================================================================
 *
 * Class CDFImgFile Method - boolean ReadHeader (pFileHandle);
 *
 * Protected class method which reads in the img file header from the
 * current position in the file stream. Returns FALSE on any error.
 *
 *=========================================================================*/
boolean CDFImgFile::ReadHeader (FILE* pFileHandle) {

	/* Ensure valid parameters if not loading a header */
  if (HasNoHeader) {
    if (Width == 0 || Height == 0) {
      SET_EXT_ERROR2(ERR_INPUT, "Invalid image width/height with no header!");
      return (FALSE);
     }

    return (TRUE);
   }

	/* Read in the image header variables */
  clearerr(pFileHandle);

  if (HasCIFWeaponHeader) {
    Width     = read_short(pFileHandle);
    Height    = read_short(pFileHandle);
    XOffset   = read_short(pFileHandle);
    YOffset   = read_short(pFileHandle);
    Unknown   = read_short(pFileHandle);
    ImageSize = (int) (unsigned short) read_short(pFileHandle);
   }
  else {
    XOffset   = read_short(pFileHandle);
    YOffset   = read_short(pFileHandle);
    Width     = read_short(pFileHandle);
    Height    = read_short(pFileHandle);
    Unknown   = read_short(pFileHandle);
    ImageSize = (int) (unsigned short) read_short(pFileHandle);
   }

  	/* Check the success of the input */
  if (ferror(pFileHandle) || feof(pFileHandle)) {
    SET_EXT_ERROR2(ERR_READ, "Failed to read header information!");
    return (FALSE);
   }

  return (TRUE);
 }
/*===========================================================================
 *		End of Class Method CDFImgFile::ReadHeader()
 *=========================================================================*/


#undef  __FUNC__
#define __FUNC__ "CDFImgFile::ReadData()"
/*===========================================================================
 *
 * Class CDFImgFile Method - boolean ReadData (pFileHandle);
 *
 * Protected class method which reads in the uncompressed image data from the
 * current position in the file stream. Returns FALSE on any error.
 *
 *=========================================================================*/
boolean CDFImgFile::ReadData (FILE* pFileHandle) {
  int Result;
  int Size = Width*Height;
  
	/* Allocate the image data */
  CreatePointerArray(pData, byte, Size);

	/* Read in image data all at once */
  Result = fread (pData, 1, Size, pFileHandle);

  if (Result != (int) Size) {
    SET_EXT_ERROR4(ERR_READ, "Error reading image data (%d of %d bytes)!", Result, Size);
    return (FALSE);
   }

  return (TRUE);
 }
/*===========================================================================
 *		End of Class Method CDFImgFile::ReadData()
 *=========================================================================*/


#undef  __FUNC__
#define __FUNC__ "CDFImgFile::ReadCompressedData()"
/*===========================================================================
 *
 * Class CDFImgFile Method - boolean ReadCompressedData (pFileHandle);
 *
 * Protected class method which reads in the compressed image data from the
 * current position in the file stream. Returns FALSE on any error.
 *
 *=========================================================================*/
boolean CDFImgFile::ReadCompressedData (FILE* pFileHandle) {
  int   Size = Width*Height;
  int   BytesWritten = 0;
  int   LoopCounter;
  int   ByteCount;
  byte* pImagePtr;
  int   Data;
  
	/* Allocate the image data */
  CreatePointerArray(pData, byte, Size);
  pImagePtr = pData;

	/* Uncompress the data to image buffer */
  while (BytesWritten < Size) { 
    clearerr(pFileHandle);
    Data = fgetc(pFileHandle);

		/* RLE type byte indicator */
    if (Data > 0x7f) {
      ByteCount = (Data & 0xFF) - 0x7f;
      BytesWritten += ByteCount;
      Data = fgetc(pFileHandle);

      for (LoopCounter = 0; LoopCounter < ByteCount; LoopCounter++) {
        *pImagePtr = Data & 0xFF;
	pImagePtr++;
       }

     }
		/* Unencoded pixel data */
    else {
      ByteCount = (Data & 0xFF) + 1;
      BytesWritten += ByteCount;

		/* Copy pixel values */
      for (LoopCounter = 0; LoopCounter < ByteCount; LoopCounter++) {
        *pImagePtr = fgetc(pFileHandle) & 0xFF;
	pImagePtr++;
       }
     }

		/* Check for input errors */
    if (ferror(pFileHandle) || feof(pFileHandle)) { 
      SET_EXT_ERROR2(ERR_READ, "Error reading image data!");
      return (FALSE);
     }
   } /* End of while uncompressed data */ 


  return (TRUE);
 }
/*===========================================================================
 *		End of Class Method CDFImgFile::ReadCompressedData()
 *=========================================================================*/