The Microsoft DrawPrimitive API

Microsoft Corporation

September 1997

Abstract

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.

Introduction

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.

Design Goals

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 for All Potential Users

Ease of use is a key design goal of DrawPrimitive because it is a critical feature for anyone using a 3-D API.

Compatibility with DirectX

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.

Scalable Performance

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.

Draw Primitive

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.

Triangles

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.

Lines and Points

DrawPrimitive supports line lists, line strips, and point lists.

Figure 2. Lines and points

Indexed Primitives

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.

Choosing a Format

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 DrawPrimitive Architecture

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 DrawPrimitive

Using the DrawPrimitive API is a three-step process: set up, set the state, and draw the primitives.

Step 1: Set up

The first step is to initialize the appropriate DirectDraw-based and Direct3D-based devices.

Step 2: Set state

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

Step 3: Draw Primitives

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:

Conclusion

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.

Summary of DrawPrimitive Methods

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

Glossary

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 More Information

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.