The biggest advantage of using either DirectDraw or Direct3D with your Fastgraph program is you can take advantage of hardware rendering and blitting using graphics accelerator chips on some modern video cards.
This can make a 3D program really fast.
Unfortunately, it can also give you inconsistent results. For more information about the advantages and disadvantages of using DirectX with Fastgraph, have a look at some benchmark results.
Fastgraph works with Direct3D in what is known as immediate mode. That means a program will access the capabilities of the video card directly, going through the driver only to a very limited extent. Fastgraph uses Direct3D in full screen applications only. Graphics are written directly to video memory as opposed to being written to a surface in RAM and then copied to video memory.
I will discuss the use of Direct3D in a program called TBench, that performs benchmark tests. This is another simple C program, very similar to the one in Chapter 2. If you had any trouble with the discussion of textures in the last chapter, take a look at the way we do textures here. It is a little simpler.
Benchmark Source CodeHere is the source code to TBench.c:
Notes on the Source CodeThe benchmark program is a good one to look at because the Fastgraph DirectX functions are highlighted within the defined symbol DIRECT3D. I did it this way so I could compile the program three different ways: using Fastgraph only, using Fastgraph with Direct3D hardware rendering, and using Fastgraph with Direct 3D software rendering. By generating three different programs from one source code file, I make my benchmark test as accurate as possible.
Here is a batch file to compile the program all three ways, using Visual C++ 6.0:
Notice when you link a DirectX program, you need to link with a different Fastgraph library. In this case we link with FGWVC32.LIB for the non-DirectX version, and FGWVC32D.LIB for the DirectX version. You also need to link with DDRAW.LIB.
Most of the Fastgraph functions behave exactly the same way whether you are using DirectDraw, Direct3D or Fastgraph by itself. There are just a few functions that are specific to Fastgraph or DirectX. Most of those have to do with initialization and blitting.
Initializing DirectXLet's look at the lines that initialize DirectX.
To initialize DirectX for blitting and rendering, we call Fastgraph's fg_ddsetup() function. This function call must be the first thing that happens in the create handler. We call fg_ddsetup() two different ways, depending on our preference.
In the first case, we set the flags FG_DX_FLIP to indicate we will use hardware page flipping and FG_DX_RENDER_SW to indicate we want to do software rendering. In the second case, we set the flag FG_DX_RENDER_HW to indicate we want to do hardware rendering.
In both cases, we are indicating the preferred method of handling rendering. If the system can not support the prefered method, the program will use Fastgraph's software blitting functions instead. This makes the software more reliable on computers that for one reason or another can't support the preferred method.
We also set the FG_DX_ZBUFFER flag to indicate we want Direct3D to handle the z buffering.
If you are not using DirectX, you can use the fg_modeset() function to set the system to a full-screen video mode (as opposed to a windowed mode), and force a screen resolution (for example, 640x480 pixels).
Checking System CapabilitiesBut how do you know if DirectDraw will work on the user's system? The fg_vbinit() must be called once in every program. If you are linking with the DirectX libraries, and DirectX is not available on the user's system, then fg_vbinit() will return a negative value. In that case, you have an error. You need to do something else, like exit with an error message, or possibly spawn a Fastgraph native-mode program (more about that later). Here is the check to see if DirectX is available onthe user's system:
The fg_ddusage() function will return 1 if Direct3D is available for software rendering. It will return 2 if Direct3D is available for hardware rendering. It will return 0 if Direct3D is not available.
Now let's look at the code to allocate the virtual buffer:
With DirectDraw flipping, you don't need to allocate any memory for the virtual buffer because the virtual buffer is actually a hardware page on the video card. If you ever did any DOS game programming, you will recognize the concept of hidden pages on the video card. (Those were the good old days, weren't they?). The DirectDraw "back buffer" is just the video card's hidden page. It always has a handle of 0. When you do a page flip, the handle flips too, so the hidden page still has a handle of 0.
Here is how you do a page flip:
The DirectDraw page flip is going to be much faster than the Fastgraph paste. That's because when you paste from system RAM to video memory, you have to move a full page of data across the bus. That's fast, but not as fast as doing a page flip. Using DirectDraw, you can do a hardware page flip, which is about as fast as the monitor's vertical retrace -- very fast indeed.
There are just a few other things you have to remember about DirectX. The order in which things happen is important. Be sure to call fg_ddsetup() first thing in your program. Be sure to call fg_vbinit() before you call any Fastgraph functions they depend upon DirectX being initialized, such as fg_tmdefine().
Before you begin and end a rendering frame, you need to call the Fastgraph function fg_ddframe(), passing a 0 at the beginning of the frame and a 1 at the end of the frame. These functions handle the calls to Direct3D's BeginScene() and EndScene() methods. I don't really know why Direct3D requires methods at the beginning and end of each frame. It's one of those DirectX mysteries. Maybe it locks and unlocks the DirectDraw surface. One of my books mentions flushing a cache.
Making High Color RGB Pixel Formats Compatible
RGB pixel formats at a 16-bit resolution can use either a 5/5/5 or 5/6/5 strategy.
On some video cards, the DirectX driver will set up the high color RGB pixel
format at 5/5/5. Fastgraph virtual buffers will match the DirectX surface.
In this program we are reading textures from a file, and we know they were
made with a 5/6/5 RGB pixel format (the default, when you use Fastgraph
without DirectX). We check to see if the texture format matches the
current DirectDraw surface with fg_gethcbpp(). If they don't match, we
translate the textures using fg_transdcb(). If you don't do this step, you may
notice odd-looking colors on some systems.
Those are the only DirectX specific functions in the TBench program. There are some other DirectDraw functions in Fastgraph. You will find them in the Fastgraph manual. If you use DirectDraw without Direct3D, you can write windowed programs, and you can blit from system RAM or write directly to video memory. So there are a few other things you can do with DirectX and Fastgraph, but the most dramatic results are to be found in the hardware rendering functions in Direct3D.
Do I Have to Write My Program Two Times?
I am afraid Direct3D is not reliable on all systems. For that matter, all of DirectX may be unreliable. If you want your game to be reliable, you should consider releasing both a DirectX version and a Fastgraph only version. You can build both exe files from the same source code file if you use the conditional compilation strategy shown above. Then you can detect DirectX during the installation process and select which program to install. Or, you can write a small "stub" program that uses fg_vbinit() to detect DirectX on the system and then calls WinExec() to launch either the DirectX version or the Fastgraph version, as appropriate.
Your DirectX version will support DirectDraw page flipping, and Direct3D hardware rendering if it is available. If 3D hardware rendering is not available, that program will default to Fastgraph rendering, but still use DirectDraw page flipping. If DirectDraw is not available, you must use the other program, the one compiled to not use any DirectX.
For example, if we write the TDemo program from chapter 4 to support both
Fastgraph native mode, and DirectX, we might end up with 2 programs:
Tdemo.exe and TdemoDD.exe. You would run the TdemoDD program
first, and if it determines DirectX was not available, you would spawn the
Tdemo program like this:
Note: Fastgraph without DirectX is extremely reliable. It works very well on every system we have tested it on -- and we have done some rigorous testing. It is only when you introduce DirectX into your programs that you have a variety of unreliability problems.
I would not bother with Direct3D software rendering at all. I can't see any point in it -- it is both slow and unreliable and Fastgraph can replace it seemlessly.
Using Fastgraph with DirectX has both advantages and disadvantages. If you decide to use Fastgraph with DirectX, you will need to add a few simple functions to your program. You will need to link with different libraries.
Functions to initialize DirectX with Fastgraph need to be done in order. First call fg_ddsetup(), then call fg_vbinit(). The fg_ddusage() function will tell you if 3D hardware rendering is available.
Most of Fastgraph's functions are called the same way whether or not you are using DirectDraw or Direct3D. That makes it easy to write a program one time, and use conditional compilation to create versions for various rendering and blitting schemes. I recommend releasing two programs, one that supports DirectX and one that uses Fastgraph without DirectX, and then detect DirectX on the user's system to decide which program to run.
That about wraps it up for the discussion of DirectX with Fastgraph. There is more specific information in the Fastgraph manual. Now take a little break before we move on to our discussion of image processing.
Chapter 1 | Chapter 2 | Chapter 3
Chapter 4 | Chapter 5 | Chapter 6 | Chapter 7
Appendix 1 | Appendix 2 | Appendix 3
Fastgraph Home Page