After you create the surfaces your application will need to render and display a scene, you can begin initializing Direct3D objects by retrieving a pointer to the IDirect3D3 interface for the DirectDraw object, which is used to create all the objects you'll need to render a scene. Note that this interface is exposed by the DirectDraw object, and represents a separate set of features, not a separate object. You retrieve the IDirect3D3 interface by calling the IUnknown::QueryInterface method of the DirectDraw object. The following code from Triangle performs this task:
// Query DirectDraw for access to Direct3D
g_pDD4->QueryInterface( IID_IDirect3D3, (VOID**)&g_pD3D );
if( FAILED( hr) )
return hr;
After retrieving a pointer to the IDirect3D3 interface, you can create a rendering device by calling the IDirect3D3::CreateDevice method. The CreateDevice method accepts the globally unique identifier (GUID) of the desired device, the address of the IDirectDrawSurface4 interface for the surface that the device will render to, and the address of a variable that the method will set to an IDirect3DDevice3 interface pointer if the device object is created successfully. Although the tutorial uses hard-coded GUID values, a real application should enumerate devices to get a GUID. For information about device enumeration, see Enumerating Direct3D Devices.
(The Triangle sample checks the display mode prior to creating the device. If the display is set to a palettized mode, it exits. Attempting to create a device for a palettized surface that doesn't have an associated palette will cause the CreateDevice method to fail. This is done for simplicity. A real-world application should create a render target surface and attach a palette, or require that the user set their display mode to 16-bit color or higher.)
The following code, taken from Triangle, checks the display mode, and creates a rendering device:
// Check the display mode, and
ddsd.dwSize = sizeof(DDSURFACEDESC2);
g_pDD4->GetDisplayMode( &ddsd );
if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 )
return DDERR_INVALIDMODE;
// The GUID here is hardcoded. In a real-world application
// this should be retrieved by enumerating devices.
hr = g_pD3D->CreateDevice( IID_IDirect3DHALDevice,
g_pddsBackBuffer,
&g_pd3dDevice, NULL );
if( FAILED( hr ) )
{
// If the hardware GUID doesn't work, try a software device.
hr = g_pD3D->CreateDevice(IID_IDirect3DRGBDevice,
g_pddsBackBuffer,
&g_pd3dDevice, NULL );
if( FAILED( hr ) )
return hr;
}
The IDirect3D3::CreateDevice method can fail for many reasons. The most likely cause is when the primary display device doesn't support 3-D features. Another possibility is if the display hardware cannot render in the current display mode. These possibilities should be checked during device enumeration. To keep the code simple, Triangle attempts to create a software rendering device if the hardware device cannot be created.
Note Even though the CreateDevice method accepts a pointer to a DirectDrawSurface object, a rendering device is not a surface. Rather, it is a discrete COM object that uses a surface to contain graphics for a rendered scene.
After the device is created, you can create a viewport object and assign it to the device, as described in Step 2.4: Prepare the Viewport.