[使用][DirectDraw][显示]如何使用DirectDraw 显示图象序列
09月 17th, 2008 by admin
Posted in VC/MFC | No Comments »
我正做一个图象序列显示程序,图象序列是352*288分辨率的,是用directshow捕获的,用StretchDIBits 定时显示图象序列,但是如果要在上面添加文字什么的,闪烁感比较强,所以想采用DirectDraw来实现,我看了CSDN上老的帖子,http://topic.csdn.net/t/20020522/17/744153.html 上面xzhangjie(飞天狐狸)发了一个类
#include "DDraw.h "
class CDDraw
{
public:
void CleanUp();
void DrawDIB(BITMAPINFOHEADER* pBI,char* pData,RECT*rt);
BOOL Init(HWND hWnd,int nWidth,int nHeight);
CDDraw();
virtual ~CDDraw();
private:
HWND m_hDrawWnd;
LPDIRECTDRAW lpDD; // DirectDraw 对象
LPDIRECTDRAWSURFACE lpDDSPrimary; // DirectDraw 主页面
LPDIRECTDRAWSURFACE lpBackdds;
LPDIRECTDRAWCLIPPER lpClipperBack;
};
CDDraw::CDDraw()
{
lpDD=NULL;
lpDDSPrimary=NULL;
lpBackdds=NULL;
lpClipperBack=NULL;
}
CDDraw::~CDDraw()
{
if(lpDD!=NULL)CleanUp();
}
BOOL CDDraw::Init(HWND hWnd,int nWidth,int nHeight)
{
if(hWnd==NULL) return FALSE;
m_hDrawWnd=hWnd;
if(DirectDrawCreate(NULL,&lpDD,NULL)!=DD_OK)return FALSE;
lpDD-> SetCooperativeLevel(hWnd, DDSCL_NORMAL);
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof( ddsd ); //结构的大小
ddsd.dwFlags = DDSD_CAPS; //指定DDSURFACEDESC结构的ddsCaps成员为可用
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; //指定要创建的是主页面
//创建主页面对象
if ( lpDD-> CreateSurface( &ddsd, &lpDDSPrimary, NULL ) != DD_OK) return FALSE;
if(lpDD-> CreateClipper(NULL,&lpClipperBack,NULL)!=DD_OK) return FALSE;
lpClipperBack-> SetHWnd(0,hWnd);
lpDDSPrimary-> SetClipper(lpClipperBack);
lpClipperBack-> Release();
lpClipperBack=NULL;
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwHeight = nHeight;
ddsd.dwWidth = nWidth;
if(lpDD-> CreateSurface(&ddsd, &lpBackdds, NULL)!=DD_OK) return FALSE;
return TRUE;
}
void CDDraw::DrawDIB(BITMAPINFOHEADER *pBI, char *pData, RECT *rt)
{
RECT srt;
srt.left=0;
srt.top=0;
srt.right=pBI-> biWidth;
srt.bottom=pBI-> biHeight;
HDC hDC;
lpBackdds-> GetDC(&hDC);
SetDIBitsToDevice(
hDC,
0,
0,
pBI-> biWidth, // source rectangle width
pBI-> biHeight, // source rectangle height
0, // x-coord of source lower-left corner
0, // y-coord of source lower-left corner
0, // first scan line in array
pBI-> biHeight, // number of scan lines
pData, // array of DIB bits
(const struct tagBITMAPINFO*)pBI, // bitmap information
DIB_RGB_COLORS // RGB or palette indexes
);
lpBackdds-> ReleaseDC(hDC);
lpDDSPrimary-> Blt(rt,lpBackdds,&srt,0,NULL);
}
void CDDraw::CleanUp()
{
if(lpDD!=NULL)
{
if(lpClipperBack!=NULL)
{
lpClipperBack-> Release();
lpClipperBack=NULL;
}
if(lpDDSPrimary!=NULL)
{
lpDDSPrimary-> Release();
lpDDSPrimary=NULL;
}
if(lpBackdds!=NULL)
{
lpBackdds-> Release();
lpBackdds=NULL;
}
lpDD-> Release();
lpDD=NULL;
}
}
但是无法显示图象序列,序列已从32位转成24位RGB
哪位大哥能告诉我原因啊?谢谢了
我的邮箱:jiaqicx@163.com
大家帮帮忙啊 谢谢了
自己顶
[DirectDraw][编程][基础]DirectDraw 编程的基础问题StretchDIBits 速度好慢
08月 30th, 2008 by admin
Posted in VC/MFC | No Comments »
我想在屏幕上输出 pOriY 里的图片,用 StretchDIBits 速度好慢,请问有什么办法可以加快速度?能否绕开 StretchDIBits ?
for(i = 0; i < iWidth; i++)
for(j = 0; j < iHeight; j++)
pOriY[i + iWidth * j] = RGB[0, 0, 255];
BITMAPINFOHEADER bi;
BYTE *pic = (BYTE*)pOriY;
bi.biSize = sizeof( BITMAPINFOHEADER );
bi.biWidth = 320;
bi.biHeight = 240;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 320 * 240 * 4 ;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
HDC hdc;
lpDDSBack-> GetDC(&hdc);
SetStretchBltMode(hdc, STRETCH_HALFTONE);
StretchDIBits( hdc , //hDC
0, //DestX
0,//DestY
320, //DestWidth
240, //DestHeight
0 , //SrcX
0 , //SrcY
320 , //SrcWidth
240 , //SrcHeight
pic, //lpBits
(LPBITMAPINFO)&bi, //lpBitsInfo
DIB_RGB_COLORS , //wUsage
SRCCOPY);
lpDDSBack-> ReleaseDC( hdc );
lpDDSPrimary-> BltFast(r.left + 1, r.top + 1, lpDDSBack, NULL, 0);
lpDDSBack-> Restore();
如果原图绘制没必要用STRETCH_HALFTONE参数,StretchDIBits速度还行吧。
有缩放的话,用DrawDibDraw,速度没得说。
既然用到DirectDraw,那就加载到纹理。不要用GDI函数。
我现在直接用 CopyMemory 将 pOriY 的数据拷贝到 lpDDSBack 里,然后 Blt 到主表面。速度比以前快多了,呵呵。
[DirectDraw][窗口][模式]请教关于DirectDraw窗口模式的一些常用方法
08月 2nd, 2008 by admin
Posted in VC/MFC | No Comments »
小弟对DirectDraw了解很浅,现在要弄一个窗口模式的DirectDraw应用程序,本来一切都OK了,却突然发现一个巨大的BUG,那就是改变屏幕分辨率后一切黑屏。
我使用的方法是将所有图元存放在各个离屏表面中,然后在各个表面之间做Blt,最终显示出画面。
经过调试发现,当屏幕分辨率发生改变时,所有的表面都失效了,->Restore根本不起作用。
请教各位前辈,做DirectDraw窗口程序,一般采用什么来存放图元,是自定义的结构体还是DirectDraw表面,如果是前者又如何利用DirectDraw的高效性,如果是后者又如何避免表面的丢失呢?
另外附带一个问题,在两个离屏表面之间作Blt可以利用硬件特性么?
我的DIRECTDRAWSURFACE在按下“Ctrl+Alt+Del”调出系统登录界面后也会丢失,并且用Restore也不能恢复。
后来多Lock几次,成功了,表面就可用了。
从1400×1050改变为1024×768时(未改变色深),所有表面都失效了(包括离屏表面),症状是Blt失败,Lock也失败。
我再把症状描述的详细一点吧:
1、从1400×1050改变为1024×768时,Restore后,Blt还是失败,错误号887601C2(DDERR_INVALIDRECT)???
2、从1400×1050改变为1024×768时,再改变回1400×1050,Blt成功,返回DD_OK,但是画面花屏。
2先不管,1肯定是要解决的,如果改变分辨后,DirectDraw就会失效,那岂不是只能把数据存在自定义结构体里面,需要的时候再创建一下表面了?
所以才来请教一下各位前辈一般是怎么处理这类应用的?
我也碰到了同样的问题,改变分辨率,离屏页面lock失败,返回0×887601c2,盼高手指点!
关注
关注
分配到系统内存可以防止表面丢失,不过这样就无法利用硬件的性能了。
想不通了!?DirectDraw要是只能这样,那岂不是很废?
就是这么设计的,现在连restore都成了专门的学问.
一般来说这种情况都是把这些重新载入一次,可以看到很多游戏都是这样,在这种时候请观测指示灯,硬盘在读
那岂不是不能将中间产物常驻保存了???因为这东西没法简单复原啊!
我试过写一个Backup类备份图元数据,虽然可以工作,但是备份时要从显存读数据,而这速度实在不是人类可以忍受的。
另外由于某些图片有alpha通道,我将所有离屏表面都设为32位,后来发现某些老式的显卡结合98系统,无法直接将32位表面Blt到16位的Primary表面。
如果通过GetDC结合GDI的方式写入倒是可以,不过却要涉及2次图形拷贝:
1、由于表面和DIB的图形存放顺序不同,所以需要生成一个HBITMAP作中间变量,这里是一次拷贝。
2、如果直接将1中的HBITMAP画到HDC上,会发现CLIPPER失效,比如让记事本在DirectDraw窗口上面移动,记事本无法覆盖住它的绘图;
所以需要再创建一个与Primary表面相同色深的中间表面过渡,最后还是利用Blt绘制,这里是二次拷贝。
这样的代价是不是大了一点?