/***************************************************************************
texture.cpp
----------------------------------------------------------------------------
begin                : june 2003
copyright            : (C) 2003 by Pierre Alliez - INRIA
email                : pierre.alliez@sophia.inria.fr
***************************************************************************/

#include <math.h>
#include <string.h>
#include "texture.h"


//////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////

//********************************************
// Constructor
//********************************************
Texture::Texture()
{
  m_pData = NULL;
  m_Width = 0;
  m_WidthByte32 = 0;
  m_Height = 0;
  m_Depth = 0;
}

//********************************************
// Destructor
//********************************************
Texture::~Texture()
{
  Free();
}


//////////////////////////////////////////////
// DATA
//////////////////////////////////////////////

//********************************************
// Alloc
//********************************************
int Texture::Alloc(unsigned int width, unsigned int height, unsigned int depth)
{
  Free();

  unsigned int Width32 = WidthByte32(width,depth);

  m_pData = new unsigned char [Width32 * height];
  if(m_pData == NULL)
  {
    return 0;
  }

  // Set members variables
  m_Width       = width;
  m_WidthByte32 = Width32;
  m_Height      = height;
  m_Depth       = depth;
  UpdateHeader();

  return 1;
}

//********************************************
// Free
//********************************************
void Texture::Free()
{
  if(m_pData != NULL)
  {
    delete [] m_pData;
    m_pData = NULL;
  }
  m_Width = 0;
  m_Height = 0;
  m_Depth = 0;
}



//********************************************
// UpdateWidthByte32
//********************************************
void Texture::UpdateWidthByte32()
{
  m_WidthByte32 = WidthByte32(m_Width,m_Depth);
}

//********************************************
// WidthByte32
//********************************************
unsigned int Texture::WidthByte32(unsigned int width, unsigned int depth)
{
  // 32 bits alignment (4 bytes)
  int rest=(width*depth/8)%4;
  if(rest != 0)
    return (width*depth/8 + 4-rest);
  else
    return (width*depth/8);
}

//********************************************
// UpdateHeader
//********************************************
void Texture::UpdateHeader()
{
  UpdateWidthByte32();
}



//////////////////////////////////////////////
//////////////////////////////////////////////
// CHECKING
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// IsValid
//********************************************
int Texture::IsValid()
{
  int success = 0;
  success = (m_Depth == 24) || (m_Depth == 32);
  success &= (m_Width != 0);
  success &= (m_Height != 0);
  success &= (m_pData != NULL);
  return success;
}

//********************************************
// HigherPowerOfTwo
//********************************************
int Texture::HigherPowerOfTwo(int value)
{
  if(value <= 0)
    return value;

  int power = 1;
  int x = 0;

  while(1)
  {
    x = (int)pow(2.0,(double)power);
    if(x >= value)
      return x;
    power++;
  }
}

//********************************************
// LowerPowerOfTwo
//********************************************
int Texture::LowerPowerOfTwo(int value)
{
  if(value <= 0)
    return value;

  int power = 1;
  int x = 0;

  while(1)
  {
    x = (int)pow(2.0,(double)power);
    if(x >= value)
      return (int)pow(2.0,(double)power-1);
    power++;
  }
}

//********************************************
// SameSize
//********************************************
int Texture::SameSize(Texture *pTexture)
{
  int success = (m_Width == pTexture->GetWidth());
  success &= (m_Height == pTexture->GetHeight());
  return success;
}


//********************************************
// Flip BGR to RGB
//********************************************
int Texture::BGRtoRGB()
{
  if(!IsValid())
    return 0;

  unsigned char pixel;
  int BytePerPixel = m_Depth/8;
  for(unsigned int j=0;j<m_Height;j++)
    for(unsigned int i=0;i<m_Width;i++)
    {
      pixel = m_pData[m_WidthByte32*j+i*BytePerPixel+2];
      m_pData[m_WidthByte32*j+i*BytePerPixel+2] = m_pData[m_WidthByte32*j+i*BytePerPixel];
      m_pData[m_WidthByte32*j+i*BytePerPixel] = pixel;
    }
  return 1;
}

//////////////////////////////////////////////
//////////////////////////////////////////////
// DUPLICATE
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// Extract
//********************************************
int Texture::Extract(int left, int top, int right, int bottom)
{
  // Saturate
  if(right == -1)
    right = m_Width-1;
  if(bottom == -1)
    bottom = m_Height-1;

  // Check
  if(left >= right || top >= bottom)
    return 0;
  if(left < 0  || left >= (int)m_Width || 
    right < 0 || right >= (int)m_Width)
    return 0;
  if(top < 0  || top >= (int)m_Height || 
    bottom < 0 || bottom >= (int)m_Height)
    return 0;

  int NewWidth = right-left+1;
  int NewWidthByte32 = WidthByte32(NewWidth,m_Depth);
  int NewHeight = bottom-top+1;
  int BytePerPixel = m_Depth / 8;
  int i,j,k;

  //TRACE("Start extracting...\n");
  //TRACE("New width : %d\n",NewWidth);
  //TRACE("New height : %d\n",NewHeight);

  // Alloc
  unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
  if(pData == NULL)
  {
    //TRACE("Insufficiant memory");
    return 0;
  }

  for(j=0;j<NewHeight;j++)
    for(i=0;i<NewWidth;i++)
      for(k=0;k<BytePerPixel;k++)
	pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(m_Height-1-(j+top))+(i+left)*BytePerPixel+k];

  // Replace datas
  delete [] m_pData;
  m_pData = pData;
  m_Width = NewWidth;
  m_WidthByte32 = NewWidthByte32;
  m_Height = NewHeight;

  UpdateHeader();

  return 1;
}


//********************************************
// DuplicateMirror
//********************************************
int Texture::DuplicateMirror(int left, int top, int right, int bottom)
{

  if(!Extract(left,top,right,bottom))
    return 0;

  left = 0;
  right = m_Width-1;
  top = 0;
  bottom = m_Height-1;

  int NewWidth = 2*m_Width;
  int NewWidthByte32 = WidthByte32(NewWidth,m_Depth);
  int NewHeight = 2*m_Height;
  int BytePerPixel = m_Depth / 8;
  int i,j,k;

  //TRACE("Start duplicate mirror...\n");
  //TRACE("New width : %d\n",NewWidth);
  //TRACE("New widthbyte32 : %d\n",NewWidthByte32);
  //TRACE("New height : %d\n",NewHeight);

  // Alloc
  unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
  if(pData == NULL)
  {
    //TRACE("Insufficiant memory");
    return 0;
  }

  // o o
  // x o
  for(j=0;j<NewHeight/2;j++)
    for(i=0;i<NewWidth/2;i++)
      for(k=0;k<BytePerPixel;k++)
	pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(bottom-(j+top))+(i+left)*BytePerPixel+k];
  // o o
  // o x
  for(j=0;j<NewHeight/2;j++)
    for(i=NewWidth/2;i<NewWidth;i++)
      for(k=0;k<BytePerPixel;k++)
	pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(bottom-(j+top))+(right-(i-NewWidth/2+left))*BytePerPixel+k];
  // x o
  // o o
  for(j=NewHeight/2;j<NewHeight;j++)
    for(i=0;i<NewWidth/2;i++)
      for(k=0;k<BytePerPixel;k++)
	pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(j-NewHeight/2+top)+(i+left)*BytePerPixel+k];
  // o x
  // o o
  for(j=NewHeight/2;j<NewHeight;j++)
    for(i=NewWidth/2;i<NewWidth;i++)
      for(k=0;k<BytePerPixel;k++)
	pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(j-NewHeight/2+top)+(right-(i-NewWidth/2+left))*BytePerPixel+k];

  // Replace datas
  delete [] m_pData;
  m_pData = pData;
  m_Width = NewWidth;
  m_WidthByte32 = NewWidthByte32;
  m_Height = NewHeight;

  UpdateHeader();

  return 1;
}




//********************************************
// DuplicateRepeatWidth
//********************************************
int Texture::DuplicateRepeatWidth(int left, int top, int right, int bottom)
{
  if(!Extract(left,top,right,bottom))
    return 0;

  left = 0;
  right = m_Width-1;
  top = 0;
  bottom = m_Height-1;

  int NewWidth = 2*m_Width;
  int NewWidthByte32 = WidthByte32(NewWidth,m_Depth);
  int NewHeight = m_Height;
  int BytePerPixel = m_Depth / 8;
  int i,j,k;

  ////TRACE("Start duplicate repeat width...\n");
  ////TRACE("New width : %d\n",NewWidth);
  ////TRACE("New widthbyte32 : %d\n",NewWidthByte32);
  ////TRACE("New height : %d\n",NewHeight);

  // Alloc
  unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
  if(pData == NULL)
  {
    ////TRACE("Insufficiant memory");
    return 0;
  }

  // x o
  for(j=0;j<NewHeight;j++)
    for(i=0;i<NewWidth/2;i++)
      for(k=0;k<BytePerPixel;k++)
	pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(bottom-(j+top))+(i+left)*BytePerPixel+k];
  // o x
  for(j=0;j<NewHeight;j++)
    for(i=NewWidth/2;i<NewWidth;i++)
      for(k=0;k<BytePerPixel;k++)
	pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(bottom-(j+top))+(i-NewWidth/2+left)*BytePerPixel+k];

  // Replace datas
  delete [] m_pData;
  m_pData = pData;
  m_Width = NewWidth;
  m_WidthByte32 = NewWidthByte32;
  m_Height = NewHeight;

  UpdateHeader();

  return 1;
}


//********************************************
// Fill
//********************************************
void Texture::Fill(unsigned char r,
		   unsigned char g,
		   unsigned char b)
{
  if(!IsValid()) return;
  if(m_Depth != 24) return;
  for(unsigned int j=0;j<m_Height;j++)
    for(unsigned int i=0;i<m_Width;i++)
    {
      m_pData[m_WidthByte32*j+i*3] = b;
      m_pData[m_WidthByte32*j+i*3+1] = g;
      m_pData[m_WidthByte32*j+i*3+2] = r;
    }
}


//***************************************
// GreyToColor
//***************************************
void Texture::GreyToColor(unsigned char grey,
			  unsigned char r, 
			  unsigned char g,
			  unsigned char b)
{
  if(!IsValid()) return;
  if(m_Depth != 24) return;
  for(unsigned int j=0;j<m_Height;j++)
    for(unsigned int i=0;i<m_Width;i++)
    {
      if(m_pData[m_WidthByte32*j+i*3] == grey)
      {
	m_pData[m_WidthByte32*j+i*3] = b;
	m_pData[m_WidthByte32*j+i*3+1] = g;
	m_pData[m_WidthByte32*j+i*3+2] = r;
      }
    }
}

//***************************************
// ColorToColor
//***************************************
void Texture::ColorToColor(unsigned char r1,
			   unsigned char g1,
			   unsigned char b1,
			   unsigned char r2, 
			   unsigned char g2,
			   unsigned char b2)
{
  if(!IsValid()) return;
  if(m_Depth != 24) return;
  for(unsigned int j=0;j<m_Height;j++)
    for(unsigned int i=0;i<m_Width;i++)
    {
      if(m_pData[m_WidthByte32*j+i*3] == b1 &&
	m_pData[m_WidthByte32*j+i*3+1] == g1 &&
	m_pData[m_WidthByte32*j+i*3+2] == r1)
      {
	m_pData[m_WidthByte32*j+i*3]   = b2;
	m_pData[m_WidthByte32*j+i*3+1] = g2;
	m_pData[m_WidthByte32*j+i*3+2] = r2;
      }
    }
}

//////////////////////////////////////////////
//////////////////////////////////////////////
// ALPHA
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// SetAlphaLayer
//********************************************
int Texture::SetAlphaLayer(unsigned char alpha) // 0 - 255
{
  // Check
  if(!IsValid())
    return 0;

  if(m_Depth != 32)
    return 0;

  // Fill alpha layer 
  int size = m_Width * m_Height;
  for(int i=0;i<4*size;i+=4)
    m_pData[i+3] = alpha;

  return 1;
}

//********************************************
// AddAlphaLayer
//********************************************
int Texture::AddAlphaLayer(unsigned char alpha) // 0 - 255
{
  // Check
  if(!IsValid())
    return 0;

  // Has soon alpha
  if(HasAlpha())
    return SetAlphaLayer(alpha);

  // Alloc memory
  unsigned char *pData = new unsigned char[4*m_Width*m_Height];
  if(pData == NULL)
  {
    //TRACE("Texture::AddAlphaLayer : insufficiant memory");
    return 0;
  }

  // Fill new data
  int size = m_Width * m_Height;
  int BytePerPixel = m_Depth / 8;
  for(int i=0;i<size;i++)
  {
    pData[4*i+0] = m_pData[BytePerPixel*i+0];
    pData[4*i+1] = m_pData[BytePerPixel*i+1];
    pData[4*i+2] = m_pData[BytePerPixel*i+2];
    pData[4*i+3] = alpha;
  }

  // Set new depth
  m_Depth = 32;

  // Replace datas
  delete [] m_pData;
  m_pData = pData;

  return 1;
}


//********************************************
// SetAlpha
// From RGB to grey scales, then alpha layer
//********************************************
int Texture::SetAlphaLayer(Texture *pTexture) 
{
  // Check
  if(!IsValid())
    return 0;
  if(!pTexture->IsValid())
    return 0;

  if(!SameSize(pTexture))
    return 0;

  if(!AddAlphaLayer(0))
    return 0;

  // Fill new data
  unsigned char *pData = pTexture->GetData();
  int size = m_Width * m_Height;
  int BytePerPixel = pTexture->GetDepth() / 8;
  for(int i=0;i<size;i++)
    m_pData[4*i+3] = (unsigned char)((int)pData[BytePerPixel*i+0]+
    (int)pData[BytePerPixel*i+1]+
    (int)pData[BytePerPixel*i+2])/3;

  return 1;
}

//////////////////////////////////////////////
//////////////////////////////////////////////
// DISPLAY
//////////////////////////////////////////////
//////////////////////////////////////////////


//********************************************
// ReadBuffer
//********************************************
int Texture::ReadBuffer(unsigned char *buffer, 
			int width, 
			int height, 
			int depth)
{
  if(buffer == NULL)
    return 0;

  if(!Alloc(width,height,depth))
    return 0;

  int BytePerPixel = depth / 8;

  for(int j=0;j<height;j++)
    for(int i=0;i<width;i++)
      for(int k=0;k<BytePerPixel;k++)
	m_pData[m_WidthByte32*j + i*BytePerPixel+k] = 
	buffer[(width*j+i)*BytePerPixel+k];

  return 1;
}


//********************************************
// ReadBufferByte32
//********************************************
int Texture::ReadBufferByte32(unsigned char *pData, 
			      int width, 
			      int height)
{
  // alloc 32 bits buffer
  if(!Alloc(width,height,32))
    return 0;

  if(pData == NULL)
    return 0;

  memcpy(m_pData,pData,height*m_WidthByte32);
  return 1;
}


//***************************************
// Copy
//***************************************
void Texture::Copy(Texture *pTexture)
{
  unsigned char *pBuffer = pTexture->GetData();
  if(pBuffer == NULL)
    return;

  unsigned int width = pTexture->GetWidth();
  unsigned int height = pTexture->GetHeight();
  unsigned int depth = pTexture->GetDepth();
  if(!Alloc(width,height,depth))
    return;

  unsigned int BytePerPixel = depth / 8;

  for(unsigned int j=0;j<height;j++)
    for(unsigned int i=0;i<width;i++)
      for(unsigned int k=0;k<BytePerPixel;k++)
	m_pData[m_WidthByte32*j + i*BytePerPixel+k] = 
	pBuffer[(width*j+i)*BytePerPixel+k];
}


//********************************************
// ReadBuffer
//********************************************
int Texture::ReadBuffer(float *buffer, 
			int width, 
			int height, 
			int depth)
{
  if(buffer == NULL)
    return 0;

  if(!Alloc(width,height,depth))
    return 0;

  int BytePerPixel = depth / 8;

  for(int j=0;j<height;j++)
    for(int i=0;i<width;i++)
      for(int k=0;k<BytePerPixel;k++)
	m_pData[m_WidthByte32*j + i*BytePerPixel+k] = 
	(unsigned char)(255.0f * buffer[(width*j+i)*BytePerPixel+k]);

  return 1;
}

//********************************************
// ReadBuffer
//********************************************
int Texture::ReadBuffer(float **ppBuffer, 
			int width, 
			int height,
			float ratio)
{
  if(ppBuffer == NULL)
    return 0;

  if(!Alloc(width,height,24))
    return 0;

  for(int j=0;j<height;j++)
    for(int i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = (unsigned char)(ratio*ppBuffer[j][i]);
      m_pData[m_WidthByte32*j + i*3+1] = (unsigned char)(ratio*ppBuffer[j][i]);
      m_pData[m_WidthByte32*j + i*3+2] = (unsigned char)(ratio*ppBuffer[j][i]);
    }
  return 1;
}

//********************************************
// WriteBuffer
//********************************************
int Texture::WriteBuffer(float **ppBuffer, 
			 int width, 
			 int height)
{
  if(ppBuffer == NULL)
    return 0;

  for(int j=0;j<height;j++)
    for(int i=0;i<width;i++) // only first channel
      ppBuffer[j][i] = m_pData[m_WidthByte32*j + i*3];
  return 1;
}

//********************************************
// WriteBuffer32
//********************************************
int Texture::WriteBuffer32(float **ppBuffer, 
			   int width, 
			   int height)
{
  if(ppBuffer == NULL)
    return 0;
  //ASSERT(m_Depth == 32);
  unsigned int r,g,b;
  int tmp;
  for(int j=0;j<height;j++)
  {
    tmp = m_WidthByte32*j;
    for(int i=0;i<width;i++) // from 3 channels
    {
      b = m_pData[tmp + i*4];
      g = m_pData[tmp + i*4+1];
      r = m_pData[tmp + i*4+2];
      unsigned int value = (r << 16) + (g << 8) + b;
      ppBuffer[j][i] = (float)value;
    }
  }
  return 1;
}

//********************************************
// ReadBuffer
//********************************************
int Texture::ReadBuffer(double *buffer, 
			int width, 
			int height, 
			int depth)
{
  if(buffer == NULL)
    return 0;

  if(!Alloc(width,height,depth))
    return 0;

  int BytePerPixel = depth / 8;

  for(int j=0;j<height;j++)
    for(int i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*BytePerPixel]   = (unsigned char)buffer[width*j+i];
      m_pData[m_WidthByte32*j + i*BytePerPixel+1] = (unsigned char)buffer[width*j+i];
      m_pData[m_WidthByte32*j + i*BytePerPixel+2] = (unsigned char)buffer[width*j+i];
    }

  return 1;
}


//********************************************
// Grey
//********************************************
int Texture::Grey(unsigned int x, unsigned int y)
{
  int BytePerPixel = m_Depth / 8;
  // Grey scale
  if(BytePerPixel == 1)
    return (int)m_pData[m_WidthByte32*y + x]; 
  else // 24 or 32 bits (alpha layer)
    return (int)((int)m_pData[m_WidthByte32*y + x*BytePerPixel+0]+ 
    (int)m_pData[m_WidthByte32*y + x*BytePerPixel+1]+
    (int)m_pData[m_WidthByte32*y + x*BytePerPixel+2])/3;
}

//********************************************
// Color
//********************************************
void Texture::Color(unsigned int x, unsigned int y, 
		    unsigned char *pRed, unsigned char *pGreen, unsigned char *pBlue)
{
  int BytePerPixel = m_Depth / 8;
  // Grey scale
  if(BytePerPixel == 1)
  {
    *pRed = m_pData[m_WidthByte32*y + x]; 
    *pGreen = m_pData[m_WidthByte32*y + x]; 
    *pBlue = m_pData[m_WidthByte32*y + x]; 
  }
  else // 24 or 32 bits (alpha layer)
  {
    *pRed = m_pData[m_WidthByte32*y + x*BytePerPixel]; 
    *pGreen = m_pData[m_WidthByte32*y + x*BytePerPixel+1]; 
    *pBlue = m_pData[m_WidthByte32*y + x*BytePerPixel+2]; 
  }
}





void Texture::GenerateMirrorV(unsigned int width,
			      unsigned int height, 
			      unsigned char r,
			      unsigned char g,
			      unsigned char b,
			      unsigned char rb,
			      unsigned char gb,
			      unsigned char bb)
{
  Alloc(width,height,24);

  for(unsigned j=0;j<height;j++)
    for(unsigned int i=0;i<width/4;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = r;
      m_pData[m_WidthByte32*j + i*3+1] = g;
      m_pData[m_WidthByte32*j + i*3+2] = b;
    }
  for(unsigned j=0;j<height;j++)
    for(unsigned int i=width/4;i<3*width/4;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = rb;
      m_pData[m_WidthByte32*j + i*3+1] = gb;
      m_pData[m_WidthByte32*j + i*3+2] = bb;
    }
  for(unsigned j=0;j<height;j++)
    for(unsigned int i=3*width/4;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = r;
      m_pData[m_WidthByte32*j + i*3+1] = g;
      m_pData[m_WidthByte32*j + i*3+2] = b;
    }
}

void Texture::GenerateMirrorH(unsigned int width,
			      unsigned int height, 
			      unsigned char r,
			      unsigned char g,
			      unsigned char b,
			      unsigned char rb,
			      unsigned char gb,
			      unsigned char bb)
{
  Alloc(width,height,24);

  for(unsigned j=0;j<height/4;j++)
    for(unsigned int i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = r;
      m_pData[m_WidthByte32*j + i*3+1] = g;
      m_pData[m_WidthByte32*j + i*3+2] = b;
    }
  for(unsigned j=height/4;j<3*height/4;j++)
    for(unsigned int i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = rb;
      m_pData[m_WidthByte32*j + i*3+1] = gb;
      m_pData[m_WidthByte32*j + i*3+2] = bb;
    }
  for(unsigned j=3*height/4;j<height;j++)
    for(unsigned int i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = r;
      m_pData[m_WidthByte32*j + i*3+1] = g;
      m_pData[m_WidthByte32*j + i*3+2] = b;
  }
}


void Texture::GenerateCheckerBoard(unsigned int width,
				   unsigned int height, 
				   int size,
				   unsigned char r,
				   unsigned char g,
				   unsigned char b,
				   unsigned char rb,
				   unsigned char gb,
				   unsigned char bb)
{
  Alloc(width,height,24);

  for(unsigned j=0;j<height;j++)
    for(unsigned int i=0;i<width;i++)
    {
      int h = (int)((double)i/(double)size);
      int v = (int)((double)j/(double)size);
      bool h_odd = (h%2) == 0;
      bool v_odd = (v%2) == 0;
      if((h_odd	+ v_odd)%2 == 0)
      {
	m_pData[m_WidthByte32*j + i*3]   = rb;
	m_pData[m_WidthByte32*j + i*3+1] = gb;
	m_pData[m_WidthByte32*j + i*3+2] = bb;
      }
      else
      {
	m_pData[m_WidthByte32*j + i*3]   = r;
	m_pData[m_WidthByte32*j + i*3+1] = g;
	m_pData[m_WidthByte32*j + i*3+2] = b;
      }
    }
}

void Texture::GenerateVStripes(unsigned int width,
			       unsigned int height, 
			       int size,
			       unsigned char r,
			       unsigned char g,
			       unsigned char b,
			       unsigned char rb,
			       unsigned char gb,
			       unsigned char bb)
{
  Alloc(width,height,24);

  for(unsigned j=0;j<height;j++)
    for(unsigned int i=0;i<width;i++)
    {
      int h = (int)((double)i/(double)size);
      bool h_odd = (h%2) == 0;
      if(h_odd)
      {
	m_pData[m_WidthByte32*j + i*3]   = rb;
	m_pData[m_WidthByte32*j + i*3+1] = gb;
	m_pData[m_WidthByte32*j + i*3+2] = bb;
      }
      else
      {
	m_pData[m_WidthByte32*j + i*3]   = r;
	m_pData[m_WidthByte32*j + i*3+1] = g;
	m_pData[m_WidthByte32*j + i*3+2] = b;
      }
    }
}

