Introduction

D3DQuake is a modification of the id Software GLQuake program. D3DQuake is just GLQuake modified to use Direct3D 8.0 instead of
OpenGL. Similarly, D3Dqwcl is the GL QuakeWorld client modified to use Direct3D 8.0.

Mini FAQ

Q: What is D3DQuake?

A: D3DQuake is GLQuake modified to run on top of Direct3D 8.0 instead
of OpenGL. GLQuake uses a fairly small (50 function) subset of OpenGL. It only
took a few days to write Direct3D versions of these calls. (It's taken quite a
few more days to get all the bugs out.)

Q: Why did you do this?

A: Because I wanted to learn about Quake, and about Direct3D, and I
thought it would be cool.

Q: In your day job you work for
Microsoft. Don't you have an ulterior motive for doing this?

A: Sure! OpenGL is great, but DirectX deserves more respect that it
currently gets.. One reason I wrote D3DQuake is that I wanted to see how well
Direct3D compares to OpenGL in terms of ease-of-use and performance.

Q: And what did you find?

A: So far, I have to admit that OpenGL's API is cleaner and easier to use
than Direct3D. As for performance, I think with enough work, I could match OpenGL's performance.
The trouble is that current OpenGL drivers are optimized for running Quake, and
current DirectX drivers aren't. Currently the big bottleneck appears to be
related to updating lightmaps.

Q: Will D3DQuake work on any video card that supports Direct3D?

A: No. Right now the D3D card has to have DirectX 8 drivers, and 8 MB of
RAM. D3DQuake has only been tested on Windows 2000
with the NVIDIA GeForce cards. (However, other users have reported some success
running D3DQuake on other video cards.)

Q: Any relation between your code and the controversial 1996 D3DQuake
written by a Microsoft summer intern?

A: Nope. I didn't even know about that when I began writing my
version. That version was reported to be only 3% to 5% slower than GLQuake. I
wish I knew how they made it that fast!

Q: Quake II's source code has been released. Are you going to make
a DirectX / Direct3D version of Quake II?

A: Probably not. I was all set to do a Quake II port of my code,
but then I played Quake II again. I found that I just
wasn't enjoying myself -- more recent
FPS games like Halo (on Xbox) are just so much better. Also, while Quake II
was innovative for its day, it looks quite dated now. It basicly doesn't
seem interesting to me. Sorry!

That being said, I think it would be quite easy to write a DX / D3D graphics
driver for Quake II. Anyone who does this is certainly welcome to use any
code they want to from D3DQuake!

Known Bugs / Limitations

Does not check caps bits.

When run full screen, or run with 16-bit-per-pixel desktop, some levels
have bad lighting.

Card Notes (alphabetical)

3dfx
Voodoo3

Runs for a while, but then the textures get messed up. (If you're using prerelease Windows
2000 Voodoo drivers, you will need to define the symbol USE_D3DFRAME and
recompile the application.)

ATI
128

Works.

Matrox
G400
G400 MAX

Mixed reports. Some users have reported crashes at
startup. One user reported that the D3D graphics are actually better
than the GLQuake, due to bugs in the Matrox OpenGL driver.

Code Notes

All the Direct3D-specific code is in the file gl_fakegl.cpp. In addition, I
had to make a few changes to the main sources. These changes are #ifdef'd
using the preprocessor symbol D3DQUAKE. Presumably, you could merge this code
base with any of the other modifications to GLQuake, and it would still work.
The only caveat is that if the other modification uses some new feature of
OpenGL, you'd have to add support for that new feature.

If you look at the source code for gl_fakegl.cpp, you'll see that it's all
pretty straightforward. For the most part, each of the OpenGL calls that Quake
uses has a corresponding D3D call. All I had to do was convert the arguments.

To compile, open the WinQuake project in Visual Studio 6.0 or later. Choose
either the "Win32 D3D Release" or the Win32 D3D Debug"
configuration. Build. The resulting executable can be used the same way as
GLQuake.exe.

