Download source files - 496 Kb
Download demo project - 583 Kb
Description
Most of the samples that come with DirectX 8 SDK don't use MFC.
What if we want to take a sample and add some code that requires MFC?
This article describes the steps to convert the 'Space Donuts 3D'
into an MFC application.
Create the Framework
Start VC, Select File/New from the menu and select MFC�Appwizard(exe).
Give a name (ex.'BattleMachine') and press OK to start the wizard.
Select Single�document as the type of application and uncheck the
Document/View�architecture�support (Fig.1).
Click Finish.
Adding Donuts
The Sample from the SDK have a lot of global functions & variables. I created
a new class named C3DEngine
and copy most of the global functions/variables as members of C3DEngine
. Then i added a global instance of C3DEngine
after the decleration of theApp
.
CBattleMachineApp theApp;
C3DEngine g_3DEngine;
I also added the following two lines in BattleMachine.h after the definition
of CBattleMachineApp
extern CBattleMachineApp theApp;
extern C3DEngine g_3DEngine;
You can use the Space Donuts 3D engine in you application by adding the files
3DEngine.cpp and 3DEngine.h. Those files contain any other
classes, structs and definitions used by space donuts.
There are 2 functions from space donuts 3D that we can't make them members of
C3DEngine
. One is ConfigureInputDevicesCB
which is a Callback function. We have to change it's code a little, to reference g_3DEngine member functions.
BOOL CALLBACK ConfigureInputDevicesCB( IUnknown* pUnknown, VOID* pUserData )
{
if( g_3DEngine.g_dwAppState != APPSTATE_ACTIVE )
return TRUE;
...
The other function is WindowProc
. I moved all of it's code to the
CMainFrame::WindowProc
. Once again, references to previously globals
has to change into references to members of g_3DEngine
.
Initialisation and Changes to the framework
To initialise the 3D Engine you have to set g_hWndMain
to a valid
HWND
and then call CreateGameObjects
by passing that same HWND.
Also a good idea is to set the window size to 640x480 as the space donuts 3D.
We do that in CMainFrame::OnCreate
by using the WHND of the MainFrame.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
lpCreateStruct->cx=640;
lpCreateStruct->cy=480;
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("Failed to create view window\n");
return -1;
}
SetWindowPos( NULL , 50,50, 640,480, SWP_NOOWNERZORDER | SWP_NOREPOSITION |SWP_NOZORDER );
g_3DEngine.g_hWndMain = GetSafeHwnd();
if( FAILED( g_3DEngine.CreateGameObjects( g_3DEngine.g_hWndMain ) ) )
{
return FALSE;
}
return 0;
}
Then we have to change the function CMainFrame::OnSetFocus
.
The function generated by appwizard gives focus to the CChildView
window.
The CMainFrame
should keep the focus, because we need to handle
keypress from the CMainFrame::WindowProc
.
void CMainFrame::OnSetFocus(CWnd* pOldWnd)
{
CFrameWnd::OnSetFocus(pOldWnd);
}
Finally we add the virtual function OnIdle
to the CBattleMachineApp
class. The following code will render the next frame.
BOOL CBattleMachineApp::OnIdle(LONG lCount)
{
if( g_3DEngine.g_bDisplayReady )
{
g_3DEngine.FrameMove();
g_3DEngine.RenderFrame();
}
return true;
}
Other changes
I made some changes to the original space donuts engine.
First, i replaced the sprites of donuts, pyramid, cube and sphere with Tux.
There's no fun killing donuts after all!
Second, I made the landscape more flat by changing the function C3DEngine::HeightField
.
The height of every object (ship,bullets,donuts ) depence on that function.
inline FLOAT C3DEngine::HeightField( FLOAT x, FLOAT z )
{
return (cosf(x/2.0f+0.2f)*cosf(z/1.5f-0.2f)+1.0f)*0.1f - 2.0f;
}
Third, i added the ability to the ship to change altitude. By using
the mouse wheel, instead of changing ships, you can lift or drop the ship's nose.
Try to fly above all those Tuxs and kill them with no fear of dropping on them.