//-------------------------------------------------------------------------------------- // Main.cpp: // - DirectX initialization // - create resources (textures) //-------------------------------------------------------------------------------------- #include "dxstdafx.h" #include "resource.h" #include #include //#define DEBUG_VS // Uncomment this line to debug vertex shaders //#define DEBUG_PS // Uncomment this line to debug pixel shaders #include "Mesh.h" #include "Parameters.h" #include "CameraEffects.h" const int WIDTH = 512; const int HEIGHT = WIDTH; const int CHARBUFFER_SIZE = 200; //-------------------------------------------------------------------------------------- // Global variables //-------------------------------------------------------------------------------------- int currentMethod=0; int methodCount=1; bool showUI=true; CameraEffects PD; IDirect3DDevice9* g_pd3dDevice = NULL; ID3DXEffect* g_pEffect = NULL; CDXUTDialogResourceManager g_DialogResourceManager; // manager for shared resources of dialogs CD3DSettingsDlg g_SettingsDlg; // Device settings dialog CDXUTDialog g_HUD; // Dialog for sample specific controls ID3DXFont* g_pFont = NULL; // Font for drawing text ID3DXSprite* g_pTextSprite = NULL; // Sprite for batching draw text calls IDirect3DSurface9* g_pSaveSurface; // screenshot capturing support bool bSavingScreenshot = false; int counter = 0; D3DXVECTOR3 LightPosition; HRESULT hr; Parameters pp; // managing parameters of the algorithm CModelViewerCamera camera; // camera //-------------------------------------------------------------------------------------- // Forward declarations (CALLBACK) //-------------------------------------------------------------------------------------- bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext ); bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext ); HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* g_pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ); HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* g_pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ); void CALLBACK OnFrameMove( IDirect3DDevice9* g_pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnFrameRender( IDirect3DDevice9* g_pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext ); void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext ); void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext ); void CALLBACK OnLostDevice( void* pUserContext ); void CALLBACK OnDestroyDevice( void* pUserContext ); void InitApp(); void RenderText(); //-------------------------------------------------------------------------------------- // Forward declarations //-------------------------------------------------------------------------------------- void SaveCameraPosition( char* fileName ); void LoadCameraPosition( char* fileName ); int GenerateNewFileName( int& counter ); //-------------------------------------------------------------------------------------- // Entry point to the program. Initializes everything and goes into a message processing // loop. Idle time is used to render the scene. //-------------------------------------------------------------------------------------- INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) { // Enable run-time memory check for debug builds. #if defined(DEBUG) | defined(_DEBUG) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif DXUTSetCallbackDeviceCreated( OnCreateDevice ); DXUTSetCallbackDeviceReset( OnResetDevice ); DXUTSetCallbackDeviceLost( OnLostDevice ); DXUTSetCallbackDeviceDestroyed( OnDestroyDevice ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( KeyboardProc ); DXUTSetCallbackFrameRender( OnFrameRender ); DXUTSetCallbackFrameMove( OnFrameMove ); InitApp(); // Show the cursor and clip it when in full screen DXUTSetCursorSettings( true, true ); DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes DXUTCreateWindow( L"Depth of Field Demo" ); DXUTCreateDevice( D3DADAPTER_DEFAULT, true, WIDTH, HEIGHT, IsDeviceAcceptable, ModifyDeviceSettings ); camera.SetButtonMasks( 0, MOUSE_WHEEL, MOUSE_LEFT_BUTTON ); DXUTMainLoop(); return DXUTGetExitCode(); } void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext ) { pp.UpdateFromHUD( nControlID ); } void OnLoad() { LoadCameraPosition( ".matrix" ); } void OnSave() { SaveCameraPosition( ".matrix" ); bSavingScreenshot = true; } void OnReset() { LightPosition.x=-0.4f; LightPosition.y=1.3f; LightPosition.z=9; } void InitApp() { g_SettingsDlg.Init( &g_DialogResourceManager ); g_HUD.Init( &g_DialogResourceManager ); g_HUD.SetCallback( OnGUIEvent ); // Event handling pp.Setup( &g_HUD, OnReset, OnSave, OnLoad); // you can add callbacks to these actions pp.Add( bShowHelp, "Show Help", VK_F1 ); PD.addUiParams(pp); pp.UpdateFromHUD( IDC_RESET_BUTTON ); // do a reset } //-------------------------------------------------------------------------------------- // Rejects any devices that aren't acceptable by returning false //-------------------------------------------------------------------------------------- bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext ) { // Skip backbuffer formats that don't support alpha blending IDirect3D9* pD3D = DXUTGetD3DObject(); if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) ) return false; return true; } //-------------------------------------------------------------------------------------- // Before a device is created, modify the device settings as needed //-------------------------------------------------------------------------------------- bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext ) { // VSync off pDeviceSettings->pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW // then switch to SWVP. if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 || pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) ) pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING; else pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING; // This application is designed to work on a pure device by not using // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP. if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 ) pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE; // Debugging vertex shaders requires either REF or software vertex processing // and debugging pixel shaders requires REF. #ifdef DEBUG_VS if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF ) { pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING; pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE; pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; } #endif #ifdef DEBUG_PS pDeviceSettings->DeviceType = D3DDEVTYPE_REF; #endif // For the first device created if its a REF device, optionally display a warning dialog box static bool s_bFirstTime = true; if( s_bFirstTime ) { s_bFirstTime = false; if( pDeviceSettings->DeviceType == D3DDEVTYPE_REF ) DXUTDisplaySwitchingToREFWarning(); } return true; } //-------------------------------------------------------------------------------------- // Create any D3DPOOL_MANAGED resources here //-------------------------------------------------------------------------------------- HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) { ::g_pd3dDevice = pd3dDevice; HRESULT hr; V_RETURN( g_DialogResourceManager.OnCreateDevice( g_pd3dDevice ) ); V_RETURN( g_SettingsDlg.OnCreateDevice( g_pd3dDevice ) ); // Initialize the font V_RETURN( D3DXCreateFont( g_pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) ); float initialEyeDist = 6.82f; D3DXVECTOR3 vecEye(0, 0, -initialEyeDist); D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f); camera.SetViewParams( &vecEye, &vecAt ); PD.OnCreateDevice(g_pd3dDevice); PD.camera = &camera; return S_OK; } //-------------------------------------------------------------------------------------- // Release resources created in the OnCreateDevice callback here //-------------------------------------------------------------------------------------- void CALLBACK OnDestroyDevice( void* pUserContext ) { g_DialogResourceManager.OnDestroyDevice(); g_SettingsDlg.OnDestroyDevice(); SAFE_RELEASE(g_pFont); PD.OnDestroyDevice(); } //-------------------------------------------------------------------------------------- // Create any D3DPOOL_DEFAULT resources here //-------------------------------------------------------------------------------------- HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* g_pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnResetDevice() ); V_RETURN( g_SettingsDlg.OnResetDevice() ); if( g_pFont ) V_RETURN( g_pFont->OnResetDevice() ); // Create a sprite to help batch calls when drawing many lines of text V_RETURN( D3DXCreateSprite( g_pd3dDevice, &g_pTextSprite ) ); // Create a surface to save screenshots IDirect3DTexture9* pSaveTexture = NULL; V( D3DXCreateTexture( g_pd3dDevice, pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSaveTexture) ); pSaveTexture->GetSurfaceLevel( 0, &g_pSaveSurface ); SAFE_RELEASE( pSaveTexture ); // Setup the camera's projection parameters float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height; camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 100 ); camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height ); // Position the on-screen dialog g_HUD.SetLocation( 0, 0 ); g_HUD.SetSize( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height ); PD.OnResetDevice((D3DSURFACE_DESC*)pBackBufferSurfaceDesc); return S_OK; } //-------------------------------------------------------------------------------------- // Release resources created in the OnResetDevice callback here //-------------------------------------------------------------------------------------- void CALLBACK OnLostDevice( void* pUserContext ) { g_DialogResourceManager.OnLostDevice(); g_SettingsDlg.OnLostDevice(); if( g_pFont ) g_pFont->OnLostDevice(); SAFE_RELEASE( g_pTextSprite ); SAFE_RELEASE( g_pSaveSurface ); PD.OnLostDevice(); } LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext ) { // Always allow dialog resource manager calls to handle global messages // so GUI state is updated correctly *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; if( g_SettingsDlg.IsActive() ) { g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam ); return 0; } // Give the dialogs a chance to handle the message first *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Pass all remaining windows messages to camera so it can respond to user input camera.HandleMessages( hWnd, uMsg, wParam, lParam ); return 0; } //-------------------------------------------------------------------------------------- // Handle updates to the scene //-------------------------------------------------------------------------------------- void CALLBACK OnFrameMove( IDirect3DDevice9* g_pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) { camera.FrameMove( fElapsedTime ); } //-------------------------------------------------------------------------------------- // Render the scene //-------------------------------------------------------------------------------------- void CALLBACK OnFrameRender( IDirect3DDevice9* g_pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) { /* // If the settings dialog is being shown, then // render it instead of rendering the app's scene if( g_SettingsDlg.IsActive() ) { g_SettingsDlg.OnRender( fElapsedTime ); return; }*/ IDirect3DSurface9* oldRenderTarget = NULL; if (bSavingScreenshot) { V( g_pd3dDevice->GetRenderTarget(0, &oldRenderTarget) ); V( g_pd3dDevice->SetRenderTarget(0, g_pSaveSurface) ); } V( g_pd3dDevice->BeginScene() ); D3DXMATRIXA16 mView = *camera.GetViewMatrix(); D3DXMATRIXA16 mProj = *camera.GetProjMatrix(); V( g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(75, 75, 75), 1.0f, 0L) ); PD.currentmethod=currentMethod; PD.camera = &camera; PD.LightPos=&LightPosition; PD.OnFrameRender(mView,mProj); if (!bSavingScreenshot) { RenderText(); if(showUI) { V( g_HUD.OnRender( fElapsedTime ) ); } } V( g_pd3dDevice->EndScene() ); if (bSavingScreenshot) { // saving surface char buf[CHARBUFFER_SIZE]; wchar_t wbuf[CHARBUFFER_SIZE]; GenerateNewFileName( counter ); sprintf(buf, "shots\\%03i.png", counter); mbstowcs( wbuf, buf, CHARBUFFER_SIZE ); D3DXSaveSurfaceToFileW(wbuf, D3DXIFF_PNG, g_pSaveSurface, NULL, NULL); sprintf(buf, "shots\\%03i", counter); pp.SaveToFile( buf ); sprintf(buf, "shots\\%03i.matrix", counter); SaveCameraPosition( buf ); g_pd3dDevice->SetRenderTarget(0, oldRenderTarget); bSavingScreenshot = false; } } int GenerateNewFileName( int& counter ) { char buf[CHARBUFFER_SIZE]; FILE* f; do { sprintf(buf, "shots\\%03i.png", counter); if ( (f = fopen(buf, "rt")) != NULL ) { fclose( f ); counter++; } } while (f != NULL); return counter; } //-------------------------------------------------------------------------------------- // The framework does not remove the underlying keystroke messages, // which are still passed to the application's MsgProc callback. //-------------------------------------------------------------------------------------- void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext ) { if( bKeyDown ) { if ( nChar >= '0' && nChar <= '9' ) { UINT whichMesh = nChar-'0'; PD.changeMesh(whichMesh); } switch(nChar) { case VK_SPACE: showUI=!showUI; break; case VK_TAB: currentMethod=(++currentMethod)%methodCount; break; case VK_DOWN: LightPosition.z-=0.1f; break; case VK_UP: LightPosition.z+=0.1f; break; case VK_LEFT: LightPosition.x-=0.1f; break; case VK_RIGHT: LightPosition.x+=0.1f; break; case VK_DELETE: LightPosition.y+=0.1f; break; case VK_END: LightPosition.y-=0.1f; break; default: break; } } } void SaveCameraPosition( char* fileName ) { // save parameters to file: // world matrix (4x4) // camera position (3) // save world matrix D3DXMATRIXA16 W = *camera.GetViewMatrix(); FILE* f; if ((f = fopen(fileName, "wt")) == NULL) { wchar_t wbuf[CHARBUFFER_SIZE]; mbstowcs( wbuf, fileName, CHARBUFFER_SIZE ); MessageBox(NULL, wbuf, L"File creation failed!", MB_ICONEXCLAMATION); return; } fprintf(f, "\n"); fprintf(f, "World matrix:\n"); fprintf(f, "%10.4g %10.4g %10.4g %10.4g\n", W._11, W._12, W._13, W._14); fprintf(f, "%10.4g %10.4g %10.4g %10.4g\n", W._21, W._22, W._23, W._24); fprintf(f, "%10.4g %10.4g %10.4g %10.4g\n", W._31, W._32, W._33, W._34); fprintf(f, "%10.4g %10.4g %10.4g %10.4g\n", W._41, W._42, W._43, W._44); // save camera position fprintf(f, "\n"); fprintf(f, "Camera position:\n"); const D3DXVECTOR3* eye = camera.GetEyePt(); fprintf(f, "%10g %10g %10g", eye->x, eye->y, eye->z); fprintf(f, "\n"); fclose(f); } void LoadCameraPosition( char* fileName ) { FILE* f; if ((f = fopen(fileName, "rt")) == NULL) { wchar_t wbuf[CHARBUFFER_SIZE]; mbstowcs( wbuf, fileName, CHARBUFFER_SIZE ); MessageBox(NULL, wbuf, L"File not found!", MB_ICONEXCLAMATION); return; } const int BufSize = 500; // size of char buffers char buf[BufSize]; D3DXMATRIXA16 W; fgets(buf, BufSize, f); // skip comment fgets(buf, BufSize, f); // skip comment fgets(buf, BufSize, f); sscanf(buf, "%f %f %f %f", &W._11, &W._12, &W._13, &W._14); fgets(buf, BufSize, f); sscanf(buf, "%f %f %f %f", &W._21, &W._22, &W._23, &W._24); fgets(buf, BufSize, f); sscanf(buf, "%f %f %f %f", &W._31, &W._32, &W._33, &W._34); fgets(buf, BufSize, f); sscanf(buf, "%f %f %f %f", &W._41, &W._42, &W._43, &W._44); // load camera position D3DXVECTOR3 vecAt(0.0f, 0.0f, 0.0f); D3DXVECTOR3 vecEye; fgets(buf, BufSize, f); // skip comment fgets(buf, BufSize, f); // skip comment fgets(buf, BufSize, f); sscanf(buf, "%f %f %f", &vecEye.x, &vecEye.y, &vecEye.z); fclose(f); camera.SetViewParams( &vecEye, &vecAt ); D3DXQUATERNION q; D3DXQuaternionRotationMatrix(&q, &W); camera.SetViewQuat(q); } //-------------------------------------------------------------------------------------- // Util function. // Creates an empty texture. These textures will be used as render targets, therefore // the Usage flag is set to D3DUSAGE_RENDERTARGET and consequently, the assigned // memory pool is D3DPOOL_DEFAULT. // Params: size and format (eg. D3DFMT_A32B32G32R32F) of the new texture. //-------------------------------------------------------------------------------------- IDirect3DTexture9* CreateTexture( int size, D3DFORMAT Format ) { HRESULT hr; IDirect3DTexture9* pTexture; V( g_pd3dDevice->CreateTexture( size, size, // dimensions 1, // mipmap levels D3DUSAGE_RENDERTARGET, // usage Format, D3DPOOL_DEFAULT,// memory pool &pTexture, NULL ) ); return pTexture; } //-------------------------------------------------------------------------------------- // Util function. // Creates an empty cubemap texture of the given resolution and format. //-------------------------------------------------------------------------------------- IDirect3DCubeTexture9* CreateCubeTexture( int size, D3DFORMAT Format ) { HRESULT hr; IDirect3DCubeTexture9* pCubeTexture; V( g_pd3dDevice->CreateCubeTexture( size, 1, D3DUSAGE_RENDERTARGET, Format, D3DPOOL_DEFAULT, &pCubeTexture, NULL ) ); return pCubeTexture; } //-------------------------------------------------------------------------------------- // Render the help and statistics text. //-------------------------------------------------------------------------------------- void RenderText() { const D3DSURFACE_DESC* backBufferDesc = DXUTGetBackBufferSurfaceDesc(); CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 ); txtHelper.Begin(); txtHelper.SetInsertionPos( 5, 5 ); txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) ); if(showUI) { txtHelper.DrawFormattedTextLine( L"%.2f fps @ %i x %i", DXUTGetFPS(), backBufferDesc->Width, backBufferDesc->Height ); //txtHelper.DrawTextLine( DXUTGetFrameStats() ); txtHelper.DrawTextLine( DXUTGetDeviceStats() ); //txtHelper.DrawTextLine( L"" ); txtHelper.SetInsertionPos( 5, 120 ); txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); switch(currentMethod) { case 0:txtHelper.DrawFormattedTextLine( L"Method : Depth of Field with Circle of Confusion");break; } } txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) ); if ( pp.Get( bShowHelp ) ) { txtHelper.SetInsertionPos( backBufferDesc->Width - 260, backBufferDesc->Height-24*15 ); txtHelper.DrawTextLine( L"Controls (F1 to hide):\n\n" L"___________________________________\n" L" GENERAL CONTROLS\n" L"Left click drag: Rotate mesh\n" L"Mouse wheel: Zoom\n" L"F3: Switch to REF device\n" L"F8: Switch to Wireframe mode\n" L"Space: Show/Hide UI Elements\n" L"___________________________________\n" L" ALGORITHM\n" L"TAB: Turn Displacement On/Off\n" L"___________________________________\n" L" UTILITIES\n" L"L: [L]oad view & eye params\n" L"S: [S]ave view & eye params\n" L"Alt+S: [S]ave Screenshot\n" L"___________________________________\n" L" Quit: ESC"); } else { // txtHelper.DrawTextLine( L"Press F1 for help" ); } txtHelper.End(); }