|
|
DirectX Programming
Charlie Calvert
Part1: Introduction to DirectX
Part2: Initializing DirectDraw
Part3: Developing Applications
Part4: Various Demos
|
DirectX Programming
Part I: Introduction to DirectX
Introduction
Why DirectX?
What is DirectX?
Windows 95/98 and NT Installation
Getting the DirectX SDK.
What are the DirectX Technologies?
What about Direct3D?
DirectX and COM
Hardware and Software Emulation
Time to get more technical
DirectX Programming
Part II: Initializing DirectDraw
Creating
a DirectDraw Object
Initializing
DirectDraw
Calling
DirectDrawCreate and CoCreateInstance
DirectX
Modes
Setting
the Display Mode
Surfaces
and Page Flipping
CreateSurface
(Primary and Back Surfaces)
The
DDUtil Routines
Palettes
Transparent
Colors
DirectX Programming
Part III: Developing Applications
Flipping
and Restoring the Focus
Animation
Idle
Loops
Exclusive
Mode Exception Handling
Working
with Sprites
Clippers
Home
DirectX Programming
Part I: Introduction to DirectX
- DirectSound
- DirectPlay
- Direct3D
Overview
- My name is Charlie Calvert
- Code and information from this talk is availble on my Web site: http://www.elvenware.com.
- The talk will focus primarily on DirectX, and on how to find DirectX resources
- I can't cover everything, so I will pick DirectDraw as the technical focus of talk
- But I will show other technologies such as DirectSound, DirectPlay and Direct3D
Part1
Why DirectX?
- DirectX is about games, visualization, and simulations, but it is also about communication
- Tens of millions of computer users are not primarily focused on business
- They are interested in entertainment, education, science, games, information and communication
- All of these fields can be enhanced by DirectX
- So yes, its about games and simulations, but its also about the human side of computing, and that's not a trivial matter.
Part1
What is DirectX?
- DirectX provides tools for multimedia programming in Windows.
- From a graphics or sound programmers perspective, Windows is slow.
- The problem is that Windows forces the programmer to access hardware through drivers (VxDs).
- Drivers let you write once, run anywhere, and they let you share resources. But they are slow.
- The solution is DirectX, which gives programmers direct access to hardware.
- It gives you direct access to blocks of memory that exist on devices such as video cards of sound cards.
- The goal is real time performance, as fast as DOS or game consoles.
Part1
Windows 95/98 vs Windows NT Installation
- DirectX comes with NT and Windows 98, but does not come with Windows 95
- Windows 95/98 users can download the latest drivers from http://www.microsoft.com/directx
- You cannot update the drivers that come with Windows NT, but you can get services packs to upgrade to at least DirectX 3.
- Win 2000 supports DirectX 7.0, which is the current version.
Part1
DirectX SDK
- The DirectX SDK has samples, media, declarations.
- There is a good help file and numerous long documents, approaching book length.
- Go to www.microsoft.com/directx/default.asp
- You can download the DirectX 6.0 SDK from the MS web site, a mere 91 MB, or ...
- At selected times you can buy the SDK CDROM for $8.65 ($12.50 via airmail) if you are a US citizen, or $11.65 if you live outside the US.
Part1
What are the Direct X technologies?
- The key technologies are DirectDraw, DirectSound, DirectInput, DirectPlay, DirectMusic and Direct3D.
- DirectDraw gives you direct access to the video buffer.
- DirectSound gives you direct access to the sound hardware.
- DirectInput gives you access to mouse and joystick facilities.
- DirectPlay helps you create networked games or simulations.
- DirectMusic allows you to creating music on the fly, and provides advanced MIDI services.
- The advantage of these technologies is speed. They are fast!
Part1
What about Direct3D?
- Direct3D let's you manipulate triangles out of which 3D objects can be made.
- Direct3D has two modes.
- Immediate Mode provides 3D graphics primitives similar to the OpenGL specification.
- Retained Mode provides high level routines that make 3D programming easier.
- Direct3D provides specifications that hardware venders can write to.
- This has brought us greatly enhanced 3D performance in the last few months and years.
Part1
DirectX and COM
- DirectX is implemented through a serious of COM objects, which means it is OOP based from the ground up.
- These are very simple COM objects, so you don't need to understand much about COM to use them.
- Each technology provides simple functions that retrieve the COM object.
- Rather than call CoCreateInstance and QueryInterface, you can just call these functions.
- This technology shows that COM is a lot faster than many people suspected.
- Be sure to call CoInitialize at the beginning and and CoUnitialize at the end of your program.
Part1
Hardware and Software Emulation
- DirectX gives you direct access to hardware.
- If possible, it will ask optimized routines built into the hardware to perform operations
- For instance, if you want to draw a rectangle, blit a bitmap, or perform a transform on an object, it will ask the hardware to perform these tasks for you.
- If hardware does not support a feature the Hardware Emulation Layer (HEL), will do it for you.
- If hardware supports a particular feature, then it is handled by the Hardware Abstraction Layer, or HAL.
- You don't have to understand these things. DirectX automatically takes advantage of features such as MMX or 3D hardware features.
- Drivers that ship with DirectX automatically access these features.
Part1
Time to get more technical
- So much for the overview. Let's look at some details.
- I will cover DirectDraw first, then DirectSound, DirectPlay and finally Direct3D.
- There will be code examples available for all these technologies, but time is limited.
- Because DirectX is complex, I will show you several high level libraries that save work.
Part2
Creating a DirectDraw Object
- To create a DirectDraw object, just call DirectDrawCreate, CoGetClassObject or CoCreateInstance.
- Once you get the object back, you need to initialize DirectDraw.
- This is a complex process, so I provide you with both raw code and C++ classes that do it automatically.
- However, I want to discuss this technology in some depth, so I will look beneath the hood.
Part2
Initializing DirectDraw
- Key methods: DirectDrawCreate, SetCooperativeLevel, SetDisplayMode, CreateSurface
- Subjects covered: DirectX Modes, Palettes, Surfaces, Page Flipping, Exception Handling, Restoring Surfaces
- We'll need to cover all subjects before you will fully understand the initialization
- The complexity of this operation is why you need high level objects!
Part2
Calling DirectDrawCreate and CoCreateInstance
LPDirectDraw is a pointer to a DirectDraw Interface: IDirectDraw * LPDirectDraw
IDirectDraw and DirectDrawCreate are declared in DDraw.h
LPDIRECTDRAW DirectDraw;
/* DirectDrawCreate(
GUID // Emulation or Hardware,
LPDIRECTDRAW // Your DirectDraw Object,
PUnkOuter // Must be NULL); */
HRESULT hr = DirectDrawCreate(NULL, &DirectDraw, NULL);
if (SUCCEEDED(hr))
{
// Party on your DirectDraw object
}
IDirectDraw is just a COM object, so you can initialize it by calling CoCreateInstance.
CoInitialize(NULL)
hr = CoCreateInstance(CLSID_DirectDraw, NULL, CLSCTX_ALL,
IID_IDirectDraw, (VOID **)&DirectDraw);
if (SUCCEEDED(hr)
{
hr = DirectDraw->Initialize(NULL);
// Party on your DirectDraw object
}
Part2
DirectX Modes
- Exclusive Mode vs Windowed Mode: determined by calling SetCooperativeLevel.
- In Exclusive mode you own the whole screen, and can set it to whatever resolution you want.
- This gives you fast access to the video buffer, so no one else is using it.
- It gives you complete control over the palette.
Here's how you go into exclusive mode:
HRESULT ddrval = DirectDraw->SetCooperativeLevel(Handle,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
For windowed mode, pass in DDSCL_NORMAL all by itself in the last parameter:
HRESULT ddrval = DirectDraw->SetCooperativeLevel(Handle, DDSCL_NORMAL);
Part2
Setting the Display Mode
- You can choose your display mode. For instance 640 X 480 or 1024 X 768 or even 320 X 200
- You can also choose your bitdepth, which can be 8, 16, 24, etc, depending on your system.
- This will work even if you are not in Exclusive mode, but it is best to be in exclusive mode.
// SetDisplayMode(Width, Height, BitDepth)
HRESULT ddrval = DirectDraw->SetDisplayMode(640, 480, 8)
Part2
Surfaces and Page Flipping
- The idea is that you can write to a back buffer while the user is looking at a second image
- When you are done drawing, Windows swaps your new picture into memory, in sync with refresh rate
- The picture appears instantly to the user, which illiminates flickering
- You can only call DirectDraw->Flip when in exclusive mode
Part
2
Calling CreateSurface
- In typical exclusive mode application you will have a Primary Surface and a Back Surface
- You can create additional surfaces, typical one for each bitmap or set of bitmaps
- The primary surface represents the area the user sees
- The back surface is an off screen buffer you can draw to, as explained later in the talk
DDSURFACEDESC SurfaceDescription;
DDSCAPS ddscaps;
SurfaceDescription.dwSize = sizeof(SurfaceDescription);
SurfaceDescription.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
SurfaceDescription.ddsCaps.dwCaps =
DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
SurfaceDescription.dwBackBufferCount = 1;
hr = DirectDraw->CreateSurface(&SurfaceDescription, &PrimarySurface, NULL);
if SUCCEEDED(hr)
{
// Get a pointer to the back buffer
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = PrimarySurface->GetAttachedSurface(&ddscaps, &BackSurface);
... // Party on
}
Part2
The DDUtil Routines
- With the DirectX SDK, in the obscure sdk\misc directory comes a small file called DDUtil.cpp
- This files contains all the missing routines you need to glue DirectX together
IDirectDrawPalette * DDLoadPalette(...);
IDirectDrawSurface * DDLoadBitmap(...);
HRESULT DDReLoadBitmap(...);
HRESULT DDCopyBitmap(...);
DWORD DDColorMatch(...);
HRESULT DDSetColorKey(...);
Part2
Palettes
- I think of 256 color mode as having a palette, while higher bit depths just have RGB values.
- In exclusive mode, you may want to work with a 256 color palette - smaller files, faster animation
- In recent months, 256 color mode is finally showing signs of becoming obsolete. Almost all the new games support larger bit depths.
- In windowed mode, you don't really have a palette, you just have X number of colors, unless you
happen to be in 256 color mode
// Get and set a palette from a bitmap
lpDDPal = DDLoadPalette(DirectDraw, szBitmap);
if (lpDDPal)
lpDDSPrimary->SetPalette(lpDDPal);
// Create an offscreen surface containing a bitmap
ADirectDrawSurface = DDLoadBitmap(DirectDraw, szBitmap, 0, 0);
if(ADirectDrawSurface == NULL )
{
return SomeErrorCode; // Exceptions handled later in talk
}
Part2
Transparent Colors
- You can specify a transparent color, or specify an index into a palette.
- In 256 color mode you specify an index into a palette
- In windowed mode, you specify the color as an RGB value
// Set the transpareent color for a bitmap:
DDSetColorKey(ADirectDrawSurface, RGB(0,0,0));
Part2
Flipping and Restoring the Focus
- In exclusive mode, the user can usually still Alt-Tab from you application
- You have to restore the surfaces when the alt tab back
- IDirectDrawSurface->Restore() is the call.
while(1)
{
HRESULT hr;
hr = lpDDSPrimary->Flip(NULL, 0);
if(hr == DD_OK)
break;
if(hr == DDERR_SURFACELOST)
{
hr = lpDDSPrimary->Restore();
if (hr != DD_OK)
break;
}
if((hr != DDERR_WASSTILLDRAWING) &&
(hr != DDERR_SURFACELOST) &&
(hr != DD_OK))
{
FActive = False;
DirectDraw->FlipToGDISurface();
throw Exception(IntToStr(hr));
}
}
Part3
Animation
- To animate sprites, you must be in a very fast loop. You need fram rates of 30 plus per second.
- A timer is not fast enough!
- I use the OnIdle event, as explained in the next section
- You can also call Application->ProcessMessages
- Demo
do {
PerformAction(); // Party on
Application->ProcessMessages();
} while (FActive);
Part3
Idle Loopers
- The application has an OnIdle event that you can hook
- This is my preferred way to handle animation in the VCL
- Always set Done to False if you want to be called again immediately
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
CoInitialize(NULL);
Application->OnIdle = IdleProc;
}
Set Done to False or you want get called again till the user does something
void __fastcall TForm1::IdleProc(TObject *Sender, bool &Done)
{
Done = False;
... // Party on.
}
Part3
Exclusive Mode Exception Handling
- If you are in exclusive mode and want to raise an exception, then call DirectDraw->FlipToGDISurface().
- Especially in the early stages, you might want to debug in windowed mode and run in exclusive mode.
- A general solution is to override the exception handler for your program:
- Don't forget to turn off "Break on Exception!", and call FlipToGDISurface in your exception handler.
- It definitely helps to debug on NT, as you can usually recover from exceptions, but not always on 98
- Remote Debugging is another important solution
Examples on DDraw1B and DDraw1C
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
CoInitialize(NULL);
Application->OnIdle = IdleProc;
Application->OnException = ExecpProc;
}
void __fastcall ExceptProc(TObject *Sender, Exception *E)
{
DirectDraw->FlipToGDISurface();
ShowMessage('Something went wrong: ' + E.Message);
}
Part3
Working with sprites
- You need to paint the sprites onto the surface in the proper order
- Therefore you paint them to the BackSurface, then call Flip
- I maintain a linked list of surfaces, and repaint each one before flipping
- You can have a Visible property, along with the X and Y location
Part3
Clippers
- Restricts output to a specific area
- Useful for moving an object in from the edge of the screen
- You don't have to restrict which part of a sprite is blited. The clipper handles it.
- You can have "cliplists": lists of clipped regions owned by IDirectDrawClipper object.
Part3