Creating the Primary Surface and Clipper Object
The CreatePrimary function creates the primary surface (representing the desktop) and creates and attaches a clipper object. If necessary, this function also creates a palette.
static HRESULT
CreatePrimary(HWND hwnd)
{
HRESULT hRes;
DDSURFACEDESC ddsd;
LPDIRECTDRAWCLIPPER lpddClipper;
HDC hdc;
int i;
PALETTEENTRY peColorTable[256];
ASSERT(NULL != hwnd);
ASSERT(NULL != lpdd);
ASSERT(NULL == lpddPrimary);
ASSERT(NULL == lpddPalette);
// Create the primary surface.
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &lpddPrimary, NULL);
if (FAILED(hRes))
return hRes;
// Create the clipper. We bind the application's window to the
// clipper and attach it to the primary. This ensures that when we
// blit from the rendering surface to the primary we don't write
// outside the visible region of the window.
hRes = DirectDrawCreateClipper(0, &lpddClipper, NULL);
if (FAILED(hRes))
return hRes;
hRes = lpddClipper->lpVtbl->SetHWnd(lpddClipper, 0, hwnd);
if (FAILED(hRes))
{
lpddClipper->lpVtbl->Release(lpddClipper);
return hRes;
}
hRes = lpddPrimary->lpVtbl->SetClipper(lpddPrimary, lpddClipper);
if (FAILED(hRes))
{
lpddClipper->lpVtbl->Release(lpddClipper);
return hRes;
}
// We release the clipper interface after attaching it to the
// surface because we don't need to use it again. The surface
// holds a reference to the clipper when it has been attached.
// The clipper will therefore be released automatically when the
// surface is released.
lpddClipper->lpVtbl->Release(lpddClipper);
// If the primary surface is palettized, the device will be, too.
// (The device surface must have the same pixel format as the
// current primary surface if we want to double buffer with
// DirectDraw.) Therefore, if the primary surface is palettized we
// need to create a palette and attach it to the primary surface
// (and to the device surface when we create it).
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
hRes = lpddPrimary->lpVtbl->GetSurfaceDesc(lpddPrimary, &ddsd);
if (FAILED(hRes))
return hRes;
if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
{
// Initializing the palette correctly is essential. Since we are
// running in a window, we must not change the top ten and bottom
// ten static colors. Therefore, we copy them from the system
// palette and mark them as read only (D3DPAL_READONLY). The middle
// 236 entries are free for use by Direct3D so we mark them free
// (D3DPAL_FREE).
// NOTE: In order that the palette entries are correctly
// allocated it is essential that the free entries are
// also marked reserved to GDI (PC_RESERVED).
// NOTE: We don't need to specify the palette caps flag
// DDPCAPS_INITIALIZE. This flag is obsolete. CreatePalette
// must be given a valid palette-entry array and always
// initializes from it.
hdc = GetDC(NULL);
GetSystemPaletteEntries(hdc, 0, 256, peColorTable);
ReleaseDC(NULL, hdc);
for (i = 0; i < 10; i++)
peColorTable[i].peFlags = D3DPAL_READONLY;
for (i = 10; i < 246; i++)
peColorTable[i].peFlags = D3DPAL_FREE | PC_RESERVED;
for (i = 246; i < 256; i++)
peColorTable[i].peFlags = D3DPAL_READONLY;
hRes = lpdd->lpVtbl->CreatePalette(lpdd,
DDPCAPS_8BIT, peColorTable, &lpddPalette, NULL);
if (FAILED(hRes))
return hRes;
hRes = lpddPrimary->lpVtbl->SetPalette(lpddPrimary,
lpddPalette);
return hRes;
}
return DD_OK;
}