Sample Chapter
Total Page:16
File Type:pdf, Size:1020Kb
06 6612 ch03 11/4/04 11:00 AM Page 35 CHAPTER 3 Understanding the Sample Framework Now that the idea is complete, the object model has enough information, and you’ve laid out the specification, you’re almost ready to jump into what you’ve been waiting for: actually writing the code for the game. Normally, you would need to write a lot of “boilerplate” code before you begin this development, which would include such things as enumerat- ing through the devices on your system and picking the most appropriate one to render your scene, as well as creating and maintaining this device. Because the DirectX SDK Summer 2004 Update now includes a robust sample framework that is designed to be used directly by your code and that handles much of this work for you, you can save yourself a lot of time and hassle by simply using that. The examples in this book use this sample framework, so you will spend this chapter examining it. In this chapter, you'll learn . How to create your project . How to use the sample framework to enumerate devices Creating Your Project Construction For the rest of this book, I assume that you are using Visual Studio .NET Cue 2003 for all your development needs. If you do not want to use this envi- ronment, you can look back to Chapter 1, “Game Development and Managed Code,” to see the discussion on compiling code on the command line, which allows you to use any text editor or integrated development envi- ronment (IDE) you want. All the sample code included with the CD has an accompanying Visual Studio .NET 2003 project and solution file for easy loading. 06 6612 ch03 11/4/04 11:00 AM Page 36 36 Chapter 3 Go ahead and load up Visual Studio .NET 2003, and click the New Project button on the start page. If you do not use the start page, click the Project item under the New submenu on the File menu, or use the shortcut Ctrl+Shift+N. Choose the Windows Application item under the Visual C# Projects section. (See Figure 1.3 in Chapter 1 for a reminder of what this dialog looks like.) Name this project Blockers because that is what the name of the game will be. Before you start looking at the code that was automatically generated, first add the code files for the sample framework into your project. Normally, I put these files into a separate folder by right-clicking on the project in the solution explorer and choosing New Folder from the Add menu. Call this folder Framework. Right- click on the newly created folder and this time choose Add Existing Item from the Add menu. Navigate to the DirectX SDK folder, and you will find the sample framework files in the Samples\Managed\Common folder. Select each of these files to add to your project. With the sample framework added to the project now, you can get rid of the code that was automatically generated. Most of it is used to make fancy Windows Forms applications, so it’s irrelevant to the code you will be writing for this game. Replace the existing code and class (named Form1) with the code in Listing 3.1. LISTING 3.1 The Empty Framework using System; using System.Configuration; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; using Microsoft.Samples.DirectX.UtilityToolkit; public class GameEngine : IDeviceCreation { /// <summary> /// Entry point to the program. Initializes everything and goes into a /// message processing loop. Idle time is used to render the scene. /// </summary> static int Main() { using(Framework sampleFramework = new Framework()) { return sampleFramework.ExitCode; } } } Three things should stand out from this new code. First, you’ll notice that every- thing was removed, with the exception of the static main method, which was modified. The rest of the code was support code for the Windows Form designer. 06 6612 ch03 11/4/04 11:00 AM Page 37 Understanding the Sample Framework 37 Because you won’t be using that designer for this application, the code isn’t rele- vant and can be removed. Second, this code won’t compile because the two inter- faces the game engine class is supposed to implement haven’t been implemented yet. Third, the code doesn’t actually do anything. Before you begin fixing those last two problems, you’ll need to add some refer- ences. Because you will be rendering fancy 3D graphics during this project, you probably need to add references to an assembly capable of doing this rendering. This book focuses on using the Managed DirectX assemblies to do this work, so in the Project menu, click Add Reference. It brings up a dialog much like you see in Figure 3.1. FIGURE 3.1 The Add Reference dialog. If you have the Summer 2004 SDK update of DirectX 9 installed (which you should because the code in this book requires it), you notice that there might be more than one version of each of the Managed DirectX assemblies. Pick the latest version (marked with version 1.0.2902.0). For this project, you add three different assemblies to your references: . Microsoft.DirectX . Microsoft.DirectX.Direct3D . Microsoft.DirectX.Direct3DX 06 6612 ch03 11/4/04 11:00 AM Page 38 38 Chapter 3 The root DirectX assembly contains the math structures that help formulate any computations needed for the rendering. The other two assemblies contain the functionality of Direct3D and D3DX, respectively. With the references added, you should look briefly at the using clause you added in Listing 3.1 to make sure that the namespaces referenced as well. This step ensures that you don’t have to fully qualify your types. For example, without adding the using clause, to declare a variable for a Direct3D device, you would need to declare it as Microsoft.DirectX.Direct3D.Device device = null; The using clauses allow you to eliminate the majority of this typing. (No one wants to type all that stuff for every single variable you would be declaring.) Because you’ve already added the using clauses, you could instead declare that same device in this way: private Device device = null; As you can see, declaring the device in this way is much easier. You’ve saved yourself an immense amount of typing. With these few things out of the way, now you begin to fix the compilation errors in the application and get ready to write your first 3D game. The only interface you’ve currently got to implement is IDeviceCreation, which is designed to let you control the enumeration and cre- ation of your device. You might be thinking, “Enumerating devices? I’ve only got one monitor!” Although most top-of-the-line, modern graphics cards actually do support multi- ple monitors (multimon for short), even if you have only a single device, you still have many different modes to choose from. The format of the display can vary. (You might have even seen this variety in your desktop settings on the Windows desktop, as in 16-bit or 32-bit colors.) The width and height of the full-screen modes can have different values, and you can even control the refresh rate of the screen. All in all, there are quite a few things to account for. To fix the compilation errors in the application, add the code in Listing 3.2. LISTING 3.2 Implementing the Interface /// <summary> /// Called during device initialization, this code checks the device for a /// minimum set of capabilities and rejects those that don’t pass by /// returning false. /// </summary> public bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool windowed) { // Skip back buffer formats that don’t support alpha blending 06 6612 ch03 11/4/04 11:00 AM Page 39 Understanding the Sample Framework 39 LISTING 3.2 Continued if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType, adapterFormat, Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backBufferFormat)) return false; // Skip any device that doesn’t support at least a single light if (caps.MaxActiveLights == 0) return false; return true; } /// <summary> /// This callback function is called immediately before a device is created /// to allow the application to modify the device settings. The supplied /// settings parameter contains the settings that the framework has selected /// for the new device, and the application can make any desired changes /// directly to this structure. Note however that the sample framework /// will not correct invalid device settings so care must be taken /// to return valid device settings; otherwise, creating the device will fail. /// </summary> public void ModifyDeviceSettings(DeviceSettings settings, Caps caps) { // This application is designed to work on a pure device by not using // any get methods, so create a pure device if supported and using HWVP. if ( (caps.DeviceCaps.SupportsPureDevice) && ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) ) settings.BehaviorFlags |= CreateFlags.PureDevice; } Look at the first method you declared, the IsDeviceAcceptable method. While the sample framework is busy enumerating the devices on the system, it calls this method for every combination it finds. Notice how the method returns a bool value? This is your opportunity to tell the sample framework whether you consid- er this device acceptable for your needs. Before you look at the code in that first method, however, notice the second method that’s been declared, ModifyDeviceSettings. This method is called by the sample framework immedi- ately before the device is created, allowing you to tweak any options you want. Be careful with the options you choose because you could cause the device creation to fail. Now, back to that first method: first take a look at the parameters that it accepts.