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;

}