Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
96 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Preface
 Compiling
 the Source

 The Application
 Class

 Initialization
 Rendering
 Cleaning Up

 Printable version

 


  The Series

 The Basics
 First Steps to
 Animation

 Multitexturing
 Building Worlds
 With X Files


 

FrameMove()

The next method the framework calls is FrameMove():

HRESULT CMyD3DApplication::FrameMove( FLOAT fTimeKey ) { return S_OK; }

Because we're not animating a scene, there doesn't have to be any code inside of this method.

Render()

Now one of the key methods is called:

HRESULT CMyD3DApplication::Render() { // Begin the scene if( SUCCEEDED( m_pd3dDevice->BeginScene() ) ) { // Draw the background m_pd3dDevice->SetTexture( 0, D3DTextr_GetSurface("lake.bmp") ); m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX, m_Background, 4, 0 ); // End the scene. m_pd3dDevice->EndScene(); } return S_OK; }

This function calls the BeginScene()/EndScene() pair. The first function is called before performing rendering, the second after that. BeginScene causes the system to check its internal data structures, the availability and validity of rendering surfaces, and sets an internal flag to signal that a scene is in progress. Attempts to call rendering methods when a scene is not in progress fail, returning D3DERR_SCENE_NOT_IN_SCENE. Once your rendering is complete, you need to call EndScene(). It clears the internal flag that indicates that a scene is in progress, flushes the cached data and makes sure the rendering surfaces are OK.

If you like to use GDI functions, make sure that all GDI calls are made outside of the scene functions.

The IDirect3DDevice7::SetTexture() method assigns a texture to a given stage for a device. The first parameter must be a number in the range of 0-7 inclusive. Pass the texture interface pointer as the second parameter. This method method increments the reference count of the texture surface being assigned. When the texture is no longer needed, you should set the texture at the appropriate stage to NULL. If you fail to do this, the surface will not be released, resulting in a memory leak. Since Version 6, Direct3D maintains a list of up to eight current textures. So Direct3D supports the blending of up to eight textures onto a primitive at once. It blends these textures onto all of the primitives it renders. Only textures created as texture interface pointers can be used in the set of current textures.

Note: Textures under the IDirect3D2 interface were manipulated using texture handles. With the IDirect3D7 interface (and the legacy IDirect3D3 interface), you create and use textures through interface pointers to the texture surfaces. You obtain a texture surface interface pointer when you create the texture surface by calling the IDirectDraw7::CreateSurface() which is called in the framework by D3Dtextr_CreateTextureFromFile() method.

When your application selects a texture as the current texture, it instructs the Direct3D device to apply the texture to all primitives that are rendered from that time until the current texture is changed again. If each primitive in a 3-D scene has its own texture, the texture must be set before each primitive is rendered.

Software devices do not support assigning a texture to more than one texture stage at a time.

The IDirect3DDevice7::DrawPrimitive() method renders the specified array of vertices as a sequence of geometric primitives of the specified type:

HRESULT DrawPrimitive ( D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPVOID lpvVertices, DWORD dwVertexCount, DWORD dwFlags );

The first parameter is dptPrimitiveType. These are the types of primitive which could be rendered by this command:

typedef enum _D3DPRIMITIVETYPE { D3DPT_POINTLIST = 1, D3DPT_LINELIST = 2, D3DPT_LINESTRIP = 3, D3DPT_TRIANGLELIST = 4, D3DPT_TRIANGLESTRIP = 5, D3DPT_TRIANGLEFAN = 6, D3DPT_FORCE_DWORD = 0x7fffffff, } D3DPRIMITIVETYPE;

You can see the different primitives as pictures in the DirectX SDK. The second parameter of DrawPrimitive(), D3DFVF_TLVERTEX, describes the vertex format used for this set of primitives. The d3dtypes.h header file declares these flags to explicitly describe a vertex format and provides helper macros that act as common combinations of such flags. Each of the rendering methods of IDirect3Ddevice7 accepts a combination of these flags, and uses them to determine how to render primitives. Basically, these flags tell the system which vertex components—position, normal, colors, and the number of texture coordinates–your application uses and, indirectly, which parts of the rendering pipeline you want Direct3D to apply to them. In addition, the presence or absence of a particular vertex format flag communicates to the system which vertex component fields are present in memory, and which you've omitted. By using only the needed vertex components, your application can conserve memory and minimize the processing bandwidth required to render models. The d3dtypes.h header file defines the following helper macro that you can use to describe the vertex format declared by the D3DTLVERTEX structure:

#define D3DFVF_TLVERTEX ( D3DFVF_XYZRHW | \ D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1 )

D3DFVF_XYZRHW tells your system that your application is using transformed and lit vertices. Therefore, Direct3D doesn't transform your vertices with the world, view, or projection matrices, nor does it perform any lighting calculations. It passes them directly to the driver to be rasterized. D3DFVF_DIFFUSE indicates, that the Vertex format includes a diffuse color component. D3DFVF_SPECULAR indicates, that the vertex format includes a specular color component. D3DFVF_TEX1 shows us the number of texture coordinate sets for this vertex.

// The vertex format description for this vertex // would be: (D3DFVF_XYZRHW | // D3DFVF_DIFFUSE |D3DFVF_SPECULAR |D3DFVF_TEX1) typedef struct _D3DTLVERTEX { D3DVALUE sx, sy, sz; /* Screen coordinates */ D3DVALUE rhw; /* Reciprocal of homogeneous w */ D3DCOLOR color; /* Vertex color */ D3DCOLOR specular; /* Specular component of vertex */ float tu1,tv1; // texture coordinates } D3DTLVERTEX, *LPD3DTLVERTEX;

I've described an overloaded version in the OneTimeSceneInit() section above.

Prior to DirectX 6.0, applications were required to use one of three vertex types - D3DVERTEX, D3DLVERTEX, and D3DTLVERTEX - depending on which parts of the Direct3D geometry pipeline were being used. With the introduction of more flexible vertex formats in DirectX 6.0, you can declare vertices in many more ways than before, but you can still use the predefined structures to describe untransformed and unlit vertices, untransformed but lit vertices, and vertices that are both transformed and lit.

With the new flexible vertex format, vertices may contain both vertex color and vertex normal information. By default, Direct3D uses this information when it calculates lighting.

The third parameter of DrawPrimitive() is a pointer to the array of vertices to be used in the primitive sequence. After that the number of vertices in the array can be provided.

Indexed and nonindexed primitives: There are two ways of grouping the vertices that define a primitive: using nonidexed primitives and using indexed primitves. To create a nonindexed primitve, you fill an array with an ordered list of vertices. Ordered means that the order of the vertices in the array indicates how to build the triangles. The first triangle consists of the first three vertices, the second triangle consists of the next three vertices and so on. If you have two triangles that are connected, you'll have to specify the same vertices multiple times. To create an indexed primitive, you fill an array with an unordered list of vertices and specify the order with a second array (index array). This means that vertices can be shared by multiple triangles, simply by having multiple entries in the index array refer to the same vertex. Most 3D models share a number of vertices. Therefore, you can save bandwith and CPU time sharing these vertices among multiple triangles. Indexed primitves are called f.e. by


// Display the object 
m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, D3DFVF_VERTEX,
                                    m_pCubeVertices, NUM_CUBE_VERTICES, 
                                    m_pCubeIndices, NUM_CUBE_INDICES, 0 );

The maximum number of vertices allowed is D3DMAXNUMVERTICES (0xFFFF). The last parameter is a flag, which has to be zero to render the primitive without waiting, or D3DDP_WAIT, which causes the method to wait until the polygons have been rendered before it returns, instead of returning as soon as the polygons have been sent to the card. (On scene-capture cards, the method returns as soon as the card responds.) This flag is typically used for debugging. Applications should not attempt to use this flag to ensure that a scene is up to date before continuing.



Next : Cleaning Up