Click here to Skip to main content
Click here to Skip to main content
Articles » Multimedia » OpenGL » General » Downloads
 
Add your own
alternative version

True OpenGL Zooming

, 11 Feb 2002
True zooming on a perspective view...
zoomperspective.zip
ZoomPerspective
Release
ZoomPerspective.exe
res
Apple.bmp
Toolbar.bmp
ZoomPerspective.ico
ZoomPerspectiveDoc.ico
Zoom.jpg
ZoomPerspective.dep
ZoomPerspective.dsp
ZoomPerspective.dsw
ZoomPerspective.mak
ZoomPerspective.ver
//********************************************
// Texture.cpp
//********************************************
// class CTexture
//********************************************
// pierre.alliez@cnet.francetelecom.fr
// Created : 17/12/97
// Modified : 19/12/97
//********************************************

#include "stdafx.h"
#include "math.h"
#include "Texture.h"

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

//********************************************
// Constructor
//********************************************
CTexture::CTexture()
{
	m_pData = NULL;
	m_Width = 0;
	m_WidthByte32 = 0;
	m_Height = 0;
	m_Depth = 0;
	m_FileName = _T("");
}

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


//////////////////////////////////////////////
// DATAS
//////////////////////////////////////////////

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

	unsigned int BytePerPixel = (unsigned int)(depth / 8);
	unsigned int Width32 = WidthByte32(width,depth);

	// Only rgb and rgba modes
	ASSERT(BytePerPixel == 3 || 
		     BytePerPixel == 4);

	m_pData = new unsigned char [Width32 * height];
	if(m_pData == NULL)
		{
		TRACE("CTexture::Alloc : Insuffisant memory\n");
		AfxMessageBox("CTexture::Alloc : Insufisant memory");
		return 0;
		}

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

	return 1;
}

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


//////////////////////////////////////////////
//////////////////////////////////////////////
// FILE READING
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// ReadFile
// Redirection
//********************************************
int CTexture::ReadFile(char *filename,
											 unsigned int width,
											 unsigned int height,
											 unsigned int depth)
{
	// Cleanup
	Free();

	// Storage
	m_FileName = filename;

	// Extension
	CString string = filename;
	string.MakeLower();
	TRACE("CTexture::ReadFile : file : %s\n",filename);
	CString extension = string.Right(4);

	// Redirection BMP
	if(extension == ".bmp")
		return ReadFileBMP(filename);

	// Redirection RAW
	if(extension == ".raw")
		return ReadFileRAW(filename,width,height,depth);

	// Unrecognized file format
	CString message;
	message.Format("CTexture::ReadFile : invalid file redirection : %s\n",filename);
	AfxMessageBox(string);

	return 0;
}


