Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

# 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 = { 0, WndProc, 0, 0, hInst,
    00125                         LoadIcon(0, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
    00126                         (HBRUSH)GetStockObject(BLACK_BRUSH), 0, "KeosD3D9Wnd" };
    00127                 RegisterClass(&wc);
    00128
    00129                 // Create our main window
    00130                 // Pass pointer to self
    00131                 m_HWnd = CreateWindow("KeosD3D9Wnd", title.c_str(), dwStyle,
    00132                         m_nLeft, m_nTop, m_nWidth, m_nHeight, (HWND) NULL, 0, hInst, this);
    00133
    00134                 // top and left represent outer window coordinates
    00135                 GetWindowRect(m_HWnd, &rc);
    00136                 m_nTop = rc.top;
    00137                 m_nLeft = rc.left;
    00138                 // width and height represent interior drawable area
    00139                 GetClientRect(m_HWnd, &rc);
    00140                 m_nWidth = rc.right;
    00141                 m_nHeight = rc.bottom;
    00142
    00143                 m_strName = strName;
    00144                 //mIsDepthBuffered = depthBuffer;
    00145                 m_bIsFullScreen = bFullScreen;
    00146                 m_nColourDepth = colourDepth;
    00147
    00148                 ILogger::Log("Created CD3D9Window '%s' : %dx%d, %dbpp",
    00149                      m_strName.c_str(), m_nWidth, m_nHeight, m_nColourDepth);
    00150
    00151                 CreateD3DResources();
    00152
    00153                 m_bActive = true;
    00154         }
    00155
    00156     void CD3D9Window::CreateD3DResources(void)
    00157         {
    00158                 // Set up the presentation parameters
    00159                 HRESULT hr;
    00160                 LPDIRECT3D9 pD3D = m_pD3D9->pD3D;
    00161
    00162         D3DDEVTYPE devType = D3DDEVTYPE_HAL;
    00163
    00164                 ZeroMemory( &m_d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
    00165             m_d3dpp.Windowed                            = !m_bIsFullScreen;
    00166                 m_d3dpp.SwapEffect                              = D3DSWAPEFFECT_DISCARD;
    00167                 m_d3dpp.BackBufferCount                 = 1;
    00168                 m_d3dpp.EnableAutoDepthStencil  = true;
    00169                 m_d3dpp.hDeviceWindow                   = m_HWnd;
    00170                 m_d3dpp.BackBufferWidth                 = m_nWidth;
    00171                 m_d3dpp.BackBufferHeight                = m_nHeight;
    00172
    00173                 if (m_bVSync)
    00174                         m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
    00175                 else
    00176                         m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    00177
    00178                 m_d3dpp.BackBufferFormat                = D3DFMT_R5G6B5;
    00179                 if( m_nColourDepth > 16 )
    00180                         m_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    00181
    00182                 if (m_nColourDepth > 16 )
    00183                 {
    00184                         // Try to create a 32-bit depth, 8-bit stencil
    00185                         if( FAILED( pD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,
    00186                                 devType,  m_d3dpp.BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL,
    00187                                 D3DRTYPE_SURFACE, D3DFMT_D24S8 )))
    00188                         {
    00189                                 // Bugger, no 8-bit hardware stencil, just try 32-bit zbuffer
    00190                                 if( FAILED( pD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,
    00191                                         devType,  m_d3dpp.BackBufferFormat,  D3DUSAGE_DEPTHSTENCIL,
    00192                                         D3DRTYPE_SURFACE, D3DFMT_D32 )))
    00193                                 {
    00194                                         // Jeez, what a naff card. Fall back on 16-bit depth buffering
    00195                                         m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    00196                                 }
    00197                                 else
    00198                                         m_d3dpp.AutoDepthStencilFormat = D3DFMT_D32;
    00199                         }
    00200                         else
    00201                         {
    00202                                 // Woohoo!
    00203                                 if( SUCCEEDED( pD3D->CheckDepthStencilMatch( D3DADAPTER_DEFAULT, devType,
    00204                                         m_d3dpp.BackBufferFormat, m_d3dpp.BackBufferFormat, D3DFMT_D24S8 ) ) )
    00205                                 {
    00206                                         m_d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
    00207                                 }
    00208                                 else
    00209                                         m_d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
    00210                         }
    00211                 }
    00212                 else
    00213                         // 16-bit depth, software stencil
    00214                         m_d3dpp.AutoDepthStencilFormat  = D3DFMT_D16;
    00215
    00216                 m_d3dpp.MultiSampleType = m_FSAAType;
    00217                 m_d3dpp.MultiSampleQuality = (m_FSAAQuality == 0) ? 0 : m_FSAAQuality;
    00218
    00219
    00220                 if (!m_pD3D9->pD3DDevice)
    00221                 {
    00222                         // We haven't created the device yet, this must be the first time
    00223
    00224                         // Do we want to preserve the FPU mode? Might be useful for scientific apps
    00225                         DWORD extraFlags = 0;
    00226
    00227                         hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, devType, m_HWnd,
    00228                                 D3DCREATE_HARDWARE_VERTEXPROCESSING | extraFlags, &m_d3dpp, &(m_pD3D9->pD3DDevice) );
    00229                         if( FAILED( hr ) )
    00230                         {
    00231                                 hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, devType, m_HWnd,
    00232                                         D3DCREATE_MIXED_VERTEXPROCESSING | extraFlags, &m_d3dpp, &(m_pD3D9->pD3DDevice) );
    00233                                 if( FAILED( hr ) )
    00234                                 {
    00235                                         hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, devType, m_HWnd,
    00236                                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING | extraFlags, &m_d3dpp, &(m_pD3D9->pD3DDevice) );
    00237                                 }
    00238                         }
    00239                         if( FAILED( hr ) )
    00240                         {
    00241                                 Destroy();
    00242                                 D3D9_EXCEPT("Failed to create Direct3D9 Device", "CD3D9Window::CreateD3DResources");
    00243                         }
    00244                 }
    00245                 // Store references to buffers for convenience
    00246                 m_pD3D9->pD3DDevice->GetRenderTarget( 0, &m_pRenderSurface );
    00247                 m_pD3D9->pD3DDevice->GetDepthStencilSurface( &m_pRenderZBuffer );
    00248                 // release immediately so we don't hog them
    00249                 if (m_pRenderSurface)m_pRenderSurface->Release();
    00250                 if (m_pRenderZBuffer) m_pRenderZBuffer->Release();
    00251     }
    00252
    00253     //-----------------------------------------------------------------------
    00254     void CD3D9Window::Destroy(void)
    00255     {
    00256                 m_pRenderSurface = 0;
    00257                 m_pRenderZBuffer = 0;
    00258
    00259                 m_pD3D9->ReleaseDevice();
    00260
    00261                 DestroyWindow( m_HWnd );
    00262                 m_HWnd = 0;
    00263         m_bActive = false;
    00264     }
    00265
    00266     //-----------------------------------------------------------------------
    00267     bool CD3D9Window::IsClosed() const
    00268     {
    00269         return m_bClosed;
    00270     }
    00271
    00272     //-----------------------------------------------------------------------
    00273     void CD3D9Window::Reposition(int left, int top)
    00274     {
    00275         // @todo
    00276     }
    00277
    00278     //-----------------------------------------------------------------------
    00279     void CD3D9Window::Resize(uint nWidth, uint nHeight)
    00280     {
    00281                 m_nWidth = nWidth;
    00282                 m_nHeight = nHeight;
    00283
    00284                 // @todo resize window
    00285     }
    00286
    00287     //-----------------------------------------------------------------------
    00288         void CD3D9Window::WindowMovedOrResized()
    00289         {
    00290                 RECT temprect;
    00291                 ::GetClientRect(GetWindowHandle(),&temprect);
    00292                 Resize(temprect.right-temprect.left,temprect.bottom-temprect.top);
    00293         }
    00294
    00295     //-----------------------------------------------------------------------
    00296     void CD3D9Window::SwapBuffers(bool bWaitForVSync)
    00297     {
    00298         if( m_pD3D9->pD3DDevice )
    00299                 {
    00300                         HRESULT hr;
    00301                         hr = m_pD3D9->pD3DDevice->Present( NULL, NULL, NULL, NULL );
    00302                         if( FAILED(hr) )
    00303                         {
    00304                                 if (hr == D3DERR_DEVICELOST)
    00305                                 {
    00306                                         static_cast<CD3D9RenderSystem*>(
    00307                                                 CRoot::Instance().GetRenderSystem())->_NotifyDeviceLost();
    00308                                         Sleep(500);
    00309                                 }
    00310                                 else D3D9_EXCEPT("Error Presenting surfaces", "CD3D9Window::SwapBuffers" );
    00311                         }
    00312                 }
    00313     }
    00314
    00315         //-----------------------------------------------------------------------
    00316         void CD3D9Window::Update(void)
    00317         {
    00318                 CD3D9RenderSystem* pRS = static_cast<CD3D9RenderSystem*>(
    00319                         CRoot::Instance().GetRenderSystem());
    00320                 if (pRS->IsDeviceLost())
    00321                 {
    00322                         // Test the cooperative mode first
    00323                         HRESULT hr = m_pD3D9->pD3DDevice->TestCooperativeLevel();
    00324                         if (hr == D3DERR_DEVICELOST)
    00325                         {
    00326                                 // device lost, and we can't reset
    00327                                 // can't do anything about it here, wait until we get
    00328                                 // D3DERR_DEVICENOTRESET; rendering calls will silently fail until
    00329                                 // then (except Present, but we ignore device lost there too)
    00330                                 m_pRenderSurface = 0;
    00331                                 m_pRenderZBuffer = 0;
    00332                                 Sleep(500);
    00333                                 return;
    00334                         }
    00335                         else if (hr == D3DERR_DEVICENOTRESET)
    00336                         {
    00337                                 // device lost, and we can reset
    00338                                 pRS->RestoreLostDevice();
    00339
    00340                                 // Still lost?
    00341                                 if (pRS->IsDeviceLost())
    00342                                 {
    00343                                         // Wait a while
    00344                                         Sleep(500);
    00345                                         return;
    00346                                 }
    00347
    00348                                 // re-qeuery buffers
    00349                                 m_pD3D9->pD3DDevice->GetRenderTarget( 0, &m_pRenderSurface );
    00350                                 m_pD3D9->pD3DDevice->GetDepthStencilSurface( &m_pRenderZBuffer );
    00351                                 // release immediately so we don't hog them
    00352                                 if (m_pRenderSurface) m_pRenderSurface->Release();
    00353                                 if (m_pRenderZBuffer) m_pRenderZBuffer->Release();
    00354                         }
    00355                 }
    00356                 IRenderWindow::Update();
    00357         }
    00358
    00359         //-----------------------------------------------------------------------
    00360         LRESULT CD3D9Window::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
    00361         {
    00362                 if (uMsg == WM_CREATE)
    00363                 {
    00364                         // copy CD3D9Window* from createwindow param to userdata slot
    00365                         SetWindowLong(hWnd, GWL_USERDATA,
    00366                                 (LONG)(((LPCREATESTRUCT)lParam)->lpCreateParams));
    00367                         return 0;
    00368                 }
    00369
    00370                 CD3D9Window* win =
    00371                         (CD3D9Window*)GetWindowLong(hWnd, GWL_USERDATA);
    00372
    00373                 if (!win)
    00374                         return DefWindowProc(hWnd, uMsg, wParam, lParam);
    00375
    00376                 switch( uMsg )
    00377                 {
    00378                 case WM_ACTIVATE:
    00379                         win->m_bActive = (LOWORD(wParam) != WA_INACTIVE);
    00380                         break;
    00381
    00382                 case WM_ENTERSIZEMOVE:
    00383                         win->m_bSizing = true;
    00384                         break;
    00385
    00386                 case WM_EXITSIZEMOVE:
    00387                         win->WindowMovedOrResized();
    00388                         win->m_bSizing = false;
    00389                         break;
    00390
    00391                 case WM_MOVE:
    00392                 case WM_SIZE:
    00393                         if (!win->m_bSizing)
    00394                                 win->WindowMovedOrResized();
    00395                         break;
    00396
    00397                 case WM_GETMINMAXINFO:
    00398                         // Prevent the window from going smaller than some minimu size
    00399                         ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
    00400                         ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
    00401                         break;
    00402
    00403                 case WM_CLOSE:
    00404                         win->Destroy(); // cleanup and call DestroyWindow
    00405                         win->m_bClosed = true;
    00406                         return 0;
    00407
    00408                 // On arrete le rendu lorsque l'on appuie sur Echap
    00409         // Provisoire en attendant une gestion plus fine des "Input"
    00410                 case WM_KEYDOWN:
    00411             switch (wParam)
    00412             {
    00413                         case VK_ESCAPE :win->m_bClosed = true; break;
    00414                         case VK_F1 :     CConsole::Instance().Enable(true);  break; // F1 = activer la console
    00415             case VK_F2 :     CConsole::Instance().Enable(false); break; // F2 = désactiver la console
    00416             }
    00417                     break;
    00418         // Caractère = envoi à la console
    00419         case WM_CHAR :
    00420             CConsole::Instance().SendChar(static_cast<char>(LOWORD(wParam)));
    00421             return 0;
    00422
    00423                 }
    00424
    00425                 return DefWindowProc( hWnd, uMsg, wParam, lParam );
    00426         }
    00427
    00428 } // namespace Keos