The D3DPRIMITIVETYPE enumerated type used by the DrawPrimitive methods lists all the primitives that these methods support. Here's the definition for this type:
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; |
These are the members of the D3DPRIMITIVETYPE enumerated type:
The following sections cover each of these primitive types, which you can use to create the 3D content for your applications.
You can use the first primitive type, the point list, to define a collection of vertices that are rendered as isolated points. You can use a point list in a 3D scene to represent objects such as dotted lines.
To create a point list, you need to fill an array of vertices. The code that follows shows an example of how to perform this task. Although I show a simple six-element list, you could use a point list to create a star field if you wanted; of course, your list would need many more points. I tend to create star fields using a texture-wrapped sphere surrounding the 3D world because it allows me to create a number of effects using texture animation.
const DWORD TOTAL_VERTICES = 6; D3DVERTEX lpVertices[TOTAL_VERTICES]; D3DVECTOR v1(-1, 4, 0); D3DVECTOR v2( 2,-1, 0); D3DVECTOR v3( 1, 3, 0); D3DVECTOR v4(-3,-2, 0); D3DVECTOR v5( 3, 2, 0); D3DVECTOR v6( 2, 1, 0); D3DVECTOR vNormal(0, 0, -1); lpVertices[0] = D3DVERTEX(v1, vNormal, 0, 0); lpVertices[1] = D3DVERTEX(v2, vNormal, 0, 0); lpVertices[2] = D3DVERTEX(v3, vNormal, 0, 0); lpVertices[3] = D3DVERTEX(v4, vNormal, 0, 0); lpVertices[4] = D3DVERTEX(v5, vNormal, 0, 0); lpVertices[5] = D3DVERTEX(v6, vNormal, 0, 0); |
Once you've defined the point list, you can render it by using the IDirect3DDevice7::DrawPrimitive method discussed earlier. The code for rendering the point list follows. As you also learned earlier in the chapter, any call you make to IDirect3DDevice7::DrawPrimitive must occur between calls to IDirect3DDevice7::BeginScene and IDirect3DDevice7::EndScene.
if (FAILED(lpDirect3DDevice7->BeginScene())) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->DrawPrimitive(D3DPT_POINTLIST, D3DFVF_VERTEX, lpVertices, TOTAL_VERTICES, 0))) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->EndScene())) { // Handle any error here. } |
You can apply materials and textures to a point list, but one tiny pixel on the screen probably won't represent a texture or a material very well. Also, be aware that these points are always 1 pixel in diameter regardless of their distance from the camera. To produce bigger points, you need to use small triangles to represent them. When the rendering is complete, you'll see a scene similar to that shown in Figure 6-2.
Figure 6-2 A rendered point list
You can use the second primitive type, the line list, to define a group of straight-line segments. You can use this type to define groups of simple single-line objects.
To create a line list, simply fill an array of vertices as shown in the next code snippet. Always remember that the amount of vertices defined in a line list must be an even number that is greater than or equal to 2. This example shows the code needed to define three lines:
const DWORD TOTAL_VERTICES = 6; D3DVERTEX lpVertices[TOTAL_VERTICES]; D3DVECTOR v1(-10, 10, 0); D3DVECTOR v2( -8, -5, 0); D3DVECTOR v3( -4, 3, 0); D3DVECTOR v4( 1, -6, 0); D3DVECTOR v5( 2, -1, 0); D3DVECTOR v6( 12, 9, 0); D3DVECTOR vNormal(0, 0, -1); lpVertices[0] = D3DVERTEX(v1, vNormal, 0, 0); lpVertices[1] = D3DVERTEX(v2, vNormal, 0, 0); lpVertices[2] = D3DVERTEX(v3, vNormal, 0, 0); lpVertices[3] = D3DVERTEX(v4, vNormal, 0, 0); lpVertices[4] = D3DVERTEX(v5, vNormal, 0, 0); lpVertices[5] = D3DVERTEX(v6, vNormal, 0, 0); |
Once you've defined the line list, you can render it by using the IDirect3DDevice7::DrawPrimitive method as you did with the point list. The code for rendering the line list follows. When the rendering is complete, you'll see a scene similar to that shown in Figure 6-3.
if (FAILED(lpDirect3DDevice7->BeginScene())) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->DrawPrimitive(D3DPT_LINELIST, D3DFVF_VERTEX, lpVertices, TOTAL_VERTICES, 0))) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->EndScene())) { // Handle any error here. } |
Figure 6-3 A rendered line list
As with point lists, you can apply materials and textures to line lists. And like points, which always remain 1 pixel in size, lines are always 1 pixel wide. If you need to render wider lines or if you want the width to vary according to a line's distance from the camera, you should instead use pairs of thin triangles to represent the lines.
You can use the third primitive type, the line strip, to describe a series of connected line segments. You can use line strips to create polygons that are open—in other words, polygons whose last vertex isn't connected to the first vertex with a line segment.
You can create a line strip by filling an array of vertices the same way you did for point and line lists. This next code segment presents an example of how to fill this list:
const DWORD TOTAL_VERTICES = 5; D3DVERTEX lpVertices[TOTAL_VERTICES]; D3DVECTOR v1(-8, -8, 0); D3DVECTOR v2(-3, -9, 0); D3DVECTOR v3(-1, 0, 0); D3DVECTOR v4( 9, -2, 0); D3DVECTOR v5( 7, -6, 0); D3DVECTOR vNormal(0, 0, -1); lpVertices[0] = D3DVERTEX(v1, vNormal, 0, 0); lpVertices[1] = D3DVERTEX(v2, vNormal, 0, 0); lpVertices[2] = D3DVERTEX(v3, vNormal, 0, 0); lpVertices[3] = D3DVERTEX(v4, vNormal, 0, 0); lpVertices[4] = D3DVERTEX(v5, vNormal, 0, 0); |
Once you've defined the line strip, you can render it by using the IDirect3DDevice7::DrawPrimitive method as you did for the point and line lists. The code to render the line strip follows, and Figure 6-4 shows the line strip produced by this code.
if (FAILED(lpDirect3DDevice7->BeginScene())) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->DrawPrimitive(D3DPT_LINESTRIP, D3DFVF_VERTEX, lpVertices, TOTAL_VERTICES, 0))) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->EndScene())) { // Handle any error here. } |
Figure 6-4 A rendered line strip
You can use the fourth primitive type, the triangle list, to create lists of isolated triangles. Always remember that the number of vertices defined in a triangle list must be divisible by 3. You can use these lists to create objects that are made up of unconnected pieces. A code example that defines a list of two triangles follows:
const DWORD TOTAL_VERTICES = 6; D3DVERTEX lpVertices[TOTAL_VERTICES]; D3DVECTOR v1(-10, -5, 0); D3DVECTOR v2( -5, 5, 0); D3DVECTOR v3( 0, -5, 0); D3DVECTOR v4( 1, -5, 0); D3DVECTOR v5( 6, 5, 0); D3DVECTOR v6( 11, -5, 0); D3DVECTOR vNormal(0, 0, -1); lpVertices[0] = D3DVERTEX(v1, vNormal, 0, 0); lpVertices[1] = D3DVERTEX(v2, vNormal, 0, 0); lpVertices[2] = D3DVERTEX(v3, vNormal, 0, 0); lpVertices[3] = D3DVERTEX(v4, vNormal, 0, 0); lpVertices[4] = D3DVERTEX(v5, vNormal, 0, 0); lpVertices[5] = D3DVERTEX(v6, vNormal, 0, 0); |
As with the other primitive types, you can render the triangle list by using the IDirect3DDevice7::DrawPrimitive method. The following code shows an example of how to render a triangle list. Figure 6-5 shows the result.
if (FAILED(lpDirect3DDevice7->BeginScene())) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX, lpVertices, TOTAL_VERTICES, 0))) { // Handle error here. } if (FAILED(lpDirect3DDevice7->EndScene())) { // Handle any error here. } |
Figure 6-5 A rendered triangle list
You can use the fifth primitive type, the triangle strip, to create a series of connected triangles. When you use connected triangles, the code will have to specify shared vertices only once. For example, you need only six vertices to define the triangle strip illustrated in Figure 6-6, which is composed of four triangles.
Figure 6-6 A triangle strip
As Figure 6-6 shows, the first three triangles share v3, two of the triangles share v4, and so on. By default, Direct3D culls triangles that are specified in counterclockwise order. Therefore, when rendering triangle strips, Direct3D reads the vertices out of order for every even triangle in the strip. To render the triangle strip in Figure 6-6, Direct3D reads vertices from the vertex list as follows: v1, v2, and v3 for the first triangle; v2, v4, and v3 for the second triangle; v3, v4, and v5 for the third triangle; v4, v6, and v5 for the fourth triangle; and so on. That way, the front side of the strip is always shown when it faces the camera, and the back side of the strip is always culled.
Triangle strips make efficient use of memory and processing time, so it's a good idea to use them whenever possible. The following code segment produces the triangle strip illustrated in Figure 6-6 by filling an array of vertices, just as you did with the other primitive types:
const DWORD TOTAL_VERTICES=6; D3DVERTEX lpVertices[TOTAL_VERTICES]; D3DVECTOR v1(-10, -5, 0); D3DVECTOR v2( -5, 7, 0); D3DVECTOR v3( 0, -1, 0); D3DVECTOR v4( 6, 4, 0); D3DVECTOR v5( 11, -7, 0); D3DVECTOR v6( 9, 9, 0); D3DVECTOR vNormal(0, 0, -1); lpVertices[0] = D3DVERTEX(v1, vNormal, 0, 0); lpVertices[1] = D3DVERTEX(v2, vNormal, 0, 0); lpVertices[2] = D3DVERTEX(v3, vNormal, 0, 0); lpVertices[3] = D3DVERTEX(v4, vNormal, 0, 0); lpVertices[4] = D3DVERTEX(v5, vNormal, 0, 0); lpVertices[5] = D3DVERTEX(v6, vNormal, 0, 0); |
This next code snippet shows how to render a triangle strip by using the IDirect3DDevice7::DrawPrimitive method, just as you've done with all the other primitive types. Figure 6-7 illustrates the rendered strip.
if (FAILED(lpDirect3DDevice7->BeginScene())) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX, lpVertices, TOTAL_VERTICES, 0))) { // Handle error here. } if (FAILED(lpDirect3DDevice7->EndScene())) { // Handle any error here. } |
Figure 6-7 The rendered triangle strip
The sixth primitive type, the triangle fan, is a lot like a triangle strip. The difference is that all the triangles share one vertex, as Figure 6-8 shows.
Figure 6-8 A triangle fan
Here's an example of the code needed to fill an array that defines a triangle fan:
const DWORD TOTAL_VERTICES = 6; D3DVERTEX lpVertices[TOTAL_VERTICES]; D3DVECTOR v1( -3, 0, 0); D3DVECTOR v2( 1, 4, 0); D3DVECTOR v3(1.5, 3, 0); D3DVECTOR v4( 2, 1, 0); D3DVECTOR v5( 2, -1, 0); D3DVECTOR v6(1.5, -3, 0); D3DVECTOR v7( 1, -4, 0); D3DVECTOR vNormal(0, 0, -1); lpVertices[0] = D3DVERTEX(v1, vNormal, 0, 0); lpVertices[1] = D3DVERTEX(v2, vNormal, 0, 0); lpVertices[2] = D3DVERTEX(v3, vNormal, 0, 0); lpVertices[3] = D3DVERTEX(v4, vNormal, 0, 0); lpVertices[4] = D3DVERTEX(v5, vNormal, 0, 0); lpVertices[5] = D3DVERTEX(v6, vNormal, 0, 0); lpVertices[6] = D3DVERTEX(v7, vNormal, 0, 0); |
The code can then render the triangle fan by using the IDirect3DDevice3::DrawPrimitive method you've been using, specifying D3DPT_TRIANGLEFAN as the first parameter. Figure 6-9 shows the rendered triangle fan.
if (FAILED(lpDirect3DDevice7->BeginScene())) { // Handle any error here. } if (FAILED(lpDirect3DDevice3->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_VERTEX, lpVertices, TOTAL_VERTICES, 0))) { // Handle any error here. } if (FAILED(lpDirect3DDevice7->EndScene())) { // Handle any error here. } |
Figure 6-9 A rendered triangle fan