之前一直苦于不知道如何实现覆盖表面的的关键色和透明同时使用,以为只支持其中的一种。后来在放弃之后,在无意中发现实现的方法,天意啊。
以下为窗口的一个函数,用来初始化我的directdraw离屏表面,表面同时支持支持关键色和透明:
所有以“m_”开头的都为类的成员变量
BOOL MyMainWin::MyInitDD()
{
HRESULT ret = DirectDrawCreate(NULL, &m_pDD, NULL);
if (ret != DD_OK)
{
printf("获取directdraw实例失败!");
return FALSE;
}
ret = m_pDD->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL);
if (ret != DD_OK)
{
printf("设置登记失败!");
return FALSE;
}
//g_pDD->GetDisplayMode(&ddsd);
//hRet = g_pDD->SetDisplayMode(480, 720, 32, 0, DDSDM_STANDARDVGAMODE);
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
ret = m_pDD->CreateSurface(&ddsd, &m_pDDSPrimary, NULL);
if (ret != DD_OK)
{
printf("创建主表面失败!");
return FALSE;
}
DDCAPS ddcaps;
// 申请离屏表面
memset(&ddcaps, 0, sizeof(ddcaps));
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
ddsd.dwHeight = 720;
ddsd.dwWidth = 480;
ret = m_pDD->CreateSurface( &ddsd, &m_pDDSOffScreenOne, NULL);
if( ret != DD_OK )
{
printf("创建离屏表面失败");
return FALSE;
}
memset(&ddcaps, 0, sizeof(ddcaps));
ddcaps.dwSize = sizeof(ddcaps);
ret = m_pDD->GetCaps(&ddcaps, NULL);
if (ret != DD_OK)
{
printf("获取caps描述失败!");
return FALSE;
}
if (ddcaps.dwOverlayCaps == 0)
{
printf("不支持覆盖表面");
return FALSE;
}
RECT rs;
rs.left = 0;
rs.top = 0;
// 我要创建的表面的大小(此处为全屏幕),如果表面非全屏,需要判断设备支持的表面大小以及坐标开始值,请参考网上资料
rs.right = PIC_SIZE_WIDTH;
rs.bottom = PIC_SIZE_HEIGHT;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP ;
//ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT;
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_BACKBUFFERCOUNT;
ddsd.dwWidth = rs.right;
ddsd.dwHeight = rs.bottom;
//ddsd.dwBackBufferCount = 2;
ddsd.dwBackBufferCount = 1;
ret = m_pDD->CreateSurface(&ddsd, &m_pDDSOverlay, NULL);
if (ret != DD_OK)
{
printf("创建覆盖表面失败!");
return FALSE;
}
// 获取缓冲表面(MyGetSurfaceCallback为回调函数,在后面给出,作用是获取后备缓冲表面的指针)
ret = m_pDDSOverlay->EnumAttachedSurfaces(this, MyGetSurfaceCallback);
if (FAILED(ret))
{
printf("获取缓冲表面失败!");
return FALSE;
}
// 覆盖表面的标志
//DWORD dwUpdateFlags = DDOVER_SHOW;
DWORD dwUpdateFlags = 0;
// 检查是否支持关键色(透明色)
//DDOVERLAYFX ovfx;
memset(&m_ovfx, 0, sizeof(m_ovfx));
m_ovfx.dwSize = sizeof(m_ovfx);
// 这个判断是我自己加的,无特别意义,可去掉
if(IF_PAINT_COLORKEY)
{
//if (ddcaps.dwOverlayCaps & DDOVERLAYCAPS_ALPHAANDKEYDEST)
{
if (ddcaps.dwOverlayCaps & DDOVERLAYCAPS_CKEYSRC)
{
dwUpdateFlags |= DDOVER_KEYSRCOVERRIDE;
// 设置透明色
m_ovfx.dckSrcColorkey.dwColorSpaceLowValue = BG_COLORKEY; // black as the color key
m_ovfx.dckSrcColorkey.dwColorSpaceHighValue = BG_COLORKEY;
}
}
}
// 更新覆盖表面的值
ret = m_pDDSOverlay->UpdateOverlay(&rs, m_pDDSPrimary, &rs, dwUpdateFlags, &m_ovfx);
if (ret != DD_OK)
{
printf("更新覆盖表面初始信息失败!");
return FALSE;
}
// BG_TRANS_VALUE为背景色透明度(即关键色的透明度),FG_TARANS_VALUE为前景色透明度(即关键色外的所有颜色)
// 两个值的范围都是 0~15,0表示完全透明,15表示完全不透
m_ovfx.dwAlphaConst = ((BG_TRANS_VALUE&0xF) << 4 ) | (FG_TARNS_VALUE & 0xF);
ret = m_pDDSOverlay->UpdateOverlay(&rs, m_pDDSPrimary, &rs, 0, &m_ovfx);
if (ret != DD_OK)
{
printf("更新覆盖表面初始信息失败!");
return FALSE;
}
// 此处给表面填充关键色(可不做),以免显示时出现黑色的闪烁(因为表面的初始颜色为黑色)
HDC hdc = NULL;
if (FAILED(m_pDDSOverlay->GetDC(&hdc)))
{
return FALSE;
}
FillRect(hdc, &rs, m_hb);
m_pDDSOverlay->ReleaseDC(hdc);
// 显示
ret = m_pDDSOverlay->UpdateOverlay(&rs, m_pDDSPrimary, &rs, DDOVER_SHOW, &m_ovfx);
if (ret != DD_OK)
{
printf("更新覆盖表面初始信息失败!");
return FALSE;
}
return TRUE;