
Introduction
Welcome to my first tutorial on Managed DirectX, included with DirectX 9 SDK. Most C# developers were waiting for this release. Before Managed DirectX, C# developers were using DirectX via COM Interop of DirectX 7 or 8 VB component. The new Managed DirectX components offers best performance and easier programming over DirectX COM Interop. This tutorial is for newcomers in DirectX development, like me, or for people who were using COM Interop for DirectX development.
In this tutorial, we will make a clone of Super Metroid game called Managed Metroid. We will try to use all the components of Managed DirectX (DirectDraw, DirectSound, DirectInput, Direct3D, DirectPlay and AudioVideoPlayback). In part 1, we will start with basic DirectDraw implementation by showing the title screen and text in full screen.
Requirements
These articles require some knowledge of C#. Also a basic game development background would be useful.
Software requirements:
- Microsoft Windows NT4 SP6, Windows 2000, Windows XP Pro (for compiling only)
- Visual C# .NET or Visual Studio .NET
- DirectX 9 SDK Full or only C# Part (available from Microsoft
- Image editing tool (optional but useful)
- SNES Emulator with Super Metroid ROM (optional)
The Title Screen
Adding DirectX namespaces to the project
Add the references to Microsoft.DirectX.dll and Microsoft.DirectX.DirectDraw.dll to your project and add these namespaces to the project.
using Microsoft.DirectX;
using Microsoft.DirectX.DirectDraw;
Adding DirectX variables
First of all, we need to create a DirectDraw device. After that, we create the Surface
s. A Surface
is a part of memory where you draw the needed stuff; it also acts like a layer. The Clipper
is the boundaries you set to the device, so the device will not draw over the Clipper
. The back
Surface
represents the BackBuffer
. The title
and text
represents the layers of the title screen. Finally, the titlescreen
string point to the bitmap to load into title
Surface
.
private Device display;
private Surface front = null;
private Surface back = null;
private Surface title = null;
private Surface text = null;
private Clipper clip = null;
string titlescreen = Application.StartupPath + "\\title.bmp";
Initialize DirectDraw
For initializing any Managed DirectX component, I suggest you to create methods for each component you use. Here is the method I used to init my DirectDraw
stuff.
private void InitDirectDraw()
{
SurfaceDescription description = new SurfaceDescription();
display = new Device();
#if DEBUG
display.SetCooperativeLevel(this, CooperativeLevelFlags.Normal);
#else
display.SetCooperativeLevel(this,
CooperativeLevelFlags.FullscreenExclusive);
display.SetDisplayMode(640, 480, 16, 0, false);
#endif
description.SurfaceCaps.PrimarySurface = true;
#if DEBUG
front = new Surface(description, display);
#else
description.SurfaceCaps.Flip = true;
description.SurfaceCaps.Complex = true;
description.BackBufferCount = 1;
front = new Surface(description, display);
#endif
description.Clear();
#if DEBUG
description.Width = front.SurfaceDescription.Width;
description.Height = front.SurfaceDescription.Height;
description.SurfaceCaps.OffScreenPlain = true;
back = new Surface(description, display);
#else
SurfaceCaps caps = new SurfaceCaps();
caps.BackBuffer = true;
back = front.GetAttachedSurface(caps);
#endif
clip = new Clipper(display);
clip.Window = this;
front.Clipper = clip;
description.Clear();
title = new Surface(titlescreen, description, display);
description.Clear();
description.Width = 600;
description.Height = 16;
description.SurfaceCaps.OffScreenPlain = true;
text = new Surface(description, display);
text.ColorFill(Color.Black);
text.ForeColor = Color.White;
text.DrawText(0, 0,
"Managned DirectX Tutorial 1 - Press Enter or Escape to exit",
true);
}
The Draw method
The Draw
is called each time we need to draw the content of the Surface
to the screen.
private void Draw()
{
if (front == null)
{
return;
}
if(this.WindowState == FormWindowState.Minimized)
{
return;
}
try
{
back.DrawFast(0, 0, title, DrawFastFlags.Wait);
back.DrawFast(10, 10, text, DrawFastFlags.Wait);
#if DEBUG
front.Draw(back, DrawFlags.Wait);
#else
front.Flip(back, FlipFlags.Wait);
#endif
}
catch(WasStillDrawingException)
{
return;
}
catch(SurfaceLostException)
{
RestoreSurfaces();
}
}
The RestoreSurfaces method
The RestoreSurfaces
method is called when the user defocus the application and then refocus the application (like an Alt-Tab switch).
private void RestoreSurfaces()
{
SurfaceDescription description = new SurfaceDescription();
display.RestoreAllSurfaces();
text.ColorFill(Color.Black);
text.DrawText(0, 0,
"Managned DirectX Tutorial 1 - Press Enter or Escape to exit",
true);
title.Dispose();
title = null;
title = new Surface(titlescreen, description, display);
return;
}
The Final touch
At last, add the method InitDirectDraw
to the constructor. Also implement the main loop of the application where the Draw
method is used. Application.DoEvents()
makes the application, process the messages event if the application is in a loop.
public Tutorial1()
{
InitializeComponent();
InitDirectDraw();
this.Cursor.Dispose();
this.Show();
while(Created)
{
Draw();
Application.DoEvents();
}
}
Made a change to the Main
method. Application.Run
method doesn't work in this context. You need to create the form by yourself.
static void Main()
{
Tutorial1 app = new Tutorial1();
Application.Exit();
}
The KeyUp
event, is used to quit the Tutorial
.
private void Tutorial1_KeyUp(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if(e.KeyCode == Keys.Escape || e.KeyCode == Keys.Enter)
this.Close();
}
Conclusion
In this tutorial, we learned how to show a bitmap in full screen using DirectDraw
with Managed DirectX. The next tutorial will be on sprite animation and background music with AudioVideoPlayback
. If you have any comments, suggestions, code corrections, please make me a remark in the bottom of the article.
History
Update 1.1
- Fixed drawing on slower machines
- Separated code for Debug and Release, suggestion by kalme
- Release version more faster, doing a flip instead of a drawing
Update 1.0