//********************************************
// ReadFileBMP (*.bmp)
//********************************************
// Read windows bmp files
// Accept only 24 bits
// Size : 2^n x 2^m
//********************************************
int CTexture::ReadFileBMP(char *filename)
{

	// Check for valid bmp file
	CFile file;
	CFileException ex;
	
	// Try to open file
	if(!file.Open(filename, CFile::modeRead | CFile::typeBinary,&ex))
	{
		#ifdef _DEBUG
		  afxDump << "File could not be opened " << ex.m_cause << "\n";
		#endif
		AfxMessageBox("Unable to open file for reading");
		return 0;
	}

	// File header
	BITMAPFILEHEADER FileHeader;
	TRY
	{
		file.Read(&FileHeader,sizeof(BITMAPFILEHEADER));
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during reading " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during reading file header");
		file.Close();
		return 0;
	}
	END_CATCH

	TRACE("FileHeader.bfType : %d\n",FileHeader.bfType);
	TRACE("FileHeader.bfSize : %d\n",FileHeader.bfSize);
	TRACE("FileHeader.bfReserved1 : %d\n",FileHeader.bfReserved1);
	TRACE("FileHeader.bfReserved2 : %d\n",FileHeader.bfReserved2);
	TRACE("FileHeader.bfOffBits : %d\n",FileHeader.bfOffBits);

	// Is it a Windows BMP file ? (BM)
  WORD sign = ((WORD) ('M' << 8) | 'B');
	if(FileHeader.bfType != sign)
	{
		AfxMessageBox("Invalid BMP file");
		file.Close();
		return 0;
	}

	// Image header
	TRY
	{
		file.Read(&m_Header,sizeof(BITMAPINFOHEADER));
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during reading " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during reading image header");
		file.Close();
		return 0;
	}
	END_CATCH

	// DEBUG
	TRACE("\n");
	TRACE("**** IMAGE HEADER :\n");
	TRACE("**** biSize : %d\n",m_Header.biSize);
	TRACE("**** biWidth : %d\n",m_Header.biWidth);
	TRACE("**** biHeight : %d\n",m_Header.biHeight);
	TRACE("**** biPlanes : %d\n",m_Header.biPlanes);
	TRACE("**** biBitCount : %d\n",m_Header.biBitCount);
	TRACE("**** biCompression : %d\n",m_Header.biCompression);
	TRACE("**** biSizeImage : %d\n",m_Header.biSizeImage);
	TRACE("**** biXPelsPerMeter : %d\n",m_Header.biXPelsPerMeter);
	TRACE("**** biYPelsPerMeter : %d\n",m_Header.biYPelsPerMeter);
	TRACE("**** biClrUsed : %d\n",m_Header.biClrUsed);
	TRACE("**** biClrImportant : %d\n",m_Header.biClrImportant);

	// 24 bits ?
	if(m_Header.biPlanes != 1 ||
		 m_Header.biBitCount != 24)
	{
		AfxMessageBox("Texture file must have 24 bits depth");
		file.Close();
		return 0;
	}
   //
   // Non ho capito perche' ma molti editor settano a 0 biSizeImage !
   //
   if( !m_Header.biSizeImage ){
      UINT  nStride = (m_Header.biWidth * (m_Header.biBitCount/8) + 1) & (~1); // Stride is the BMP's bytes per row.
      m_Header.biSizeImage = nStride * m_Header.biHeight;
   }

	// Alloc (does call Free before)
	Free();
	m_pData = new unsigned char[m_Header.biSizeImage];
	if(m_pData == NULL)
	{
		AfxMessageBox("Insuffisant memory");
		file.Close();
		return 0;
	}

	// Update datas
	m_Width = m_Header.biWidth;
	m_Height = m_Header.biHeight;
	m_Depth = m_Header.biBitCount;

	// Image reading
	TRY
	{
		file.Read(m_pData,m_Header.biSizeImage);
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during reading " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during reading image");
		file.Close();
		return 0;
	}
	END_CATCH

	// Close file
  file.Close();

	// Success, also set FileName
	m_FileName = filename;

	UpdateWidthByte32();

	return 1;
}

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

//********************************************
// WidthByte32
//********************************************
unsigned int CTexture::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 CTexture::UpdateHeader()
{
	UpdateWidthByte32();

	m_Header.biWidth = m_Width;
	m_Header.biHeight = m_Height;
	m_Header.biSizeImage = m_WidthByte32 * m_Height;

	m_Header.biSize = 40;
	m_Header.biPlanes = 1;
	m_Header.biBitCount = m_Depth;
	m_Header.biCompression = 0;
	m_Header.biXPelsPerMeter = 0;
	m_Header.biYPelsPerMeter = 0;
	m_Header.biClrUsed = 0;
	m_Header.biClrImportant = 0;
}


//********************************************
// ReadFileRAW (*.raw)
//********************************************
// Read raw files
// Accept only 24 or 32 bits
// Size : 2^n x 2^m
//********************************************
int CTexture::ReadFileRAW(char *filename,
													unsigned int width,
													unsigned int height,
													unsigned int depth)
{

	ASSERT(width>0);
	ASSERT(height>0);
	ASSERT(depth>0);
	ASSERT(depth%8==0);
	ASSERT(depth/8==3 || depth/8==4);

	// Check for valid file
	CFile file;
	CFileException ex;
	
	// Try to open file
	if(!file.Open(filename, CFile::modeRead | CFile::typeBinary,&ex))
	{
		#ifdef _DEBUG
		  afxDump << "File could not be opened " << ex.m_cause << "\n";
		#endif
		AfxMessageBox("Unable to open file for reading");
		return 0;
	}

	// Alloc (does call Free before)
	if(!Alloc(width,height,depth))
	{
		AfxMessageBox("Insuffisant memory");
		file.Close();
		return 0;
	}

	// Image reading
	TRY
	{
		file.Read(m_pData,m_Width*m_Height*depth/8);
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during reading " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during reading image");
		file.Close();
		return 0;
	}
	END_CATCH

	// Close file
  file.Close();

	// Success, also set FileName
	m_FileName = filename;

	return 1;
}

