DirectDraw Overlay Surfaces

来源:互联网 发布:可小猫真武捏脸数据 编辑:程序博客网 时间:2024/06/06 17:55

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

Type

Name

Description

RECT

rectOverlay

Overlay source rectangle

RECT

rectClient

Window size and position

LPDIRECTDRAWSURFACE

lpOverlay

Pointer to the overlay surface

LPDIRECTDRAWSURFACE

lpPrimary

Pointer to the primary surface

LPDIRECTDRAWCLIPPER

lpClipper

Pointer to the clipper

LPDIRECTDRAW

lpDD

Pointer to the global DirectDraw object

HWND

hwnd

Handle of the window inside which the overlay is to be displayed.

HRESULT

ddrval

Return value from DirectDraw API calls

DWORD

dwKeyColour

The colour to be used as the key for the overlay. This value will change depending upon the primary surface mode.

DWORD

dwFlags

Work variable used in the move/size code

DDSURFACEDESC

ddsd

Surface description used in creation of primary and overlay surfaces

DDPIXELFORMAT

ddPixelFormat

Pixel format description for the overlay surface

DDOVERLAYFX

ddofx

Effects used in displaying the overlay

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);

 

原创粉丝点击