The FillExecuteBuffer sample function fills the single execute buffer used in this sample with all the vertices, transformations, light and render states, and drawing primitives necessary to draw our triangle.
The method shown here is not the most efficient way of organizing the execute buffer. For best performance you should minimize state changes. In this sample we submit the execute buffer for each frame in the animation loop and no state in the buffer is modified. The only thing we modify is the world matrix (its contents—not its handle). Therefore, it would be more efficient to extract all the static state instructions into a separate execute buffer which we would issue once only at startup and, from then on, simply execute a second execute buffer with vertices and triangles.
However, because this sample is more concerned with clarity than performance, it uses only one execute buffer and resubmits it in its entirety for each frame.
static HRESULT
FillExecuteBuffer(void)
{
HRESULT hRes;
D3DEXECUTEBUFFERDESC d3dExeBufDesc;
LPD3DVERTEX lpVertex;
LPD3DINSTRUCTION lpInstruction;
LPD3DPROCESSVERTICES lpProcessVertices;
LPD3DTRIANGLE lpTriangle;
LPD3DSTATE lpState;
ASSERT(NULL != lpd3dExecuteBuffer);
ASSERT(0 != hd3dSurfaceMaterial);
ASSERT(0 != hd3dWorldMatrix);
ASSERT(0 != hd3dViewMatrix);
ASSERT(0 != hd3dProjMatrix);
// Lock the execute buffer.
ZeroMemory(&d3dExeBufDesc, sizeof(d3dExeBufDesc));
d3dExeBufDesc.dwSize = sizeof(d3dExeBufDesc);
hRes = lpd3dExecuteBuffer->lpVtbl->Lock(lpd3dExecuteBuffer,
&d3dExeBufDesc);
if (FAILED(hRes))
return hRes;
// For purposes of illustration, we fill the execute buffer by
// casting a pointer to the execute buffer to the appropriate data
// structures.
lpVertex = (LPD3DVERTEX)d3dExeBufDesc.lpData;
// First vertex.
lpVertex->dvX = D3DVAL( 0.0); // Position in model coordinates
lpVertex->dvY = D3DVAL( 1.0);
lpVertex->dvZ = D3DVAL( 0.0);
lpVertex->dvNX = D3DVAL( 0.0); // Normalized illumination normal
lpVertex->dvNY = D3DVAL( 0.0);
lpVertex->dvNZ = D3DVAL(-1.0);
lpVertex->dvTU = D3DVAL( 0.0); // Texture coordinates (not used)
lpVertex->dvTV = D3DVAL( 1.0);
lpVertex++;
// Second vertex.
lpVertex->dvX = D3DVAL( 1.0); // Position in model coordinates
lpVertex->dvY = D3DVAL(-1.0);
lpVertex->dvZ = D3DVAL( 0.0);
lpVertex->dvNX = D3DVAL( 0.0); // Normalized illumination normal
lpVertex->dvNY = D3DVAL( 0.0);
lpVertex->dvNZ = D3DVAL(-1.0);
lpVertex->dvTU = D3DVAL( 1.0); // Texture coordinates (not used)
lpVertex->dvTV = D3DVAL( 1.0);
lpVertex++;
// Third vertex.
lpVertex->dvX = D3DVAL(-1.0); // Position in model coordinates
lpVertex->dvY = D3DVAL(-1.0);
lpVertex->dvZ = D3DVAL( 0.0);
lpVertex->dvNX = D3DVAL( 0.0); // Normalized illumination normal
lpVertex->dvNY = D3DVAL( 0.0);
lpVertex->dvNZ = D3DVAL(-1.0);
lpVertex->dvTU = D3DVAL( 1.0); // Texture coordinates (not used)
lpVertex->dvTV = D3DVAL( 0.0);
lpVertex++;
// Transform state - world, view and projection.
lpInstruction = (LPD3DINSTRUCTION)lpVertex;
lpInstruction->bOpcode = D3DOP_STATETRANSFORM;
lpInstruction->bSize = sizeof(D3DSTATE);
lpInstruction->wCount = 3U;
lpInstruction++;
lpState = (LPD3DSTATE)lpInstruction;
lpState->dtstTransformStateType = D3DTRANSFORMSTATE_WORLD;
lpState->dwArg[0] = hd3dWorldMatrix;
lpState++;
lpState->dtstTransformStateType = D3DTRANSFORMSTATE_VIEW;
lpState->dwArg[0] = hd3dViewMatrix;
lpState++;
lpState->dtstTransformStateType = D3DTRANSFORMSTATE_PROJECTION;
lpState->dwArg[0] = hd3dProjMatrix;
lpState++;
// Lighting state.
lpInstruction = (LPD3DINSTRUCTION)lpState;
lpInstruction->bOpcode = D3DOP_STATELIGHT;
lpInstruction->bSize = sizeof(D3DSTATE);
lpInstruction->wCount = 2U;
lpInstruction++;
lpState = (LPD3DSTATE)lpInstruction;
lpState->dlstLightStateType = D3DLIGHTSTATE_MATERIAL;
lpState->dwArg[0] = hd3dSurfaceMaterial;
lpState++;
lpState->dlstLightStateType = D3DLIGHTSTATE_AMBIENT;
lpState->dwArg[0] = RGBA_MAKE(128, 128, 128, 128);
lpState++;
// Render state.
lpInstruction = (LPD3DINSTRUCTION)lpState;
lpInstruction->bOpcode = D3DOP_STATERENDER;
lpInstruction->bSize = sizeof(D3DSTATE);
lpInstruction->wCount = 3U;
lpInstruction++;
lpState = (LPD3DSTATE)lpInstruction;
lpState->drstRenderStateType = D3DRENDERSTATE_FILLMODE;
lpState->dwArg[0] = D3DFILL_SOLID;
lpState++;
lpState->drstRenderStateType = D3DRENDERSTATE_SHADEMODE;
lpState->dwArg[0] = D3DSHADE_GOURAUD;
lpState++;
lpState->drstRenderStateType = D3DRENDERSTATE_DITHERENABLE;
lpState->dwArg[0] = TRUE;
lpState++;
// The D3DOP_PROCESSVERTICES instruction tells the driver what to
// do with the vertices in the buffer. In this sample we want
// Direct3D to perform the entire pipeline on our behalf, so
// the instruction is D3DPROCESSVERTICES_TRANSFORMLIGHT.
lpInstruction = (LPD3DINSTRUCTION)lpState;
lpInstruction->bOpcode = D3DOP_PROCESSVERTICES;
lpInstruction->bSize = sizeof(D3DPROCESSVERTICES);
lpInstruction->wCount = 1U;
lpInstruction++;
lpProcessVertices = (LPD3DPROCESSVERTICES)lpInstruction;
lpProcessVertices->dwFlags = D3DPROCESSVERTICES_TRANSFORMLIGHT;
lpProcessVertices->wStart = 0U; // First source vertex
lpProcessVertices->wDest = 0U;
lpProcessVertices->dwCount = NUM_VERTICES; // Number of vertices
lpProcessVertices->dwReserved = 0;
lpProcessVertices++;
// Draw the triangle.
lpInstruction = (LPD3DINSTRUCTION)lpProcessVertices;
lpInstruction->bOpcode = D3DOP_TRIANGLE;
lpInstruction->bSize = sizeof(D3DTRIANGLE);
lpInstruction->wCount = 1U;
lpInstruction++;
lpTriangle = (LPD3DTRIANGLE)lpInstruction;
lpTriangle->wV1 = 0U;
lpTriangle->wV2 = 1U;
lpTriangle->wV3 = 2U;
lpTriangle->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
lpTriangle++;
// Stop execution of the buffer.
lpInstruction = (LPD3DINSTRUCTION)lpTriangle;
lpInstruction->bOpcode = D3DOP_EXIT;
lpInstruction->bSize = 0;
lpInstruction->wCount = 0U;
// Unlock the execute buffer.
lpd3dExecuteBuffer->lpVtbl->Unlock(lpd3dExecuteBuffer);
return DD_OK;
}