/*===========================================================================
 *
 * File:	Dftexture.CPP
 * Author:	Dave Humphrey (uesp@m0use.net)
 * Created On:	Thursday, June 28, 2001
 *
 * Implements the CDFTextureFileFile class for manipulating Daggerfall texture
 * files.
 *
 *=========================================================================*/

	/* Include Files */
#include "dftexture.h"
#include "dfpal.h"

/*===========================================================================
 *
 * Begin Local Variable Definitions
 *
 *=========================================================================*/
  DEFINE_FILE();
/*===========================================================================
 *		End of Local Variable Definitions
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Constructor
 *
 *=========================================================================*/
CDFTextureFile::CDFTextureFile() {
  m_NumImages = 0;
  m_Tag = 0;
  m_Name[0] = NULL_CHAR;

	/* Initialize the image and offset arrays */
  m_pImages  = NULL;
  m_pOffsets = NULL;
 }
/*===========================================================================
 *		End of Class CDFTextureFile Constructor
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Destructor
 *
 *=========================================================================*/
void CDFTextureFile::Destroy (void) {
  	
	/* Unallocate the image and offset arrays */
  DestroyArrayPointer(m_pImages);
  DestroyArrayPointer(m_pOffsets);
  
  m_Name[0] = NULL_CHAR;
  m_NumImages = 0;
  m_Tag = 0;

 }
/*===========================================================================
 *		End of Class CDFTextureFile Destructor
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Method - void AllocateArrays (NumImages);
 *
 * Protected class method to allocate the image and offset arrays.
 *
 *=========================================================================*/
void CDFTextureFile::AllocateArrays (const int NumImages) {
  DEFINE_FUNCTION("CDFTextureFile::AllocateArrays()");

	/* Ensure valid object state and input */
  ASSERT(m_pImages == NULL && m_pOffsets == NULL);
  ASSERT(NumImages > 0);

	/* Allocate the arrays */
  CreateArrayPointer(m_pImages,  CDFTextureImage,   NumImages);
  CreateArrayPointer(m_pOffsets, dftextureoffset_t, NumImages);

  m_NumImages = NumImages;
 }
/*===========================================================================
 *		End of Class Method CDFTextureFile::AllocateArrays()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Method - void ClearTags (void);
 *
 * Clears the tags for all the texture sub-images.
 *
 *=========================================================================*/
void CDFTextureFile::ClearTags (void) {
  int LoopCounter;

  for (LoopCounter = 0; LoopCounter < m_NumImages; LoopCounter++) {
    m_pImages[LoopCounter].SetTag(0);
   }

 }
/*===========================================================================
 *		End of Class Method CDFTextureFile::ClearTags()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Method - boolean Load (pFilename);
 *
 * Attempt to load the entire texture file.  Returns FALSE on any error.
 *
 *=========================================================================*/
