/*
 * Class Methods for loading bitmaps
 * TextureLoadBitmap() - Load a bitmap file and define it as a 1D or 2D texture.
 *   TextureLoadMipmap() - Load a bitmap file and define it as a 1D or 2D mipmapped-texture.
 *
 */
#include "stdafx.h"
#include "texture.h"

CTexture::CTexture()
{
	// TODO: add member initialization code here
	
}

CTexture::~CTexture()
{
	if (m_rgb != NULL)
		free(m_rgb);
	if (m_info != NULL)
		free(m_info);
}


/*
 * 'TextureLoadBitmap()' - Load a bitmap file and define it as a 1D or 2D texture.
 *
 * Returns 0 on success or -1 on error.
 */

int CTexture::TextureLoadBitmap(char *filename)		/* I - Bitmap file to load */
{				/* Bitmap information */
  BITMAPINFO	*bits;				/* Bitmap pixel bits */


 /*
  * Try loading the bitmap and converting it to RGB...
  */
  bits = LoadDIBitmap(filename, &m_info);
  if (bits == NULL)
    return (-1);

  m_rgb = ConvertRGB(m_info, bits);
  if (m_rgb == NULL)
  {
    free(m_info);
    free(bits);

    return (-1);
  };

  
 /*
  * Free the bitmap and RGB images, then return 0 (no errors).
  */

  
  free(bits);
	m_bBitMap = TRUE;
  return (0);
}


/*
 * 'TextureLoadMipmap()' - Load a bitmap file and define it as a 1D or 2D mipmapped-texture.
 *
 * Returns 0 on success or -1 on error.
 */

int CTexture::TextureLoadMipmap(char *filename)		/* I - Bitmap file to load */
{
  BITMAPINFO	*bits;				/* Bitmap pixel bits */


 /*
  * Try loading the bitmap and converting it to RGB...
  */

  bits = LoadDIBitmap(filename, &m_info);
  if (bits == NULL)
    return (-1);

  m_rgb = ConvertRGB(m_info, bits);
  if (m_rgb == NULL)
  {
    free(m_info);
    free(bits);

    return (-1);
  };

 /*
  * Free the bitmap and RGB images, then return 0 (no errors).
  */
  free(bits);
	m_bBitMap = FALSE;
  return (0);
}

/*
 * 'LoadDIBitmap()' - Load a DIB/BMP file from disk.
 *
 * Returns a pointer to the bitmap if successful, NULL otherwise...
* I - File to load  
* O - Bitmap information
*/

BITMAPINFO* CTexture::LoadDIBitmap(char	*filename, BITMAPINFO	**info)		
{
  FILE			*fp;		/* Open file pointer */
  BITMAPINFO *bits;		/* Bitmap pixel bits */
  ULONG		bitsize,	/* Size of bitmap */
			infosize;	/* Size of header information */
  BITMAPFILEHEADER	header;		/* File header */


 /*
  * Try opening the file; use "rb" mode to read this *binary* file.
  */

  if ((fp = fopen(filename, "rb")) == NULL)
    return (NULL);

 /*
  * Read the file header and any following bitmap information...
  */

  if (fread(&header, sizeof(BITMAPFILEHEADER), 1, fp) < 1)
  {
   /*
    * Couldn't read the file header - return NULL...
    */

    fclose(fp);
    return (NULL);
  };

  if (header.bfType != 'MB')	/* Check for BM reversed... */
  {
   /*
    * Not a bitmap file - return NULL...
    */

    fclose(fp);
    return (NULL);
  };

  infosize = header.bfOffBits - sizeof(BITMAPFILEHEADER);
  if ((*info = (BITMAPINFO *)malloc(infosize)) == NULL)
  {
   /*
    * Couldn't allocate memory for bitmap info - return NULL...
    */

    fclose(fp);
    return (NULL);
  };

  if (fread(*info, 1, infosize, fp) < infosize)
  {
   /*
    * Couldn't read the bitmap header - return NULL...
    */

    free(*info);
    fclose(fp);
    return (NULL);
  };

 /*
  * Now that we have all the header info read in, allocate memory for the
  * bitmap and read *it* in...
  */

  if ((bitsize = (*info)->bmiHeader.biSizeImage) == 0)
    bitsize = ((*info)->bmiHeader.biWidth *
               (*info)->bmiHeader.biBitCount + 7) / 8 *
  	      abs((*info)->bmiHeader.biHeight);

  if ((bits = (BITMAPINFO *)malloc(bitsize)) == NULL)
  {
   /*
    * Couldn't allocate memory - return NULL!
    */

    free(*info);
    fclose(fp);
    return (NULL);
  };

  if (fread(bits, 1, bitsize, fp) < bitsize)
  {
   /*
    * Couldn't read bitmap - free memory and return NULL!
    */

    free(*info);
    free(bits);
    fclose(fp);
    return (NULL);
  };

 /*
  * OK, everything went fine - return the allocated bitmap...
  */

  fclose(fp);
  return (bits);
}

/*
 * 'ConvertRGB()' - Convert a DIB/BMP image to 24-bit RGB pixels.
 *
 * Returns an RGB pixel array if successful and NULL otherwise.
 * I - Original bitmap information 
 * I - Original bitmap pixels 
 */
GLubyte * CTexture::ConvertRGB(BITMAPINFO *info, BITMAPINFO* bits)		
{
  int i, j;			/* Looping vars */
  int bitsize;		/* Total size of bitmap */
	int width;			/* Aligned width of bitmap */
  GLubyte	*newbits;		/* New RGB bits */
  GLubyte	*from, *to;		/* RGB looping vars */


 /*
  * Allocate memory for the RGB bitmap...
  */

  width   = 3 * info->bmiHeader.biWidth;
  width   = (width + 3) & ~3;	
  bitsize = width * info->bmiHeader.biHeight;
  if ((newbits = (GLubyte *)calloc(bitsize, 1)) == NULL)
    return (NULL);

 /*
  * Copy the original bitmap to the new array, converting as necessary.
  */

  switch (info->bmiHeader.biCompression)
  {
    case BI_RGB :
        if (info->bmiHeader.biBitCount == 24)
		{
         /*
          * Swap red & blue in a 24-bit image...
          */

          for (i = 0; i < info->bmiHeader.biHeight; i ++)
						for (j = 0, from = ((GLubyte *)bits) + i * width,
	             to = newbits + i * width;
								j < info->bmiHeader.biWidth;
								j ++, from += 3, to += 3)
						{
							to[0] = from[2];
              to[1] = from[1];
              to[2] = from[0];
            };
	};
	break;
    case BI_RLE4 :
    case BI_RLE8 :
    case BI_BITFIELDS :
        break;
  };

  return (newbits);
}

/**
*Bind this texture to make it the current one
*/
void CTexture::MakeCurrent()
{
	/*
  * Define the texture image.  If the width or height is 1, then we
  * define a 1D texture.
  */

  glPixelStorei(GL_UNPACK_ALIGNMENT, 4);	/* Force 4-byte alignment */
  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
  glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);


	if (!m_bBitMap)
	{
		if (m_info->bmiHeader.biHeight == 1)
		{
			gluBuild1DMipmaps(GL_TEXTURE_1D, 3, m_info->bmiHeader.biWidth, GL_RGB, GL_UNSIGNED_BYTE, m_rgb);
			glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
		}
		else if (m_info->bmiHeader.biWidth == 1)
		{
			gluBuild1DMipmaps(GL_TEXTURE_1D, 3, m_info->bmiHeader.biHeight, GL_RGB, GL_UNSIGNED_BYTE, m_rgb);
			glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
		}
		else
		{
			gluBuild2DMipmaps(GL_TEXTURE_2D, 3, m_info->bmiHeader.biWidth, m_info->bmiHeader.biHeight,
                      GL_RGB, GL_UNSIGNED_BYTE, m_rgb);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
		}
	}
	else
	{//its a bitmap
		if (m_info->bmiHeader.biHeight == 1)
		{
			glTexImage1D(GL_TEXTURE_1D, 0, 3, m_info->bmiHeader.biWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, m_rgb);
			glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}
		else if (m_info->bmiHeader.biWidth == 1)
		{
			glTexImage1D(GL_TEXTURE_1D, 0, 3, m_info->bmiHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, m_rgb);
			glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}
		else
		{
			glTexImage2D(GL_TEXTURE_2D, 0, 3, m_info->bmiHeader.biWidth, m_info->bmiHeader.biHeight, 0,
                 GL_RGB, GL_UNSIGNED_BYTE, m_rgb);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}

	}
	//generate an id for it
	/*glGenTextures(1, &m_textureID);
	*/
}



