DPTri is a sample that demonstrates Direct3D Immediate Mode
to render a triangle using DrawPrimitive API. To close the application, select Esc
and then Alt+F4
The following file is available for download from the Microsoft
additional information about how to download Microsoft Support files, click the
following article number to view the article in the Microsoft Knowledge Base:
How to Obtain Microsoft Support Files from Online Services
Microsoft scanned this file for viruses. Microsoft used the most
current virus-detection software that was available on the date that the file
was posted. The file is stored on security-enhanced servers that help to
prevent any unauthorized changes to the file.
When you run the self-extracting executable, the following
files are expanded:
- D3d.ico (2Kb)
- Dptri.c (42Kb)
- Dptri.def (1Kb)
- Dptri.exe (42Kb)
- Dptri.mak (8Kb)
- Dptri.rc (2Kb)
- Dxerrors.c (13Kb)
- Dxerrors.h (1Kb)
- Readme.txt--you are reading this file
- Resource.h (1Kb)
How the Sample Works
The following discussion is a "walkthrough" of the code.
The entry point of the sample is the same as any other Windows
. This function is where all initialization takes place for the
sample. The first initialization registers the window class and creates the
window. After the window is successfully created, the program enters an
infinite message loop until it closes. DirectX programs (particularly games)
should only run when the program has the activation. If it loses activation, or
if the program is paused, the program should just process Window's messages
instead of running the game loop and trying to render.
There are no
differences in registering the window class for a DirectX program. The sample
registers the class with an icon. This icon is used by Windows to visibly
represent the application on the task bar when the program loses activation
with a task switch. No menu is used since the sample is a full-screen exclusive
mode application. After the standard CreateWindow, ShowWindow, and UpdateWindow
calls, the sample initializes DirectDraw and Direct3D in InitDDrawAndD3D()
The window callback procedure processes Windows
messages. WM_ACTIVATEAPP must be handled for a "well-behaved" program. When the
program loses activation, set a flag and do not enter the game loop. Let other
programs use the CPU for a while. When the program gains activation, make sure
to restore the program's internal status including DirectX. Hide the Windows
cursor in the WM_SETCURSOR case as described. All DirectDraw programs should
render their own cursor. Do not let Windows handle cursor rendering unless a
flickering cursor is a feature of the program. Determine the cursor position
with GetCursorPos then render your own software cursor. All the other messages
Initializing DirectDraw and Direct3D can be
complex. The sample uses a user-defined data structure to hold some global
information. The keywords for initialization are "never assume anything about
the hardware." Follow these steps to initialize DirectDraw and Direct3D:
- Enumerate all DDraw supported video devices on the system.
A system can have more than one video card. Use DirectDrawEnumerate to
determine which is the best video card. In the enumerating callback procedure,
check which device supports 3D, and then save that information. Make sure to
enumerate the display mode that the application requires with EnumDisplayModes.
Notice that this sample doesn't have that code. Do not assume that the
particular mode that the program requires is supported on all devices. If a
device does not support the required mode, have an alternative plan. Fall back
on a different mode, if possible.
- The sample tries to use RGB color model. If 3D hardware is
used, RGB color model is a must. In the case of software HEL, RGB is chosen if
the processor supports MMX instructions. Note that starting with a DX5, MMX
system will have two flavors of the RGB driver: the standard one, and an MMX
enhanced one. The fallback is MONO color model when no acceleration is
- After a IDirect3D interface is queried off of a IDirectDraw
interface, enumerate the devices supported. This is where you need to check for
HW support for particular features if HW is to be used. If the program requires
HW Z-buffer at 16bpp, fog, perspective corrected texturing, point lights, etc.,
then check and make sure. DrawPrimitive and its cousin APIs are methods of the
IDirect3DDevice2 interface. First, get the IDirect3D2 interface by querying for
it off of the IDirect3D interface. Then, use IDirect3D2::CreateDevice to get to
IDirect3DDevice2. If the IDirect3DDevice interface is needed, use
IDirect3DDevice2::QueryInterface. One point that this sample does not go into
is the idea of enumerating all available devices and letting the user choose.
Programs should profile the available devices and then display the options
available to the user and have a default pre-selected.
- After all of DirectDraw and Direct3D devices have been
enumerated, you need to create some surface for the rendering engine. You will
need a primary surface with one back buffer and a Z buffer. Whether the device
is HW or SW determines where the Z buffer should be allocated from. If it's HW
then the Z buffer is allocated from video memory (if the HW supports Z
buffers). If it's SW, create the surface in system memory.
- The last initialization this code performs is querying for
the D3DDEVICE off the back buffer.
The key to this sample is the RenderTriangle
function. An array of vertices is defined for one triangle with
vertices at (0, 1, 0), (1, 0, 0), (-1, 0, 0). The normal of each vertex is -1
z, which points away from the monitor.
Setting up the matrices
requires defining the world, view, and projection matrices, associate them with
the IDirect3DDevice by calling IDirect3DDevice::CreateMatrix and
In the SetupLightAndViewport
function, a directional light is created and a viewport is setup
to map the 3D world to the visible 2D window.
To give the triangle
and background some visual appeal, it needs to have colors to define each. D3D
materials are used for this purpose. If you use 3D HW acceleration, the color
of the triangle will be green. If you use SW, the color will be red. On DX5, if
MMX is detected, the triangle will be yellow. The background will always be a
shade of blue.
The world, view, and projection transforms are
specified with IDirect3DDevice2::SetTransform.
Gouraud shade is
turned on with IDirect3DDevice2::SetRenderState along with other
After you have created everything, you are ready to
render the triangle. First, clear the viewport and Z-buffer with Clear. Then
render the triangle with BeginScene, DrawPrimitive, and EndScene. Those 4 APIs
usually are called together in that sequence. Make sure to not call
SetRenderState with each frame. This is an expensive operation. If the render
state doesn't change, then apply it once.
When using DrawPrimitive
or DrawIndexedPrimitive, make sure to send as many triangles in one call as
possible (that is, don't call the API for each triangle). Applications can
minimize vertices to optimize for speed by rearranging a list of triangles to
use D3DPT_TRIANGLESTRIP or D3DPT_TRIANGLEFAN.
With each frame, the
triangle is animated by modifying the world matrix to apply a rotation around
the Y-axis and then making the four rendering calls:
Finally, the image is made visible with a call to
During execution the application may be
deactivated and switched away. Make sure to pause all processing as mentioned
earlier. When the application is activated, restore all surfaces and reload any
artwork onto respective surfaces. The sample doesn't use any textures so
IDDrawSurface::Restore is sufficient.
When cleaning up, release all
objects in the reverse order of creation. Notice that only the front buffer is
released, and that the back and the Z buffer are not released. Releasing a
surface with attached surfaces will release all attached surfaces.