DirectX8 under the MFC architecture

zhaozj2021-02-08  307

DirectX8 under the MFC architecture

Chapter 1 MFC framework

(DX8MFC)

The MFC framework here refers to a framework that conforms to the game development application, of course, you can also write a MFC framework that meets your requirements. If you are familiar with MFC, you can start reading from the second chapter. This framework is the basis of several examples. If you don't know much about MFC, you must read this chapter carefully to seek a deep understanding of this MFC framework.

Two classes include two classes:

CDX8MFCAPP classes and CFraMewIN classes, CDX8MFCAPP classes are application classes, and the CFraMewIN class is the main class of the framework. Most of our code is extended here. First take a look at the CDX8MFCAPP class, including CDX8MFCAPP (), EXITINSTANCE (), INITINSTANCE (), ONIDE (long lcount) and other member functions and a GAME object.

The initInstance () member function is called when the program is initialized, here I built a window:

BOOL CDX8MFCAPPPPPPPPPPPPPPPPPPPPPPPP :: InitInstance ()

{

// The one and only window has been initialized, so show and update it.

m_pmainwnd = new cframewin ();

m_pmainwnd-> showwindow (m_ncmdshow);

m_pmainwnd-> UpdateWindow ();

Game = (cframewin *) m_pmainwnd;

Game-> init ();

Return True;}

The EXITINSTANCE () member function is called when the program is terminated, here we release some objects and pointers: int CDX8MFCapp :: EXITINSTANCE () {// Todo: add your specialized code here and / or call the base class game-> end ( DELETE GAME;

Return CWINAPP :: EXITINSTANCE ();

The onIdle (long lcount) member function is called when there is no Windows message to handle, that is, the onIdle () member function is constantly called, which is just as a game cycle. BOOL CDX8MFCApp :: OnIdle (LONG lCount) {// TODO: Add your specialized code here and / or call the base class if (Game-> window_active == TRUE) {Game-> Active (); Game-> window_active = FALSE }

Game-> Go ();

Return True;}

The Game object is a CFRAMEWIN pointer, we created a CFraMewin object in the initInstance () member function and assigned a pointer value of the CFraMewin object to GAME. Let's take a look at the CFraMewIn class, including active (), end (), go (), init (), update (), etc. member functions. INIT () member function, you can do some of your own initialization here. Retrospecting the initInstance () member function of the CDX8MFCAPP class. Game-> init () in the initInstance () member function is called after completing the window initialization, that is, init () is called after the window is initialized. Void cframewin :: init () {AFXMessageBox ("init");}

The Go () member function will continue to be called, which calls Update () and DestroyWindow (). Update () is used to update the window, calling DestroyWindow (), will end the application. If you delete the DestroyWindow () statement, the program will constantly loop. Void cframewin :: go () // Game loop {AFXMessageBox ("go"); Update (); design;} Active () member function is called when the application is hit. Void cframewin :: active () // window activated {trace ("Active / N"); AFXMESSAGEBOX ("Active");}

This program does not do anything, just an MFC framework. You can download an example of the example from http://gamedev.363.net, or by e-mail: laical@21cn.com.

Chapter II Initialization DirectX8 (DX8MFC1) This example will expand the CFraMewIN class based on the MFC framework of the first chapter. Mainly joined DrawScene (), initdirect3d (hwnd hwnd), and three functions of ShutDowndirect3D (). The initdirect3d function is initialized to Direct3D: HRESULT CFRAMEWIN :: InitDirect3D (hwnd hwnd) {pid3d = direct3dcreate8 (d3d_sdk_version);

HRESULT hr; do {// we need the display mode so we can get the properties of our back buffer D3DDISPLAYMODE d3ddm //; hr = pID3D-> GetAdapterDisplayMode (D3DADAPTER_DEFAULT, & d3ddm); if (FAILED (hr)) break;

D3DPresent_Parameters Present; ZeromeMory (& present); present.swapeffect = d3dswapeffect_copy; present.windowed = true; present.backbufferformat = d3ddm.format;

HR = PID3D-> CreateDevice (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, HWND, D3DCREATE_SOFTWARE_VERTEXPROCESSING, & present, & PID3DDEVICE);

IF (Failed (HR)) BREAK;

// We dour w coloring, so disable lighting hr = pid3ddevice-> setrenderstate (D3DRS_Lighting, False);

} while (0);

Return HR;} iDirect3d is the first interface we have to use, you can write: iDirect3d8 * pid3d = Direct3dcreate8 (D3D_SDK_VERSION); before you use PID3D, check if PID3D is non-empty. Your next step is usually created a D3D device, but you want to call the getadapterdisplayMode method before creating a D3D device: D3DDisplayMode D3DDM; PID3D-> GetAdapterDisplayMode (D3DADAPTER_DEFAULT, & D3DDM); Next is the current display mode parameter. The following parameters are the Surface format. You can use these parameters to create a structure D3DPRESENT_PARAMETERS: D3DPRESENT_PARAMETERS present; ZeroMemory (& present, sizeof (present)); present.SwapEffect = D3DSWAPEFFECT_COPY; present.Windowed = TRUE; present.BackBufferFormat = d3ddm.Format; D3DPRESENT_PARAMETERS describes the display of Surface Information, switching mechanism type, application is a window or full screen mode. In this example, Surface is flipped in a copy method because it is an application of a window mode. Set the background surface into the format that matches the current display mode, a prepared Surface can DRAW on the background surface.

Now you can create an interface to the IDirect3DDevice8: pID3D-> CreateDevice (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, & present, & pID3DDevice); This function has six parameters, fortunately no one is quite complex. D3DADAPTER_DEFAULT tells Direct3D to use the main display, only when you use multiple displays. You can use a value to specify another display. Calling IDirect3D getAdapterCount will return the number of adapters for the system. The second parameter, D3DDEVTYPE_HAL tells Direct3D to use hardware acceleration. Other options include D3DDEVTYPE_REF and D3DDEVTYPE_SW, usually you want to use hardware acceleration, but sometimes you may use software acceleration to test. The specified window acquires the focus. If you are a full screen application, you need a top-level window. D3DCREATE_SOFTWARE_VERTEXPROCESSING Specifies the vertex processing type. You can also use hardware acceleration or a joint type, I don't use hardware acceleration to extensive compatibility. If you want to support T & L, you must use hardware acceleration. The last two parameters are very simple, one is the previously established, and Pid3DDevice is the IDirect3DDevice8 interface you want to create now. If the method returns D3DERR_NOTAVAILABLE, the parameters you write are correct, but your device does not support the parameters you specified. The most perfect is this method automatically creates Back Buffers and DePth Buffers (DEPTH BUFFERS). Clarge (Clipping) is automatically activated as a backface cooling. The light is also automatically activated until you define the vertex color before you can use the light: PID3DDevice-> setrenderstate (D3DRS_Lighting, False); DrawScene () function: hResult cframewin :: DrawScene () {HRESULT HR; do {// Clear Back Buffer HR = PID3DDevice-> Clear (0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA (0, 63, 0, 0), 0, 0); IF (Failed (HR)) Break;

// start drawing hr = pid3ddevice-> beginscene (); if (Failed (HR)) Break;

// Put All Drawing Code Here

HR = pid3ddevice-> endscene (); if (Failed (HR)) Break;

// Flip back buffer to front hr = pid3ddevice-> present (null, null, null, null);} while (0); returnh HR;}

Clear will populate the buffer you specified. You can populate the Z buffer, the background buffer or tattoo buffer buffer. In this example you will use green to fill the background buffer. So, we set the D3DCLEAR_TARGET logo and green. In this example, Beginscene and Endscene did not do anything, but we will use it in the later example. These two functions are routine codes when drawing chart, which is constantly flipping the background surface. We can keep some things on the background surface, then turn the background surface to the front desk.

ShutdownDirect3D () function void CFrameWin :: ShutdownDirect3D () {HELPER_RELEASE (pTexture); HELPER_RELEASE (pIndexBuffer); HELPER_RELEASE (pStreamData); HELPER_RELEASE (pID3DDevice); HELPER_RELEASE (pID3D);} ShutdownDirect3D release all interfaces. In the future, you may have to join additional code to close the Direct3D interface, but now it is enough. If you run the program, you will get a window on a green background. You can use the "ESC" button to exit the application.

The third chapter draws a triangle (DX8MFC2) Defines your vertex format, Direct3D introduces a deformable vertex format (FVF) concept. In FVF, you define a structure in which the required vertex components are included. This structure changes as your program, but here you will initially define it as this: struct myvertex {float x, y, z; // the transformed position float rhw; // 1.0 (Reciprocal of Homogeneous W DWORD color; // the Vertex Color}; Example The beginning defines a vertex structure, the name of the vertex, and the vertices of each triangle. In your InitDirect3D function, you must create a vertex buffer: int num_elems = sizeof (vertices) / sizeof (vertices [0]); pID3DDevice-> CreateVertexBuffer (sizeof (MYVERTEX) * num_elems, D3DUSAGE_WRITEONLY, D3DFVF_XYZRHW | D3DFVF_DIFFUSE, D3DPOOL_DEFAULT & Pstreamdata); The first parameter of the function is the byte size of the vertex structure. A D3DUSAGE_WRITEONLY tag is sent to it before the application cannot read the vertices. Here you can have different tags to specify how to handle your vertices, but now you can confirm that Direct3D has been working correctly. Next, specify what we use the FVF format. The D3DFVF_XYZRHW tag is specified before you have not used the coordinate system pre-conversion. When you use your own matrix coordinate system to convert it to D3DFVF_XYZ. D3DFVF_DIFFUSE tells Direct3D, we will specify a color for each vertex. D3DPOOL_DEFAULT Specifies the management mode of the memory. The last parameter is a pointer to the vertex buffer, you have defined it in Example 1, but it is not used. If you don't fill in useful data, the vertex buffer is useless: myvertex * v; pstreamdata-> lock (0, 0, (byte **) & v, 0); for (int II = 0 ii unlock (); this is not difficult to understand, Lock Returns a write Pointer for vertex data. Next, you copy data from your vertex array. Then, refund this pointer. This pair can tell Direct3D your FVF format and set the vertex array as the current active vertex array. (You can have multiple vertices arrays). PID3DDEVICE-> SetvertexShader (D3DFVF_XYZRHW | D3DFVF_DIFFUSE);

Pid3DDevice-> setStreamSource (0, pstreamdata, sizeof (myvertex)); setVertexShader tells Direct3D to use the same format as CreatevertExBuffer. SetStreamSource told Direct3D to use PStreamData as the current vertex array and get the size of all elements. You can now add a code of the triangle. Between DrawScene () and the BeginScene EndScene adding the following code: int num_elems = sizeof (vertices) / sizeof (vertices [0]); pID3DDevice-> DrawPrimitive (D3DPT_TRIANGLELIST, 0, num_elems / 3); D3DPT_TRIANGLELIST tag command Direct3D Videos Discontinuous triangle. You specify starting from the 0th vertex of the index, specify the number of triangles you want to draw. If you do it correctly, you will see a triangular painting on the previous green background window.

The fourth chapter draws the drawn triangle (DX8MFC3) The drawing triangle operation efficiency is lower, and in fact, we will use DrawIndexedPrimitive () instead of DrawPrimitive (). Think about it, if you want to draw two connected triangles, there are four vertices. DrawindexedPrimitive () draw four vertices, and drawprimitive () draws six vertices. If you can build an index at the vertices, you can draw triangles with DrawIndexedprimitive (). We can establish such an index for a triangle: Word INDICES [] = {0, 1, 2}; it represents the triangular, the first vertex corresponds to the 0 top point of the vertex array; in the triangle, the second vertex corresponds In the first top of the vertex array; in the triangle, the third vertex corresponds to the second top point of the vertex array; to draw the triangle, first establish an index buffer: num_lems = sizeof (indices) / sizeof (INDICES [0] ); pID3DDevice-> CreateIndexBuffer (sizeof (WORD) * num_elems, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, & pIndexBuffer); second step is filled with the index vertex buffer: WORD * pIndex; pIndexBuffer-> Lock (0, 0, (BYTE * *) & pindex, 0); for (ii = 0; II UNLOCK (); Set Index Cushion: PID3DDevice-> Setindices (PindexBuffer, 0); convert DrawScene () to PID3DDEVICE-> DRAWPRIMITIVE (...): PID3DDevice-> DrawIndexedprimitive (D3DPT_TRIANGLIST, 0, SIZEOF (INDES) / SIZEOF (INDICES [0]), 0, SIZEOF (Indices) / sizeof (INDICES [0]) / 3); Run the program or a triangle. Chapter 5 Join Posts (DX8MFC4) First, add posts coordinate tu and TV in the MyVertex structure, and assign the vertex array with an appropriate value. Next, set your post: D3DXCREATEXTUREFROMFILE (PID3DDevice, "DX5_LOGO.BMP", & PTexture); pid3ddevice-> settexture (0, ptexture); "DX5_LOGO.BMP" refers to the post file, you can use other Instead of it, run the program you will see a triangle with a post.

Chapter VI Tap Cube (DX8MFC5) Now let's enter the three-dimensional world! Here you have to enable z-buffer, set the material, the world coordinate system, and projection coordinate system. Enable Z-buffer (z-buffer), you want to join in D3DPRESENT_PARAMETERS structure: present.EnableAutoDepthStencil = TRUE; present.AutoDepthStencilFormat = D3DFMT_D16; DirectX8 used here to tell the 16-bit Z-buffer, the next step: pID3DDevice-> SetRenderState (D3DRS_ZENABLE, TRUE The z buffered here has been set. Finally, you have to call the code to clear Z buffer content in DrawScene (): PID3DDevice-> Clear (0, NULL, D3DCLEAR_TARGET | D3DCLOR_ZBUFFER, D3DCOLOR_RGBA (0, 0, 0), 1.0, 0); MYVERTEX structure is changed : Struct MyVERTEX {Float X, Y, Z; // The Transformed Position DWORD COLOR; // The Vertex Color Float Tu, Tv; // Texture Coordinates}; in InitDirect3D (), the corresponding change is made, specific visible source code. There are several matrices in Direct3D, only three of them: world, view, and projection matrices. The world matrix transformation will put the square in the world coordinate system, and the view matrix transform puts the square in the visual space, and the projection matrix makes the square look deep. BuildMatrices () function will create these three matrices: void CFrameWin :: BuildMatrices () {D3DXMATRIX matrix; D3DXMatrixRotationY (& matrix, timeGetTime () / 1000.0f); pID3DDevice-> SetTransform (D3DTS_WORLD, & matrix); D3DXMatrixLookAtLH (& matrix, & D3DXVECTOR3 ( 0.0F, 3.0F, -5.0F), // Camera Spatial Location & D3DxVector3 (0.0F, 0.0F, 0.0F), // Video Observation Point & D3DXVector3 (0.0F, 1.0F, 0.0F)); / / Video machine upward vector pid3ddevice-> setTransform (D3DTS_VIEW, & Matrix);

// Set our flat section to 45 degrees D3DXMAMATRIXPERSPECTIVEFOVLH (& Matrix, D3DX_PI / 4, 4.0F / 3.0F, 1.0F, 100.0F); PID3DDevice-> setTransform (D3DTS_Projection, & Matrix);} You will see this chapter Go to a rotating positive body.

Disclaimer: this article can be obtained from SourceCode http://gamedev.363.net Welcome to my home page: http: //gamedev.363.net Author: Chen Wei Fan E-mail: laical@21cn.com2001/1/12

转载请注明原文地址:https://www.9cbs.com/read-1503.html

New Post(0)