1491 lines
35 KiB
C++
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;
|
|
} |