void Texture::GenerateHStripes(unsigned int width,
			       unsigned int height, 
			       int size,
			       unsigned char r,
			       unsigned char g,
			       unsigned char b,
			       unsigned char rb,
			       unsigned char gb,
			       unsigned char bb)
{
  Alloc(width,height,24);

  for(unsigned j=0;j<height;j++)
    for(unsigned int i=0;i<width;i++)
    {
      int v = (int)((double)j/(double)size);
      bool v_odd = (v%2) == 0;
      if(v_odd)
      {
	m_pData[m_WidthByte32*j + i*3]   = rb;
	m_pData[m_WidthByte32*j + i*3+1] = gb;
	m_pData[m_WidthByte32*j + i*3+2] = bb;
      }
      else
      {
	m_pData[m_WidthByte32*j + i*3]   = r;
	m_pData[m_WidthByte32*j + i*3+1] = g;
	m_pData[m_WidthByte32*j + i*3+2] = b;
      }
    }
}


//***************************************
// GenerateGrid
//***************************************
void Texture::GenerateGrid(unsigned int width,
			   unsigned int height, 
			   int /*size*/,
			   unsigned int thickness,
			   unsigned char r,
			   unsigned char g,
			   unsigned char b,
			   unsigned char rb,
			   unsigned char gb,
			   unsigned char bb)
{
  Alloc(width,height,24);

  // fill background
  unsigned int i,j;
  for(j=0;j<height;j++)
    for(i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = rb;
      m_pData[m_WidthByte32*j + i*3+1] = gb;
      m_pData[m_WidthByte32*j + i*3+2] = bb;
    }

  // horizontal
  for(j=height/2-thickness/2;j<height/2+thickness/2;j++)
  {
    for(i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = r;
      m_pData[m_WidthByte32*j + i*3+1] = g;
      m_pData[m_WidthByte32*j + i*3+2] = b;
    }
  }

  // vertical
  for(unsigned int i=width/2-thickness/2;i<width/2+thickness/2;i++)
    for(unsigned int j=0;j<height;j++)
    {
      m_pData[m_WidthByte32*j + i*3]   = r;
      m_pData[m_WidthByte32*j + i*3+1] = g;
      m_pData[m_WidthByte32*j + i*3+2] = b;
    }
}

void Texture::GenerateGradientH(unsigned int width,
				unsigned int height,
				int /*size*/)
{
  Alloc(width,height,24);

  // fill background
  for(unsigned int i=0;i<width;i++)
  {
    unsigned char g = (unsigned char)(255.0 * (double)i / (double)(width-1));
    for(unsigned int j=0;j<height;j++)
    {
      m_pData[m_WidthByte32*j + i*3]   = g;
      m_pData[m_WidthByte32*j + i*3+1] = g;
      m_pData[m_WidthByte32*j + i*3+2] = g;
    }
  }
}
void Texture::GenerateGradientV(unsigned int width,
				unsigned int height,
				int /*size*/)
{
  Alloc(width,height,24);

  // fill background
  for(unsigned int j=0;j<height;j++)
  {
    unsigned char g = (unsigned char)(255.0 * (double)j / (double)(height-1));
    for(unsigned int i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = g;
      m_pData[m_WidthByte32*j + i*3+1] = g;
      m_pData[m_WidthByte32*j + i*3+2] = g;
    }
  }
}

//***************************************
// GenerateLines
//***************************************
void Texture::GenerateLines(unsigned int width,
			    unsigned int height, 
			    int size,
			    unsigned char r,
			    unsigned char g,
			    unsigned char b,
			    unsigned char rb,
			    unsigned char gb,
			    unsigned char bb)
{
  Alloc(width,height,24);

  // fill background
  unsigned int i,j;
  for(j=0;j<height;j++)
    for(i=0;i<width;i++)
    {
      m_pData[m_WidthByte32*j + i*3]   = rb;
      m_pData[m_WidthByte32*j + i*3+1] = gb;
      m_pData[m_WidthByte32*j + i*3+2] = bb;
    }

    // horizontal zebra
    for(j=0;j<height;j++)
    {
      if((j/size)%2 == 0)
	for(i=0;i<width;i++)
	{
	  m_pData[m_WidthByte32*j + i*3]   = r;
	  m_pData[m_WidthByte32*j + i*3+1] = g;
	  m_pData[m_WidthByte32*j + i*3+2] = b;
	}
    }
}






// ** EOF **



