DirectDraw Overlay Surfaces

There appears to be a great deal of confusion over how to create and display an overlay surface under DirectDraw so here's some sample code showing (very simply) how to create an overlay and show it stretched into a window. This code is not intended to be directly compiled (I cut and pasted it from various testcases) but to show the basic flow of events. Also, to aid clarity, it is rather oversimplified. It assumes the FOURCC when, in fact, it should query the supported formats from the driver and it doesn't consider multipage overlays and flipping (these are left as an exercise for the reader :-) ).

Disclaimer

You use this code at your own risk. I make no guarantee that it will work and I will not be held responsible for anything nasty that happens as a result of you using it. Having said that, it's worked fine for me and may be of use to you too. Also, if you find any blatant errors, please let me know.

Assumptions

The sample code assumes the following variables :

TypeNameDescription
DDOVERLAYFXddofxEffects used in displaying the overlay
DDPIXELFORMATddPixelFormatPixel format description for the overlay surface
DDSURFACEDESCddsdSurface description used in creation of primary and overlay surfaces
DWORDdwFlagsWork variable used in the move/size code
DWORDdwKeyColourThe colour to be used as the key for the overlay. This value will change depending upon the primary surface mode.
HRESULTddrvalReturn value from DirectDraw API calls
HWNDhwndHandle of the window inside which the overlay is to be displayed.
LPDIRECTDRAWlpDDPointer to the global DirectDraw object
LPDIRECTDRAWCLIPPERlpClipperPointer to the clipper
LPDIRECTDRAWSURFACElpPrimaryPointer to the primary surface
LPDIRECTDRAWSURFACElpOverlayPointer to the overlay surface
RECTrectClientWindow size and position
RECTrectOverlayOverlay source rectangle
Showing 1 to 13 of 13 entries

Object Creation

/*************************/
/* Initialise DirectDraw */
/*************************/
ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
if(ddrval != DD_OK)
{
  TRACE("Can't initialise DirectDraw ! 0x%08lx\n", ddrval);
  return(FALSE);
}

ddrval = IDirectDraw_SetCooperativeLevel(lpDD, hwnd, DDSCL_NORMAL);
if(ddrval != DD_OK)
{
  TRACE("Can't set DirectDraw cooperative level ! 0x%08lx\n", ddrval);
  IDirectDraw_Release(lpDD);
  return(FALSE);
}

/******************************/
/* Create the primary surface */
/******************************/
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpPrimary, NULL );

if( ddrval != DD_OK )
{
  TRACE("Can't create primary surface ! 0x%08lx\n", ddrval);
  IDirectDraw_Release(lpDD);
  return(FALSE);
}

/******************************/
/* Create the overlay surface */
/******************************/
ddPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
ddPixelFormat.dwFlags = DDPF_FOURCC;
ddPixelFormat.dwFourCC = mmioFOURCC('U','Y','V','Y');
ddPixelFormat.dwYUVBitCount = 16;

ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS |
               DDSD_HEIGHT |
               DDSD_WIDTH |
               DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY;
ddsd.dwHeight = 240; /* Change these values as appropriate (obviously !) */
ddsd.dwWidth = 320;

memcpy(&(ddsd.ddpfPixelFormat), &ddPixelFormat, sizeof(DDPIXELFORMAT));

ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpOverlay, NULL );

if( ddrval != DD_OK )
{
  TRACE("Can't create overlay surface ! 0x%08lx\n", ddrval);
  IDirectDrawSurface_Release(lpPrimary);
  IDirectDraw_Release(lpDD);
  return(FALSE);
}
/***********************************/
/* Create a clipper for our window */
/***********************************/
ddrval = IDirectDraw_CreateClipper(lpDD, 0, &lpClipper, NULL);
if( ddrval != DD_OK )
{
  TRACE("Can't create DirectDraw clipper ! 0x%08lx\n", ddrval);
}
else
  ddrval = IDirectDrawClipper_SetHWnd(lpClipper, 0, hwnd);

Window Move/Size Processing

The following code should be put in a function called when processing WM_MOVE and WM_SIZE messages. Note that it is vitally important that your window receives WM_MOVE messages even if the size has not changed. If the window is a child of the main application window (as in most cases), these messages are not posted to it by default and you have to relay them from the parent's window handler function.

/***************************************/
/* Show the overlay with colour keying */
/***************************************/

/*************************/
/* Where is the window ? */
/*************************/
GetWindowRect(hwnd, &rectClient);

/*********************************/
/* Position and show the overlay */
/*********************************/
SetRect(&rectOverlay, 0, 0, 320, 240);

ddofx.dwSize = sizeof(DDOVERLAYFX);
ddofx.dckDestColorkey.dwColorSpaceLowValue = dwKeyColour;
ddofx.dckDestColorkey.dwColorSpaceHighValue = dwKeyColour;

dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW;

ddrval = IDirectDrawSurface_UpdateOverlay(lpOverlay,
                                          &rectOverlay,
                                          lpPrimary,
                                          &rectClient,
                                          dwFlags,
                                          &ddofx);
if(ddrval != DD_OK)
{
  // Oops - can't update overlay. Put your error handling code here.
}

Window Paint Processing

This is the basic code required inside WM_PAINT processing to fill the client area with a colour key value above which the overlay will be displayed. Note the use of a clipper to prevent the DirectDraw Blt call from corrupting any overlying windows, menus, etc.

Many people use normal GDI calls to draw the colour key but this requires a great deal of care when using a palettised desktop since the palette index of a particular RGB colour can change if the palette is altered by another application resulting in your user seeing a lovely (for example) magenta rectangle instead of your nice overlay surface. Using the DirectDraw Blt, however, you can guarantee the value written to the primary surface so your colour key will work regardless of the state of the system palette.

/****************************************************************/
/* Attach the clipper to the primary surface for this operation */
/****************************************************************/
ddrval = IDirectDrawSurface_SetClipper(lpPrimary, lpClipper);

hdc = BeginPaint(hwnd, &ps);

/* Fill the client area with colour key */
ptClient.x = ps.rcPaint.left;
ptClient.y = ps.rcPaint.top;
ClientToScreen(hwnd, &ptClient);
rectBlt.left = ptClient.x;
rectBlt.top = ptClient.y;

ptClient.x = ps.rcPaint.right;
ptClient.y = ps.rcPaint.bottom;
ClientToScreen(hwnd, &ptClient);
rectBlt.right = ptClient.x;
rectBlt.bottom = ptClient.y;

ddbfx.dwSize = sizeof(DDBLTFX);
ddbfx.dwFillColor = dwKeyColour;

TRACE("Filling rectangle (%d, %d), (%d, %d) with colour 0x%08lx\n",
      rectBlt.left,
      rectBlt.top,
      rectBlt.right,
      rectBlt.bottom,
      ddbfx.dwFillColor);

IDirectDrawSurface_Blt(lpPrimary,
                       &rectBlt,
                       NULL,
                       &rectBlt,
                       DDBLT_COLORFILL | DDBLT_WAIT,
                       &ddbfx);

EndPaint(hwnd, &ps);

ddrval = IDirectDrawSurface_SetClipper(lpPrimary, NULL);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值