📄 blp2convertdlg.cpp
字号:
// 9-25-2004
// written by kingmark
// didiverycool@hotmail.com
#include "stdafx.h"
#include "blp2convert.h"
#include "blp2convertDlg.h"
#include "dds.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// Cblp2convertDlg dialog
//Save2TGA() is code
//written by Alexander Zaprjagaev
//frustum@frustum.org
//http://frustum.org
BOOL Save2TGA(const char *szFileName, const unsigned char *data, int width, int height)
{
unsigned char *buf;
buf = new unsigned char[18 + width * height * 4];
if(buf == NULL)return FALSE;
memset(buf,0,18);
buf[2] = 2;
buf[12] = (unsigned char)(width % 256);
buf[13] = (unsigned char)(width / 256);
buf[14] = (unsigned char)(height % 256);
buf[15] = (unsigned char)(height / 256);
buf[16] = 32;
buf[17] = 0x28;
memcpy(buf + 18, data, width * height * 4);
DWORD w;
HANDLE hFile = NULL;
hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Create File Error!", MB_OK);
return FALSE;
}
WriteFile(hFile, buf, 18 + width * height * 4, &w, NULL);
CloseHandle(hFile);
SAFE_DELETE_ARRAY(buf);
return TRUE;
}
BOOL DECODEDDSFormat(int nFormat, unsigned char* buf, int width,int height, char** pdesbuf)
{
if(nFormat == DDS_RGB)
{
unsigned char *src = buf;
unsigned char *dest = (unsigned char *)*pdesbuf;
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = 255;
}
}
}
else if(nFormat == DDS_RGBA)
{
unsigned char *src = buf;
unsigned char *dest = (unsigned char *)*pdesbuf;
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
}
}
delete buf;
} else {
unsigned char *src = buf;
for(int y = 0; y < height; y += 4)
{
for(int x = 0; x < width; x += 4)
{
unsigned long long alpha = 0;
unsigned int a0 = 0;
unsigned int a1 = 0;
if(nFormat == DDS_DXT3)
{
alpha = *(unsigned long long*)src;
src += 8;
}
else if(nFormat == DDS_DXT5)
{
alpha= (*(unsigned long long*)src) >> 16;
a0 = src[0];
a1 = src[1];
src += 8;
}
unsigned int c0 = *(unsigned short*)(src + 0);
unsigned int c1 = *(unsigned short*)(src + 2);
src += 4;
dds_color color[4];
color[0].r = (unsigned char)((c0 >> 11) & 0x1f) << 3;
color[0].g = (unsigned char)((c0 >> 5) & 0x3f) << 2;
color[0].b = (unsigned char)(c0 & 0x1f) << 3;
color[1].r = (unsigned char)((c1 >> 11) & 0x1f) << 3;
color[1].g = (unsigned char)((c1 >> 5) & 0x3f) << 2;
color[1].b = (unsigned char)(c1 & 0x1f) << 3;
if(c0 > c1)
{
color[2].r = (color[0].r * 2 + color[1].r) / 3;
color[2].g = (color[0].g * 2 + color[1].g) / 3;
color[2].b = (color[0].b * 2 + color[1].b) / 3;
color[3].r = (color[0].r + color[1].r * 2) / 3;
color[3].g = (color[0].g + color[1].g * 2) / 3;
color[3].b = (color[0].b + color[1].b * 2) / 3;
}else {
color[2].r = (color[0].r + color[1].r) / 2;
color[2].g = (color[0].g + color[1].g) / 2;
color[2].b = (color[0].b + color[1].b) / 2;
color[3].r = 0;
color[3].g = 0;
color[3].b = 0;
}
for(int i = 0; i < 4; i++)
{
unsigned int index = *src++;
unsigned char *dest = (unsigned char *)*pdesbuf + (width * (y + i) + x) * 4;
for(int j = 0; j < 4; j++)
{
*dest++ = color[index & 0x03].r;
*dest++ = color[index & 0x03].g;
*dest++ = color[index & 0x03].b;
if(nFormat == DDS_DXT1)
{
*dest++ = ((index & 0x03) == 3 && c0 <= c1) ? 0 : 255;
} else if(nFormat == DDS_DXT3)
{
*dest++ = (unsigned char)(alpha & 0x0f) << 4;
alpha >>= 4;
}
else if(nFormat == DDS_DXT5)
{
unsigned int a = (unsigned char)alpha & 0x07;
if(a == 0) *dest++ = (unsigned char)a0;
else if(a == 1) *dest++ = (unsigned char)a1;
else if(a0 > a1) *dest++ = (unsigned char)((8 - a) * a0 + (a - 1) * a1) / 7;
else if(a > 5) *dest++ = (a == 6) ? 0 : 255;
else *dest++ = (unsigned char)((6 - a) * a0 + (a - 1) * a1) / 5;
alpha >>= 3;
}
else
*dest++ = 255;
index >>= 2;
}
}
}
}
}
return TRUE;
}
Cblp2convertDlg::Cblp2convertDlg(CWnd* pParent /*=NULL*/)
: CDialog(Cblp2convertDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void Cblp2convertDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST_FILE, m_List);
}
BEGIN_MESSAGE_MAP(Cblp2convertDlg, CDialog)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_WM_DROPFILES()
ON_BN_CLICKED(IDOK, OnBnClickedOk)
END_MESSAGE_MAP()
// Cblp2convertDlg message handlers
BOOL Cblp2convertDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void Cblp2convertDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR Cblp2convertDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void Cblp2convertDlg::OnDropFiles(HDROP hDropInfo)
{
char *lpszFileName=new char[512];
int nFileCount,i;
nFileCount=::DragQueryFile(hDropInfo,0xFFFFFFFF,NULL,512);
for (i=0;i<nFileCount;i++)
{
UINT nChars= ::DragQueryFile(hDropInfo,i,&lpszFileName[0],512);
CString str(&lpszFileName[0],nChars);
if(str.Right(4) == ".blp")
m_List.AddString(str);
}
::DragFinish (hDropInfo);
SAFE_DELETE_ARRAY(lpszFileName);
if(m_List.GetCount()>0)
{
GetDlgItem(IDOK)->EnableWindow();
}
}
void Cblp2convertDlg::OnBnClickedOk()
{
GetDlgItem(IDOK)->SetWindowText(_T("Convert..."));
GetDlgItem(IDCANCEL)->EnableWindow(FALSE);
GetDlgItem(IDOK)->EnableWindow(FALSE);
//Start Convert
ConvertNow();
GetDlgItem(IDOK)->SetWindowText(_T("OK"));
GetDlgItem(IDCANCEL)->EnableWindow();
GetDlgItem(IDOK)->EnableWindow();
}
void Cblp2convertDlg::ConvertNow()
{
CString strFileName;
for(;;)
{
if(m_List.GetCount()>0)
{
m_List.SetCurSel(0);
m_List.GetText( 0, strFileName );
char *pBuff;
LoadAndConvert( (LPCSTR)strFileName, &pBuff);
SAFE_DELETE_ARRAY(pBuff);
m_List.DeleteString(0);
}else{
break;
}
}
}
// 装载文件,并转换
// 参数* 文件名、内存指针[放在这里为了当错误产生时候,返回后才释放新开辟的内存]
// 返回* 空
void Cblp2convertDlg::LoadAndConvert(const char * pszFileName, char** pBuff)
{
// WOW BLP文件头
struct T_BLP2HEADER
{
char ident[4];
int type;
BYTE subtype[4];
int width;
int height;
int mipmapoffsets[16];
int mipmaplengths[16];
};
struct T_RGBAPIX
{
unsigned char R;
unsigned char G;
unsigned char B;
unsigned char A;
};
struct T_PAPIX
{
unsigned char i;
unsigned char A;
};
struct T_PPIX
{
unsigned char i;
};
// 准备存盘的文件名
char szTgaFileName[MAX_PATH];
memset(szTgaFileName, 0, MAX_PATH);
strncpy(szTgaFileName, pszFileName, strlen(pszFileName)-4);
strncat(szTgaFileName, ".tga", MAX_PATH);
// 先将blp文件内容全部读到内存
HANDLE hFile = NULL;
hFile = CreateFile(pszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)return;
DWORD r = 0, nFileSize = 0;
nFileSize = GetFileSize(hFile, NULL);
// 读取文件
char* pTmpBuf = new char[nFileSize];
if(pTmpBuf==NULL)
{
CloseHandle(hFile);
return;
}
ReadFile(hFile, pTmpBuf, nFileSize, &r, NULL);
CloseHandle(hFile);
*pBuff = pTmpBuf;
// 读blp文件头,并判断文件格式是否正确
T_BLP2HEADER mBlp2Header;
unsigned long curpos = 0;
memcpy(&mBlp2Header, pTmpBuf+curpos, sizeof(T_BLP2HEADER));
if (memcmp(mBlp2Header.ident, "BLP2", 4) !=0 )
{
AfxMessageBox("Not a BLP2 file", MB_OK);
return;
}
curpos+=sizeof(T_BLP2HEADER);
// 准备存盘tga文件内容的内存
char* destBuf = new char[mBlp2Header.width * mBlp2Header.height * 4];
if(destBuf == NULL)return;
memset(destBuf, 0, sizeof(mBlp2Header.width * mBlp2Header.height * 4));
switch(mBlp2Header.type)
{
case 0:
{
//JPG格式存放,WOW的BLP文件似乎没有标示,但是网上很多人都这个标示是jpg格式。不管它先放在这里好了
//但是不确定是否正确,该代码抄写自wc3的blp转换分析,所以我这里都注释掉了
//curpos=sizeof(T_BLP2HEADER);
//long JPEGHeaderSize;
//memcpy(&JPEGHeaderSize, pTmpBuf+curpos, 4);
//unsigned char *tdata = new unsigned char[mBlp2Header.mipmaplengths[0] + JPEGHeaderSize];
//if(tdata == NULL)
//{
// SAFE_DELETE_ARRAY(destBuf);
// return;
//}
//curpos = sizeof(T_BLP2HEADER)+4;
//memcpy(tdata, pTmpBuf+curpos, JPEGHeaderSize);
//curpos=mBlp2Header.mipmapoffsets[0];
//memcpy((tdata+JPEGHeaderSize), pTmpBuf+curpos, mBlp2Header.mipmaplengths[0]);
//if(JPGRead(tdata, mBlp2Header.mipmaplengths[0] + JPEGHeaderSize, NULL, NULL, NULL, (unsigned char*)destBuf) == FALSE)
//{
// SAFE_DELETE_ARRAY(destBuf);
// SAFE_DELETE_ARRAY(tdata);
// return;
//}else{
// SAFE_DELETE_ARRAY(tdata);
// Save2TGA(szTgaFileName, (unsigned char*)destBuf, mBlp2Header.width, mBlp2Header.height);
//}
}
break;
case 1://paletted compress[好像还是采用wc3的blp压缩方式]
{
T_RGBAPIX mPal[256];
memcpy(&mPal, pTmpBuf+curpos, sizeof(T_RGBAPIX)*256);
curpos += sizeof(T_RGBAPIX)*256;
if(mBlp2Header.subtype[0] == 1)
{
unsigned char *tdata = NULL;
tdata = new unsigned char[mBlp2Header.mipmaplengths[0]];
if(tdata == NULL)
{
SAFE_DELETE_ARRAY(destBuf);
return;
}
curpos = mBlp2Header.mipmapoffsets[0];
memcpy(tdata, pTmpBuf+curpos, mBlp2Header.mipmaplengths[0]);
T_RGBAPIX *pic = (T_RGBAPIX*)destBuf;
T_PAPIX *ptdata = (T_PAPIX*)tdata;
unsigned long k,j,i;
j=0;
i=(mBlp2Header.width*mBlp2Header.height)/2;
for(k=0; k<i; ++k)
{
pic[j].R = mPal[ptdata[k].i].R;
pic[j].G = mPal[ptdata[k].i].G;
pic[j].B = mPal[ptdata[k].i].B;
if(mBlp2Header.subtype[1] == 0)
{
pic[j].A = 255-mPal[ptdata[k].i].A;
}else{
pic[j].A = ptdata[k+i].i;
}
++j;
pic[j].R = mPal[ptdata[k].A].R;
pic[j].G = mPal[ptdata[k].A].G;
pic[j].B = mPal[ptdata[k].A].B;
if(mBlp2Header.subtype[1] == 0)
{
pic[j].A = 255-mPal[ptdata[k].i].A;
}else{
pic[j].A = ptdata[k+i].A;
}
++j;
}
SAFE_DELETE_ARRAY(tdata);
Save2TGA(szTgaFileName, (unsigned char*)destBuf, mBlp2Header.width, mBlp2Header.height);
}
else if(mBlp2Header.subtype[0] == 2)
{
unsigned char *tdata = new unsigned char[mBlp2Header.mipmaplengths[0]];
if(tdata == NULL)
{
SAFE_DELETE_ARRAY(destBuf);
return;
}
curpos = mBlp2Header.mipmapoffsets[0];
memcpy(tdata, pTmpBuf+curpos, mBlp2Header.mipmaplengths[0]);
if(mBlp2Header.subtype[1] == 8)
{
//DXT3
if(DECODEDDSFormat(DDS_DXT3, tdata, mBlp2Header.width, mBlp2Header.height, &destBuf) == TRUE)
{
Save2TGA(szTgaFileName, (unsigned char*)destBuf, mBlp2Header.width, mBlp2Header.height);
}
SAFE_DELETE_ARRAY(tdata);
}
//else if(mBlp2Header.subtype[1] == 0)// 不知道????
//{
// if(DECODEDDSFormat(DDS_DXT5, tdata, mBlp2Header.width, mBlp2Header.height, &destBuf) == TRUE)
// {
// Save2TGA(szTgaFileName, (unsigned char*)destBuf, mBlp2Header.width, mBlp2Header.height);
// }
// SAFE_DELETE_ARRAY(tdata);
//}
else{
//DXT1
if(DECODEDDSFormat(DDS_DXT1, tdata, mBlp2Header.width, mBlp2Header.height, &destBuf) == TRUE)
{
// 转换成功
Save2TGA(szTgaFileName, (unsigned char*)destBuf, mBlp2Header.width, mBlp2Header.height);
}
SAFE_DELETE_ARRAY(tdata);
}
}
}
break;
}
SAFE_DELETE_ARRAY(destBuf);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -