Creating Surfaces

[Previous] [Next]

A surface controlled by the IDirectDrawSurface7 interface represents a rectangular area of display memory. You use this surface for items such as the primary display surface presented to the user on the screen or the textures applied to 3D surfaces. You can use either video memory or system memory for your surfaces. If you don't specify a particular memory type, DirectDraw places the DirectDrawSurface7 object into whatever memory allows for the best performance.

To create a surface, just call the IDirectDraw7::CreateSurface method, which is declared as shown here:

 HRESULT CreateSurface(     LPDDSURFACEDESC2 lpDDSurfaceDesc2,     LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface,     IUnknown FAR *pUnkOuter ); 

ParameterDescription
lpDDSurfaceDesc2The address of a DDSURFACEDESC2 structure that describes the requested surface. Before calling this method, set any unused members of the DDSURFACEDESC2 structure to 0. A DDSCAPS2 structure is a member of DDSURFACEDESC2.
lplpDDSurfaceThe address of a variable that will be set to a valid IDirectDrawSurface7 interface pointer if the call succeeds.
pUnkOuterAllows for compatibility with future COM aggregation features. The IDirectDraw7::CreateSurface currently returns an error if this parameter is set to anything other than NULL.

You can use the IDirectDraw7::CreateSurface method to create a single surface object, a complex surface-flipping chain, or a three-dimensional surface. The IDirectDrawSurface7::Lock method lets you directly access display memory by locking the display memory and retrieving the address for that surface. This address can point to visible frame buffer memory, such as the primary surface, or to nonvisible buffers, such as overlay or off-screen surfaces.

The Front Buffer, Back Buffers, and Clipper

The primary surface, also known as the front buffer, is the surface that is visible on the monitor. Each DirectDraw object can have only one primary surface, which is identified by the DDSCAPS_PRIMARYSURFACE flag.

When the primary surface is created, its dimensions and pixel format match the current display mode, so you don't need to declare them. Accidentally specifying them will cause the call to fail.

Full-Screen Buffers