boolean CDFTextureFile::Load (const char* pFilename) {
  DEFINE_FUNCTION("CDFTextureFile::Load(char*)");
  boolean Result;

  	/* Delete the current image information */
  Destroy();

	/* Attempt to open file for input */
  Result = Open(pFilename, "rb");
  if (!Result) return (FALSE);

	/* Read in the file */
  Result = Read();

  Close();
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFTextureFile::Load()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Method - boolean Load (pFileHandle);
 *
 * Attempt to load the entire texture file based on an existing file handle.
 * Returns FALSE on any error.
 *
 *=========================================================================*/
boolean CDFTextureFile::Load (FILE* pFileHandle) {
  DEFINE_FUNCTION("CDFTextureFile::Load(FILE*)");
  boolean Result;

	/* Ensure valid input */
  if (pFileHandle == NULL) return (FALSE);
  
  	/* Delete the current image information */
  Destroy();
  m_pFileHandle = pFileHandle;

	/* Read in the file */
  Result = Read();
  Close();

  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFTextureFile::Load()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Method - boolean Read (void);
 *
 * Helper function to read a texture file once it has been opened.
 * Returns FALSE on any error.  Protected class method.
 *
 *=========================================================================*/
boolean CDFTextureFile::Read (void) {
  DEFINE_FUNCTION("CDFTextureFile::Read()");
  boolean Result;

  	/* Read in the header, offset and image data */
  Result = ReadHeader();
  if (Result) Result = ReadOffsets();
  if (Result) Result = ReadImages();
  
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFTextureFile::ReadOffsets()
 *=========================================================================*/



/*===========================================================================
 *
 * Class CDFTextureFile Method - boolean ReadHeader (void);
 *
 * Attempt to read the texture header data from the current position in
 * thje file stream.  Returns FALSE on any error.  Protected class method.
 *
 *=========================================================================*/
boolean CDFTextureFile::ReadHeader (void) {
  DEFINE_FUNCTION("CDFTextureFile::ReadHeader()");
  boolean Result;
  short   NumImages;

	/* Move to the start of the header data and read data */
  Result = Seek(DFTEXTURE_HEADER_OFFSET, SEEK_SET);
  if (Result) Result = ReadShort(NumImages);
  if (Result) Result = CGenFile::Read(m_Name, DFTEXTURE_NAME_SIZE);
  if (!Result) return (FALSE);

	/* Ensure a valid number of images */
  if (NumImages < 0 || NumImages >= DFTEXTURE_MAX_IMAGES) { 
    ErrorHandler.AddError(DFERR_TEXTURE_NUMIMAGES, "NumImages=%d", NumImages);
    return (FALSE);
   }

	/* Allocate the arrays */
  AllocateArrays(NumImages);
  return (TRUE);
 }
/*===========================================================================
 *		End of Class Method CDFTextureFile::ReadHeader()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Method - boolean ReadImages (void);
 *
 * Attempt to read the image data from the current position in the file
 * stream. Returns FALSE on any error. Protected class member.
 *
 *=========================================================================*/
boolean CDFTextureFile::ReadImages (void) {
  DEFINE_FUNCTION("CDFTextureFile::ReadImages()");
  boolean Result;
  int     ImageIndex;

	/* Ensure valid object state */
  ASSERT(m_pOffsets != NULL && m_pImages != NULL);

	/* Input all image data */
  for (ImageIndex = 0; ImageIndex < m_NumImages; ImageIndex++) { 

		/* Ignore if image offset is zero (for textures 000 and 001) */
    if (m_pOffsets[ImageIndex].HeaderOffset == 0) continue;
	
		/* Jump to image header position and read */
    Result = Seek(m_pOffsets[ImageIndex].HeaderOffset, SEEK_SET);
    m_pImages[ImageIndex].Attach(GetHandle());
    if (Result) Result = m_pImages[ImageIndex].Read();
    m_pImages[ImageIndex].Detach();

    if (!Result) return (FALSE);
   }

  return (TRUE);
 }
/*===========================================================================
 *		End of Class Method CDFTextureFile::ReadImages()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFTextureFile Method - boolean ReadOffsets (void);
 *
 * Attempt to read the texture offset data from the current position in
 * the file stream.  Returns FALSE on any error.  Protected class method.
 *
 *=========================================================================*/
boolean CDFTextureFile::ReadOffsets (void) {
  DEFINE_FUNCTION("CDFTextureFile::ReadOffsets()");
  boolean Result;

	/* Move to the start of the offset records and read */
  Result = Seek(DFTEXTURE_OFFSETLIST_OFFSET, SEEK_SET);
  if (Result) Result = CGenFile::ReadEx((char *) m_pOffsets, DFTEXTURE_OFFSET_RECORDSIZE, m_NumImages);
  
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFTextureFile::ReadOffsets()
 *=========================================================================*/


/*===========================================================================
 *
 * Function - rgbpalraw_t GetDFTextureSolidColor (TextureIndex, ImageIndex);
 *
 * Returns a DF palette entry for the given solid color texture.  TextureIndex
 * must be 0 or 1 and ImageIndex from 0 to 127.  Invalid indices will result
 * in black (0) being returned.
 *
 *=========================================================================*/
rgbpalraw_t GetDFTextureSolidColor (const int TextureIndex, const int ImageIndex) {
  rgbpalraw_t* pPalette = GetDefaultDFPal();

	/* Ensure valid indices */
  if (!IsValidDFTextureIndex(TextureIndex) ||
       (ImageIndex < 0 || ImageIndex > 127)) {
       return (pPalette[0]);
   }

  return (pPalette[TextureIndex*128 + ImageIndex]);
 }
/*===========================================================================
 *		End of Function GetDFTextureSolidColor()
 *=========================================================================*/


/*===========================================================================
 *
 * Function - boolean IsDFTextureSolidColor (Index);
 *
 * Returns TRUE if the given texture index represents one of the special
 * solid color textures (0 and 1).
 *
 *=========================================================================*/
boolean IsDFTextureSolidColor (const int Index) {
  if (Index == 0 || Index == 1) return (TRUE);
  return (FALSE);
 }
/*===========================================================================
 *		End of Function IsDFTextureSolidColor()
 *=========================================================================*/
 

/*===========================================================================
 *
 * Function - boolean IsValidDFTextureIndex (Index);
 *
 * Returns TRUE if the given index is a valid Daggerfall texture index.
 *
 *=========================================================================*/
boolean IsValidDFTextureIndex (const int Index) {

  if (Index < 0 || Index >= DFTEXTURE_MAXFILES) {
    ErrorHandler.AddError(DFERR_TEXTURE_BADINDEX, "Invalid texture index %d received!", Index);
    return (FALSE);
   }

  return (TRUE);
 }
/*===========================================================================
 *		End of Function IsValidDFTextureIndex()
 *=========================================================================*/