This section discusses the DrawPrimitive methods, an innovation in DirectX 5 that both simplifies Immediate Mode programming and adds new flexibility. Information is divided into the following groups.
·API Extensions for DrawPrimitive
·Architecture of DrawPrimitive Capabilities
·Using Both DrawPrimitive and Execute Buffers
·A Simple DrawPrimitive Example
API Extensions for DrawPrimitive
There is a way to tap into the power of Immediate Mode programming without explicitly using execute buffers. The heart of this system is the IDirect3DDevice2::DrawPrimitive method (and its companion, IDirect3DDevice2::DrawIndexedPrimitive).
The IDirect3D and IDirect3DDevice interfaces have been extended to support the ability to draw primitives. These extended versions are called the IDirect3D2 and IDirect3DDevice2 interfaces.
To use IDirect3DDevice2, retrieve a pointer to the interface by calling the IDirect3D2::CreateDevice method. If you need to use some of the methods in IDirect3DDevice that are not supported in IDirect3DDevice2, you can call IDirect3DDevice2::QueryInterface to retrieve a pointer to an IDirect3DDevice interface.
The IDirect3DViewport interface has also been extended. The new interface, IDirect3DViewport2, introduces a closer correspondence between the dimensions of the clipping volume and the viewport than was true for the IDirect3DViewport interface.
Architecture of DrawPrimitive Capabilities
The methods provided by the IDirect3D2 and IDirect3DDevice2 interfaces enable a user to avoid the execute buffer model. Avoiding the execute buffer model can be useful for two reasons:
1A new Direct3D developer wants to get up and running quickly.
2Certain classes of applications (for example, BSP-style games with graphics engines that produce transformed, lit and clipped triangles) do not lend themselves easily to porting to the execute-buffer model. The execute-buffer model does not inherently impose restrictions, but it can be difficult to use.
The IDirect3DDevice2 interface can be created with the IDirect3D2::CreateDevice method. This method takes the DirectDraw surface to render into as a parameter, enabling applications to avoid querying the device interface off of the DirectDraw surface.
A "primitive" in the DrawPrimitive API can be one of the following constructs:
·Point list
·Line list
·Line strip
·Triangle list
·Triangle strip
·Triangle fan
The IDirect3DDevice2::DrawPrimitive and IDirect3DDevice2::DrawIndexedPrimitive methods draw a primitive in a single call. When possible, these functions call into the driver directly to draw the primitive.
Alternatively, the application can specify the vertices one at a time. To draw a primitive by specifying the vertices individually, the application calls IDirect3DDevice2::Begin and specifies the primitive and vertex type, IDirect3DDevice2::Vertex to specify each vertex, and IDirect3DDevice2::End to finish drawing the primitive. Similarly, to draw an indexed primitive by specifying the indices individually, the application calls IDirect3DDevice2::BeginIndexed and specifies the primitive and vertex type, IDirect3DDevice2::Index to specify each index, and IDirect3DDevice2::End to finish drawing the primitive.
IDirect3DDevice2::Vertex is the only valid method between calls to IDirect3DDevice2::Begin and IDirect3DDevice2::End.
IDirect3DDevice2::Index is the only valid method between calls to IDirect3DDevice2::BeginIndexed and IDirect3DDevice2::End.
Note The DrawPrimitive methods are designed to enable asynchronous operation. Unless you specify D3DDP_WAIT when you call IDirect3DDevice2::DrawPrimitive or IDirect3DDevice2::DrawIndexedPrimitive, the method will fail if the 3-D hardware cannot currently accept the command, returning DDERR_WASSTILLDRAWING. This behavior is modeled after the DirectDraw IDirectDrawSurface3::Blt operation, where DDBLT_WAIT specifies that the call should return after the command has actually been queued up for execution by the accelerator.
Using Both DrawPrimitive and Execute Buffers
DirectX 5 applications can use both styles of programming in the same application by using the two interfaces to the device object. The application should retrieve an IDirect3D2 interface by calling the QueryInterface method on the DirectDraw object and then use the IDirect3D2::CreateDevice method to create a device object. The application should keep the IDirect3DDevice2 interface thus obtained and also call IDirect3DDevice2::QueryInterface to retrieve an IDirect3DDevice interface.
It is recommended that you use IDirect3DMaterial2 and IDirect3DTexture2 interfaces (created using IDirect3D2). You can get handles from these objects using the IDirect3DDevice2 interface as an argument to the IDirect3DMaterial2::GetHandle and IDirect3DTexture2::GetHandle methods. You can use these handles both in IDirect3DDevice2 methods and in execute buffers rendered through IDirect3DDevice. This is because IDirect3DDevice2 and IDirect3DDevice are two interfaces to the same underlying object.
Similarly, you can create viewport objects using IDirect3D2 and use the new IDirect3DViewport2 interface. These viewport objects can be added to the device using IDirect3DDevice2::AddViewport. Because the IDirect3DViewport2 interface inherits from IDirect3DViewport, you can pass it to IDirect3DDevice methods that expect the IDirect3DViewport interface.
A Simple DrawPrimitive Example
For a complete working example of an application that uses the DrawPrimitive methods, see the files in the Flip3D directory in the samples that ship with the DirectX 5 Programmer's Reference.
/*
* Constants
*/
#define NUM_VERTICES 3
#define NUM_TRIANGLES 1
D3DTLVERTEX src_v[NUM_VERTICES];
WORD src_t[NUM_TRIANGLES * 3];
DWORD hTex;
D3DSTATEVALUE hMat;
/*
* A routine that assumes that the above data is initialized
*/
BOOL RenderScene(LPDIRECT3DDEVICE2 lpDev, LPDIRECT3DVIEWPORT lpView,
LPD3DRECT lpExtent)
{
if (IDirect3DDevice2_BeginScene(lpDev) != D3D_OK)
return FALSE;
if (IDirect3DDevice2_SetLightState(lpDev, D3DLIGHTSTATE_MATERIAL,
hMat) != D3D_OK)
return FALSE;
if (IDirect3DDevice2_SetRenderState(lpDev,
D3DRENDERSTATE_TEXTUREHANDLE, hTex) != D3D_OK)
return FALSE;
if (IDirect3DDevice2_DrawIndexedPrimitive(lpDev,
DPT_TRIANGLELIST, DVT_TLVERTEX,
(LPVOID)src_v, NUM_VERTICES,(LPWORD)src_t, NUM_TRIANGLES*3)
!= D3D_OK)
return FALSE;
if (IDirect3DDevice2_EndScene(lpDev) != D3D_OK)
return FALSE;
return TRUE;
}