Current Performance

Current performance of D3DQuake is not very good. On a GeForce card it's
about half the speed of GLQuake. VTune tells me that 50% of D3DQuake's time is
being spent in the file gl_fakegl.cpp. This is a file that I wrote to convert
OpenGL calls to D3D calls.

To speed D3DQuake up further I will have to modify Quake's GL-specific code
to make it more D3D aware. VTune tells me that I'm spending at least 10% of my
time just copying vertices into buffers to hand to DrawPrimitive. If I use
vertex buffers, and change the Quake code to fill the vertex buffer, I bet I
could get a significant speedup.

Lately I've discovered that updating light maps on NVIDIA hardware
is much slower using NVIDIA's D3D driver than when using NVIDIA's OpenGL driver. This is why the frame rate is so slow when
you're in a room with dynamic lighting effects. This is probably due to NVIDIA's
texture maps being stored in a non-linear format. Presumably there is some way
around this problem, but I haven't figured it out yet.

Computer

Pentium III Celeron-A 500, 192 MB RAM

Software

Windows 2000 Pro SP1

3D Accelerator

Generic Geforec 2 GTS 64 MB with beta NVIDIA W2K driver 6.47

Command line args

none

console args

timedemo demo2

Version

FPS

Speed

Remarks

GLQuake

73.0

100%

Normal GLQuake.

D3DQuake v0.73

53.8

73%

Older benchmarks

Computer

Pentium II 300, 128 MB RAM

Software

Windows 2000 RC3

3D Accelerator

WinFast GeForce 256 SDR with beta NVIDIA W2K driver 3.6.5

Command line args

-window -nosound -nocdaudio

console args

timedemo demo2

Version

FPS

Speed

Remarks

GLQuake

110.7

100%

Normal GLQuake.

D3DQuake v0.1

39.9

36%

Original D3DQuake.

D3DQuake v0.2 Single Texture

43.5

39%

Eliminated some redundant state changes.

D3DQuake v0.2 Multitexture

33.5

30%

Yes, multitexture really is slower than single texture. I
must be doing something wrong.

D3DQuake v0.3 Single Texture

49.6

45%

Shortened code paths.

D3DQuake v0.4 Single Texture

50.3

46%

More VTune-directed tweaking.

GLQuake Win98

116.9

100%

D3DQuake v0.71 Win98

66.0

56%

Use vertex buffers with append mode.

GLQuake Win98

129

100%

Full optimizations

D3DQuake v0.72 Win98

95.6

74%

Full optimizations

Future Work

Serious modification of the gl_xxx files to be D3D friendly.

Acknowledgements

I'd like to thank id Software, especially John Carmack, for releasing the
sources to Quake. And I'd like to thank the members of the DIRECTXDEV mailing
list for answering my questions.

Version History

01-17-2001 0.81 After many requests, finally implemented
D3DQuakeWorld. Also fixed
minor bug that caused problems running the DX8 version of D3DQuake in a window.

12-30-2000 0.80 Converted D3D Quake to use Direct X 8.0. Converting to
Direct X 8.0 didn't make any difference on speed, but did allow me to throw out
several hundred lines of initialization code. The source ZIP file got larger
because I include the DX 8 header files and libraries, which are larger than in
DX 7.

01-29-2000 0.73 Thanks to a bug report from "The Spectere",
D3DQuake new works with more screen resolutions and depths.

Fixed the window size logic to work with sizes larger than 640 x 480.

Added a -zbpp command line option for setting the z-buffer depth from the
command line.

01-29-2000 0.72 I turned on full optimization. Wow, what a
difference! I think this confirms that a lot of time is being spent converting
the graphics from OpenGL format to D3D format. The optimizer did a good job of
speeding up this conversion code.

01-29-2000 0.71 Got vertex buffers working correctly.

01-29-2000 0.7 A little faster, with more compile options.

