Microsoft Corporation
September 1997
Microsoft® DrawPrimitive provides a simple, yet extremely powerful set of functions to perform the foundation operations of three-dimensional (3-D) drawing. It is an easy-to-use application programming interface (API) that draws 3-D triangles, lines, and points—the fundamental primitives of 3-D—into DirectDraw® API surfaces. This article describes the features, architecture, and use of DrawPrimitive.
Microsoft DrawPrimitive is an easy-to-use API for 3-D drawing. DrawPrimitive draws 3-D triangles, lines, and points—the fundamental primitives of 3-D—into DirectDraw API surfaces.
DrawPrimitive is a simple, compact API. This design simplicity makes it ideal for a wide range of 3-D–related tasks, from quick prototyping and adding 3-D elements to existing applications, to more complex challenges such as interfacing 3-D engines and toolkits to 3-D hardware.
DrawPrimitive does not require specific 3-D hardware; it is optimized to deliver maximum performance on both software-only and hardware-accelerated systems. DrawPrimitive is designed to be a foundation interface for 3-D acceleration, which is rapidly becoming a standard computing capability.
DrawPrimitive was designed to achieve three key goals: ease-of-use, compatibility with the Microsoft DirectX® set of APIs, and scalable performance.
Ease of use is a key design goal of DrawPrimitive because it is a critical feature for anyone using a 3-D API.
The second design goal for DrawPrimitive is compatibility with DirectX. The reason is simple: DirectX is enormously successful, with hundreds of applications using DirectX technologies and millions of DirectX-enabled devices already in use. The DirectX family of performance graphics and media services is quickly becoming a core, universal PC media playback facility. As an extension of DirectX, the DrawPrimitive API continues the DirectX "direct" design and interface philosophy, combining software emulation and hardware abstraction to unify and allow innovation in digital media playback.
And, indeed, users of DirectX will find DrawPrimitive familiar. Users of the immediate mode in the Microsoft Direct3D® API will perceive DrawPrimitive as a natural extension of the Direct3D execute buffers, which are essentially user-compiled blocks of DrawPrimitive commands. Users of DirectDraw will find DrawPrimitive a simple and fast way to draw 3-D primitives into the DirectDraw surfaces they already use. Device-driver writers will find that adding a DrawPrimitive extension to existing drivers for DirectX involves only a matter of days or weeks of effort.
All of the foregoing underscores the Microsoft commitment to DirectX as a core technology. DrawPrimitive protects the investment that ISVs and IHVs have made in DirectX technologies; at the same time, DrawPrimitive extends the functionality of DirectX over time.
The final design goal of DrawPrimitive is scalable performance. This means that DrawPrimitive is designed to deliver to the API user the maximum performance available on the full range of 3-D-capable computing architectures.
There is no single, universal, 3-D computing architecture and innovation in media computing architectures is sure to continue. A foundation 3-D draw API must therefore be scalable from software-only systems to various media processing architectures, and from simple hardware triangle engines to advanced commodity media architectures such as the Microsoft hardware reference design, code-named "Talisman." This requirement is a major design challenge that requires hardware abstraction, software emulation, and the capability of the programmer to query and configure for a particular system.
DrawPrimitive is designed to do one thing very well—draw 3-D primitives. This requires supporting a variety of formats for describing 3-D primitives.
DrawPrimitive supports triangle fans, triangle strips, and triangle lists.
Figure 1. Triangles
DrawPrimitive uses triangles to represent both simple and complex surfaces through texture mapping and shading algorithms.
DrawPrimitive supports line lists, line strips, and point lists.
Figure 2. Lines and points
DrawPrimitive can represent primitives in two formats: as a list of vertices, or as a list of vertices plus an index into the list of vertices. For primitives described as a list of vertices, the draw engine simply processes the vertices in the order they appear in the list. For indexed primitives, the draw engine processes the list of vertices in the order described by the index.
The choice of which primitive format to use depends on the application. Some 3-D hardware designs achieve optimal performance with triangle strips and fans. Indexed primitives are commonly used in 3-D file formats, modeling tools, and surface-deforming algorithms.
The conceptual architecture of DrawPrimitive is straightforward. A core set of functions is used to pass 3-D primitives to a draw engine, which then draws the primitives into a DirectDraw surface. The draw engine uses a transform formula to calculate how to convert locations in 3-D space into 2-D screen coordinates, and it uses a set of state variables that specify the stylistic characteristics of the draw operation.
The DrawPrimitive architecture is summarized in Figure 3.
Figure 3. The DrawPrimitive architecture
The three components of the Direct3D-based device are transform, state variables and draw engine.
Using the DrawPrimitive API is a three-step process: set up, set the state, and draw the primitives.
The first step is to initialize the appropriate DirectDraw-based and Direct3D-based devices.
The next step is to set the transform and specify any desired state variable settings.
For example, a statement like the following would be used to turn on anti-aliasing for drawing operations:
lpD3DDevice->SetRenderState(ANTIALIAS,TRUE) //turn on anti-aliasing
The third step is to draw the primitives. Each group of like primitives is drawn together in blocks of commands. For example, a code fragment to draw a single triangle would look something like the following:
lpD3DDevice->Begin(0,Vertex,TriangleList); //begin drawing a triangle list
lpD3DDevice->Vertex(lpVertex1); //vertex 1
lpD3DDevice->Vertex(lpVertex2); //vertex 2
lpD3DDevice->Vertex(lpVertex3); //vertex 3
lpD3Ddevice->End(0); //end drawing
Code to draw a triangle strip from a list of vertices would look like this:
lpD3DDevice->DrawIndexedPrimitive(0, TriangleStrip, Vertex, lpVertexList, dwVertexCount, lpIndex, dwIndexCount);
In the preceding examples:
DrawPrimitive provides a simple yet extremely powerful set of functions to perform the foundation operations of 3-D drawing. Whether one's task is to add a few 3-D elements to an existing application or create an interface between an entire 3-D game engine or tool to 3-D hardware, DrawPrimitive provides the essential primitive-level draw functionality needed.
Method | Description |
Set Up | |
SetRenderTarget | Select a DirectDraw-based surface to draw to |
SetCurrentViewport | Describe 3-D space to be viewable on screen |
Set State | |
SetRenderState | Set a state variable in the draw engine |
SetLightState | Set a state variable for a light |
Get/SetTransform | Get/set the transformation formula from world space (3-D) to screen coordinates (2-D) |
MultiplyTransform | Modify the transformation formula |
GetStatus | Get the current value of a state variable |
Draw | |
Begin, BeginIndexed | Start drawing primitives (triangles, lines or points) |
DrawPrimitive | Draw a primitive |
DrawIndexedPrimitive | Draw a primitive from an indexed list |
Vertex, Lvertex, TLVertex | Add a vertex |
Index | Add an entry to an index |
End | Complete drawing primitives |
Indexed primitive. A method of describing a group of 3-D primitives. The vertices of the primitives are stored in a vertex list, and each primitive (a triangle or line segment) is described as index values that point to particular vertices in the vertex list.
Matrix (plural: matrices). Shorthand for a type of mathematical formula commonly used in 3-D calculations. A matrix is a grid of numbers that represent the coefficients of a set of equations.
Rasterize. To draw the pixels of a primitive. Rasterization is the third step of the draw engine, after transformation and lighting.
Transform. To convert a spatial coordinate—for example, to convert a 3-D coordinate into 2-D screen coordinates.
Triangle fan. A series of triangles that share a common central vertex.
Triangle strip. A series of triangles organized so that each new triangle shares two vertices with the previous triangle. Triangle strips are convenient for 3-D hardware because less bandwidth is required to send the vertices to the hardware, and the hardware can load a single vertex to draw another triangle.
Vertex (plural: vertices). A point in space. A vertex can represent a corner of a triangle or an end point of a line segment. DrawPrimitive uses three data structures to describe vertices, depending on whether the calling application wants the draw engine to transform the vertices from 3-D to 2-D space or perform lighting calculations before drawing a triangle.
For the latest information on DirectX, check out the Microsoft DirectX Web site (http://www.microsoft.com/directX).
The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication.
This document is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS DOCUMENT.