mirror of https://github.com/CGAL/cgal
1250 lines
27 KiB
C++
1250 lines
27 KiB
C++
/***************************************************************************
|
|
texture.cpp
|
|
----------------------------------------------------------------------------
|
|
begin : june 2003
|
|
copyright : (C) 2003 by Pierre Alliez - INRIA
|
|
email : pierre.alliez@sophia.inria.fr
|
|
***************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include "texture.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
// Constructor
|
|
CTexture::CTexture()
|
|
{
|
|
m_pData = NULL;
|
|
m_Width = 0;
|
|
m_WidthByte32 = 0;
|
|
m_Height = 0;
|
|
m_Depth = 0;
|
|
m_pFileName = new char[MAX_PATH];
|
|
strcpy(m_pFileName,"");
|
|
}
|
|
|
|
|
|
// Destructor
|
|
|
|
CTexture::~CTexture()
|
|
{
|
|
Free();
|
|
delete [] m_pFileName;
|
|
}
|
|
|
|
|
|
// Alloc
|
|
int CTexture::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)
|
|
{
|
|
TRACE("CTexture::Alloc : Insufficiant memory\n");
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
// ReadFile (dispatch function)
|
|
|
|
int CTexture::ReadFile(char *filename,
|
|
unsigned int width,
|
|
unsigned int height,
|
|
unsigned int depth)
|
|
{
|
|
// Cleanup
|
|
Free();
|
|
|
|
// Storage
|
|
strcpy(m_pFileName,filename);
|
|
|
|
// Extension
|
|
TRACE("CTexture::ReadFile : file : %s\n",filename);
|
|
int len = strlen(filename);
|
|
char extension[10];
|
|
strcpy(extension,&(filename[len-4]));
|
|
|
|
if(extension == ".bmp")
|
|
return ReadFileBMP(filename);
|
|
if(extension == ".raw")
|
|
return ReadFileRAW(filename,width,height,depth);
|
|
|
|
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))
|
|
{
|
|
TRACE("Unable to open file for reading");
|
|
return 0;
|
|
}
|
|
|
|
// File header
|
|
BITMAPFILEHEADER FileHeader;
|
|
file.Read(&FileHeader,sizeof(BITMAPFILEHEADER));
|
|
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)
|
|
{
|
|
TRACE("Invalid BMP file");
|
|
file.Close();
|
|
return 0;
|
|
}
|
|
|
|
file.Read(&m_Header,sizeof(BITMAPINFOHEADER));
|
|
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)
|
|
{
|
|
TRACE("Texture file must have 24 bits depth");
|
|
file.Close();
|
|
return 0;
|
|
}
|
|
|
|
// Alloc (does call Free before)
|
|
Free();
|
|
m_pData = new unsigned char[m_Header.biSizeImage];
|
|
if(m_pData == NULL)
|
|
{
|
|
TRACE("Insufficiant memory");
|
|
file.Close();
|
|
return 0;
|
|
}
|
|
|
|
// Update datas
|
|
m_Width = m_Header.biWidth;
|
|
m_Height = m_Header.biHeight;
|
|
m_Depth = m_Header.biBitCount;
|
|
|
|
// Image reading
|
|
file.Read(m_pData,m_Header.biSizeImage);
|
|
|
|
// Close file
|
|
file.Close();
|
|
|
|
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 = (WORD)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)
|
|
{
|
|
// Check for valid file
|
|
FILE *fp = fopen(filename,"rb");
|
|
|
|
// Try to open file
|
|
if(!fp)
|
|
{
|
|
TRACE("Unable to open file for reading");
|
|
return 0;
|
|
}
|
|
|
|
// Alloc (does call Free before)
|
|
if(!Alloc(width,height,depth))
|
|
{
|
|
TRACE("Insufficiant memory");
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
fread(m_pData,sizeof(unsigned char),m_Width*m_Height*depth/8,fp);
|
|
|
|
// Close file
|
|
fclose(fp);
|
|
|
|
// Success, also set FileName
|
|
strcpy(m_pFileName,filename);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
// SaveFile (dispatch function)
|
|
|
|
int CTexture::SaveFile(char *filename)
|
|
{
|
|
TRACE("CTexture::SaveFile : file : %s\n",filename);
|
|
int len = strlen(filename);
|
|
char extension[10];
|
|
strcpy(extension,&(filename[len-4]));
|
|
|
|
if(extension == ".raw")
|
|
return SaveFileRAW(filename);
|
|
if(extension == ".bmp")
|
|
return SaveFileBMP(filename);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
// SaveFileRAW
|
|
|
|
int CTexture::SaveFileRAW(char *filename)
|
|
{
|
|
// Check for valid image
|
|
if((m_Width * m_Height * m_Depth) == 0)
|
|
{
|
|
TRACE("CTexture::SaveFileRAW : invalid image");
|
|
return 0;
|
|
}
|
|
|
|
// Check for valid file
|
|
FILE *fp = fopen(filename,"wb");
|
|
|
|
// Try to open file
|
|
if(!fp)
|
|
{
|
|
TRACE("Unable to open file for writing");
|
|
return 0;
|
|
}
|
|
|
|
// Image writing
|
|
fwrite(m_pData,sizeof(unsigned char),m_Width*m_Height*m_Depth/8,fp);
|
|
|
|
// Close file
|
|
fclose(fp);
|
|
|
|
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))
|
|
{
|
|
TRACE("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);
|
|
|
|
file.Write(&FileHeader,sizeof(BITMAPFILEHEADER));
|
|
|
|
file.Write(&m_Header,sizeof(BITMAPINFOHEADER));
|
|
|
|
// 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
|
|
file.Write(m_pData,m_Header.biSizeImage);
|
|
|
|
// Close file
|
|
file.Close();
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
{
|
|
if(value <= 0)
|
|
return value;
|
|
|
|
int power = 1;
|
|
int x = 0;
|
|
|
|
while(1)
|
|
{
|
|
x = (int)pow(2,power);
|
|
if(x >= value)
|
|
return x;
|
|
power++;
|
|
}
|
|
}
|
|
|
|
|
|
// LowerPowerOfTwo
|
|
|
|
int CTexture::LowerPowerOfTwo(int value)
|
|
{
|
|
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++;
|
|
}
|
|
}
|
|
|
|
|
|
// 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()
|
|
{
|
|
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;
|
|
}
|
|
|
|
// Extract
|
|
int CTexture::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 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);
|
|
|
|
// 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 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 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 CTexture::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 CTexture::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 CTexture::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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
TRACE("CTexture::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 CTexture::SetAlphaLayer(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;
|
|
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;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
|
|
// Stretch
|
|
|
|
int CTexture::Stretch(CDC *pDC,
|
|
CRect *pRect)
|
|
{
|
|
// Checking
|
|
if(!IsValid())
|
|
return 0;
|
|
|
|
SetStretchBltMode(pDC->m_hDC,COLORONCOLOR);
|
|
|
|
// Painting
|
|
return StretchDIBits(pDC->m_hDC,
|
|
pRect->left,
|
|
pRect->top,
|
|
pRect->Width(),
|
|
pRect->Height(),
|
|
0,
|
|
0,
|
|
m_Width,
|
|
m_Height,
|
|
GetData(),
|
|
(CONST BITMAPINFO *)&m_Header,
|
|
DIB_RGB_COLORS,SRCCOPY);
|
|
}
|
|
|
|
|
|
// 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;
|
|
}
|
|
|
|
|
|
|
|
// ReadBufferByte32
|
|
int CTexture::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 CTexture::Copy(CTexture *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 CTexture::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] =
|
|
(BYTE)(255.0f * buffer[(width*j+i)*BytePerPixel+k]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
// ReadBuffer
|
|
|
|
int CTexture::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 CTexture::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 CTexture::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 CTexture::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 CTexture::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 CTexture::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];
|
|
}
|
|
}
|
|
|
|
// ExportHandle
|
|
HANDLE CTexture::ExportHandle()
|
|
{
|
|
HANDLE handle;
|
|
|
|
TRACE("Export handle...");
|
|
// Process source handle size
|
|
int size = sizeof(BITMAPINFOHEADER) + m_WidthByte32 * m_Height;
|
|
// Alloc memory
|
|
TRACE("alloc...");
|
|
handle = (HANDLE)::GlobalAlloc (GHND,size);
|
|
if(handle != NULL)
|
|
{
|
|
char *pData = (char *) ::GlobalLock((HGLOBAL)handle);
|
|
TRACE("lock...");
|
|
// Copy header
|
|
TRACE("header...");
|
|
memcpy(pData,&m_Header,sizeof(BITMAPINFOHEADER));
|
|
// Copy datas
|
|
TRACE("datas...");
|
|
memcpy(pData+sizeof(BITMAPINFOHEADER),m_pData,m_WidthByte32*m_Height);
|
|
// Unlock
|
|
TRACE("unlock...");
|
|
::GlobalUnlock((HGLOBAL)handle);
|
|
}
|
|
TRACE("ok\n");
|
|
ASSERT(handle);
|
|
return handle;
|
|
}
|
|
|
|
// ImportHandle
|
|
int CTexture::ImportHandle(HANDLE handle)
|
|
{
|
|
TRACE("Import handle...");
|
|
ASSERT(handle != NULL);
|
|
char *pData = (char *) ::GlobalLock((HGLOBAL)handle);
|
|
|
|
// Header
|
|
memcpy(&m_Header,pData,sizeof(BITMAPINFOHEADER));
|
|
|
|
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");
|
|
return 0;
|
|
}
|
|
|
|
// Alloc (does call Free before)
|
|
Alloc(m_Header.biWidth,m_Header.biHeight,m_Header.biBitCount);
|
|
memcpy(m_pData,pData+sizeof(BITMAPINFOHEADER),m_WidthByte32*m_Height);
|
|
|
|
::GlobalUnlock((HGLOBAL)handle);
|
|
return 1;
|
|
}
|
|
|
|
|
|
// GenerateGrid
|
|
void CTexture::GenerateGrid(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
|
|
for(unsigned int j=0;j<height;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;
|
|
}
|
|
|
|
// horizontal
|
|
for(j=0;j<height;j+=size)
|
|
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;
|
|
}
|
|
|
|
// vertical
|
|
for(j=0;j<height;j++)
|
|
for(unsigned int i=0;i<width;i+=size)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
// GenerateLines
|
|
void CTexture::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
|
|
for(unsigned int j=0;j<height;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;
|
|
}
|
|
|
|
// horizontal zebra
|
|
for(j=0;j<height;j++)
|
|
{
|
|
if((j/size)%2 == 0)
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
// ** EOF **
|
|
|
|
|
|
|