The following code shows the entire CreateFullScreenBuffers routine. This routine is used to create the front and back buffers. (You don't need a clipper object because you're not in windowed mode.) In the paragraphs following the code, each segment is described in detail, in the order in which it should be performed.

 //------------------------------------------------------------------- // Name: CreateFullscreenBuffers // Desc: Creates the primary surface and (optional) back buffer for  //       rendering. Windowed mode and full-screen mode are handled  //       differently. //------------------------------------------------------------------- HRESULT CD3DFramework7::CreateFullscreenBuffers(                                  DDSURFACEDESC2* pddsd ) {     HRESULT hr;     // STEP 1 - Full-Screen Mode     // Get the dimensions of the screen bounds.     // Store the rectangle that contains the renderer.     SetRect( &m_rcScreenRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight );     m_dwRenderWidth  = m_rcScreenRect.right  - m_rcScreenRect.left;     m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top;     // STEP 2 - Full-Screen Mode     // Set the display mode to the requested dimensions. Check for     // 320 x 200 x 8 modes, and set the flag to avoid using Mode X.     DWORD dwModeFlags = 0;     if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) &&         (8==pddsd->ddpfPixelFormat.dwRGBBitCount) )         dwModeFlags |= DDSDM_STANDARDVGAMODE;     if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth,                                  m_dwRenderHeight,                                 pddsd->ddpfPixelFormat.dwRGBBitCount,                                 pddsd->dwRefreshRate,                                  dwModeFlags ) ) )     {         DEBUG_MSG( _T("Can't set display mode") );         return D3DFWERR_BADDISPLAYMODE;     }     // STEP 3 - Full-Screen Mode     // Set up to create the primary surface with a back buffer.     DDSURFACEDESC2 ddsd;     ZeroMemory( &ddsd, sizeof(ddsd) );     ddsd.dwSize            = sizeof(ddsd);     ddsd.dwFlags           = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;     ddsd.ddsCaps.dwCaps    = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE |                              DDSCAPS_FLIP | DDSCAPS_COMPLEX;     ddsd.dwBackBufferCount = 1;     // Support for stereoscopic viewing     if( m_bIsStereo )     {         ddsd.ddsCaps.dwCaps  |= DDSCAPS_VIDEOMEMORY;         ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;     }     // STEP 4 - Full-Screen Mode     // Create the primary surface.     if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,                                             NULL ) ) )     {         DEBUG_MSG( _T("Error: Can't create primary surface") );         if( hr != DDERR_OUTOFVIDEOMEMORY )             return D3DFWERR_NOPRIMARY;         DEBUG_MSG( _T("Error: Out of video memory") );         return DDERR_OUTOFVIDEOMEMORY;     }     // STEP 5 - Full-Screen Mode     // Get the back buffer, which was created along with the primary     // surface.     DDSCAPS2 ddscaps = { DDSCAPS_BACKBUFFER, 0, 0, 0 };     if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,                                               &m_pddsBackBuffer ) ) )     {         DEBUG_ERR( hr, _T("Error: Can't get the back buffer") );         return D3DFWERR_NOBACKBUFFER;     }     // Increment the back-buffer count (for consistency with      // windowed mode).     m_pddsBackBuffer->AddRef();     // STEP 6 - Full-Screen Mode     // Support for stereoscopic viewing     if( m_bIsStereo )     {         // Get the left back buffer, which was created along with the          // primary surface.         DDSCAPS2 ddscaps = { 0, DDSCAPS2_STEREOSURFACELEFT, 0, 0 };         if( FAILED( hr =                  m_pddsBackBuffer->GetAttachedSurface( &ddscaps,                                        &m_pddsBackBufferLeft ) ) )         {             DEBUG_ERR( hr,                  _T("Error: Can't get the left back buffer") );             return D3DFWERR_NOBACKBUFFER;         }         m_pddsBackBufferLeft->AddRef();     }     FILE *fplog = fopen("rrlogfile.txt","a");     ZeroMemory(&m_ddpfBackBufferPixelFormat, sizeof(DDPIXELFORMAT));     m_ddpfBackBufferPixelFormat.dwSize = sizeof(DDPIXELFORMAT);     hr = m_pddsBackBuffer->             GetPixelFormat(&m_ddpfBackBufferPixelFormat);     if(hr == DD_OK)     {                 fprintf( fplog, "Backbuffer Pixelformat RGB bits  = : ");         fprintf( fplog, "%d\n",                  m_ddpfBackBufferPixelFormat.dwRGBBitCount);         fprintf( fplog, "Backbuffer Pixelformat RGB masks = : ");         fprintf( fplog, "%d %d %d\n\n",         m_ddpfBackBufferPixelFormat.dwRBitMask,         m_ddpfBackBufferPixelFormat.dwGBitMask,         m_ddpfBackBufferPixelFormat.dwBBitMask);     }     else         fprintf( fplog, "Check on back-buffer pixel format FAILED ");          hr = m_pddsBackBuffer->GetSurfaceDesc( &ddsd );          fclose(fplog);     return S_OK; } 

In STEP 1 of the CD3DFramework7::CreateFullscreenBuffers routine, m_rcScreenRect is filled with the rectangle defining the screen resolution information (for example, 640 × 480, 800 × 600, and so on). The m_dwRenderWidth and m_dwRenderHeight member variables are also set to the computed width and height of the screen.

In STEP 2, the code calls IDirectDraw7::SetDisplayMode, making sure to skip using the Mode X mode. The IDirectDraw7::SetDisplayMode method sets the mode of the display-device hardware. This method is defined as follows:

 HRESULT SetDisplayMode (   DWORD dwWidth,    DWORD dwHeight,    DWORD dwBPP,    DWORD dwRefreshRate,    DWORD dwFlags  ); 

ParameterDescription
dwWidth and dwHeightWidth and height of the new mode.
dwBPPBits per pixel (bpp) of the new mode.
dwRefreshRateRefresh rate of the new mode. Set this value to 0 to request the default refresh rate for the driver.
dwFlagsFlags describing additional options. Currently, the only valid flag is DDSDM_STANDARDVGAMODE, which causes the method to set Mode 13 instead of Mode X 320 × 200 × 8 mode. If you're setting another resolution, bit depth, or a Mode X mode, don't use this flag and set the parameter to 0.