//////////////////////////////////////////////
//////////////////////////////////////////////
// FILE SAVING
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// SaveFile
// Redirection
//********************************************
int CTexture::SaveFile(char *filename)
{
	CString string = filename;
	string.MakeLower();
	TRACE("CTexture::SaveFile : file : %s\n",filename);

	CString extension = string.Right(4);

	// Redirection RAW
	if(extension == ".raw")
		return SaveFileRAW(filename);

	// Redirection BMP
	if(extension == ".bmp")
		return SaveFileBMP(filename);

	// Unrecognized file format
	CString message;
	message.Format("CTexture::SaveFile : invalid file redirection : %s\n",filename);
	AfxMessageBox(message);

	return 0;
}


//********************************************
// SaveFileRAW
//********************************************
int CTexture::SaveFileRAW(char *filename)
{
	// Check for valid image
	if((m_Width * m_Height * m_Depth) == 0)
		{
		AfxMessageBox("CTexture::SaveFileRAW : invalid image");
		return 0;
		}

	// Check for valid file
	CFile file;
	CFileException ex;
	
	// Try to open file
	if(!file.Open(filename, CFile::modeWrite | CFile::typeBinary,&ex))
	{
		#ifdef _DEBUG
		  afxDump << "File could not be opened " << ex.m_cause << "\n";
		#endif
		AfxMessageBox("Unable to open file for writing");
		return 0;
	}

	// Image writing
	TRY
	{
		file.Write(m_pData,m_Width*m_Height*m_Depth/8);
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during writing " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during writing image");
		file.Close();
		return 0;
	}
	END_CATCH

	// Close file
  file.Close();

	return 1;
}


//********************************************
// SaveFileBMP (*.bmp)
//********************************************
// Save windows bmp files
// Accept only 24 bits
//********************************************
int CTexture::SaveFileBMP(char *filename)
{
	if(!IsValid())
		return 0;

	if(m_Depth != 24)
		return 0;

	// Check for valid bmp file
	CFile file;
	CFileException ex;
	
	// Try to open file
	if(!file.Open(filename,CFile::modeCreate | CFile::modeWrite | CFile::typeBinary,&ex))
	{
		#ifdef _DEBUG
		  afxDump << "File could not be opened " << ex.m_cause << "\n";
		#endif
		AfxMessageBox("Unable to open file for writing");
		return 0;
	}

	// File header
	BITMAPFILEHEADER FileHeader;
  WORD sign = ((WORD) ('M' << 8) | 'B');
	FileHeader.bfType = sign;
  FileHeader.bfSize = 14 + 40 + m_WidthByte32*m_Height; 
  FileHeader.bfReserved1 = 0; 
  FileHeader.bfReserved2 = 0; 
  FileHeader.bfOffBits = 54; 

	TRACE("\nSave BMP File...\n");
	TRACE("FileHeader.bfType : %d\n",FileHeader.bfType);
	TRACE("FileHeader.bfSize : %d\n",FileHeader.bfSize);
	TRACE("FileHeader.bfReserved1 : %d\n",FileHeader.bfReserved1);
	TRACE("FileHeader.bfReserved2 : %d\n",FileHeader.bfReserved2);
	TRACE("FileHeader.bfOffBits : %d\n",FileHeader.bfOffBits);

	TRY
	{
		file.Write(&FileHeader,sizeof(BITMAPFILEHEADER));
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during writing " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during writing file header");
		file.Close();
		return 0;
	}
	END_CATCH

	// Image header
	TRY
	{
		file.Write(&m_Header,sizeof(BITMAPINFOHEADER));
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during writing " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during writing image header");
		file.Close();
		return 0;
	}
	END_CATCH

	// DEBUG
	TRACE("\n");
	TRACE("**** IMAGE HEADER :\n");
	TRACE("**** biSize : %d\n",m_Header.biSize);
	TRACE("**** biWidth : %d\n",m_Header.biWidth);
	TRACE("**** biHeight : %d\n",m_Header.biHeight);
	TRACE("**** biPlanes : %d\n",m_Header.biPlanes);
	TRACE("**** biBitCount : %d\n",m_Header.biBitCount);
	TRACE("**** biCompression : %d\n",m_Header.biCompression);
	TRACE("**** biSizeImage : %d\n",m_Header.biSizeImage);
	TRACE("**** biXPelsPerMeter : %d\n",m_Header.biXPelsPerMeter);
	TRACE("**** biYPelsPerMeter : %d\n",m_Header.biYPelsPerMeter);
	TRACE("**** biClrUsed : %d\n",m_Header.biClrUsed);
	TRACE("**** biClrImportant : %d\n",m_Header.biClrImportant);

	// Image writing
	TRY
	{
		file.Write(m_pData,m_Header.biSizeImage);
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during writing " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during writing image");
		file.Close();
		return 0;
	}
	END_CATCH

	// Close file
  file.Close();

	return 1;
}




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

//********************************************
// IsValid
//********************************************
int CTexture::IsValid()
{
	int success = 0;
	success = (m_Depth == 24) || (m_Depth == 32);
	success &= (m_Width != 0);
	success &= (m_Height != 0);
	success &= (m_pData != NULL);
	if(!success)
		{
		TRACE("\n");
		TRACE("Invalid texture\n");
		TRACE("Width  : %d\n",m_Width);
		TRACE("Height : %d\n",m_Height);
		TRACE("Depth  : %d\n",m_Depth);
		TRACE("Data   : %x\n",m_pData);
		}
	return success;
}


//********************************************
// HigherPowerOfTwo
//********************************************
int CTexture::HigherPowerOfTwo(int value)
{
	ASSERT(value > 0);
	if(value <= 0)
		return value;

	int power = 1;
	int x = 0;

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

	return value;
}

//********************************************
// LowerPowerOfTwo
//********************************************
int CTexture::LowerPowerOfTwo(int value)
{
	ASSERT(value > 0);
	if(value <= 0)
		return value;

	int power = 1;
	int x = 0;

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

	return value;
}

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


//********************************************
// Flip BGR to RGB
//********************************************
int CTexture::BGRtoRGB(void)
{
	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 CTexture::Extract(int left,
											int top,
											int right,
											int bottom)
{
	ASSERT(IsValid());

	// 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);

	ASSERT(NewWidth>=1);
	ASSERT(NewHeight>=1);

	// Alloc
	unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
	if(pData == NULL)
		{
		AfxMessageBox("Insuffisant memeory");
		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 CTexture::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);

	ASSERT(NewWidth>=1);
	ASSERT(NewHeight>=1);

	// Alloc
	unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
	if(pData == NULL)
		{
		AfxMessageBox("Insuffisant memeory");
		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 CTexture::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 mirror...\n");
	TRACE("New width : %d\n",NewWidth);
	TRACE("New widthbyte32 : %d\n",NewWidthByte32);
	TRACE("New height : %d\n",NewHeight);

	ASSERT(NewWidth>=1);
	ASSERT(NewHeight>=1);

	// Alloc
	unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
	if(pData == NULL)
		{
		AfxMessageBox("Insuffisant memeory");
		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;
}





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

//********************************************
// SetAlphaLayer
//********************************************
int CTexture::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 CTexture::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)
		{
		AfxMessageBox("CTexture::AddAlphaLayer : insuffisant memory");
		return 0;
		}

	// Fill new data
	int size = m_Width * m_Height;
	int BytePerPixel = m_Depth / 8;
	ASSERT(size > 0);
	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;
}


//********************************************
// PutAlpha
// From RGB to grey scales, then alpha layer
//********************************************
int CTexture::PutAlpha(CTexture *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;
	ASSERT(size > 0);
	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
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// Draw
//********************************************
int CTexture::Draw(CDC *pDC,
									 int xOffset,
									 int yOffset,
									 int width,
									 int height)
{
	// Checking
	if(!IsValid())
	  return 0;

	// Flags	
	if(width == -1)
		width = m_Width;
	if(height == -1)
		height = m_Height;

	// Painting
	return SetDIBitsToDevice(pDC->m_hDC,
		                       xOffset,
													 yOffset,
													 width,
													 height,
													 0,
													 0,
													 0,
													 m_Height,
													 GetData(),
													 (CONST BITMAPINFO *)&m_Header,
													 DIB_RGB_COLORS);
}

//********************************************
// ReadBuffer
//********************************************
int CTexture::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;
}

//********************************************
// Grey
//********************************************
int CTexture::Grey(unsigned int x,
									 unsigned int y)
{
	ASSERT(x<m_Width && x>=0);
	ASSERT(y<m_Height && y>=0);
	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;
}



// ** EOF **

//********************************************
// ReadFromResource
//********************************************
int CTexture::ReadFromResource(const WORD ResourceId,LPCTSTR lpszSection)
{
	// Check
	ASSERT(ResourceId != 0);
	
	// Secret hand-made decomp. method
	HINSTANCE hInst = AfxGetResourceHandle();
	HRSRC hrsrc = ::FindResource(hInst,MAKEINTRESOURCE(ResourceId),lpszSection);
	if(hrsrc == NULL) 
	{
		TRACE("DIB resource not found");
		return 0;
	}
	
	// Famous decomp. algorithm
	HGLOBAL hg = LoadResource(hInst, hrsrc); // you do not need to call any free
	if(hg == NULL) 
	{
		TRACE("Failed to load DIB resource");
		return FALSE;
	}
	
	void* pRes = LockResource(hg);
	ASSERT(pRes != NULL);
	int size = ::SizeofResource(hInst, hrsrc);
#ifdef _DEBUG
	TRACE("Size resource : %d\n",size);
#endif	
	// This must be a windows .BMP file
	BITMAPFILEHEADER FileHeader;
	memcpy(&FileHeader,pRes,sizeof(BITMAPFILEHEADER));
	
#ifdef _DEBUG
	TRACE("FILE HEADER :\n");
	TRACE("FileHeader.bfType : %d\n",FileHeader.bfType);
	TRACE("FileHeader.bfSize : %d\n",FileHeader.bfSize);
	TRACE("FileHeader.bfReserved1 : %d\n",FileHeader.bfReserved1);
	TRACE("FileHeader.bfReserved2 : %d\n",FileHeader.bfReserved2);
	TRACE("FileHeader.bfOffBits : %d\n",FileHeader.bfOffBits);
#endif	
	// Is it a Windows BMP file ? (BM)
	if(FileHeader.bfType != 0x4D42)
	{
		AfxMessageBox("Invalid BMP file");
		return 0;
	}
#ifdef _DEBUG
	TRACE("yes, this is a valid BMP image\n");
#endif	
	// Image header
	memcpy(&m_Header,(BYTE *)pRes+sizeof(BITMAPFILEHEADER),sizeof(BITMAPINFOHEADER));
	
	// DEBUG
#ifdef _DEBUG
	TRACE("\n");
	TRACE("IMAGE HEADER :\n");
	TRACE("biSize : %d\n",m_Header.biSize);
	TRACE("biWidth : %d\n",m_Header.biWidth);
	TRACE("biHeight : %d\n",m_Header.biHeight);
	TRACE("biPlanes : %d\n",m_Header.biPlanes);
	TRACE("biBitCount : %d\n",m_Header.biBitCount);
	TRACE("biCompression : %d\n",m_Header.biCompression);
	TRACE("biSizeImage : %d\n",m_Header.biSizeImage);
	TRACE("biXPelsPerMeter : %d\n",m_Header.biXPelsPerMeter);
	TRACE("biYPelsPerMeter : %d\n",m_Header.biYPelsPerMeter);
	TRACE("biClrUsed : %d\n",m_Header.biClrUsed);
	TRACE("biClrImportant : %d\n",m_Header.biClrImportant);
	TRACE("biSizeImage : %d\n",m_Header.biSizeImage);
#endif	
	// 24 bits ?
	if(m_Header.biPlanes != 1 ||
		m_Header.biBitCount != 24)
	{
		AfxMessageBox("Image file must have 24 bits depth");
		return 0;
	}
#ifdef _DEBUG
	TRACE("yes, this is a 24 bits image\n");
#endif	
	// Alloc (does call Free before)
	Free();
   if( !m_Header.biSizeImage ){
      UINT  nStride = (m_Header.biWidth * (m_Header.biBitCount/8) + 1) & (~1); // Stride is the BMP's bytes per row.
      m_Header.biSizeImage = nStride * m_Header.biHeight;
   }
   if( !AllocImageData(m_Header.biSizeImage) ){
		AfxMessageBox("Insuffisant memory");
		return 0;
	}
	
	// Update datas
	m_Width = m_Header.biWidth;
	m_Height = m_Header.biHeight;
	m_Depth = m_Header.biBitCount;
	
	// Image reading
	CMemoryException e;
	memcpy(m_pData,(BYTE *)((BYTE *)pRes+FileHeader.bfOffBits),m_Header.biSizeImage);
	
	UpdateWidthByte32();
	
	return 1;
}

bool  CTexture::AllocImageData(unsigned int sizeData)
{
      m_pData     = new unsigned char[sizeData];
      return (bool)( m_pData != NULL ? true : false );
}



By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

No Biography provided

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 12 Feb 2002
Article Copyright 2002 by pepito sbarzeguti
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid