Advanced 3D Game Programming with DirectX - phần 2 doc

71 486 0
Advanced 3D Game Programming with DirectX - phần 2 doc

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

72 adapter. If you have one of these older cards, it is definitely time to get out of the Stone Age and go out and purchase a new one, especially if you are interested in development. The Direct3D object lets you do things you could never do with only the standard Windows API. For example, you can change the bit depth and the resolution of the display to any mode the card supports. You can ask the object for a list of available resolutions and select from among them. The Direct3D device object is created by the Direct3D object, which I will show you shortly. Windowed vs. Full-screen The two main modes of operation of Direct3D are windowed rendering and full-screen rendering. In windowed rendering, your application draws its graphics to the client rectangle of a regular old window, sharing space with other running applications. When your window is resized, you need to take care to resize your internal structures to adapt to the new size. The same applies when the window is moved around the screen. In addition, windowed rendering makes use of a Direct3D concept called a clipper. A clipper object keeps track of any windows that are on top of your window, so that when you draw your surface to the screen only the pixels that actually belong to the application's client rectangle are drawn. Luckily the process of handling clipping is completely handled by Direct3D, so you never have to touch it. Figure 2.8 shows the kind of issue I'm talking about. If you just drew arbitrarily to the client rectangle, you would overwrite the top left part of the Notepad application floating over the window. Figure 2.8: You can't draw just anywhere! The Direct3D Object The IDirect3D9 interface is the first interface that you will interact with when you are using DirectX Graphics. It does basically nothing except for creating the Direct3D device object, which I talked about previously. It is the device that is used to interact with the graphics hardware. Well, I kind of lied; 73 IDirect3D9 does have some functionality, but to tell you the truth in all the time I have used Direct3D, I have rarely used any of its functionality since most of it is replicated in the device object anyway. IDirect3D9 is created with the Direct3DCreate9() function, which I will show you shortly. Now, before I bring all this stuff together, let me take a moment to show you how to create surfaces. Creating Direct3D Surfaces Creating surfaces used to be a total pain before version 9.0 came out. You had to fill out massive annoying structures that contained an unbelievable amount of entries and substructures. Couple that with poor, badly structured documentation, and it was no wonder that so many people found the learning curve for DirectX Graphics so steep. Luckily these days all that is gone and all you have to do is make a simple call to a function called IDirect3DDevice9::CreateOffscreenPlain- Surface(). HRESULT CreateOffscreenPlainSurface ( UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface HANDLE* pHandle ); Table 2.5: CreateOffscreenPlainSurface parameters Width The width that you want the new surface to be, in pixels. Height The height that you want the new surface to be, in pixels. Format A member of the D3DFORMAT enumerated type, specifying the format for the surface. You can see the full list of possible values for this parameter earlier in the chapter in the table for D3DSURFACE_DESC structure. However, you will usually want to set this to D3DFMT_ A8R8G8B8 for 32-bit surfaces. For more information, see DirectX 9.0 C++ Documentation/DirectX Graphics/Direct3D C++ Reference/Enumerated Types/D3DFORMAT. 74 Pool The type of surface pool to use ppSurface Takes the address of a pointer that will be filled with the address of the newly created surface. pHandle Reserved. Set this parameter to NULL. So if you wanted to create a simple 32-bit ARGB, 640x480 surface, you could use the following code: Listing 2.1: Creating a new image surface HRESULTr=0; LPDIRECT3DSURFACE9 pSurface = 0; r = g_pDevice->CreateOffscreenPlainSurface( 640, 480, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pSurface, NULL ); if( FAILED(r)) { // Error } // Success! When you are finished with a surface that uses a large amount of resources, don't forget to release it using the IDirect3DSurface9::Release() function, like this: pSurface->Release(); pSurface = 0; More on Direct3D Devices There are two pieces of code running in Direct3D applications. The first is the extremely thin layer that takes requests to blit surfaces, for example, and converts those into hardware instructions for the video 75 card to perform. This thin layer that wraps the hardware, abstracting it away, is called the hardware abstraction layer (HAL). In the event that a desired effect in Direct3D is not supported by the HAL, usually it is handled by a larger piece of code that emulates what the hardware would do, actually performing the work with the CPU. This layer is called the hardware emulation layer (HEL). The HEL can be considerably slower than the HAL, both because it isn't asynchronous and because it needs to use the CPU to do its dirty work, which isn't specialized for graphics operations. Any piece of hardware that can accelerate 3D graphics will support the subset of Direct3D (which, essentially, is just surface blits and filled blits). If you plan on using more esoteric features, you should check the device capabilities. This can be done using IDirect3DDevice9::GetDeviceCaps(). There isn't space to cover the function or the structure of capability bits it fills up because it is literally massive. However, if you are feeling motivated, you can check this bad boy out in DirectX 9.0 C++ Documentation/ DirectX Graphics/Reference/Direct3D C++ Reference/Interfaces/IDirect3D- Device9/GetDeviceCaps in the online documentation. Implementing Direct3D with cGraphicsLayer To implement Direct3D I'm going to create a class called cGraphicsLayer. Like cApplication, it is a class that can only have one instance. In creating this class, there are several abilities that it should possess:  Initialization of full-screen Direct3D should be automatic.  It should be easy to get access to the Direct3D objects if need be, but that need should arise as rarely as possible.  You should be able to initialize Direct3D with the primary display adapter. Let's dive into the code. First, have a look at the header file DxHelper.h, which helps simplify some of the programming tasks. Listing 2.2: DxHelper.h /******************************************************************* * Advanced 3D Game Programming using DirectX 9.0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Desc: Sample application for Direct3D * * copyright (c) 2003 by Peter A Walsh and Adrian Perez * See license.txt for modification and distribution information ******************************************************************/ 76 #ifndef _D3DHELPER_H #define _D3DHELPER_H #include <memory.h> /** * This class takes care of the annoying gruntwork * of having to zero-out and set the size parameter * of our Windows and DirectX structures. */ template <class T> struct sAutoZero : public T { sAutoZero() { memset( this, 0, sizeof(T) ); dwSize = sizeof(T); } }; /** * The Right Way to release our COM interfaces. * If they're still valid, release them, then * invalidate them and null them. */ template <class T> inline void SafeRelease( T& iface ) { if( iface ) { iface->Release(); iface = NULL; 77 } } #endif // _D3DHELPER_H The interface for the graphics layer appears in GraphicsLayer.h, which is given in Listing 2.3. Listing 2.3: GraphicsLayer.h /******************************************************************* * Advanced 3D Game Programming using DirectX 9.0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Desc: Sample application for Direct3D * * (C) 2003 by Peter A Walsh and Adrian Perez * See license.txt for modification and distribution information ******************************************************************/ #ifndef _GRAPHICSLAYER_H #define _GRAPHICSLAYER_H #include <list> #include <string> using std::string; using std::list; #include "GameTypes.h" #include "DxHelper.h" #include <d3d9.h> class cApplication; 78 class cGraphicsLayer { protected: HWND m_hWnd; // The handle to the window LPDIRECT3D9 m_pD3D; // The IDirect3D9 interface LPDIRECT3DDEVICE9 m_pDevice; // The IDirect3DDevice9 interface LPDIRECT3DSURFACE9 m_pBackSurf; // Pointer to the back buffer RECT m_rcScreenRect; // The dimensions of the screen cGraphicsLayer( HWND hWnd ); // Constructor static cGraphicsLayer* m_pGlobalGLayer; // Pointer to main global gfx object public: void DestroyAll(); ~cGraphicsLayer(); /** * Initialization calls. */ void InitD3DFullScreen( GUID* pGuid, int width, int height, int bpp ); /** * This function uses Direct3DX to write text to the back buffer. * It's much faster than using the GDI */ 79 void DrawTextString( int x, int y, DWORD color, const char * str ); //========== Accessor functions // Gets a pointer to the IDirect3D9 LPDIRECT3D9 GetD3D() { return m_pD3D; } // Gets a pointer to the device LPDIRECT3DDEVICE9 GetDevice() { return m_pDevice; } // Gets a pointer to the back buffer LPDIRECT3DSURFACE9 GetBackBuffer() { return m_pBackSurf; } // Gets the screen width int Width() const { return m_rcScreenRect.right; } // Gets the screen height int Height() const { return m_rcScreenRect.bottom; } // Presents the back buffer to the primary surface void Flip(); // Gets a pointer to the main gfx object static cGraphicsLayer* GetGraphics() { return m_pGlobalGLayer; } 80 // Initializes this object static void Create( HWND hWnd, // handle to the window short width, short height, // width and height GUID* pGuid ); // Device guid }; inline cGraphicsLayer* Graphics() { return cGraphicsLayer::GetGraphics(); } #endif //_GRAPHICSLAYER_H GraphicsLayer.cpp is pretty long, so I'll show it to you step by step. There are a few functions that don't deal with initialization, which I'll list here. The first is a helper function used to draw text onto a Direct3D surface (such as the back buffer). It uses the D3DX utility COM object ID3DXFont to display the text. Listing 2.4: cGraphicsLayer::DrawTextString void cGraphicsLayer::DrawTextString( int x, int y, DWORD color, const char * str ) { HRESULTr=0; if( !m_pBackSurf ) return; // Get a handle for the font to use HFONT hFont = (HFONT)GetStockObject( SYSTEM_FONT ); LPD3DXFONT pFont = 0; 81 // Create the D3DX Font r = D3DXCreateFont( m_pDevice, hFont, &pFont ); if( FAILED(r)) return; // Rectangle where the text will be located RECT TextRect={x,y,0,0}; // Inform font it is about to be used pFont->Begin(); // Calculate the rectangle the text will occupy pFont->DrawText( str, -1, &TextRect, DT_CALCRECT, 0 ); // Output the text, left aligned pFont->DrawText( str, -1, &TextRect, DT_LEFT, color ); // Finish up drawing pFont->End(); // Release the font pFont->Release(); } The other function not covered by the initialization code is Flip(). It is called when you are finished rendering the frame to the back buffer. Flipping is accomplished with a call to IDirect3DDevice9::Present(), which takes no parameters. Listing 2.5: cGraphicsLayer::Flip void cGraphicsLayer::Flip() [...]... standard, full-screen, 640x480, 3 2- bit application: Listing 2. 7: Filling in the D3DPRESENT_PARAMETERS structure D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof( d3dpp ) ); // The width and height for the initial back buffer d3dpp.BackBufferWidth = width; d3dpp.BackBufferHeight = height; // Set the flags for the bit depth - only supports 1 6-, 2 4-, and 3 2- bit formats if( bpp == 16 ) d3dpp.BackBufferFormat... D3DFMT_R5G6B5; else if( bpp == 24 ) d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; else if( bpp == 32 ) d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; else { OutputDebugString( "Invalid surface format - defaulting to 32bit"); d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; } 86 // Only have one back buffer associated with the primary surface d3dpp.BackBufferCount = 1; // No multisampling d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;... ZeroMemory( &d3dpp, sizeof( d3dpp ) ); // The width and height for the initial back buffer d3dpp.BackBufferWidth = width; d3dpp.BackBufferHeight = height; // Set the flags for bit depth - only supports 16, 24 , and 32 bit formats if( bpp == 16 ) d3dpp.BackBufferFormat = D3DFMT_R5G6B5; else if( bpp == 24 ) d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; else if( bpp == 32 ) d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;... Listing 2. 9: Direct3D full-screen initialization in cGraphicsLayer void cGraphicsLayer::InitD3DFullScreen (GUID* pGuid, int width, int height, int bpp ) { 89 HRESULTr=0; // Create the Direct3D object m_pD3D = Direct3DCreate9( D3D_SDK_VERSION ); if( !m_pD3D ) { throw cGameError( "Could not create IDirect3D9" ); } // Structure to hold the creation parameters for the device D3DPRESENT_PARAMETERS d3dpp;... wrapped-up function called Direct3DCreate9(): IDirect3D9* Direct3DCreate9( UINT SDKVersion ); Table 2. 6: Direct3DCreate9 parameters SDKVersion An identifier specifying the version of Direct3D that you are using You should always specify D3D_SDK_VERSION for this parameter, which automatically contains the correct version // Create the Direct3D object m_pD3D = Direct3DCreate9( D3D_SDK_VERSION ); if( !m_pD3D... device with software vertex processing you could use the following code: Listing 2. 8: Creating the device // Create the device using hardware acceleration if available r = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_pDevice ); if( FAILED(r)) { throw cGameError( "Could not create IDirect3DDevice9" ); } In previous versions of DirectX. .. surface format - defaulting to 32bit" ); d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; } // Only have one back buffer associated with the primary surface 90 d3dpp.BackBufferCount = 1; // No multisampling d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; // The quality of the multisampling d3dpp.MultiSampleQuality = 0; // Copy the back buffer to the primary surface normally d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;... d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Allow the back buffer to be locked d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; // Create the device using hardware acceleration if available r = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_pDevice ); if( FAILED(r)) { throw cGameError( "Could not create IDirect3DDevice9" ); }... include all of the source code for it This appears in Listing 2. 12 Listing 2. 12: DDSample.cpp /******************************************************************* * Advanced 3D Game Programming using DirectX 9.0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Desc: Sample application for Direct3D * * copyright (c) 20 03 by Peter A Walsh and Adrian Perez * See license.txt for modification... rand() %25 5, rand() %25 5 ); // Draw the rectangle (i.e., clear a rectangle to a color) Graphics( )-> GetDevice( )-> Clear( 1, (D3DRECT*)&Rect, D3DCLEAR_TARGET, Color, 1.0f, 0 ); } // Unlock the back surface Very important to do this! pBackSurf->UnlockRect(); pBackSurf = 0; // - PART 3: Output text to the back surface // Tell Direct3D we are about to start rendering through Direct3D Graphics( )-> GetDevice( )-> BeginScene(); . out in DirectX 9.0 C++ Documentation/ DirectX Graphics/Reference/Direct3D C++ Reference/Interfaces/IDirect3D- Device9/GetDeviceCaps in the online documentation. Implementing Direct3D with cGraphicsLayer. standard, full-screen, 640x480, 3 2- bit application: Listing 2. 7: Filling in the D3DPRESENT_PARAMETERS structure D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof( d3dpp ) ); . back buffer d3dpp.BackBufferWidth = width; d3dpp.BackBufferHeight = height; // Set the flags for the bit depth - only supports 1 6-, 2 4-, and 3 2- bit formats if( bpp == 16 ) d3dpp.BackBufferFormat

Ngày đăng: 08/08/2014, 23:20

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan