KeosD3D9Window.cpp

Go to the documentation of this file.
00001 /*
00002  * This source file is part of KEOS (Free 3D Engine)
00003  * For the latest info, see http://www.keosengine.org/
00004  * E-mails : thierry.vouriot@keosengine.org, yeri@keosengine.org
00005  *
00006  * This program is free software; you can redistribute it and/or modify it under
00007  * the terms of the GNU Lesser General Public License as published by the Free Software
00008  * Foundation; either version 2 of the License, or (at your option) any later
00009  * version.
00010  *
00011  * This program is distributed in the hope that it will be useful, but WITHOUT
00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License along with
00016  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00017  * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00018  * http://www.gnu.org/copyleft/lesser.txt.
00019  *
00020  */
00021 
00022 #include "KeosD3D9Window.h"
00023 #include "KeosD3D9Exception.h"
00024 #include "KeosLogger.h"
00025 #include "KeosD3D9RenderSystem.h"
00026 #include "KeosConsole.h"
00027 
00028 namespace Keos
00029 {
00030 
00031   //=======================================================================
00032   // CD3D9Window implementation
00033   //=======================================================================
00034 
00035   //-----------------------------------------------------------------------
00036   CD3D9Window::CD3D9Window(CD3D9* pD3D9)
00037   {
00038     m_pD3D9 = pD3D9;
00039     m_bIsFullScreen = false;
00040     m_HWnd = NULL;
00041     m_bActive = false;
00042     m_bSizing = false;
00043     m_bIsFullScreen = false;
00044     m_bReady = false;
00045     m_bClosed = false;
00046   }
00047 
00048   //-----------------------------------------------------------------------
00049   CD3D9Window::~CD3D9Window()
00050   {
00051     Destroy();
00052   }
00053 
00054   //-----------------------------------------------------------------------
00055   void CD3D9Window::Create(const String& strName, uint nWidth, uint nHeight, uint nColourDepth, bool bFullScreen)
00056   {
00057 
00058     HINSTANCE hInst = GetModuleHandle( KEOS_D3D9_LIB );
00059 
00060     m_FSAAType = D3DMULTISAMPLE_NONE;
00061     m_FSAAQuality = 0;
00062     m_bVSync = false;
00063     unsigned int displayFrequency = 0;
00064     String title = strName;
00065     unsigned int colourDepth = nColourDepth;
00066     int left = -1; // Defaults to screen center
00067     int top = -1; // Defaults to screen center
00068     bool depthBuffer = true;
00069     String border = "";
00070     bool outerSize = false;
00071 
00072     // Destroy current window if any
00073     if ( m_HWnd )
00074       Destroy();
00075 
00076     DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
00077     RECT rc;
00078 
00079     m_nWidth = nWidth;
00080     m_nHeight = nHeight;
00081     m_nTop = top;
00082     m_nLeft = left;
00083 
00084     if (!bFullScreen)
00085     {
00086       if (border == "none")
00087         dwStyle |= WS_POPUP;
00088       else if (border == "fixed")
00089         dwStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
00090                    WS_SYSMENU | WS_MINIMIZEBOX;
00091       else
00092         dwStyle |= WS_OVERLAPPEDWINDOW;
00093 
00094       if (!outerSize)
00095       {
00096         // Calculate window dimensions required
00097         // to get the requested client area
00098         SetRect(&rc, 0, 0, m_nWidth, m_nHeight);
00099         AdjustWindowRect(&rc, dwStyle, false);
00100         m_nWidth = rc.right - rc.left;
00101         m_nHeight = rc.bottom - rc.top;
00102 
00103         // Clamp width and height to the desktop dimensions
00104         int screenw = GetSystemMetrics(SM_CXSCREEN);
00105         int screenh = GetSystemMetrics(SM_CYSCREEN);
00106         if ((int)m_nWidth > screenw)
00107           m_nWidth = screenw;
00108         if ((int)m_nHeight > screenh)
00109           m_nHeight = screenh;
00110         if (m_nLeft < 0)
00111           m_nLeft = (screenw - m_nWidth) / 2;
00112         if (m_nTop < 0)
00113           m_nTop = (screenh - m_nHeight) / 2;
00114       }
00115     }
00116     else
00117     {
00118       dwStyle |= WS_POPUP;
00119       m_nTop = m_nLeft = 0;
00120     }
00121 
00122     // Register the window class
00123     // NB allow 4 bytes of window data for D3D9RenderWindow pointer
00124     WNDCLASS wc =
00125       {
00126         0, WndProc, 0, 0, hInst,
00127         LoadIcon(0, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
00128         (HBRUSH)GetStockObject(BLACK_BRUSH), 0, "KeosD3D9Wnd"
00129       };
00130     RegisterClass(&wc);
00131 
00132     // Create our main window
00133     // Pass pointer to self
00134     m_HWnd = CreateWindow("KeosD3D9Wnd", title.c_str(), dwStyle,
00135                           m_nLeft, m_nTop, m_nWidth, m_nHeight, (HWND) NULL, 0, hInst, this);
00136 
00137     // top and left represent outer window coordinates
00138     GetWindowRect(m_HWnd, &rc);
00139     m_nTop = rc.top;
00140     m_nLeft = rc.left;
00141     // width and height represent interior drawable area
00142     GetClientRect(m_HWnd, &rc);
00143     m_nWidth = rc.right;
00144     m_nHeight = rc.bottom;
00145 
00146     m_strName = strName;
00147     //mIsDepthBuffered = depthBuffer;
00148     m_bIsFullScreen = bFullScreen;
00149     m_nColourDepth = colourDepth;
00150 
00151     ILogger::Log("Created CD3D9Window '%s' : %dx%d, %dbpp",
00152                  m_strName.c_str(), m_nWidth, m_nHeight, m_nColourDepth);
00153 
00154     CreateD3DResources();
00155 
00156     m_bActive = true;
00157   }
00158 
00159   void CD3D9Window::CreateD3DResources(void)
00160   {
00161     // Set up the presentation parameters
00162     HRESULT hr;
00163     LPDIRECT3D9 pD3D = m_pD3D9->pD3D;
00164 
00165     D3DDEVTYPE devType = D3DDEVTYPE_HAL;
00166 
00167     ZeroMemory( &m_d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
00168     m_d3dpp.Windowed    = !m_bIsFullScreen;
00169     m_d3dpp.SwapEffect    = D3DSWAPEFFECT_DISCARD;
00170     m_d3dpp.BackBufferCount   = 1;
00171     m_d3dpp.EnableAutoDepthStencil = true;
00172     m_d3dpp.hDeviceWindow   = m_HWnd;
00173     m_d3dpp.BackBufferWidth   = m_nWidth;
00174     m_d3dpp.BackBufferHeight  = m_nHeight;
00175 
00176     if (m_bVSync)
00177       m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
00178     else
00179       m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
00180 
00181     m_d3dpp.BackBufferFormat  = D3DFMT_R5G6B5;
00182     if ( m_nColourDepth > 16 )
00183       m_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
00184 
00185     if (m_nColourDepth > 16 )
00186     {
00187       // Try to create a 32-bit depth, 8-bit stencil
00188       if ( FAILED( pD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,
00189                                            devType,  m_d3dpp.BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL,
00190                                            D3DRTYPE_SURFACE, D3DFMT_D24S8 )))
00191       {
00192         // Bugger, no 8-bit hardware stencil, just try 32-bit zbuffer
00193         if ( FAILED( pD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,
00194                                              devType,  m_d3dpp.BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL,
00195                                              D3DRTYPE_SURFACE, D3DFMT_D32 )))
00196         {
00197           // Jeez, what a naff card. Fall back on 16-bit depth buffering
00198           m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
00199         }
00200         else
00201           m_d3dpp.AutoDepthStencilFormat = D3DFMT_D32;
00202       }
00203       else
00204       {
00205         // Woohoo!
00206         if ( SUCCEEDED( pD3D->CheckDepthStencilMatch( D3DADAPTER_DEFAULT, devType,
00207                         m_d3dpp.BackBufferFormat, m_d3dpp.BackBufferFormat, D3DFMT_D24S8 ) ) )
00208         {
00209           m_d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
00210         }
00211         else
00212           m_d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
00213       }
00214     }
00215     else
00216       // 16-bit depth, software stencil
00217       m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
00218 
00219     m_d3dpp.MultiSampleType = m_FSAAType;
00220     m_d3dpp.MultiSampleQuality = (m_FSAAQuality == 0) ? 0 : m_FSAAQuality;
00221 
00222 
00223     if (!m_pD3D9->pD3DDevice)
00224     {
00225       // We haven't created the device yet, this must be the first time
00226 
00227       // Do we want to preserve the FPU mode? Might be useful for scientific apps
00228       DWORD extraFlags = 0;
00229 
00230       hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, devType, m_HWnd,
00231                                D3DCREATE_HARDWARE_VERTEXPROCESSING | extraFlags, &m_d3dpp, &(m_pD3D9->pD3DDevice) );
00232       if ( FAILED( hr ) )
00233       {
00234         hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, devType, m_HWnd,
00235                                  D3DCREATE_MIXED_VERTEXPROCESSING | extraFlags, &m_d3dpp, &(m_pD3D9->pD3DDevice) );
00236         if ( FAILED( hr ) )
00237         {
00238           hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, devType, m_HWnd,
00239                                    D3DCREATE_SOFTWARE_VERTEXPROCESSING | extraFlags, &m_d3dpp, &(m_pD3D9->pD3DDevice) );
00240         }
00241       }
00242       if ( FAILED( hr ) )
00243       {
00244         Destroy();
00245         D3D9_EXCEPT("Failed to create Direct3D9 Device", "CD3D9Window::CreateD3DResources");
00246       }
00247     }
00248     // Store references to buffers for convenience
00249     m_pD3D9->pD3DDevice->GetRenderTarget( 0, &m_pRenderSurface );
00250     m_pD3D9->pD3DDevice->GetDepthStencilSurface( &m_pRenderZBuffer );
00251     // release immediately so we don't hog them
00252     if (m_pRenderSurface)m_pRenderSurface->Release();
00253     if (m_pRenderZBuffer) m_pRenderZBuffer->Release();
00254   }
00255 
00256   //-----------------------------------------------------------------------
00257   void CD3D9Window::Destroy(void)
00258   {
00259     m_pRenderSurface = 0;
00260     m_pRenderZBuffer = 0;
00261 
00262     m_pD3D9->ReleaseDevice();
00263 
00264     DestroyWindow( m_HWnd );
00265     m_HWnd = 0;
00266     m_bActive = false;
00267   }
00268 
00269   //-----------------------------------------------------------------------
00270   bool CD3D9Window::IsClosed() const
00271   {
00272     return m_bClosed;
00273   }
00274 
00275   //-----------------------------------------------------------------------
00276   void CD3D9Window::Reposition(int left, int top)
00277   {
00279   }
00280 
00281   //-----------------------------------------------------------------------
00282   void CD3D9Window::Resize(uint nWidth, uint nHeight)
00283   {
00284     m_nWidth = nWidth;
00285     m_nHeight = nHeight;
00286 
00288   }
00289 
00290   //-----------------------------------------------------------------------
00291   void CD3D9Window::WindowMovedOrResized()
00292   {
00293     RECT temprect;
00294     ::GetClientRect(GetWindowHandle(), &temprect);
00295     Resize(temprect.right - temprect.left, temprect.bottom - temprect.top);
00296   }
00297 
00298   //-----------------------------------------------------------------------
00299   void CD3D9Window::SwapBuffers(bool bWaitForVSync)
00300   {
00301     if ( m_pD3D9->pD3DDevice )
00302     {
00303       HRESULT hr;
00304       hr = m_pD3D9->pD3DDevice->Present( NULL, NULL, NULL, NULL );
00305       if ( FAILED(hr) )
00306       {
00307         if (hr == D3DERR_DEVICELOST)
00308         {
00309           static_cast<CD3D9RenderSystem*>(
00310             CRoot::Instance().GetRenderSystem())->_NotifyDeviceLost();
00311           Sleep(500);
00312         }
00313         else D3D9_EXCEPT("Error Presenting surfaces", "CD3D9Window::SwapBuffers" );
00314       }
00315     }
00316   }
00317 
00318   //-----------------------------------------------------------------------
00319   void CD3D9Window::Update(void)
00320   {
00321     CD3D9RenderSystem* pRS = static_cast<CD3D9RenderSystem*>(
00322                                CRoot::Instance().GetRenderSystem());
00323     if (pRS->IsDeviceLost())
00324     {
00325       // Test the cooperative mode first
00326       HRESULT hr = m_pD3D9->pD3DDevice->TestCooperativeLevel();
00327       if (hr == D3DERR_DEVICELOST)
00328       {
00329         // device lost, and we can't reset
00330         // can't do anything about it here, wait until we get
00331         // D3DERR_DEVICENOTRESET; rendering calls will silently fail until
00332         // then (except Present, but we ignore device lost there too)
00333         m_pRenderSurface = 0;
00334         m_pRenderZBuffer = 0;
00335         Sleep(500);
00336         return;
00337       }
00338       else if (hr == D3DERR_DEVICENOTRESET)
00339       {
00340         // device lost, and we can reset
00341         pRS->RestoreLostDevice();
00342 
00343         // Still lost?
00344         if (pRS->IsDeviceLost())
00345         {
00346           // Wait a while
00347           Sleep(500);
00348           return;
00349         }
00350 
00351         // re-qeuery buffers
00352         m_pD3D9->pD3DDevice->GetRenderTarget( 0, &m_pRenderSurface );
00353         m_pD3D9->pD3DDevice->GetDepthStencilSurface( &m_pRenderZBuffer );
00354         // release immediately so we don't hog them
00355         if (m_pRenderSurface) m_pRenderSurface->Release();
00356         if (m_pRenderZBuffer) m_pRenderZBuffer->Release();
00357       }
00358     }
00359     IRenderWindow::Update();
00360   }
00361 
00362   //-----------------------------------------------------------------------
00363   LRESULT CD3D9Window::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
00364   {
00365     if (uMsg == WM_CREATE)
00366     {
00367       // copy CD3D9Window* from createwindow param to userdata slot
00368       SetWindowLong(hWnd, GWL_USERDATA,
00369                     (LONG)(((LPCREATESTRUCT)lParam)->lpCreateParams));
00370       return 0;
00371     }
00372 
00373     CD3D9Window* win =
00374       (CD3D9Window*)GetWindowLong(hWnd, GWL_USERDATA);
00375 
00376     if (!win)
00377       return DefWindowProc(hWnd, uMsg, wParam, lParam);
00378 
00379     switch ( uMsg )
00380     {
00381       case WM_ACTIVATE:
00382         win->m_bActive = (LOWORD(wParam) != WA_INACTIVE);
00383         break;
00384 
00385       case WM_ENTERSIZEMOVE:
00386         win->m_bSizing = true;
00387         break;
00388 
00389       case WM_EXITSIZEMOVE:
00390         win->WindowMovedOrResized();
00391         win->m_bSizing = false;
00392         break;
00393 
00394       case WM_MOVE:
00395       case WM_SIZE:
00396         if (!win->m_bSizing)
00397           win->WindowMovedOrResized();
00398         break;
00399 
00400       case WM_GETMINMAXINFO:
00401         // Prevent the window from going smaller than some minimu size
00402         ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
00403         ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
00404         break;
00405 
00406       case WM_CLOSE:
00407         win->Destroy(); // cleanup and call DestroyWindow
00408         win->m_bClosed = true;
00409         return 0;
00410 
00411         // On arrete le rendu lorsque l'on appuie sur Echap
00412         // Provisoire en attendant une gestion plus fine des "Input"
00413       case WM_KEYDOWN:
00414         switch (wParam)
00415         {
00416           case VK_ESCAPE :
00417             win->m_bClosed = true;
00418             break;
00419           case VK_F1 :
00420             CConsole::Instance().Enable(true);
00421             break; // F1 = activer la console
00422           case VK_F2 :
00423             CConsole::Instance().Enable(false);
00424             break; // F2 = désactiver la console
00425         }
00426         break;
00427         // Caractère = envoi à la console
00428       case WM_CHAR :
00429         CConsole::Instance().SendChar(static_cast<char>(LOWORD(wParam)));
00430         return 0;
00431 
00432     }
00433 
00434     return DefWindowProc( hWnd, uMsg, wParam, lParam );
00435   }
00436 
00437 } // namespace Keos

Generated on Fri Mar 9 14:29:03 2007 for Keos by  doxygen 1.5.1-p1