|
IntroductionThis page provides source code for a framework for developing graphics
applications using DirectX 8. The framework provides a quick starting
point, while not imposing any high level functionality.
Using the FrameworkTo use the framework, you will need to write a minimum of three functions:
The framework is written under Visual C++ 6.0, and has not yet been compiled on other compilers. There is no guarantee of fitness for other compilers, and may require modification. If anyone adapts this for another compiler, I'd love to hear about it, and possibly post it here with your permission. Direct this or other comments to rdunlop@mvps.org. YOURPROGRAM.CPP#include "stdafx.h" DXContext *lpDX=NULL; static char szClass[] = "YourProgramClass"; static char szCaption[] = "Your Program"; void render_frame(float elapsed) { lpDX->lpDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0x00000000,1.0f,0); if (D3D_OK==lpDX->lpDevice->BeginScene()) { // Place your rendering code here lpDX->lpDevice->EndScene(); } lpDX->lpDevice->Present(NULL,NULL,NULL,NULL); } void Cleanup() { if (lpDX) lpDX->Cleanup(); } LRESULT CALLBACK WindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: Cleanup(); PostQuitMessage(0); break; case WM_SIZE: // clear or set activity flag to reflect focus if (lpDX) { if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam ) lpDX->active = FALSE; else lpDX->active = TRUE; } break; case WM_KEYUP: switch (wParam) { case VK_ESCAPE: // exit the program on escape DestroyWindow(hWnd); break; } break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0L; } int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { // create application handler and link to our WindowProc lpDX=new DXContext(hInstance,szClass,szCaption,WindowProc); if (!lpDX) return FALSE; // check for error if (lpDX->lastErr!=S_OK) { delete lpDX; return FALSE; } // initialize full screen graphics to 640 x 480 x 32 bit, with 2 back buffers if (!lpDX->Init(640,480,16,2,TRUE)) { delete lpDX; return FALSE; } // run the game loop, passing pointer to our rendering routine lpDX->Run(render_frame); SafeDelete(lpDX); return TRUE; } STDAFX.H#include <windows.h> #include <mmsystem.h> #include <d3d8.h> #include <d3dx8.h> #include <d3dx8mesh.h> #include "dxcontext.h" #define SafeRelease(x) if (x) {x->Release(); x=NULL;} #define SafeDelete(x) if (x) {delete x; x=NULL;} DXCONTEXT.Hclass DXContext { public: void SetRenderFunc(void (*ptr)(float)); BOOL TestDepth(D3DFORMAT fmt); BOOL TestFormat(D3DFORMAT fmt); void (*renderPtr)(float); DXContext(HINSTANCE hInstance,LPCSTR pClass,LPCSTR pCaption,WNDPROC pProc); ~DXContext(); BOOL Init(WORD wWidth,WORD wHeight,WORD wDepth,WORD wBackBuffers,BOOL bWindowed); int Run(void (*ptr)(float)); void Cleanup(); HRESULT hRes; HRESULT lastErr; D3DFORMAT format; D3DFORMAT zFormat; WORD height; WORD width; LPDIRECT3D8 lpD3D; LPDIRECT3DDEVICE8 lpDevice; BOOL active; HWND hwnd; }; #define DXC_ERR_REGWIN -2 #define DXC_ERR_CREATEWIN -3 #define DXC_ERR_CREATE3D -4 #define DXC_ERR_GETFORMAT -5 #define DXC_ERR_FORMAT -6 #define DXC_ERR_CREATEDEV -7 DXCONTEXT.CPP#include "stdafx.h" #include "DXContext.h" #pragma comment(lib,"winmm.lib") #pragma comment(lib,"d3d8.lib") #ifdef _DEBUG #pragma comment(lib, "d3dx8d.lib") #else #pragma comment(lib, "d3dx8.lib") #endif DXContext:: DXContext(HINSTANCE hInstance,LPCSTR pClass,LPCSTR pCaption,WNDPROC pProc) { WNDCLASS wc; // clear the error register lastErr=S_OK; // clear the active flag active=FALSE; // Set up and register window class wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) pProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(DWORD); wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = pClass; if (!RegisterClass(&wc)) { lastErr=-2; return; } // Get dimensions of display int ScreenWidth = GetSystemMetrics(SM_CXSCREEN); int ScreenHeight = GetSystemMetrics(SM_CYSCREEN); hwnd = CreateWindow(pClass, // class pCaption, // caption WS_OVERLAPPEDWINDOW, // style 0, // left 0, // top ScreenWidth, // width ScreenHeight, // height NULL, // parent window NULL, // menu hInstance, // instance NULL); // parms if (!hwnd) { lastErr=-3; return; } } DXContext::~DXContext() { // call cleanup in case program did not // the cleanup routine will only release objects once, despite repeated calls Cleanup(); } void DXContext::Cleanup() { // clear active flag active=FALSE; // release 3D interfaces SafeRelease(lpDevice); SafeRelease(lpD3D); } BOOL DXContext::TestFormat(D3DFORMAT fmt) { if (D3D_OK==lpD3D->CheckDeviceType(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,fmt,fmt,FALSE)) return TRUE; return FALSE; } BOOL DXContext::TestDepth(D3DFORMAT fmt) { if (D3D_OK!=lpD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,format, D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,fmt)) return FALSE; if (D3D_OK!=lpD3D->CheckDepthStencilMatch(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, format,format,fmt)) return FALSE; return TRUE; } #define DXTestFmt(x) if (TestFormat(x)) {format=x; break;} #define DXTestDepth(x) if (TestDepth(x)) zFormat=x BOOL DXContext::Init(WORD wWidth,WORD wHeight,WORD wDepth,WORD wBackBuffers,BOOL bWindowed) { // save screen parameters width=wWidth; height=wHeight; SetWindowPos(hwnd,HWND_TOP,0,0,width,height,SWP_SHOWWINDOW); lpD3D=Direct3DCreate8(D3D_SDK_VERSION); if (!lpD3D) { lastErr=-4; return FALSE; } D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp,sizeof(d3dpp)); if (bWindowed) { d3dpp.Windowed=TRUE; D3DDISPLAYMODE d3ddm; if( FAILED( hRes=lpD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) { lastErr=-5; return FALSE; } format=d3dpp.BackBufferFormat=d3ddm.Format; } else { d3dpp.Windowed=FALSE; switch (wDepth) { case 32: DXTestFmt(D3DFMT_A8R8G8B8); DXTestFmt(D3DFMT_X8R8G8B8); case 16: DXTestFmt(D3DFMT_R5G6B5); DXTestFmt(D3DFMT_X1R5G5B5); default: format=D3DFMT_UNKNOWN; } if (format==D3DFMT_UNKNOWN) { lastErr=-6; return FALSE; } d3dpp.BackBufferFormat=format; d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT; d3dpp.FullScreen_PresentationInterval=D3DPRESENT_INTERVAL_ONE; } d3dpp.BackBufferWidth=width; d3dpp.BackBufferHeight=height; d3dpp.BackBufferCount=wBackBuffers; d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP; zFormat=D3DFMT_UNKNOWN; DXTestDepth(D3DFMT_D32); else DXTestDepth(D3DFMT_D32); else DXTestDepth(D3DFMT_D24S8); else DXTestDepth(D3DFMT_D24X4S4); else DXTestDepth(D3DFMT_D24X8); else DXTestDepth(D3DFMT_D16); else DXTestDepth(D3DFMT_D15S1); else DXTestDepth(D3DFMT_D16_LOCKABLE); if (zFormat!=D3DFMT_UNKNOWN) { d3dpp.EnableAutoDepthStencil=TRUE; d3dpp.AutoDepthStencilFormat=zFormat; } if( FAILED( hRes=lpD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,&lpDevice ) ) ) { lastErr=-7; return FALSE; } // return success return TRUE; } int DXContext::Run(void (*ptr)(float)) { renderPtr=ptr; LONGLONG cur_time; // current time BOOL perf_flag=FALSE; // flag determining which timer to use LONGLONG last_time=0; // time of previous frame float time_elapsed; // time since previous frame float time_scale; // scaling factor for time // select timer, get current time, and calculate time scale if (QueryPerformanceFrequency((LARGE_INTEGER *) &cur_time)) { time_scale=1.0f/cur_time; QueryPerformanceCounter((LARGE_INTEGER *) &last_time); perf_flag=TRUE; } else { time_scale=0.001f; last_time=timeGetTime(); } // set status as active active=TRUE; // Now we're ready to recieve and process Windows messages. BOOL bGotMsg; MSG msg; PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE ); while( WM_QUIT != msg.message ) { if (!active) { bGotMsg=GetMessage(&msg, NULL, 0U, 0U); if( bGotMsg ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } else { bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ); if( bGotMsg ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { // use the appropriate method to get time // and calculate elapsed time since last frame if (perf_flag) QueryPerformanceCounter((LARGE_INTEGER *) &cur_time); else cur_time=timeGetTime(); // calculate elapsed time time_elapsed=(cur_time-last_time)*time_scale; // save frame time last_time=cur_time; if (renderPtr) renderPtr(time_elapsed); } } } // return final message return msg.wParam; } void DXContext::SetRenderFunc(void (__cdecl *ptr)(float)) { renderPtr=ptr; } |
Visitors Since 1/1/2000:
|