If the display mode is successfully set, you next create the primary surface and back buffer.

STEP 3 sets up a DDSURFACEDESC2 structure specifying the following flags:

  • DDSD_CAPS This member states that the ddsCaps member is valid in this type.
  • DDSD_BACKBUFFERCOUNT Indicates that you want to create a back buffer.
  • DDSCAPS_PRIMARYSURFACE Specifies that the type description is for a primary surface.
  • DDSCAPS_3DDEVICE The surface can be used for 3D rendering.
  • DDSCAPS_FLIP The surface is part of a surface flipping structure.
  • DDSCAPS_COMPLEX Indicates that a complex surface is being described. A complex surface will cause more than one surface to be created, where the extra surfaces are attached to the root surface.

If you're running in stereo video mode, you also need to specify these two flags:

  • DDSCAPS_VIDEOMEMORY The surface exists in display memory.
  • DDSCAPS2_ STEREOSURFACELEFT This surface is part of a stereo flipping chain. When this flag is set during an IDirectDraw7::CreateSurface call, a pair of stereo surfaces is created for each buffer in the primary flipping chain. You must create a complex flipping chain (with back buffers). You can't create a single set of stereo surfaces. The IDirectDrawSurface7::Flip method requires back buffers, so you must create at least four surfaces. When this flag is set in a DDSURFACEDESC2 structure as the result of an IDirectDraw7::EnumDisplayModes or IDirectDraw7::GetDisplayMode call, it indicates support for stereo in that mode.

Because we've specified that we want a complex flipping surface, we need to specify how many back buffers we want. To do this, we set the dwBackBufferCount member to 1 to indicate that we want just one back buffer.

In STEP 4, we use the IDirectDraw7::CreateSurface method to create the front buffer, using the flags set in the ddsd structure, and store the new surface in the m_pddsFrontBuffer variable.

In STEP 5, we call the IDirectDraw7::GetAttachedSurface method to get the back buffer. This method acquires the attached surface that has the requested capabilities (in this case, the back buffer). This method is defined as follows:

 HRESULT GetAttachedSurface (     LPDDSCAPS2 lpDDSCaps,      LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface  ); 

ParameterDescription
lpDDSCapsAddress of a DDSCAPS2 structure that contains the hardware capabilities of the surface.
lplpDDAttachedSurfaceAddress of a variable that will contain a pointer to the retrieved surface's IDirectDrawSurface7 interface. The retrieved surface is the one that matches the description according to the lpDDSCaps parameter.

Finally, in STEP 6, you get a pointer to the second back buffer if you're running in a stereo video mode. If you want this mode, call the IDirectDraw7::GetAttachedSurface method with the second back buffer (for the left image, since we'll use the first back buffer for the right image).

At this point, we're ready to render to these surfaces in full-screen mode.

Windowed Mode Buffers