I've spent the week experimenting with different ways of trying to speed up
D3DQuake. I haven't had much luck. My best guess is that the speed difference is
due to (a) the overhead of converting OpenGL to D3D, and (b) the lack of
Quake-specific performance optimizations in the D3D drivers.

If you're using the sources, you'll have to download the whole source
package, because there are several new files.

Made brightness control work, thanks to a tip from Stephan Kerkewitz, who
told me to make sure that the application was running in exclusive mode.

Evict managed textures at the start of each level. This might help Voodoo
cards.

Rewrote some of the vertex data stuffing code to make it run more quickly. Just
copying the data from OpenGL format to D3D format seems to be chewing up a
great deal of time. VTune showed me that on a
Pentium III copying floats as DWORDs is faster than copying them as floats.

Implemented three different ways of drawing the triangles: DrawPrimitive,
DrawIndexedPrimitive, and DrawIndexedPrimitiveVB. See the defines USE_DRAWPRIMITIVE,
USE_DRAWINDEXEDPRIMITIVE, and USE_DRAWINDEXEDPRIMITIVEVB in gl_fakegl.cpp
USE_DRAWINDEXEDPRIMITIVE runs the fastest on my GeForce card.

Use multitexture by default.

Hooked up the standard command-line options for setting color
bits-per-pixel, height, and width.

Disable debug breaks in release mode. The user won't have a debugger, so
the game might as well try and keep running.

01-23-2000 0.6 This version might actually work on a Voodoo card. Let
me know if there are still problems.

Print the D3DQuake version on the console background, for vanity, and to
make it easier to track versions.

Made the sky look right again. (I broke this when I made the console
transparency work a few releases ago.)

Made screenshot command work.

Put in work-around for GeForce full-screen-quad drawing bug. No more
diagonal lines on the screen when underwater!

Added support for 16-bit textures. This should make D3DQuake work on
Voodoo cards.

Added a command-line argument: -force16bittextures . If you use
this flag on the command line, then D3DQuake will try to use 16-bit textures
even if your card supports 32-bit textures. On some cards this may be good
for a few extra fps.

Added a console command for playing with maxanisotropy: d3d_maxanisotropyn, where n is a floating point number >= 1.0.
Just typing d3d_maxanisotropy by itself will report the current
setting. The default value is 1.0. Settings above 1.0 are supposed to
improve texture mapping image quality for mip-mapped textures that are drawn
at an angle to the viewer. It doesn't seem to have any effect on my GeForce,
but I'm pretty sure I implemented it correctly. This is a high-end feature
that probably slows down rendering quite a bit. I wonder if any cards
implement this feature?

01-21-2000 - 0.5 Fixed mip-mapping. I had accidentally turned mip-mapping
off. Now it's on again. Fixed GL_TEXTUREMODE so it takes effect immediately. (I
think this may have been a long-standing bug in GLQUAKE.) Implemented the gamma
(brightness) command, but it doesn't seem to do anything on TNT cards. Does
D3DQuake's Brightness control work for anyone? Please let me know if it does.

01-16-2000 - 0.4 Fixed a buffer-overflow bug. Rearranged some code, and played
with some compiler flags. Clamped color values, which fixed flame brightness.
Fixed console transparency to match GLQuake. Changed call to D3DXCreateContextEx
to attempt to work around crash on Win98. Avoid calling some OpenGL-specific
initialization code.

01-14-2000 - 0.3 Improved redundant state setting. Found out that multitexture is
slower than monotexture because of state changes -- GLQuake sorts single-texture
triangles by texture, but doesn't sort multi-texture triangles. Installed VTune.
Discovered that much of the time is being spent copying vertices from OpenGL
format to D3D format. Who knew?

01-13-2000 - 0.2 Fixed bugs. The output looks very close to the original OpenGL
now. Improved speed by avoiding some redundant state changes. Implemented
multi-texturing (but it's slower than not using it!)

01-12-2000 - 0.1 Got everything working. Released version 0.1

01-12-2000 - Got flash-blending to work. Got the status bar to stay on the
screen.