Example: Direct3D Texture Mapping
We'll now present a DirectX version of the TMcube example. The new version, called TMcubeX, uses conditional compilation to create either a DirectX or a native executable from the same source code. If the symbol DIRECTX is defined in the program, we link with Fastgraph's DirectX libraries to create a DirectX version. If the DIRECTX symbol is not defined, we link with Fastgraph's native libraries to create a native version. When creating a DirectX version, another symbol DIRECTX_FLAGS specifies how we want the program to use DirectX. The version of TMcubeX presented here (and supplied with Fastgraph) is set up to use DirectX with Direct3D hardware acceleration if available. If Direct3D hardware acceleration is not available, TMcubeX will still use DirectX but with Fastgraph's 3D rendering.
First, note how the TMcubeX program specifies three fg_ddsetup() flags (FG_DX_FLIP, FG_DX_RENDER_HW, and FG_DX_ZBUFFER) through the DIRECTX_FLAGS symbol. We must specify FG_DX_FLIP to set up a DirectX flipping environment (required for Direct3D programs). We specify FG_DX_RENDER_HW so the program will try to use Direct3D hardware acceleration if available; otherwise we will use Fastgraph's 3D rendering. Finally, we specify FG_DX_ZBUFFER to set up a Direct3D z-buffer in case Direct3D is available. If we want to use Direct3D software rendering or Fastgraph's 3D rendering instead of Direct3D hardware acceleration, all we need to do is specify FG_DX_RENDER_SW or FG_DX_RENDER_FG in place of the FG_DX_RENDER_HW flag.
The conditional compilation sequences identify the parts of TMcubeX that differ between creating a full screen DirectX program with page flipping and a full screen native program with blitting. In the WM_CREATE handler, we call fg_ddsetup() if creating a DirectX program, or fg_modeset() if building a native program. TMcubeX uses one virtual buffer, which we create with fg_vballoc() in the native version. In the DirectX version, fg_vbinit() automatically sets up the DirectDraw back buffer as a virtual buffer (and assigns virtual buffer handle 0 to it), so we simply set hVB to zero. In the WM_DESTROY handler, note how the native version calls fg_vbfree() to release the virtual buffer, fg_vbfin() to shut down virtual buffer operations, and fg_modeset() to restore the original display resolution. In the DirectX version, only the fg_vbfin() call is necessary.
Another difference between TMcubeX and TMcube is the use of a WM_ACTIVATEAPP event handler to support DirectX task switching. If compiled as a DirectX program, the WM_ACTIVATEAPP handler calls fg_ddrestore() to restore the DirectDraw surfaces when TMcubeX becomes active. The WM_ACTIVATEAPP handler also calls the program's CheckForMovement() function to restore the surface contents and redisplay the cube. TMcubeX uses two global variables, AppIsActive and AppIsReady, to keep track of the application's state. Both variables are initially set to FALSE. The AppIsActive global is set in the WM_ACTIVATEAPP handler; its value will be TRUE when TMcubeX is active, and FALSE when not. The AppIsReady global is set to TRUE at the end of the WM_CREATE and will remain so for the duration of the program. We need the AppIsReady variable because a WM_ACTIVATEAPP event occurs before the WM_CREATE event on program startup. The WM_ACTIVATEAPP handler can then check the value of AppIsReady to guard against restoring the surface contents before fg_vbinit() initializes DirectX in the WM_CREATE handler. Besides adding a WM_ACTIVATEAPP handler, we remove the WM_PAINT handler and modify the WM_SETFOCUS handler just as we did for the FrameDD example.
There are also some minor differences in the program's CheckForMovement() function. The most obvious is the addition of the Redraw parameter, which lets us specify if we want to redisplay the cube unconditionally, or only when its position or orientation changes. This lets us use the drawing code in CheckForMovement() when initially displaying the cube in the WM_CREATE handler, and also when restoring the surface contents in the WM_ACTIVATEAPP handler. The DirectX version of CheckForMovement() also adds two calls to fg_ddframe(), one before we begin rendering the new cube, and another after we finish. Calling fg_ddframe() is required for Direct3D programs; it is optional for DirectX programs that use Fastgraph's 3D rendering. Finally, TMcubeX displays the cube through its ShowCube() function. ShowCube() does this by performing a page flip with fg_ddflip() in the DirectX version, or by blitting with fg_vbpaste() in the native version.
copyright 2001 Ted Gruber Software, Inc.
copyright 2001 Ted Gruber Software, Inc.