Step 4: Initializing the Viewport

Each of the code samples that uses D3dmain.cpp must implement a version of the InitView function to set up the viewport and create the sample's execute buffers. This section discusses the implementation of InitView found in the Oct1.c sample.

First, InitView creates and initializes some materials, material handles, and texture handles. It uses the IDirect3D::CreateMaterial method to create a material, the IDirect3DMaterial::SetMaterial method to set the material data that InitView has just initialized, and the IDirect3DMaterial::GetHandle and IDirect3DViewport::SetBackground methods to set this material as the background for the viewport.

Now the InitView function sets the view, world, and projection matrices for the viewport. InitView uses the MAKE_MATRIX macro to create and set matrices. MAKE_MATRIX is defined in D3dmacs.h as follows:

#define MAKE_MATRIX(lpDev, handle, data) \

if (lpDev->lpVtbl->CreateMatrix(lpDev, &handle) != D3D_OK) \

return FALSE; \

if (lpDev->lpVtbl->SetMatrix(lpDev, handle, &data) != D3D_OK) \

return FALSE

As you can see, MAKE_MATRIX is simply a convenient way of calling the IDirect3DDevice::CreateMatrix and IDirect3DDevice::SetMatrix methods in a single step.

Now InitView creates and sets up an execute buffer. After initializing the members of a D3DEXECUTEBUFFERDESC structure, the code calls the IDirect3DDevice::CreateExecuteBuffer method to create the execute buffer and IDirect3DExecuteBuffer::Lock to lock it so that it can be filled.

InitView fills the execute buffer by using the OP_STATE_TRANSFORM and STATE_DATA macros from D3dmacs.h. These macros are described in Step 5: Setting the Immediate-Mode Render State, along with more information about working with execute buffers.

When the execute buffer has been set up, InitView calls the IDirect3DExecuteBuffer::Unlock method to unlock it, the IDirect3DExecuteBuffer::SetExecuteData method to set the data into the buffer, and then the IDirect3DDevice::BeginScene, IDirect3DDevice::Execute, and IDirect3DDevice::EndScene methods to execute the execute buffer. Because the function has no further use for this execute buffer, it then calls IDirect3DExecuteBuffer::Release.

The InitView function now sets up two more materials by using the same procedure it used to set the materials earlier: it uses the IDirect3D::CreateMaterial method to create a material, the IDirect3DMaterial::SetMaterial method to set the material data (after filling the members of the D3DMATERIAL structure), and the IDirect3DMaterial::GetHandle method to retrieve a handle to the material. These handles are used later with the D3DLIGHTSTATE_MATERIAL member of the D3DLIGHTSTATETYPE enumerated type to light the new materials.

Now InitView sets up the vertices. The code uses the D3DVALP macro to convert floating-point numbers into the D3DVALUE members of the D3DVERTEX structure. It also uses the D3DRMVectorNormalize function to normalize the x-coordinate of the normal vector for each of the vertices it sets up.

When the vertices have been set up, InitView creates another execute buffer, copies the vertices to the buffer, and sets the execute data. It does not execute the execute buffer, however; this time, executing the execute buffer occurs in the rendering loop.

Finally, InitView sets up the lights for Oct1.c. After initializing the members of a D3DLIGHT structure, it calls the IDirect3D::CreateLight, IDirect3DLight::SetLight, and IDirect3DViewport::AddLight methods to add the light to the viewport.