转载文章,原文链接:
https://blog.csdn.net/qq969422014/article/details/44536375
上一章,我们已经知道了如何实现游戏动画,是不是很简单哇,这一章,我们就来说说如何透明贴图,我们知道GDI只支持BMP的位图,所以图片本身是不具备透明的,那么,我们如何来实现透明效果呢?很简单,这里介绍两种方式。
第一种:遮罩法
这种方式需要两张图片,第一张为原图,背景为黑色,第二张图为遮罩图,背景为白色,比如有角色素材如下:
通过BitBlt函数的光栅操作即可实现图片背景的透明处理,说简单点就是BitBlt的最后一个参数,白色and任意色=任意色,黑色and任意色=黑色,黑色or任意色=任意色,第一步我们通过SRCAND运算先贴上遮罩图,也就是第二张图片。核心代码如下:
-
SelectObject(mm_hdc,role);
-
BitBlt(m_hdc,
100,
50,
254,
480,mm_hdc,
254,
0,SRCAND);
//AND运算
通过上述代码,得到以下效果图
第二步:通过SRCPAINT运算贴上彩色图即可实现透明,是不是很简单哇,说白了,整个透明绘制也就是两句话,对同一张图片绘制两次就行了
-
SelectObject(mm_hdc,role);
-
BitBlt(m_hdc,
100,
50,
254,
480,mm_hdc,
254,
0,SRCAND);
//AND运算,帖上遮罩图
-
BitBlt(m_hdc,
100,
50,
254,
480,mm_hdc,
0,
0,SRCPAINT);
//或运算,帖上彩色图
透明效果如下
第二种:颜色删除法
顾名思义,就是删除某个颜色即可,比如有以下素材图片
观察发现,我们只需要删除黑色颜色即可,删除某个颜色,我们可以使用TransparentBlt函数,使用这个函数,需要一个类库文件
#pragma comment(lib,"Msimg32.lib")
TransparentBlt函数参数:
-
WINGDIAPI BOOL WINAPI TransparentBlt(
-
__in HDC hdcDest,//需要绘制的设备环境
-
__in int xoriginDest,//开始绘制的X坐标
-
__in int yoriginDest,//开始绘制的Y坐标
-
__in int wDest,//绘制的宽
-
__in int hDest,//绘制的高
-
__in HDC hdcSrc,//源图片的设备环境
-
__in int xoriginSrc,//从原图的X坐标开始
-
__in int yoriginSrc,//从原图的Y坐标开始
-
__in int wSrc,//宽
-
__in int hSrc,//高
-
__in UINT crTransparent);
//删除的颜色
实列代码如下:
-
SelectObject(mm_hdc,role2);
-
TransparentBlt(m_hdc,
320,
50,
500,
700,mm_hdc,
0,
0,
500,
700,
RGB(
0,
0,
0));
//RGB(0,0,0)代表黑色
就这样一个透明就实现了,相比较前面一个,这个简单了许多
总结,第一个方法绘制的图形质量高,但是需要两张图片,第二个方法虽然简单了许多,但是缺点也很明显,质量不是很高,如果人物中有与背景相同的颜色,那么也会被去掉,就好很难看。
完整代码:
-
#include <Windows.h>
-
#include <string>
-
-
#pragma comment(lib,"winmm.lib")
-
#pragma comment(lib,"Msimg32.lib")
-
-
using
namespace std;
-
-
//窗体的过程函数
-
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam);
-
-
HDC g_hdc;
//设备环境
-
HDC m_hdc;
//兼容的设备环境
-
HDC mm_hdc;
//三级兼容设备
-
HBITMAP bg;
//背景图片
-
HBITMAP role;
//素材图片
-
HBITMAP role2;
//素材图片2
-
-
//初始化资源,用于初始化设备环境和加载背景图片
-
void Game_Init(HWND hwnd);
-
//绘制图形,正式绘制
-
void Game_Paint(HWND hwnd);
-
//清理资源,程序退出时,释放资源
-
void Game_Clear(HWND hwnd);
-
-
//WinMain主函数
-
INT WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrivInstance,LPSTR lpCmdLine,int nShowCmd)
-
{
-
//设计一个窗体
-
WNDCLASSEX wndClass = {
0};
-
wndClass.style = CS_HREDRAW|CS_VREDRAW;
-
wndClass.cbSize =
sizeof(wndClass);
-
wndClass.cbClsExtra =
0;
-
wndClass.cbWndExtra =
0;
-
wndClass.hbrBackground = (HBRUSH)
GetStockObject(GRAY_BRUSH);
-
wndClass.hCursor = ::
LoadCursor(hInstance,IDC_ARROW);
-
wndClass.hIcon = (HICON)::
LoadImage(
NULL,
L"",IMAGE_ICON,
0,
0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
-
wndClass.hInstance = hInstance;
-
wndClass.lpfnWndProc = WndProc;
-
wndClass.lpszClassName =
L"Test";
-
wndClass.lpszMenuName =
0;
-
//注册窗体
-
if (!
RegisterClassEx(&wndClass))
-
{
-
return
-1;
-
}
-
//创建窗体
-
HWND hwnd =
CreateWindow(
L"Test",
L"GDI",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
800,
600,
NULL,
NULL,hInstance,
NULL);
-
-
if (hwnd ==
NULL)
-
{
-
return
-1;
-
}
-
//初始化资源
-
Game_Init(hwnd);
-
-
//显示与更新窗体
-
ShowWindow(hwnd,nShowCmd);
-
UpdateWindow(hwnd);
-
-
//消息队列
-
MSG msg = {
0};
-
-
while (msg.message != WM_QUIT)
-
{
-
if (
PeekMessage(&msg,
0,
0,
0,PM_REMOVE))
//读取消息
-
{
-
TranslateMessage(&msg);
//翻译消息
-
DispatchMessage(&msg);
//发送消息
-
}
-
else
-
{
-
Game_Paint(hwnd);
//绘制函数
-
Sleep(
50);
//绘制间隙50毫秒
-
}
-
}
-
-
UnregisterClass(
L"Test",hInstance);
-
-
return
0;
-
}
-
-
//窗口过程函数
-
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
-
{
-
switch(message)
-
{
-
case WM_PAINT:
-
ValidateRect(hwnd,
NULL);
//重绘整个窗体
-
break;
-
case WM_DESTROY:
-
Game_Clear(hwnd);
//退出程序时,清理资源
-
PostQuitMessage(
0);
-
break;
-
default:
-
return
DefWindowProc(hwnd,message,wparam,lparam);
-
}
-
-
return
0;
-
}
-
-
//初始化资源
-
void Game_Init(HWND hwnd)
-
{
-
g_hdc =
GetDC(hwnd);
//获取设备环境DC
-
m_hdc =
CreateCompatibleDC(g_hdc);
//建立兼容的设备环境
-
mm_hdc =
CreateCompatibleDC(m_hdc);
-
-
SelectObject(m_hdc,
CreateCompatibleBitmap(g_hdc,
800,
600));
-
-
bg = (HBITMAP)
LoadImage(
NULL,
L"bg.bmp",IMAGE_BITMAP,
0,
0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
-
-
role = (HBITMAP)
LoadImage(
NULL,
L"role.bmp",IMAGE_BITMAP,
0,
0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
-
-
role2 = (HBITMAP)
LoadImage(
NULL,
L"role2.bmp",IMAGE_BITMAP,
0,
0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
-
-
//播放背景音乐
-
//第一个参数,文件路径
-
//第二参数,应用程序的实例句柄,除非pszSound的指向一个资源标识符(即fdwSound被定义为SND_RESOURCE),否则必须设置为NULL
-
//第三个参数为标示,SND_LOOP重复播放,SND_ASYNC异步播放,SND_FILENAME来自硬盘文件
-
//PlaySound(L"bg.wav",0,SND_LOOP | SND_ASYNC | SND_FILENAME);
-
}
-
-
//绘制图形
-
void Game_Paint(HWND hwnd)
-
{
-
SelectObject(mm_hdc,bg);
-
BitBlt(m_hdc,
0,
0,
800,
600,mm_hdc,
0,
0,SRCCOPY);
//拷贝到设备环境上
-
-
SelectObject(mm_hdc,role);
-
BitBlt(m_hdc,
100,
50,
254,
480,mm_hdc,
254,
0,SRCAND);
//AND运算,帖上遮罩图
-
BitBlt(m_hdc,
100,
50,
254,
480,mm_hdc,
0,
0,SRCPAINT);
//或运算,帖上彩色图
-
-
SelectObject(mm_hdc,role2);
-
TransparentBlt(m_hdc,
320,
50,
500,
700,mm_hdc,
0,
0,
500,
700,
RGB(
0,
0,
0));
-
-
BitBlt(g_hdc,
0,
0,
800,
600,m_hdc,
0,
0,SRCCOPY);
-
}
-
-
//清理内存
-
void Game_Clear(HWND hwnd)
-
{
-
ReleaseDC(hwnd,g_hdc);
-
DeleteObject(bg);
-
DeleteObject(role);
-
DeleteObject(role2);
-
DeleteObject(m_hdc);
-
}