Files
envi-code/SourceCode/Code2026/tg_shs/shs_kerncmd/Texture.cpp
T
2026-09-28 15:28:50 +08:00

1491 lines
35 KiB
C++

//********************************************
// 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"
#include "gl/gl.h"
#include "gl/glu.h"
#include "LTGA.h"
// Zyu add on 100722,支持64位
#include "ximage.h"
//#include "planydec.h"
//#include "plexcept.h"
//#include "planybmp.h"
//#include "pldibsect.h"
//#include "plbmpenc.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(_T("CTexture::Alloc : Insuffisant memory\n"));
AfxMessageBox(_T("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(const TCHAR *filename,
unsigned int width,
unsigned int height,
unsigned int depth)
{
// Cleanup
Free();
// Storage
m_FileName = filename;
// Extension
CString string = filename;
string.MakeLower();
TRACE(_T("CTexture::ReadFile : file : %s\n"),filename);
XPathParser parser(string);
CString extension=(const TCHAR *)parser.m_sExt;
//CString extension = string.Right(4);
// Redirection BMP
int nRet=FALSE;
if (extension == _T(".bmp")) {
nRet = ReadFileBMP(filename);
} else if (extension == _T(".jpg")) {
nRet = ReadFileJPG(filename);
} else if (extension == _T(".gif")) {
nRet =ReadFileGIF(filename);
} else if (extension == _T(".raw")) {
nRet = ReadFileRAW(filename,width,height,depth);
} else {
// Zyu modify on 100723,支持64位
/*
PLAnyPicDecoder Decoder;
//Decoder.SetTraceConfig (2, NULL); //_T("c:\paintlib.log"));
PLWinBmp NewBmp;
try {
Decoder.MakeBmpFromFile (_AS(filename), &NewBmp);
int iBytePixel=NewBmp.GetBitsPerPixel()/8;
if (iBytePixel==3 || iBytePixel==4) {
Free();
m_Width = NewBmp.GetWidth();
m_Height = NewBmp.GetHeight();
m_Depth=NewBmp.GetBitsPerPixel();
int nWidth32=WidthByte32(m_Width, m_Depth);
ASSERT(nWidth32==NewBmp.GetBytesPerLine());
m_pData = new unsigned char[nWidth32*m_Height];
//unsigned char **pLineArray=NewBmp.GetLineArray();
//unsigned char *pLine=m_pData;
//for(int i=m_Height-1; i>=0; i--,pLine+=nWidth32) {
// memcpy(pLine, pLineArray[i], nWidth32);
//}
memcpy(m_pData, NewBmp.GetBits(), nWidth32*m_Height);
UpdateHeader();
nRet = TRUE;
}
} catch (PLTextException e) {
char sz[1024];
sprintf (sz, "Error decoding %s: %s", filename, (const char *)e);
PLPicDecoder::Trace (1, sz);
} catch (CMemoryException e) {
TRACE (_T("Error decoding %s: Out of memory.\n"), filename);
}
*/
Free();
nRet = (int)CTangentImage::ReadOtherPicFile(filename, m_Header, (char *&)m_pData);
if (!nRet && extension == _T(".tga"))
nRet = ReadFileTGA(filename);
}
// Storage again
m_FileName = filename;
// Unrecognized file format
//CString message;
//message.Format(_T("CTexture::ReadFile : invalid file redirection : %s\n"),filename);
//AfxMessageBox(string);
return nRet;
}
//********************************************
// ReadFileBMP (*.bmp)
//********************************************
// Read windows bmp files
// Accept only 24 bits
// Size : 2^n x 2^m
//********************************************
int CTexture::ReadFileBMP(const TCHAR *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 << _T("File could not be opened ") << ex.m_cause << _T("\n");
#endif
AfxMessageBox(_T("Unable to open file for reading"));
return 0;
}
// File header
BITMAPFILEHEADER FileHeader;
TRY
{
file.Read(&FileHeader,sizeof(BITMAPFILEHEADER));
}
CATCH(CFileException, e)
{
#ifdef _DEBUG
afxDump << _T("Error during reading ") << e->m_cause << _T("\n");
#endif
AfxMessageBox(_T("Error during reading file header"));
file.Close();
return 0;
}
END_CATCH
TRACE(_T("FileHeader.bfType : %d\n"),FileHeader.bfType);
TRACE(_T("FileHeader.bfSize : %d\n"),FileHeader.bfSize);
TRACE(_T("FileHeader.bfReserved1 : %d\n"),FileHeader.bfReserved1);
TRACE(_T("FileHeader.bfReserved2 : %d\n"),FileHeader.bfReserved2);
TRACE(_T("FileHeader.bfOffBits : %d\n"),FileHeader.bfOffBits);
// Is it a Windows BMP file ? (BM)
WORD sign = ((WORD) ('M' << 8) | 'B');
if (FileHeader.bfType != sign)
{
AfxMessageBox(_T("Invalid BMP file"));
file.Close();
return 0;
}
// Image header
TRY
{
file.Read(&m_Header,sizeof(BITMAPINFOHEADER));
}
CATCH(CFileException, e)
{
#ifdef _DEBUG
afxDump << _T("Error during reading ") << e->m_cause << _T("\n");
#endif
AfxMessageBox(_T("Error during reading image header"));
file.Close();
return 0;
}
END_CATCH
// DEBUG
TRACE(_T("\n"));
TRACE(_T("**** IMAGE HEADER :\n"));
TRACE(_T("**** biSize : %d\n"),m_Header.biSize);
TRACE(_T("**** biWidth : %d\n"),m_Header.biWidth);
TRACE(_T("**** biHeight : %d\n"),m_Header.biHeight);
TRACE(_T("**** biPlanes : %d\n"),m_Header.biPlanes);
TRACE(_T("**** biBitCount : %d\n"),m_Header.biBitCount);
TRACE(_T("**** biCompression : %d\n"),m_Header.biCompression);
TRACE(_T("**** biSizeImage : %d\n"),m_Header.biSizeImage);
TRACE(_T("**** biXPelsPerMeter : %d\n"),m_Header.biXPelsPerMeter);
TRACE(_T("**** biYPelsPerMeter : %d\n"),m_Header.biYPelsPerMeter);
TRACE(_T("**** biClrUsed : %d\n"),m_Header.biClrUsed);
TRACE(_T("**** biClrImportant : %d\n"),m_Header.biClrImportant);
// 24 bits ?
if (m_Header.biPlanes != 1 ||
m_Header.biBitCount != 24)
{
AfxMessageBox(_T("Texture file must have 24 bits depth"));
file.Close();
return 0;
}
// Alloc (does call Free before)
Free();
int nSize=m_Header.biSizeImage;
if (nSize<=0)
nSize =WidthByte32(m_Header.biWidth, m_Header.biBitCount)*m_Header.biHeight;
m_pData = new unsigned char[nSize];
if (m_pData == NULL)
{
//AfxMessageBox(_T("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,nSize);
}
CATCH(CFileException, e)
{
#ifdef _DEBUG
afxDump << _T("Error during reading ") << e->m_cause << _T("\n");
#endif
//AfxMessageBox(_T("Error during reading image"));
file.Close();
return 0;
}
END_CATCH
// Close file
file.Close();
// Success, also set FileName
m_FileName = filename;
UpdateWidthByte32();
return 1;
}
// Zyu modify on 100722,支持64位
//extern BOOL ReadJpeg(FILE *input_file, BITMAPINFOHEADER &bmfHeader, char *&pData);
int CTexture::ReadFileJPG(const TCHAR *filename)
{
// Zyu modify on 100722,支持64位
/*
FILE *fp=_tfopen(filename, _T("rb"));
if (!fp)
return FALSE;
// File header
Free();
if (!ReadJpeg(fp, m_Header, (char * &)m_pData)) {
fclose(fp);
return FALSE;
}
fclose(fp);
*/
// File header
Free();
if (!CTangentImage::ReadJpeg(filename, m_Header,(char * &)m_pData))
{
return FALSE;
}
// DEBUG
TRACE(_T("\n"));
TRACE(_T("**** IMAGE HEADER :\n"));
TRACE(_T("**** biSize : %d\n"),m_Header.biSize);
TRACE(_T("**** biWidth : %d\n"),m_Header.biWidth);
TRACE(_T("**** biHeight : %d\n"),m_Header.biHeight);
TRACE(_T("**** biPlanes : %d\n"),m_Header.biPlanes);
TRACE(_T("**** biBitCount : %d\n"),m_Header.biBitCount);
TRACE(_T("**** biCompression : %d\n"),m_Header.biCompression);
TRACE(_T("**** biSizeImage : %d\n"),m_Header.biSizeImage);
TRACE(_T("**** biXPelsPerMeter : %d\n"),m_Header.biXPelsPerMeter);
TRACE(_T("**** biYPelsPerMeter : %d\n"),m_Header.biYPelsPerMeter);
TRACE(_T("**** biClrUsed : %d\n"),m_Header.biClrUsed);
TRACE(_T("**** biClrImportant : %d\n"),m_Header.biClrImportant);
// 24 bits ?
if (m_Header.biPlanes != 1 ||
(m_Header.biBitCount != 24 && m_Header.biBitCount != 32 ))
{
//AfxMessageBox(_T("Texture file must have 24 bits depth"));
return 0;
}
// Update datas
m_Width = m_Header.biWidth;
m_Height = m_Header.biHeight;
m_Depth = m_Header.biBitCount;
// Success, also set FileName
m_FileName = filename;
UpdateHeader();
return 1;
}
// Zyu modify on 100722,支持64位
//extern int WriteJpeg( FILE * input_file, FILE * output_file);
//extern int g_iSrcImgType;
int CTexture::ReadFileGIF(const TCHAR *filename)
{
// Zyu modify on 100722
/*
FILE *fpIn=_tfopen(filename, _T("rb"));
if (!fpIn)
return FALSE;
XString sTempFile=GetTempFileName(_T(".jpg"));
FILE *fpOut=_tfopen(sTempFile, _T("wb"));
if (!fpOut) {
fclose(fpIn);
return FALSE;
}
XPushMemVar<int> vTemp(g_iSrcImgType, 1);
int nRet=WriteJpeg(fpIn, fpOut);
fclose(fpIn);
fclose(fpOut);
*/
XString sTempFile=GetTempFileName(_T(".jpg"));
int nRet = CTangentImage::WriteJpeg(filename, sTempFile, CXIMAGE_FORMAT_GIF);
if (!nRet)
return nRet;
nRet=ReadFileJPG(sTempFile);
_tremove(sTempFile);
return nRet;
}
int CTexture::ReadFileTGA(const TCHAR *filename)
{
LTGA ltga;
if (!ltga.LoadFromFile(_AS(filename))) {
// Zyu modify on 100722,支持64位
/*
FILE *fpIn=_tfopen(filename, _T("rb"));
if (!fpIn)
return FALSE;
XString sTempFile=GetTempFileName(_T(".jpg"));
FILE *fpOut=_tfopen(sTempFile, _T("wb"));
if (!fpOut) {
fclose(fpIn);
return FALSE;
}
XPushMemVar<int> vTemp(g_iSrcImgType, 2);
int nRet=WriteJpeg(fpIn, fpOut);
fclose(fpIn);
fclose(fpOut);
*/
XString sTempFile=GetTempFileName(_T(".jpg"));
int nRet = CTangentImage::WriteJpeg(filename, sTempFile, CXIMAGE_FORMAT_TGA);
if (!nRet)
return nRet;
nRet=ReadFileJPG(sTempFile);
_tremove(sTempFile);
return nRet;
}
if (ltga.GetImageType()!=itRGB && ltga.GetImageType()!=itRGBA)
return FALSE;
Free();
m_FileName=filename;
m_Depth=ltga.GetPixelDepth();
m_Width = ltga.GetImageWidth();
m_Height = ltga.GetImageHeight();
UpdateWidthByte32();
int iPixelPerByte=m_Depth/8;
int nWidthNormal=iPixelPerByte*m_Width;
m_pData = new unsigned char[m_WidthByte32*m_Height];
unsigned char *pSrc=ltga.GetPixels();
for(unsigned int row=0; row<m_Height; row++) {
unsigned char *pSrcRow=pSrc+row*nWidthNormal;
unsigned char *pDstRow=m_pData+row*m_WidthByte32;
memcpy(pDstRow, pSrcRow, nWidthNormal);
}
BGRtoRGB(); // Swap R and B
UpdateHeader();
return TRUE;
}
//********************************************
// UpdateWidthByte32
//********************************************
void CTexture::UpdateWidthByte32()
{
m_WidthByte32 = WidthByte32(m_Width,m_Depth);
}
//********************************************
// WidthByte32
//********************************************
unsigned int CTexture::WidthByte32(unsigned int width,
unsigned int depth)
{
int iPixelPerByte=depth/8;
int nWidth=width*iPixelPerByte;
nWidth = (nWidth+3)/4*4;
return nWidth;
// 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.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(const TCHAR *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 << _T("File could not be opened ") << ex.m_cause << _T("\n");
#endif
AfxMessageBox(_T("Unable to open file for reading"));
return 0;
}
// Alloc (does call Free before)
if (!Alloc(width,height,depth))
{
AfxMessageBox(_T("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 << _T("Error during reading ") << e->m_cause << _T("\n");
#endif
AfxMessageBox(_T("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(const TCHAR *filename)
{
CString string = filename;
string.MakeLower();
TRACE(_T("CTexture::SaveFile : file : %s\n"),filename);
CString extension = string.Right(4);
// Redirection RAW
if (extension == _T(".raw"))
return SaveFileRAW(filename);
// Redirection BMP
if (extension == _T(".bmp"))
return SaveFileBMP(filename);
// Unrecognized file format
CString message;
message.Format(_T("CTexture::SaveFile : invalid file redirection : %s\n"),filename);
AfxMessageBox(message);
return 0;
}
//********************************************
// SaveFileRAW
//********************************************
int CTexture::SaveFileRAW(const TCHAR *filename)
{
// Check for valid image
if ((m_Width * m_Height * m_Depth) == 0)
{
AfxMessageBox(_T("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 << _T("File could not be opened ") << ex.m_cause << _T("\n");
#endif
AfxMessageBox(_T("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 << _T("Error during writing ") << e->m_cause << _T("\n");
#endif
AfxMessageBox(_T("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(const TCHAR *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 << _T("File could not be opened ") << ex.m_cause << _T("\n");
#endif
AfxMessageBox(_T("Unable to open file for writing"));
return 0;
}
// File header
BITMAPFILEHEADER FileHeader;
WORD sign = ((WORD) (_T('M') << 8) | _T('B'));
FileHeader.bfType = sign;
FileHeader.bfSize = 14 + 40 + m_WidthByte32*m_Height;
FileHeader.bfReserved1 = 0;
FileHeader.bfReserved2 = 0;
FileHeader.bfOffBits = 54;
TRACE(_T("\nSave BMP File...\n"));
TRACE(_T("FileHeader.bfType : %d\n"),FileHeader.bfType);
TRACE(_T("FileHeader.bfSize : %d\n"),FileHeader.bfSize);
TRACE(_T("FileHeader.bfReserved1 : %d\n"),FileHeader.bfReserved1);
TRACE(_T("FileHeader.bfReserved2 : %d\n"),FileHeader.bfReserved2);
TRACE(_T("FileHeader.bfOffBits : %d\n"),FileHeader.bfOffBits);
TRY
{
file.Write(&FileHeader,sizeof(BITMAPFILEHEADER));
}
CATCH(CFileException, e)
{
#ifdef _DEBUG
afxDump << _T("Error during writing ") << e->m_cause << _T("\n");
#endif
AfxMessageBox(_T("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 << _T("Error during writing ") << e->m_cause << _T("\n");
#endif
AfxMessageBox(_T("Error during writing image header"));
file.Close();
return 0;
}
END_CATCH
// DEBUG
TRACE(_T("\n"));
TRACE(_T("**** IMAGE HEADER :\n"));
TRACE(_T("**** biSize : %d\n"),m_Header.biSize);
TRACE(_T("**** biWidth : %d\n"),m_Header.biWidth);
TRACE(_T("**** biHeight : %d\n"),m_Header.biHeight);
TRACE(_T("**** biPlanes : %d\n"),m_Header.biPlanes);
TRACE(_T("**** biBitCount : %d\n"),m_Header.biBitCount);
TRACE(_T("**** biCompression : %d\n"),m_Header.biCompression);
TRACE(_T("**** biSizeImage : %d\n"),m_Header.biSizeImage);
TRACE(_T("**** biXPelsPerMeter : %d\n"),m_Header.biXPelsPerMeter);
TRACE(_T("**** biYPelsPerMeter : %d\n"),m_Header.biYPelsPerMeter);
TRACE(_T("**** biClrUsed : %d\n"),m_Header.biClrUsed);
TRACE(_T("**** biClrImportant : %d\n"),m_Header.biClrImportant);
// Image writing
TRY
{
file.Write(m_pData,m_Header.biSizeImage);
}
CATCH(CFileException, e)
{
#ifdef _DEBUG
afxDump << _T("Error during writing ") << e->m_cause << _T("\n");
#endif
AfxMessageBox(_T("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(_T("\n"));
TRACE(_T("Invalid texture\n"));
TRACE(_T("Width : %d\n"),m_Width);
TRACE(_T("Height : %d\n"),m_Height);
TRACE(_T("Depth : %d\n"),m_Depth);
TRACE(_T("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.0,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.0,power);
if (x >= value)
return (int)pow(2.0,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(_T("Start extracting...\n"));
TRACE(_T("New width : %d\n"),NewWidth);
TRACE(_T("New height : %d\n"),NewHeight);
ASSERT(NewWidth>=1);
ASSERT(NewHeight>=1);
// Alloc
unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
if (pData == NULL)
{
AfxMessageBox(_T("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(_T("Start duplicate mirror...\n"));
TRACE(_T("New width : %d\n"),NewWidth);
TRACE(_T("New widthbyte32 : %d\n"),NewWidthByte32);
TRACE(_T("New height : %d\n"),NewHeight);
ASSERT(NewWidth>=1);
ASSERT(NewHeight>=1);
// Alloc
unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
if (pData == NULL)
{
AfxMessageBox(_T("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(_T("Start duplicate mirror...\n"));
TRACE(_T("New width : %d\n"),NewWidth);
TRACE(_T("New widthbyte32 : %d\n"),NewWidthByte32);
TRACE(_T("New height : %d\n"),NewHeight);
ASSERT(NewWidth>=1);
ASSERT(NewHeight>=1);
// Alloc
unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
if (pData == NULL)
{
AfxMessageBox(_T("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(_T("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;
}
unsigned char * CTexture::RepeatData(int uRep, int vRep)
{
if (!m_pData)
return NULL;
unsigned nSize=m_Width*m_Height*m_Depth/8*uRep*vRep;
unsigned char *pNewData=new unsigned char[nSize];
if (!pNewData)
return NULL;
int iPerByte=m_Depth/8;
int nRow=m_Height*vRep;
int nCol=m_Width*uRep;
for(int v=0; v<vRep; v++) {
//unsigned char *vStart=m_nWidth*uRep*iPerByte;
for(int u=0; u<uRep; u++) {
//unsigned char *uvStart=vStart + u*m_nWidth*iPerByte;
// 复制一个Data
// 按行复制
for(unsigned int i=0; i<m_Height; i++) {
// 求(u, v)第i行地址
int iRow=v*m_Height + i;
int iCol=u*m_Width;
unsigned char *pDest=&pNewData[(iRow*nCol+iCol)*iPerByte];
memcpy(pDest, &m_pData[i*m_Width*iPerByte], m_Width*iPerByte);
}
}
}
return pNewData;
}
// ** EOF **
// Scale to 2^i alignment
BOOL CTexture::OpenGLScale(unsigned char cMaxSizeShift)
{
if (m_Width<1 || m_Height<1)
return FALSE;
//int nMax=10; //1024
int nMaxSize= 1<<cMaxSizeShift;
int nNewHeight=m_Height, nNewWidth=m_Width;
if (nNewHeight>nMaxSize)
nNewHeight=nMaxSize;
else {
for(unsigned char cShift=1; cShift<cMaxSizeShift; cShift++) {
int nLow=1<<cShift;
int nUp=1<<(cShift+1);
if (nNewHeight==nLow || nNewHeight==nUp)
break;
if (nNewHeight>nLow && nNewHeight<nUp) {
if (nNewHeight-nLow < nUp-nNewWidth)
nNewHeight=nLow;
else
nNewHeight=nUp;
break;
}
}
}
if (nNewWidth>nMaxSize)
nNewWidth=nMaxSize;
else {
for(unsigned char cShift=1; cShift<cMaxSizeShift; cShift++) {
int nLow=1<<cShift;
int nUp=1<<(cShift+1);
if (nNewWidth==nLow || nNewWidth==nUp)
break;
if (nNewWidth>nLow && nNewWidth<nUp) {
if (nNewWidth-nLow < nUp-nNewWidth)
nNewWidth=nLow;
else
nNewWidth=nUp;
break;
}
}
}
if (nNewWidth!=m_Width || nNewHeight!=m_Height) {
// Scale it
unsigned int Width32 = WidthByte32(nNewWidth, GetDepth());
unsigned char *pDataOut=new unsigned char [Width32*nNewHeight];
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//if (gluScaleImage(GL_BGR_EXT, m_Width, m_Height, GL_UNSIGNED_BYTE, m_pData,
// nNewWidth, nNewHeight, GL_UNSIGNED_BYTE, pDataOut)==0) {
if (ScaleImage(nNewWidth, nNewHeight, pDataOut)) {
delete []m_pData;
m_pData=pDataOut;
m_Width=nNewWidth;
m_Height=nNewHeight;
UpdateHeader();
//SaveFileBMP(_T("c:\\temp\\zjq.bmp"));
} else {
delete [] pDataOut;
return FALSE;
}
}
return TRUE;
}
BOOL CTexture::ScaleImage(unsigned int nNewWidth, unsigned int nNewHeight,
unsigned char *pNewData)
{
int nWidth32=WidthByte32(nNewWidth, m_Depth);
int iPerByte=m_Depth/8;
for(unsigned int i=0; i<nNewHeight; i++) {
double dv=(double)m_Height/(double)nNewHeight*i;
unsigned v=(unsigned )dv;
double vDif=dv-v;
unsigned v1=v+1;
ASSERT(v<m_Height && v>=0);
if (v1>=m_Height)
v1=m_Height-1;
for(unsigned int j=0; j<nNewWidth; j++) {
double du=(double)m_Width/(double)nNewWidth*j;
unsigned u=(unsigned )du;
unsigned u1=u+1;
ASSERT(u<m_Width && u>=0);
if (u1>=m_Width)
u1=m_Width-1;
double uDif=du-u;
// 用 (u, v), (u+1, v), (u+1, v+1), (u, v+1) 4点的坐标来插值
unsigned char *rgbNew=pNewData+i*nWidth32+j*iPerByte;
unsigned char *uv=m_pData+v*m_WidthByte32+u*iPerByte;
unsigned char *u1v=m_pData+v*m_WidthByte32+u1*iPerByte;
unsigned char *u1v1=m_pData+v1*m_WidthByte32+u1*iPerByte;
unsigned char *uv1=m_pData+v1*m_WidthByte32+u*iPerByte;
double duv=sqrt(vDif*vDif+uDif*uDif);
double du1v=sqrt(vDif*vDif+(1.0-uDif)*(1.0-uDif));
double du1v1=sqrt((1.0-vDif)*(1.0-vDif)+(1.0-uDif)*(1.0-uDif));
double duv1=sqrt((1.0-vDif)*(1.0-vDif)+uDif*uDif);
double suv = duv/(duv+du1v+du1v1+duv1);
double su1v = du1v/(duv+du1v+du1v1+duv1);
double su1v1 = du1v1/(duv+du1v+du1v1+duv1);
double suv1 = duv1/(duv+du1v+du1v1+duv1);
for(int m=0; m<iPerByte; m++)
rgbNew[m]= AS_INT(uv[m]*suv + u1v[m]*su1v + u1v1[m]*su1v1 + uv1[m]*suv1);
//memcpy(rgbNew, rgbNew, iPerByte);
}
}
return TRUE;
/*
int nRow=m_Height*vRep;
int nCol=m_Width*uRep;
for(int v=0; v<vRep; v++) {
//unsigned char *vStart=m_nWidth*uRep*iPerByte;
for(int u=0; u<uRep; u++) {
//unsigned char *uvStart=vStart + u*m_nWidth*iPerByte;
// 复制一个Data
// 按行复制
for(int i=0; i<m_Height; i++) {
// 求(u, v)第i行地址
int iRow=v*m_Height + i;
int iCol=u*m_Width;
unsigned char *pDest=&pNewData[(iRow*nCol+iCol)*iPerByte];
memcpy(pDest, &m_pData[i*m_Width*iPerByte], m_Width*iPerByte);
}
}
}*/
}
void CTexture::MakeGrey()
{
//int nWidthByte32=WidthByte32(nNewWidth, m_Depth);
int BytePerPixel=m_Depth/8;
for(unsigned int i=0; i<m_Height; i++) {
for(unsigned int j=0; j<m_Width; j++) {
unsigned char *pDat=m_pData + m_WidthByte32*i + j*BytePerPixel;
unsigned int val=(int)((pDat[0]+pDat[1]+pDat[2])/3.0);
pDat[0]=pDat[1]=pDat[2]=val;
}
}
}
unsigned char *CTexture::CloneData()
{
unsigned char *pNewData=new unsigned char[m_WidthByte32*m_Height];
memcpy(pNewData, m_pData, m_WidthByte32*m_Height);
return pNewData;
}