⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 blp2convertdlg.cpp

📁 魔兽世界blp2tga工具和源代码
💻 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 + -