| Language: | C++ |
| Category: | Multimedia |
| Date: | 2009-01-12 |
| Author: | Network Security Developer |
| Attachment: | Download |
In this article we will take a look at initializing Direct3D. To make the discussion more interesting an example application will be created and then its capabilities will be considered.
Select the File | New | Project menu sequence, and in the left pane, select the New Project dialog window open Visual C++ Projects | Win32. In the right pane, select the Win32 Project item. Specify the name of the project in the Name field and the path in the folder, in which you want to store it in the Location field.
Create a new Direct3D project
Click the OK button to open the Win32 Application Wizard window. Click the Application Settings tab, and select the Windows application radio button in the Application type group. Leave all checkboxes untouched. Click the Finish button to create a basic application. Don't forget to include the necessary libraries in the project properties. For more information read Installing and Configuring DirectX. Now clean the project of all unnecessary code. First of all, remove the code of creating and sowing the Help dialog box.
The perfect location for initializing Direct3D is right after the InitInstance function, which creates and displays the window. But first you must decide how the initialization process will be implemented. Because this is one-time operation, performed only at the start of the application, it can be implemented as a separate universal function.
Because the Direct3D initialization code for several Direct3D applications at your work or home experience may be identical, it can be contained in a module. Start by creating the dxfunc.cpp file for the source code of functions. And the related dxfunc.h header file. The contents of the dxfunc.h header file are:
#ifndef _DDFUNC_H_
#define _DDFUNC_H_
#include "ddraw.h"
// Функция инициализации Direct3D
HRESULT DXDDInit(IDirectDraw7 **ppiDD,
IDirectDrawSurface7 **primsurf,
IDirectDrawSurface7 **backsurf,
HWND hWnd,
DWORD iWidth,
DWORD iHeight,
WORD iColors,
BOOL &bFullScreen
);
#endif
In the file, the DX3DInit Direct3D initialization function is declared. Its parameters are the following:
Write the code for calling the Direct3D initialization function in the DirectX skeleton, and then the function itself. In the main module, declare two variables for storing the created IDirect3D9 interface and the IDirect3DDevice9 device:
IDirect3D9 *pD3D = NULL; IDirect3DDevice9 *pD3DDevice = NULL;
The initialization function is called in the InitInstance function after creating the window but before displaying and refreshing the main window:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
if (DX3DInit(&pD3D, &pD3DDevice, hWnd, 800, 600, FALSE)!=S_OK)
{
MessageBox(hWnd, "Initialization error", "Error", MB_OK);
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
Why must the function be called exactly in this place? You are creating a universal initialization function, which will be called with the help of a dialog window regardless of whether or not initialization should be performed the full screen mode. You must take into account that after the Direct3D initialization all dialog windows will be displayed incorrectly, if they are displayed at all. This problem is not difficult to solve; the window should simply be displayed before any Direct3D initialization.
But there is another problem: why display and redraw an initialized window? This makes no sense, because during the Direct3D initialization the window's parameters change and the 3D scene will have to be redrawn. Even though these are one-time operations, processor time is wasted on the preliminary window redrawing.
If your program is supposed to work in both the window and the full-screen modes, this is only a plus. For example, on my wide-screen notebook some graphics programs don't appear well in the full screen mode. This problem is taken care of by running them in the window mode, since the powerful video card allows this. But if a program does not offer the window mode, the image is stretched a bit horizontally.
Now let's consider the contents of the dxfunc.cpp file:
#include "dxfunc.h"
HRESULT DX3DInit(IDirect3D9 **ppiD3D9,
IDirect3DDevice9 **ppiD3DDevice9,
HWND hWnd,
DWORD iWidth,
DWORD iHeight,
BOOL bFullScreen)
{
if((*ppiD3D9 = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
return E_FAIL;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = iWidth;
d3dpp.BackBufferHeight = iHeight;
int iRes;
if (!bFullScreen)
iRes=MessageBox(hWnd, "Use fullscreen mode?", "Screen", MB_YESNO | MB_ICONQUESTION);
else
iRes = IDYES;
if(iRes == IDYES)
{
//////////////////////////////////////////////////////////
// Full screen
//////////////////////////////////////////////////////////
d3dpp.BackBufferFormat = D3DFMT_R5G6B5;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.Windowed = FALSE;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
}
else
{
//////////////////////////////////////////////////////////
// Window Mode
//////////////////////////////////////////////////////////
RECT wndRect;
RECT clientRect;
GetWindowRect(hWnd, &wndRect);
GetClientRect(hWnd, &clientRect);
iWidth = iWidth + (wndRect.right-wndRect.left) - (clientRect.right-clientRect.left);
iHeight = iHeight + (wndRect.bottom-wndRect.top) - (clientRect.bottom-clientRect.top);
MoveWindow(hWnd, wndRect.left, wndRect.top, iWidth, iHeight, TRUE);
// get pixel format
D3DDISPLAYMODE d3ddm;
(*ppiD3D9)->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
// set parameters
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed = TRUE;
}
DWORD Flags= D3DCREATE_MIXED_VERTEXPROCESSING;
HRESULT hRes;
if(FAILED(hRes = (*ppiD3D9)->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, hWnd, Flags,
&d3dpp, ppiD3DDevice9)))
return hRes;
float Aspect = (float)d3dpp.BackBufferWidth / (float)d3dpp.BackBufferHeight;
D3DXMATRIX matProjection;
D3DXMatrixPerspectiveFovLH(&matProjection, D3DX_PI/4.0f, Aspect, 0.001f, 1000.0f);
(*ppiD3DDevice9)->SetTransform(D3DTS_PROJECTION, &matProjection);
(*ppiD3DDevice9)->SetRenderState(D3DRS_LIGHTING, FALSE);
return S_OK;
}
To be continued...