#include "dxstdafx.h" #include "dxutmesh.h" #include "resource.h" #include "properties.h" //-------------------------------------------------------------------------------------- // 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 // Initialize the camera g_CamCamera.SetScalers( 0.01f, 15.0f ); g_LightCamera.SetScalers( 0.01f, 8.0f ); g_CamCamera.SetRotateButtons( true, false, false ); g_LightCamera.SetRotateButtons( false, false, true ); // Set up the view parameters for the camera D3DXVECTOR3 vFromPt = D3DXVECTOR3( 0.0f, 5.0f, -18.0f ); D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, -1.0f, 0.0f ); g_CamCamera.SetViewParams( &vFromPt, &vLookatPt ); vFromPt = D3DXVECTOR3( 0.0f, 0.0f, -12.0f ); vLookatPt = D3DXVECTOR3( 0.0f, -2.0f, 1.0f ); g_LightCamera.SetViewParams( &vFromPt, &vLookatPt ); // Set the callback functions. These functions allow DXUT to notify // the application about device changes, user input, and windows messages. The // callbacks are optional so you need only set callbacks for events you're interested // in. However, if you don't handle the device reset/lost callbacks then the sample // framework won't be able to reset your device since the application must first // release all device resources before resetting. Likewise, if you don't handle the // device created/destroyed callbacks then DXUT won't be able to // recreate your device resources. DXUTSetCallbackDeviceCreated( OnCreateDevice ); DXUTSetCallbackDeviceReset( OnResetDevice ); DXUTSetCallbackDeviceLost( OnLostDevice ); DXUTSetCallbackDeviceDestroyed( OnDestroyDevice ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( KeyboardProc ); DXUTSetCallbackMouse( MouseProc ); DXUTSetCallbackFrameRender( OnFrameRender ); DXUTSetCallbackFrameMove( OnFrameMove ); InitializeDialogs(); // Show the cursor and clip it when in full screen DXUTSetCursorSettings( true, true ); // Initialize DXUT and create the desired Win32 window and Direct3D // device for the application. Calling each of these functions is optional, but they // allow you to set several options which control the behavior of the framework. DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes DXUTCreateWindow( L"ShadowMap Techniques" ); DXUTCreateDevice( D3DADAPTER_DEFAULT, true, WINDOW_WIDTH, WINDOW_HEIGHT, IsDeviceAcceptable, ModifyDeviceSettings ); // Pass control to DXUT for handling the message pump and // dispatching render calls. DXUT will call your FrameMove // and FrameRender callback when there is idle time between handling window messages. DXUTMainLoop(); // Perform any application-level cleanup here. Direct3D device resources are released within the // appropriate callback functions and therefore don't require any cleanup code here. return DXUTGetExitCode(); } //-------------------------------------------------------------------------------------- // Sets up the dialogs //-------------------------------------------------------------------------------------- void InitializeDialogs() { g_SettingsDlg.Init( &g_DialogResourceManager ); g_HUD.Init( &g_DialogResourceManager ); g_HUD.SetCallback( OnGUIEvent ); // Initialize dialog int posX = 0; int posY = 0; // Setup for buttons g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, posY, 125, 22 ); g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, posY += 24, 125, 22 ); g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, posY += 24, 125, 22, VK_F2 ); // Setup for sliders g_HUD.AddSlider( HUNDRED + 0, posX, posY += 40, 120, 14, g_iSliderMinValues[0], g_iSliderMaxValues[0], g_iFov ); g_HUD.AddSlider( HUNDRED + 1, posX, posY += 16, 120, 14, g_iSliderMinValues[1], g_iSliderMaxValues[1], g_iLightFov ); g_HUD.AddSlider( HUNDRED + 2, posX, posY += 16, 120, 14, g_iSliderMinValues[2], g_iSliderMaxValues[2], (int)( g_fLightSize * 100 ) ); g_HUD.AddSlider( HUNDRED + 3, posX, posY += 16, 120, 14, g_iSliderMinValues[3], g_iSliderMaxValues[3], (int)( g_fIntensity * 100 ) ); g_HUD.AddSlider( HUNDRED + 4, posX, posY += 16, 120, 14, g_iSliderMinValues[4], g_iSliderMaxValues[4], (int)( g_fShadowBias * 100 ) ); g_HUD.AddSlider( HUNDRED + 5, posX, posY += 16, 120, 14, g_iSliderMinValues[5], g_iSliderMaxValues[5], (int)( g_fBiasSlope * 100 ) ); g_HUD.AddSlider( HUNDRED + 6, posX, posY += 16, 120, 14, g_iSliderMinValues[6], g_iSliderMaxValues[6], g_iKernelSize ); g_HUD.AddSlider( HUNDRED + 7, posX, posY += 16, 120, 14, g_iSliderMinValues[7], g_iSliderMaxValues[7], (int)( log( (float)g_iShadowMapSize ) / log( 2.0f ) ) ); g_HUD.AddSlider( HUNDRED + 8, posX, posY += 16, 120, 14, g_iSliderMinValues[8], g_iSliderMaxValues[8], (int)( log( (float)g_iFocusingMapSize ) / log( 2.0f ) ) ); g_HUD.AddSlider( HUNDRED + 9, posX, posY += 16, 120, 14, g_iSliderMinValues[9], g_iSliderMaxValues[9], (int)( g_fLightSourceSamples * 50 ) ); // Setup for checkbox g_HUD.AddCheckBox( IDC_CHECKBOX, L"Display GUI (F1)", 35, posY += 24, 150, 22, g_bShowText, VK_F1 ); g_HUD.AddCheckBox( IDC_LIGHTPERSPECTIVE, L"The light's view (V)", 35, posY += 24, 160, 22, !g_bCameraPerspective, L'V' ); g_HUD.AddCheckBox( IDC_PAUSE_CHECKBOX, L"Pause (P)", 35, posY += 24, 160, 22, g_bPause, L'P' ); g_HUD.AddCheckBox( IDC_USE_TEXTURE_CHECKBOX, L"Use texture (T)", 35, posY += 24, 160, 22, g_bUseTexture, L'T' ); g_HUD.AddCheckBox( IDC_USE_FOCUSING_CHECKBOX, L"Use focusing (F)", 35, posY += 24, 160, 22, g_bUseFocusing, L'F' ); g_HUD.AddComboBox( IDC_METHOD_COMBO_BOX, 60, posY + 40, 130, 20, 0, false, &g_pTechniquesListComboBox ); g_pTechniquesListComboBox->SetDropHeight(105); g_pTechniquesListComboBox->AddItem( L"0-Reference", NULL ); g_pTechniquesListComboBox->AddItem( L"6-PC soft", NULL ); g_pTechniquesListComboBox->AddItem( L"7-Shadow accu", NULL ); // number of items above: 0 .. 2 = 3 g_iNumberOfMethods = 3; } //-------------------------------------------------------------------------------------- // Called during device initialization, this code checks the device for some // minimum set of capabilities, and rejects those that don't pass 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; // Must support pixel shader 2.0 if( pCaps->PixelShaderVersion < D3DPS_VERSION( 2, 0 ) ) return false; // Check support of the used texture formats. // need to support D3DFMT_A8R8G8B8 format if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8 ) ) ) return false; // need to support D3DFMT_A32B32G32R32F format if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F ) ) ) return false; // need to support D3DFMT_A32B32G32R32F format if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F ) ) ) return false; // need to support D3DFMT_D24S8 format if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_D24S8 ) ) ) return false; return true; } //-------------------------------------------------------------------------------------- // This callback function is called immediately before a device is created to allow the // application to modify the device settings. The supplied pDeviceSettings parameter // contains the settings that the framework has selected for the new device, and the // application can make any desired changes directly to this structure. Note however that // DXUT will not correct invalid device settings so care must be taken // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail. //-------------------------------------------------------------------------------------- bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext ) { // Turn off VSYNC 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; } // 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; } //-------------------------------------------------------------------------------------- // This callback function will be called immediately after the Direct3D device has been // created, which will happen during application initialization and windowed/full screen // toggles. This is the best location to create D3DPOOL_MANAGED resources since these // resources need to be reloaded whenever the device is destroyed. Resources created // here should be released in the OnDestroyDevice callback. //-------------------------------------------------------------------------------------- HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; g_pd3dDevice = pd3dDevice; V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) ); V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) ); // Initialize the font V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) ); V_RETURN( D3DXCreateFont( pd3dDevice, 12, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFontSmall ) ); // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the // shader debugger. Debugging vertex shaders requires either REF or software vertex // processing, and debugging pixel shaders requires REF. The // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the // shader debugger. It enables source level debugging, prevents instruction // reordering, prevents dead code elimination, and forces the compiler to compile // against the next higher available software target, which ensures that the // unoptimized shaders do not exceed the shader model limitations. Setting these // flags will cause slower rendering since the shaders will be unoptimized and // forced into software. See the DirectX documentation for more information about // using the shader debugger. DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE | D3DXSHADER_PREFER_FLOW_CONTROL; #ifdef DEBUG_VS dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT; #endif #ifdef DEBUG_PS dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT; #endif // If this fails, there should be debug output as to // they the .fx file failed to compile // Read the D3DX effect file ID3DXBuffer* errBuff = NULL; if( FAILED(D3DXCreateEffectFromFile( pd3dDevice, L"ShadowMap.fx", NULL, NULL, dwShaderFlags, NULL, &g_pEffect, &errBuff ))) { int BufSize = errBuff->GetBufferSize(); // displaying error message of arbitrary length wchar_t* wbuf = new wchar_t[BufSize]; size_t convertedChars = 0; // mbstowcs_s(&convertedChars, wbuf, BufSize, (const char*)errBuff->GetBufferPointer(), _TRUNCATE); // MessageBox(NULL, wbuf, L".fx Compilation Error", MB_ICONERROR); // show error message delete wbuf; exit(-1); } // Create vertex declaration V_RETURN( pd3dDevice->CreateVertexDeclaration( g_aVertDecl, &g_pVertDecl ) ); WCHAR str[MAX_PATH]; // Initialize the meshes for( int i = 0; i < NUM_OBJ; ++i ) { V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, g_aszMeshFile[i] ) ); if( FAILED( g_Obj[i].m_Mesh.Create( pd3dDevice, str ) ) ) return DXUTERR_MEDIANOTFOUND; V_RETURN( g_Obj[i].m_Mesh.SetVertexDecl( pd3dDevice, g_aVertDecl ) ); g_Obj[i].m_mWorld = g_amInitObjWorld[i]; } // Compute Room bounding box void* data; D3DXVECTOR3 vRoomBoundingBoxMin3f; // Bounding box of room min point D3DXVECTOR3 vRoomBoundingBoxMax3f; // Bounding box of room max point g_Obj[0].m_Mesh.m_pVB->Lock(0,0,&data,0); D3DXVECTOR3 min,max; D3DVERTEXBUFFER_DESC descriptor; g_Obj[0].m_Mesh.m_pVB->GetDesc( &descriptor); UINT stride = D3DXGetFVFVertexSize(descriptor.FVF); D3DXComputeBoundingBox((D3DXVECTOR3*)data, descriptor.Size / stride, stride, &vRoomBoundingBoxMin3f, &vRoomBoundingBoxMax3f); g_fRoomRadius = (float)sqrt( pow( (double)( vRoomBoundingBoxMax3f.x - vRoomBoundingBoxMin3f.x ), 2.0 ) + pow( (double)( vRoomBoundingBoxMax3f.y - vRoomBoundingBoxMin3f.y ), 2.0 ) + pow( (double)( vRoomBoundingBoxMax3f.z - vRoomBoundingBoxMin3f.z ), 2.0 ) ) / 2.0f; // Initialize the light mesh V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"media\\objects\\spotlight.x" ) ); if( FAILED( g_LightMesh.Create( pd3dDevice, str ) ) ) return DXUTERR_MEDIANOTFOUND; V_RETURN( g_LightMesh.SetVertexDecl( pd3dDevice, g_aVertDecl ) ); // World transform to identity D3DXMATRIXA16 mIdent; D3DXMatrixIdentity( &mIdent ); V_RETURN( pd3dDevice->SetTransform( D3DTS_WORLD, &mIdent ) ); // Calculates the real samples on the light source g_fRealSamples = 0; for( float x = 0.5f / g_fLightSourceSamples; x < g_fLightSourceSamples; x++ ) { for( float y = 0.5f / g_fLightSourceSamples; y < g_fLightSourceSamples; y++ ) { if( x * x + y * y < g_fLightSourceSamples * g_fLightSourceSamples ) { g_fRealSamples++; } } } g_fRealSamples = 1.0f / g_fRealSamples; return S_OK; } //-------------------------------------------------------------------------------------- // This callback function will be called immediately after the Direct3D device has been // reset, which will happen after a lost device scenario. This is the best location to // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever // the device is lost. Resources created here should be released in the OnLostDevice // callback. //-------------------------------------------------------------------------------------- HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* 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() ); if( g_pFontSmall ) V_RETURN( g_pFontSmall->OnResetDevice() ); if( g_pEffect ) V_RETURN( g_pEffect->OnResetDevice() ); // Create a sprite to help batch calls when drawing many lines of text V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) ); // Setup the camera's projection parameters float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height; g_CamCamera.SetProjParams( D3DX_PI/4, fAspectRatio, g_fLightFrontPlane, g_fLightBackPlane ); g_LightCamera.SetProjParams( D3DX_PI/4, fAspectRatio, g_fLightFrontPlane, g_fLightBackPlane ); // Create the default texture (used when a triangle does not use a texture) V_RETURN( pd3dDevice->CreateTexture( 1, 1, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pDefaultTexture, NULL ) ); D3DLOCKED_RECT lr; V_RETURN( g_pDefaultTexture->LockRect( 0, &lr, NULL, 0 ) ); *(LPDWORD)lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 ); V_RETURN( g_pDefaultTexture->UnlockRect( 0 ) ); // Restore the scene objects for( int i = 0; i < NUM_OBJ; ++i ) V_RETURN( g_Obj[i].m_Mesh.RestoreDeviceObjects( pd3dDevice ) ); V_RETURN( g_LightMesh.RestoreDeviceObjects( pd3dDevice ) ); // Create textures CreateTexture(); // Positon the HUD g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 ); g_HUD.SetSize( 170, pBackBufferSurfaceDesc->Height ); // Create vertex declaration for the fullscreen quad V( pd3dDevice->CreateVertexDeclaration( g_aFullScreneQuadVertex, &g_pFullScreenQuadVertexDeclaration ) ); V_RETURN( pd3dDevice->CreateVertexBuffer( 6 * sizeof( FullScreenQuadVertexStruct ), D3DUSAGE_WRITEONLY, D3DFVF_FULLSCREENQUADVERTEX, D3DPOOL_DEFAULT, &g_pFullScreenQuadVertexBuffer, NULL ) ); void* pVertices; V( g_pFullScreenQuadVertexBuffer->Lock( 0, sizeof( fullscreen ), (void**)&pVertices, 0 ) ); memcpy( pVertices, fullscreen, sizeof( fullscreen ) ); g_pFullScreenQuadVertexBuffer->Unlock(); return S_OK; } //-------------------------------------------------------------------------------------- // Creates textures // They can be resized on the fly //-------------------------------------------------------------------------------------- void CreateTexture() { HRESULT hr; SAFE_RELEASE( g_pShadowMapColorTexture ); SAFE_RELEASE( g_pShadowMapColorSurface ); SAFE_RELEASE( g_pShadowWeightTexture ); SAFE_RELEASE( g_pShadowWeightSurface ); SAFE_RELEASE( g_pShadowMapZTexture ); SAFE_RELEASE( g_pShadowMapZSurface ); SAFE_RELEASE( g_pShadowWeightZTexture ); SAFE_RELEASE( g_pShadowWeightZSurface ); SAFE_RELEASE( g_pFocusingMapColorTexture ); SAFE_RELEASE( g_pFocusingMapColorSurface ); SAFE_RELEASE( g_pMemoryMappedTexture ); SAFE_RELEASE( g_pMemoryMappedTextureSurface ); // Create the shadow map texture V( g_pd3dDevice->CreateTexture( g_iShadowMapSize, g_iShadowMapSize, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &g_pShadowMapColorTexture, NULL ) ); V( g_pShadowMapColorTexture->GetSurfaceLevel( 0, &g_pShadowMapColorSurface ) ); V( g_pd3dDevice->CreateTexture( g_iShadowMapSize, g_iShadowMapSize, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, //D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &g_pShadowWeightTexture, NULL ) ); V( g_pShadowWeightTexture->GetSurfaceLevel( 0, &g_pShadowWeightSurface ) ); // Create the depth stencil texture V( g_pd3dDevice->CreateTexture( g_iShadowMapSize, g_iShadowMapSize, 1, D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24S8, D3DPOOL_DEFAULT, &g_pShadowMapZTexture, NULL ) ); V( g_pShadowMapZTexture->GetSurfaceLevel( 0, &g_pShadowMapZSurface ) ); V( g_pd3dDevice->CreateTexture( g_iShadowMapSize, g_iShadowMapSize, 1, D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24S8, D3DPOOL_DEFAULT, &g_pShadowWeightZTexture, NULL ) ); V( g_pShadowWeightZTexture->GetSurfaceLevel( 0, &g_pShadowWeightZSurface ) ); // Create the focusing map texture V( g_pd3dDevice->CreateTexture( g_iFocusingMapSize, g_iFocusingMapSize, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &g_pFocusingMapColorTexture, NULL ) ); V( g_pFocusingMapColorTexture->GetSurfaceLevel( 0, &g_pFocusingMapColorSurface ) ); // Memory mapped texture V( g_pd3dDevice->CreateTexture( g_iFocusingMapSize, g_iFocusingMapSize, 1, D3DUSAGE_DYNAMIC, D3DFMT_A32B32G32R32F, D3DPOOL_SYSTEMMEM, &g_pMemoryMappedTexture, NULL ) ); V( g_pMemoryMappedTexture->GetSurfaceLevel( 0, &g_pMemoryMappedTextureSurface ) ); } //-------------------------------------------------------------------------------------- // This callback function will be called once at the beginning of every frame. This is the // best location for your application to handle updates to the scene, but is not // intended to contain actual rendering calls, which should instead be placed in the // OnFrameRender callback. //-------------------------------------------------------------------------------------- void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) { // Update the camera's position based on user input g_CamCamera.FrameMove( fElapsedTime ); g_LightCamera.FrameMove( fElapsedTime ); if( !g_bPause ) { // Animate the plane, car and sphere meshes D3DXMATRIXA16 m; D3DXMatrixRotationY( &m, D3DX_PI * fElapsedTime / 4.0f ); D3DXMatrixMultiply( &g_Obj[1].m_mWorld, &g_Obj[1].m_mWorld, &m ); D3DXMatrixRotationY( &m, -D3DX_PI * fElapsedTime / 4.0f ); D3DXMatrixMultiply( &g_Obj[2].m_mWorld, &g_Obj[2].m_mWorld, &m ); } } //-------------------------------------------------------------------------------------- // Renders the scene onto the current render target using the current // technique in the effect. //-------------------------------------------------------------------------------------- void RenderScene( IDirect3DDevice9* pd3dDevice, float fElapsedTime, const D3DXMATRIX *pmView, const D3DXMATRIX *pmProj ) { HRESULT hr; // Initialize required parameter V( g_pEffect->SetTexture( "g_txShadowMapColor", g_pShadowMapColorTexture ) ); V( g_pEffect->SetTexture( "g_txShadowWeight", g_pShadowWeightTexture ) ); V( g_pEffect->SetTexture( "g_txShadowMapZ", g_pShadowMapZTexture ) ); V( g_pEffect->SetFloat( "g_fFov", ( (float)g_iFov ) / 57.2958f ) ); V( g_pEffect->SetFloat( "g_fLightSize", g_fLightSize ) ); V( g_pEffect->SetFloat( "g_fIntensity", g_fIntensity ) ); V( g_pEffect->SetFloat( "g_fShadowBias", g_fShadowBias ) ); V( g_pEffect->SetFloat( "near", g_fLightFrontPlane ) ); V( g_pEffect->SetFloat( "far", g_fLightBackPlane ) ); V( g_pEffect->SetFloat( "SHADOWMAP_SIZE", (float)g_iShadowMapSize)); V( g_pEffect->SetFloat( "HALF_TEXEL", 0.5f / (float)g_iShadowMapSize)); V( g_pEffect->SetFloat( "g_fBiasSlope", g_fBiasSlope) ); V( g_pEffect->SetFloat( "g_fRealSamples", g_fRealSamples ) ); V( g_pEffect->SetInt( "g_iKernelSize", g_iKernelSize ) ); V( g_pEffect->SetBool( "g_bRenderBaseTexture", g_bRenderBaseTexture ) ); //set special texture matrix for shadow mapping float fOffsetX = 0.5f + (0.5f / (float)g_iShadowMapSize); float fOffsetY = 0.5f + (0.5f / (float)g_iShadowMapSize); unsigned int range = 1; //note different scale in DX9! //float fBias = -0.001f * (float)range; float fBias = 0.0f; D3DXMATRIXA16 texScaleBiasMat( 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, (float)range, 0.0f, fOffsetX, fOffsetY, -g_fShadowBias/1000.0f, 1.0f ); V( g_pEffect->SetMatrix( "TexScaleBias", &texScaleBiasMat ) ); // Choose the right shader method switch( g_iShadowMethod ) { case 0: { if( g_bRenderShadowMap ) { V( g_pEffect->SetTechnique( "RenderShadowMap_0" ) ); } else { V( g_pEffect->SetTechnique( "RenderSceneWithTechnique_0" ) ); } break; } case 1: { if( g_bRenderShadowMap ) { V( g_pEffect->SetTechnique( "RenderShadowMap_6" ) ); } else { V( g_pEffect->SetTechnique( "RenderSceneWithTechnique_6" ) ); } break; } case 2: { if( g_bRenderShadowMap ) { V( g_pEffect->SetTechnique( "RenderShadowMap_7" ) ); } else { V( g_pEffect->SetTechnique( "RenderSceneWithTechnique_7" ) ); } break; } } if( g_bRenderFocusingMap ) { V( g_pEffect->SetTechnique( "RenderFocusingMap" ) ); } // Begin the scene if( SUCCEEDED( pd3dDevice->BeginScene() ) ) { if( !g_bRenderGUI ) { // Render the objects for( int obj = 0; obj < NUM_OBJ; ++obj ) { D3DXMATRIXA16 mWorld, mWorldView, mWorldViewProj; mWorld = g_Obj[obj].m_mWorld; D3DXMatrixMultiply( &mWorldView, &mWorld, pmView ); D3DXMatrixMultiply( &mWorldViewProj, &mWorldView, pmProj ); V( g_pEffect->SetMatrix( "WorldViewProj", &mWorldViewProj ) ); // Compute the view matrix for the light D3DXMATRIXA16 mLightView, WorldLight, WorldLightProj; if( g_bRenderBaseTexture ) { mLightView = *g_LightCamera.GetViewMatrix(); } else { mLightView = g_mLightView; } D3DXMatrixMultiply( &WorldLight, &mWorld, &mLightView ); V( g_pEffect->SetMatrix( "WorldLight", &WorldLight ) ); D3DXMatrixMultiply( &WorldLightProj, &WorldLight, &g_mLightProj ); V( g_pEffect->SetMatrix( "WorldLightProj", &WorldLightProj ) ); LPD3DXMESH pMesh = g_Obj[obj].m_Mesh.GetMesh(); UINT cPass; V( g_pEffect->Begin( &cPass, 0 ) ); for( UINT p = 0; p < cPass; ++p ) { V( g_pEffect->BeginPass( p ) ); for( DWORD i = 0; i < g_Obj[obj].m_Mesh.m_dwNumMaterials; ++i ) { D3DXVECTOR4 vDif( g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.r, g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.g, g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.b, g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.a ); if( g_bUseTexture ) { V( g_pEffect->SetVector( "g_vMaterial", &vDif ) ); if( g_Obj[obj].m_Mesh.m_pTextures[i] ) { V( g_pEffect->SetTexture( "g_txDefaultTexture", g_Obj[obj].m_Mesh.m_pTextures[i] ) ) } else { V( g_pEffect->SetTexture( "g_txDefaultTexture", g_pDefaultTexture ) ) } } else { V( g_pEffect->SetVector( "g_vMaterial", &D3DXVECTOR4(1,1,1,1) ) ); V( g_pEffect->SetTexture( "g_txDefaultTexture", g_pDefaultTexture ) ); } V( g_pEffect->CommitChanges() ); V( pMesh->DrawSubset( i ) ); } V( g_pEffect->EndPass() ); } V( g_pEffect->End() ); } // Render light source if( !g_bRenderGUI && g_bRenderBaseTexture && !g_bRenderShadowMap && !g_bRenderFocusingMap && g_bCameraPerspective ) { V( g_pEffect->SetTechnique( "RenderLight" ) ); D3DXMATRIXA16 mWorldView = *g_LightCamera.GetWorldMatrix(); D3DXMatrixMultiply( &mWorldView, &mWorldView, pmView ); D3DXMatrixMultiply( &mWorldView, &mWorldView, pmProj ); V( g_pEffect->SetMatrix( "WorldViewProj", &mWorldView ) ); UINT cPass; LPD3DXMESH pMesh = g_LightMesh.GetMesh(); V( g_pEffect->Begin( &cPass, 0 ) ); for( UINT p = 0; p < cPass; ++p ) { V( g_pEffect->BeginPass( p ) ); for( DWORD i = 0; i < g_LightMesh.m_dwNumMaterials; ++i ) { V( g_pEffect->SetTexture( "g_txDefaultTexture", g_LightMesh.m_pTextures[i] ) ); V( g_pEffect->CommitChanges() ); V( pMesh->DrawSubset( i ) ); } V( g_pEffect->EndPass() ); } V( g_pEffect->End() ); } } if( g_bRenderGUI && !g_bRenderShadowMap && !g_bRenderFocusingMap ){ // Render stats and help text RenderText(); // Render the UI elements g_HUD.OnRender( fElapsedTime ); } V( pd3dDevice->EndScene() ); } } //-------------------------------------------------------------------------------------- // Computes the focusing matrix //-------------------------------------------------------------------------------------- void ComputeFocusingMatrix( IDirect3DDevice9* g_pd3dDevice ) { float fMinU = 1.0f, fMinV = 1.0f; // min must start from 1 to decrease float fMaxU = -1.0f, fMaxV = -1.0f; // max must start from -1 to increase g_pd3dDevice->GetRenderTargetData( g_pFocusingMapColorSurface, g_pMemoryMappedTextureSurface ); // Calculate U and V, max and min values. D3DLOCKED_RECT pmLRect; g_pMemoryMappedTexture->LockRect(0, &pmLRect, NULL, D3DLOCK_DISCARD); for ( long int i = 0; i < g_iFocusingMapSize * g_iFocusingMapSize ; i++) { fMinU = min( fMinU, ( (float*)pmLRect.pBits)[4 * i] ); fMaxU = max( fMaxU, ( (float*)pmLRect.pBits)[4 * i] ); fMinV = min( fMinV, ( (float*)pmLRect.pBits)[4 * i + 1] ); fMaxV = max( fMaxV, ( (float*)pmLRect.pBits)[4 * i + 1] ); } g_pMemoryMappedTexture->UnlockRect(0); g_mFocusingMatrix = D3DXMATRIXA16( 2.0f/( fMaxU - fMinU ), 0.0f, 0.0f, 0.0f, 0.0f, 2.0f/( fMaxV - fMinV ), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -(fMaxU+fMinU)/( fMaxU - fMinU ), -(fMinV+fMaxV)/( fMaxV - fMinV ), 0.0f, 1.0f); } //-------------------------------------------------------------------------------------- // This callback function will be called at the end of every frame to perform all the // rendering calls for the scene, and it will also be called if the window needs to be // repainted. After this function has returned, DXUT will call // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain //-------------------------------------------------------------------------------------- void CALLBACK OnFrameRender( IDirect3DDevice9* 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_bShowText && !g_bSaveFrame ) { g_SettingsDlg.OnRender( fElapsedTime ); return; } HRESULT hr; // Compute the view matrix for the light D3DXMATRIXA16 mLightView = *g_LightCamera.GetViewMatrix(); D3DXVECTOR3 vLightEyePt = *g_LightCamera.GetEyePt(); float fLightDist = sqrt( vLightEyePt.x * vLightEyePt.x + vLightEyePt.y * vLightEyePt.y + vLightEyePt.z * vLightEyePt.z ); // The light is inside of the room g_fLightFrontPlane = 0.1f; g_fLightBackPlane = 7.0f * g_fRoomRadius; // 3.5 is the scale factor defined in room world matrix if( 3.5f * g_fRoomRadius <= fLightDist ){ // The light is outside of the room g_fLightFrontPlane = fLightDist - 3.5f * g_fRoomRadius; g_fLightBackPlane = fLightDist + 3.5f * g_fRoomRadius; } D3DXMatrixPerspectiveFovLH( &g_mLightProj, D3DXToRadian(g_iLightFov), 1, g_fLightFrontPlane, g_fLightBackPlane ); const D3DXMATRIX *pmView = g_bCameraPerspective ? g_CamCamera.GetViewMatrix() : &mLightView; const D3DXMATRIX *pmProj = g_bCameraPerspective ? g_CamCamera.GetProjMatrix() : &g_mLightProj; // save original LPDIRECT3DSURFACE9 pOldRT = NULL; V( pd3dDevice->GetRenderTarget( 0, &pOldRT ) ); LPDIRECT3DSURFACE9 pOldDS = NULL; V( SUCCEEDED( pd3dDevice->GetDepthStencilSurface( &pOldDS ) ) ); V( g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ) ); // Render: FOCUSING MAP -------------------------------------------------------------------------------- if( g_bUseFocusing ){ pd3dDevice->SetRenderTarget( 0, g_pFocusingMapColorSurface ); pd3dDevice->SetDepthStencilSurface( g_pShadowMapZSurface ); g_bRenderFocusingMap = true; RenderScene( pd3dDevice, fElapsedTime, g_CamCamera.GetViewMatrix(), g_CamCamera.GetProjMatrix() ); ComputeFocusingMatrix( pd3dDevice ); g_bRenderFocusingMap = false; if( g_iShadowMethod != 2 ){ // The 2. method does not use Focusing D3DXMatrixMultiply( &g_mLightProj, &g_mLightProj, &g_mFocusingMatrix ); } } // Render: FOCUSING MAP -------------------------------------------------------------------------------- g_mLightView = *g_LightCamera.GetViewMatrix(); if( g_iShadowMethod == 0 ) { // Render: to blend - Base texture -------------------------------------------------------------------------------- pd3dDevice->SetRenderTarget( 0, g_pShadowWeightSurface ); pd3dDevice->SetDepthStencilSurface( g_pShadowWeightZSurface ); pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L ); g_bRenderBaseTexture = true; RenderScene( pd3dDevice, fElapsedTime, pmView, pmProj ); g_bRenderBaseTexture = false; // Render: to blend - Base texture -------------------------------------------------------------------------------- // Render: to blend - additional shadow -------------------------------------------------------------------------------- g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE ); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE ); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true); g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false); float partial = g_fLightSize / 2.0f; float step = g_fLightSize / ( g_fLightSourceSamples * 2.0f ); for( float x = -partial + step; x < partial; x+=step ) { for( float y = -partial + step; y < partial; y+=step ) { if( x * x + y * y < g_fLightSourceSamples * g_fLightSourceSamples ) { g_mLightView = *g_LightCamera.GetViewMatrix(); g_mLightView._41 += x; g_mLightView._42 += y; // Render: SHADOW MAP -------------------------------------------------------------------------------- pd3dDevice->SetRenderTarget( 0, g_pShadowMapColorSurface ); pd3dDevice->SetDepthStencilSurface( g_pShadowMapZSurface ); // Clear the render buffers pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L ); g_bRenderShadowMap = true; float fTemp = 0.0f;// set depth bias pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&g_fBiasSlope); RenderScene( pd3dDevice, fElapsedTime, &mLightView, &g_mLightProj ); pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&fTemp); g_bRenderShadowMap = false; // Render: SHADOW MAP -------------------------------------------------------------------------------- pd3dDevice->SetRenderTarget( 0, g_pShadowWeightSurface ); pd3dDevice->SetDepthStencilSurface( g_pShadowWeightZSurface ); RenderScene( pd3dDevice, fElapsedTime, pmView, pmProj ); } } } g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); // Render: to blend - additional shadow -------------------------------------------------------------------------------- // Render: GUI -------------------------------------------------------------------------------- g_bRenderGUI = true; RenderScene( pd3dDevice, fElapsedTime, &mLightView, &g_mLightProj ); g_bRenderGUI = false; // Render: GUI -------------------------------------------------------------------------------- // save frame if( g_bSaveFrame ){ TCHAR sz[50]; sz[49] = 0; StringCchPrintf( sz, 50, L"images/ShadowWeightOrig_blend.png", g_iPictureNumber++ ); D3DXSaveSurfaceToFile( sz, D3DXIFF_PNG, g_pShadowWeightSurface, NULL,NULL); } // Render: to blend -------------------------------------------------------------------------------- // Render: to screen - render a full screene quad -------------------------------------------------------------------------------- if( pOldDS ) { pd3dDevice->SetDepthStencilSurface( pOldDS ); pOldDS->Release(); } pd3dDevice->SetRenderTarget( 0, pOldRT ); pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L ); UINT cPass; if( SUCCEEDED( pd3dDevice->BeginScene() ) ) { V( g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ) ); V( g_pEffect->SetTechnique( "RenderMapScreen" ) ); V( g_pEffect->Begin( &cPass, 0 ) ); V( g_pEffect->BeginPass( 0 ) ); V( g_pEffect->CommitChanges() ); V( g_pd3dDevice->SetVertexDeclaration( g_pFullScreenQuadVertexDeclaration ) ); V( g_pd3dDevice->SetStreamSource( 0, g_pFullScreenQuadVertexBuffer, 0, sizeof(FullScreenQuadVertexStruct) ) ); V( g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 ) ); V( g_pEffect->EndPass() ); V( g_pEffect->End() ); V( pd3dDevice->EndScene() ); } // Render: to screen -------------------------------------------------------------------------------- } else { // Render: SHADOW MAP -------------------------------------------------------------------------------- pd3dDevice->SetRenderTarget( 0, g_pShadowMapColorSurface ); pd3dDevice->SetDepthStencilSurface( g_pShadowMapZSurface ); // Clear the render buffers pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L ); g_bRenderShadowMap = true; float fTemp = 0.0f;// set depth bias pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&g_fBiasSlope); RenderScene( pd3dDevice, fElapsedTime, &mLightView, &g_mLightProj ); pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&fTemp); g_bRenderShadowMap = false; // Render: SHADOW MAP -------------------------------------------------------------------------------- if( pOldDS ) { pd3dDevice->SetDepthStencilSurface( pOldDS ); pOldDS->Release(); } pd3dDevice->SetRenderTarget( 0, pOldRT ); pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L ); // Render: to screen -------------------------------------------------------------------------------- const D3DXMATRIX *pmView = g_bCameraPerspective ? g_CamCamera.GetViewMatrix() : &mLightView; const D3DXMATRIX *pmProj = g_bCameraPerspective ? g_CamCamera.GetProjMatrix() : &g_mLightProj; RenderScene( pd3dDevice, fElapsedTime, pmView, pmProj ); g_bRenderGUI = true; RenderScene( pd3dDevice, fElapsedTime, pmView, pmProj ); g_bRenderGUI = false; // Render: to screen -------------------------------------------------------------------------------- } SAFE_RELEASE( pOldRT ); g_bSaveFrame = false; } //-------------------------------------------------------------------------------------- // Render the help and statistics text. This function uses the ID3DXFont interface for // efficient text rendering. //-------------------------------------------------------------------------------------- void RenderText() { // The helper object simply helps keep track of text position, and color // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr ); // If NULL is passed in as the sprite object, then it will work however the // pFont->DrawText() will not be batched together. Batching calls will improves performance. CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 ); // Output statistics txtHelper.Begin(); txtHelper.SetInsertionPos( 5, 5 ); // Draw help if( g_bShowText && !g_bSaveFrame ) { if( g_bUseTexture ) { txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); } else { txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) ); } txtHelper.DrawTextLine( DXUTGetFrameStats(true) ); txtHelper.DrawTextLine( DXUTGetDeviceStats() ); const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc(); txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*8 ); txtHelper.DrawTextLine( L"Controls:" ); txtHelper.SetInsertionPos( 15, pd3dsdBackBuffer->Height-15*7 ); txtHelper.DrawFormattedTextLine( L"Rotate camera\n" L"Move camera\n" L"Rotate light\n" L"Move light\n" L"Modify shadow generation method\n" L"Save picture\n" L"Quit" ); txtHelper.SetInsertionPos( 265, pd3dsdBackBuffer->Height-15*7 ); txtHelper.DrawTextLine( L"Left drag mouse\n" L"W,S,A,D,Q,E\n" L"Right drag mouse\n" L"W,S,A,D,Q,E while holding right mouse\n" L"Forward:M, backward:N, directly:combo box\n" L"Z\n" L"ESC" ); WCHAR sz0[50], sz1[50], sz2[50], sz3[50], sz4[50], sz5[50], sz6[50], sz7[50], sz8[50], sz9[50], sz10[50]; StringCchPrintf( sz0, 50, L"%i", g_iFov ); StringCchPrintf( sz1, 50, L"%i", g_iLightFov ); StringCchPrintf( sz2, 50, L"%.2f", g_fLightSize ); StringCchPrintf( sz3, 50, L"%.2f", g_fIntensity ); StringCchPrintf( sz4, 50, L"%.2f", g_fShadowBias ); StringCchPrintf( sz5, 50, L"%.2f", g_fBiasSlope ); StringCchPrintf( sz6, 50, L"%i", g_iKernelSize ); StringCchPrintf( sz7, 50, L"%i", g_iShadowMapSize ); StringCchPrintf( sz8, 50, L"%i", g_iFocusingMapSize ); StringCchPrintf( sz9, 50, L"%i", (int)( g_fLightSourceSamples * g_fLightSourceSamples ) ); StringCchPrintf( sz10,50, L"%i", (int)( 1.0f / g_fRealSamples ) ); switch( g_iShadowMethod ){ case 0: { txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width - 310, 90 ); txtHelper.DrawTextLine( L"" ); txtHelper.DrawTextLine( L"RealFov" ); txtHelper.DrawTextLine( L"LightSize" ); txtHelper.DrawTextLine( L"Intensity" ); txtHelper.DrawTextLine( L"g_fShadowBias" ); txtHelper.DrawTextLine( L"g_fBiasSlope" ); txtHelper.DrawTextLine( L"" ); txtHelper.DrawTextLine( L"ShadowMapSize" ); txtHelper.DrawTextLine( L"FocusingMapSize" ); txtHelper.DrawTextLine( L"LightSSamp" ); txtHelper.DrawTextLine( L"LightSRealSamp" ); txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width - 210, 90 ); txtHelper.DrawTextLine( L"" ); txtHelper.DrawTextLine( sz1 ); txtHelper.DrawTextLine( sz2 ); txtHelper.DrawTextLine( sz3 ); txtHelper.DrawTextLine( sz4 ); txtHelper.DrawTextLine( sz5 ); txtHelper.DrawTextLine( L"" ); txtHelper.DrawTextLine( sz7 ); txtHelper.DrawTextLine( sz8 ); txtHelper.DrawTextLine( sz9 ); txtHelper.DrawTextLine( sz10 ); break; } case 1: { txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width - 310, 90 ); txtHelper.DrawTextLine( L"" ); txtHelper.DrawTextLine( L"RealFov" ); txtHelper.DrawTextLine( L"g_fLightSize" ); txtHelper.DrawTextLine( L"sceneScale" ); txtHelper.DrawTextLine( L"g_fShadowBias" ); txtHelper.DrawTextLine( L"g_fBiasSlope" ); txtHelper.DrawTextLine( L"g_iKernelSize" ); txtHelper.DrawTextLine( L"ShadowMapSize" ); txtHelper.DrawTextLine( L"FocusingMapSize" ); txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width - 210, 90 ); txtHelper.DrawTextLine( L"" ); txtHelper.DrawTextLine( sz1 ); txtHelper.DrawTextLine( sz2 ); txtHelper.DrawTextLine( sz3 ); txtHelper.DrawTextLine( sz4 ); txtHelper.DrawTextLine( sz5 ); txtHelper.DrawTextLine( sz6 ); txtHelper.DrawTextLine( sz7 ); txtHelper.DrawTextLine( sz8 ); break; } case 2: { txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width - 310, 90 ); txtHelper.DrawTextLine( L"g_iFov" ); txtHelper.DrawTextLine( L"RealFov" ); txtHelper.DrawTextLine( L"g_fLightSize" ); txtHelper.DrawTextLine( L"g_fIntensity" ); txtHelper.DrawTextLine( L"g_fShadowBias" ); txtHelper.DrawTextLine( L"AddToRR2" ); txtHelper.DrawTextLine( L"g_iKernelSize" ); txtHelper.DrawTextLine( L"ShadowMapSize" ); txtHelper.DrawTextLine( L"FocusingMapSize" ); txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width - 210, 90 ); txtHelper.DrawTextLine( sz0 ); txtHelper.DrawTextLine( sz1 ); txtHelper.DrawTextLine( sz2 ); txtHelper.DrawTextLine( sz3 ); txtHelper.DrawTextLine( sz4 ); txtHelper.DrawTextLine( sz5 ); txtHelper.DrawTextLine( sz6 ); txtHelper.DrawTextLine( sz7 ); txtHelper.DrawTextLine( sz8 ); break; } } } else { txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); // txtHelper.DrawTextLine( L"Press F1 for GUI" ); } txtHelper.End(); } //-------------------------------------------------------------------------------------- // Updates the values of parameter from the slider's value. //-------------------------------------------------------------------------------------- void UpdateParamFromSlider() { int iSelectedSliderID = g_iSelectedMenuItem + 100; int iSelectedValue = g_HUD.GetSlider( iSelectedSliderID )->GetValue(); switch (g_iSelectedMenuItem) { case 0: g_iFov = iSelectedValue; break; case 1: g_iLightFov = iSelectedValue; break; case 2: if( g_iShadowMethod == 1 ) g_fLightSize = (float)iSelectedValue / 10000.0f; else g_fLightSize = (float)iSelectedValue / 100.0f; break; case 3: if( g_iShadowMethod == 1 ) g_fIntensity = (float)iSelectedValue / 2.0f; else g_fIntensity = (float)iSelectedValue / 100.0f; break; g_fIntensity = (float)iSelectedValue / 100.0f; break; case 4: g_fShadowBias = (float)iSelectedValue / 100.0f; break; case 5: g_fBiasSlope = (float)iSelectedValue / 100.0f; break; case 6: g_iKernelSize = iSelectedValue; break; case 7: g_iShadowMapSize = (int)pow( 2.0f, iSelectedValue ); CreateTexture(); break; case 8: g_iFocusingMapSize = (int)pow( 2.0f, iSelectedValue ); CreateTexture(); break; case 9: g_fLightSourceSamples = (float)(int)( (float)iSelectedValue / 50.0f ); g_fRealSamples = 0; for( float x = 0.5f / g_fLightSourceSamples; x < g_fLightSourceSamples; x++ ) { for( float y = 0.5f / g_fLightSourceSamples; y < g_fLightSourceSamples; y++ ) { if( x * x + y * y < g_fLightSourceSamples * g_fLightSourceSamples ) { g_fRealSamples++; } } } g_fRealSamples = 1.0f / g_fRealSamples; break; } } //-------------------------------------------------------------------------------------- // Modify the value of the slider //-------------------------------------------------------------------------------------- void IncrementSlider( int increment ) { int iSelectedSliderID = g_iSelectedMenuItem + 100; int iSelectedValue = g_HUD.GetSlider( iSelectedSliderID )->GetValue(); iSelectedValue += increment; if( iSelectedValue < g_iSliderMinValues[g_iSelectedMenuItem] ) iSelectedValue = g_iSliderMinValues[g_iSelectedMenuItem]; if( iSelectedValue > g_iSliderMaxValues[g_iSelectedMenuItem] ) iSelectedValue = g_iSliderMaxValues[g_iSelectedMenuItem]; g_HUD.GetSlider( iSelectedSliderID )->SetValue( iSelectedValue ); UpdateParamFromSlider(); } //-------------------------------------------------------------------------------------- // Before handling window messages, DXUT passes incoming windows // messages to the application through this callback function. If the application sets // *pbNoFurtherProcessing to TRUE, then DXUT will not process this message. //-------------------------------------------------------------------------------------- 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; } *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Pass all windows messages to camera and dialogs so they can respond to user input if( WM_KEYDOWN != uMsg || g_bRightMouseDown ) g_LightCamera.HandleMessages( hWnd, uMsg, wParam, lParam ); if( WM_KEYDOWN != uMsg || !g_bRightMouseDown ) { if( g_bCameraPerspective ) g_CamCamera.HandleMessages( hWnd, uMsg, wParam, lParam ); else g_LightCamera.HandleMessages( hWnd, uMsg, wParam, lParam ); } return 0; } //-------------------------------------------------------------------------------------- // As a convenience, DXUT inspects the incoming windows messages for // keystroke messages and decodes the message parameters to pass relevant keyboard // messages to the application. 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 ) { switch( nChar ) { // Change the selected shadowing method. case 'M': { bool modify = g_iShadowMethod == 1; g_iShadowMethod = ( g_iShadowMethod + 1 ) % g_iNumberOfMethods; g_pTechniquesListComboBox->SetSelectedByIndex( g_iShadowMethod ); if( !modify && ( g_iShadowMethod == 1 ) ){ g_fLightSize /= 100.0f; g_fIntensity *= 50.0f; } if( modify && !( g_iShadowMethod == 1 ) ){ g_fLightSize *= 100.0f; g_fIntensity /= 50.0f; } break; } case 'N': { bool modify = g_iShadowMethod == 1; g_iShadowMethod = ( g_iShadowMethod - 1 ); if( g_iShadowMethod < 0 ) { g_iShadowMethod += g_iNumberOfMethods; } g_pTechniquesListComboBox->SetSelectedByIndex( g_iShadowMethod ); if( !modify && ( g_iShadowMethod == 1 ) ){ g_fLightSize /= 100.0f; g_fIntensity *= 50.0f; } if( modify && !( g_iShadowMethod == 1 ) ){ g_fLightSize *= 100.0f; g_fIntensity /= 50.0f; } break; } case 'Z': { g_bSaveFrame = true; break; } } } } //-------------------------------------------------------------------------------------- // Mouse handler //-------------------------------------------------------------------------------------- void CALLBACK MouseProc( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos, void* pUserContext ) { g_bRightMouseDown = bRightButtonDown; } //-------------------------------------------------------------------------------------- // Handles the GUI events //-------------------------------------------------------------------------------------- void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext ) { if( nControlID >= HUNDRED && nControlID <= LAST_SLIDER ) { g_iSelectedMenuItem = nControlID - HUNDRED; UpdateParamFromSlider(); } switch( nControlID ) { case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break; case IDC_TOGGLEREF: DXUTToggleREF(); break; case IDC_CHANGEDEVICE: g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); break; case IDC_CHECKBOX: { CDXUTCheckBox *pCheck = (CDXUTCheckBox *)pControl; g_bShowText = pCheck->GetChecked(); g_pTechniquesListComboBox->SetVisible( g_bShowText ); const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc(); if( !g_bShowText ) { g_HUD.SetLocation( pd3dsdBackBuffer->Width-170, -500 ); } else { g_HUD.SetLocation( pd3dsdBackBuffer->Width-170, 0 ); } break; } case IDC_LIGHTPERSPECTIVE: { CDXUTCheckBox *pCheck = (CDXUTCheckBox *)pControl; g_bCameraPerspective = !pCheck->GetChecked(); if( g_bCameraPerspective ) { g_CamCamera.SetRotateButtons( true, false, false ); g_LightCamera.SetRotateButtons( false, false, true ); } else { g_CamCamera.SetRotateButtons( false, false, false ); g_LightCamera.SetRotateButtons( true, false, true ); } break; } case IDC_PAUSE_CHECKBOX: { CDXUTCheckBox *pCheck = (CDXUTCheckBox *)pControl; g_bPause = pCheck->GetChecked(); break; } case IDC_USE_TEXTURE_CHECKBOX: { CDXUTCheckBox *pCheck = (CDXUTCheckBox *)pControl; g_bUseTexture = pCheck->GetChecked(); break; } case IDC_METHOD_COMBO_BOX: { bool modify = g_iShadowMethod == 1; g_iShadowMethod = g_pTechniquesListComboBox->FindItem( g_pTechniquesListComboBox->GetSelectedItem()->strText ); if( !modify && ( g_iShadowMethod == 1 ) ){ g_fLightSize /= 100.0f; g_fIntensity *= 50.0f; } if( modify && !( g_iShadowMethod == 1 ) ){ g_fLightSize *= 100.0f; g_fIntensity /= 50.0f; } break; } case IDC_USE_FOCUSING_CHECKBOX: { CDXUTCheckBox *pCheck = (CDXUTCheckBox *)pControl; g_bUseFocusing = pCheck->GetChecked(); break; } } } //-------------------------------------------------------------------------------------- // This callback function will be called immediately after the Direct3D device has // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created // in the OnResetDevice callback should be released here, which generally includes all // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for // information about lost devices. //-------------------------------------------------------------------------------------- void CALLBACK OnLostDevice( void* pUserContext ) { g_DialogResourceManager.OnLostDevice(); g_SettingsDlg.OnLostDevice(); if( g_pFont ) g_pFont->OnLostDevice(); if( g_pFontSmall ) g_pFontSmall->OnLostDevice(); if( g_pEffect ) g_pEffect->OnLostDevice(); SAFE_RELEASE(g_pTextSprite); SAFE_RELEASE( g_pShadowMapColorTexture ); SAFE_RELEASE( g_pShadowMapColorSurface ); SAFE_RELEASE( g_pShadowWeightTexture ); SAFE_RELEASE( g_pShadowWeightSurface ); SAFE_RELEASE( g_pShadowMapZTexture ); SAFE_RELEASE( g_pShadowMapZSurface ); SAFE_RELEASE( g_pShadowWeightZTexture ); SAFE_RELEASE( g_pShadowWeightZSurface ); SAFE_RELEASE( g_pFocusingMapColorTexture ); SAFE_RELEASE( g_pFocusingMapColorSurface ); SAFE_RELEASE( g_pDefaultTexture ); SAFE_RELEASE( g_pMemoryMappedTexture ); SAFE_RELEASE( g_pMemoryMappedTextureSurface ); for( int i = 0; i < NUM_OBJ; ++i ) g_Obj[i].m_Mesh.InvalidateDeviceObjects(); g_LightMesh.InvalidateDeviceObjects(); SAFE_RELEASE( g_pFullScreenQuadVertexDeclaration ); SAFE_RELEASE( g_pFullScreenQuadVertexBuffer ); } //-------------------------------------------------------------------------------------- // This callback function will be called immediately after the Direct3D device has // been destroyed, which generally happens as a result of application termination or // windowed/full screen toggles. Resources created in the OnCreateDevice callback // should be released here, which generally includes all D3DPOOL_MANAGED resources. //-------------------------------------------------------------------------------------- void CALLBACK OnDestroyDevice( void* pUserContext ) { g_DialogResourceManager.OnDestroyDevice(); g_SettingsDlg.OnDestroyDevice(); SAFE_RELEASE( g_pEffect ); SAFE_RELEASE( g_pFont ); SAFE_RELEASE( g_pFontSmall ); SAFE_RELEASE( g_pVertDecl ); SAFE_RELEASE( g_pEffect ); for( int i = 0; i < NUM_OBJ; ++i ) g_Obj[i].m_Mesh.Destroy(); g_LightMesh.Destroy(); }