If you want the program to run in windowed mode rather than full-screen mode, you need to modify some of the settings. Here's the code to handle running in windowed mode:

 //------------------------------------------------------------------- // Name: CreateWindowedBuffers // Desc: Creates the primary surface and (optional) back buffer for  //       rendering. Windowed mode and full-screen mode are handled  //       differently. //------------------------------------------------------------------- HRESULT CD3DFramework7::CreateWindowedBuffers() {     HRESULT hr;     // STEP 1 - Windowed Mode     // Get the dimensions of the viewport and screen bounds.     GetClientRect( m_hWnd, &m_rcScreenRect );     ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left );     ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right );     m_dwRenderWidth  = m_rcScreenRect.right  - m_rcScreenRect.left;     m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top;     // STEP 2 - Windowed Mode     // Create the primary surface.     DDSURFACEDESC2 ddsd;     ZeroMemory( &ddsd, sizeof(ddsd) );     ddsd.dwSize         = sizeof(ddsd);     ddsd.dwFlags        = DDSD_CAPS;     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;     // STEP 3 - Windowed Mode     if( FAILED( hr = m_pDD->CreateSurface( &ddsd,                                             &m_pddsFrontBuffer,                                             NULL ) ) )     {         DEBUG_MSG( _T("Error: Can't create primary surface") );         if( hr != DDERR_OUTOFVIDEOMEMORY )             return D3DFWERR_NOPRIMARY;         DEBUG_MSG( _T("Error: Out of video memory") );         return DDERR_OUTOFVIDEOMEMORY;     }     // STEP 4 - Windowed Mode     // If in windowed mode, create a clipper object.     LPDIRECTDRAWCLIPPER pcClipper;     if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )     {         DEBUG_MSG( _T("Error: Couldn't create clipper") );         return D3DFWERR_NOCLIPPER;     }     // STEP 5 - Windowed Mode     // Associate the clipper with the window.     pcClipper->SetHWnd( 0, m_hWnd );     m_pddsFrontBuffer->SetClipper( pcClipper );     SAFE_RELEASE( pcClipper );     // STEP 6 - Windowed Mode     // Create a back buffer.     ddsd.dwFlags        = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;     ddsd.dwWidth        = m_dwRenderWidth;     ddsd.dwHeight       = m_dwRenderHeight;     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;     if( FAILED( hr = m_pDD->CreateSurface( &ddsd,                                             &m_pddsBackBuffer,                                             NULL ) ) )     {         DEBUG_ERR( hr, _T("Error: Couldn't create the backbuffer") );         if( hr != DDERR_OUTOFVIDEOMEMORY )             return D3DFWERR_NOBACKBUFFER;         DEBUG_MSG( _T("Error: Out of video memory") );         return DDERR_OUTOFVIDEOMEMORY;     }     ZeroMemory(&m_ddpfBackBufferPixelFormat, sizeof(DDPIXELFORMAT));     m_ddpfBackBufferPixelFormat.dwSize = sizeof(DDPIXELFORMAT);     hr = m_pddsBackBuffer->         GetPixelFormat(&m_ddpfBackBufferPixelFormat);     hr = m_pddsBackBuffer->GetSurfaceDesc( &ddsd );     return S_OK; } 

In STEP 1, we acquire the bounding rectangle of the window using the window's GetClientRect routine. This routine returns the window's bounding rectangle in the m_rcScreenRect parameter. We then use the ClientToScreen routine to convert the display coordinates of the left and right back buffers to screen coordinates. This routine replaces the client coordinates in the m_rcScreenRect structure with the equivalent screen coordinates. These newly computed screen coordinates are relative to the upper left corner of the system display. In the last two lines, the screen width and height are computed.

In STEP 2, a DDSURFACEDESC2 structure is created and the DDSCAPS_PRIMARYSURFACE flag is specified to indicate that we want to create the primary surface.

In STEP 3, we call the IDirectDraw7::CreateSurface method to create the front buffer using video memory and place it in the m_pddsFrontBuffer variable.

In STEP 4, we create a clipper object. Although a clipper isn't needed when a program is running in full-screen mode, one is required in windowed mode to handle cases in which the window is partially obscured by other windows or partially outside the display area. This clipper prevents the accidental rendering outside a window and onto other windows or the desktop.

In STEP 5, we call IDirectDrawClipper::SetHWnd to set the window handle that the clipper object will use to obtain clipping information. This method is defined as follows:

 HRESULT SetHWnd(     DWORD dwFlags,       HWND hWnd       ); 

ParameterDescription
dwFlagsThis parameter is currently not used and must be set to 0.
hWndThe window handle that obtains the clipping information.

We then call IDirectDrawSurface7::SetClipper to attach the clipper object to the surface. This method is defined as follows:

 HRESULT SetClipper (   LPDIRECTDRAWCLIPPER lpDDClipper  ); 

The IDirectDrawSurface7::SetClipper has one parameter, lpDDClipper, which is the address of the IDirectDrawClipper interface for the DirectDrawClipper object that will be attached to the DirectDrawSurface object. If this parameter is NULL, the current DirectDrawClipper object will be detached.

Finally, in STEP 6, we use IDirectDraw7::CreateSurface to create the actual back buffer. At this point, the application is ready to run in either full-screen or windowed mode.



Inside Direct3D
Inside Direct3D (Dv-Mps Inside)
ISBN: 0735606137
EAN: 2147483647
Year: 1999
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net