Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

GraphicsDevice.cpp

Go to the documentation of this file.
00001 //------------------------------------------------------------------------------
00002 // Lamp : Open source game middleware
00003 // Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
00004 //
00005 // This library is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 //
00010 // This library is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with this library; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 //------------------------------------------------------------------------------
00019 
00020 /** @file
00021  * グラフィックスデバイス実装
00022  * @author Junpee
00023  */
00024 
00025 #include "LampBasic.h"
00026 #include "Graphics/System/GraphicsDevice.h"
00027 #include "Graphics/System/LampGraphics.h"
00028 #include "Graphics/DeviceSelector/GraphicsDeviceSelector.h"
00029 #include "Graphics/System/GraphicsDeviceSettings.h"
00030 #include "Graphics/Enumeration/GraphicsDeviceInformation.h"
00031 
00032 namespace Lamp{
00033 
00034 // インスタンス
00035 GraphicsDevice* GraphicsDevice::instance_ = NULL;
00036 
00037 //------------------------------------------------------------------------------
00038 // コンストラクタ
00039 GraphicsDevice::GraphicsDevice(){
00040     Assert(instance_ == NULL);
00041     instance_ = this;
00042     direct3DDevice_ = NULL;
00043     ::memset(&presentationParameter_, 0, sizeof(D3DPRESENT_PARAMETERS));
00044     settings_ = NULL;
00045     windowHandle_ = NULL;
00046     windowStyle_ = 0;
00047     SetRect(&windowBoundsSize_, 0, 0, 0, 0);
00048     SetRect(&windowClientSize_, 0, 0, 0, 0);
00049     menuHandle_ = NULL;
00050     deviceLost_ = false;
00051     clipCursor_ = true;
00052     ignoreSizeChange_ = false;
00053     windowMaximized_ = false;
00054     windowMinimized_ = false;
00055 }
00056 //------------------------------------------------------------------------------
00057 // デストラクタ
00058 GraphicsDevice::~GraphicsDevice(){
00059     Assert(instance_ == this);
00060     instance_ = NULL;
00061 }
00062 //------------------------------------------------------------------------------
00063 // クリア
00064 void GraphicsDevice::clear(Color4c color, float zValue, u_int stencilValue){
00065     u_int clearFlag = D3DCLEAR_TARGET;
00066     if(settings_->getDepthStencilEnabled()){ clearFlag |= D3DCLEAR_ZBUFFER; }
00067     direct3DDevice_->Clear(
00068         0, NULL, clearFlag, color.getARGB(), zValue, stencilValue);
00069 }
00070 //------------------------------------------------------------------------------
00071 // プレゼンテーション
00072 bool GraphicsDevice::presentation(){
00073     // デバイスがロストしていないことを確認してからシステムループを実行し、
00074     // 描画を行うメインルーチンを想定している
00075     HRESULT result;
00076     // デバイスロスト処理
00077     if(deviceLost_){
00078         result = direct3DDevice_->TestCooperativeLevel();
00079         if(DirectXFailed(result)){
00080             // デバイスリセット要求
00081             if(result == D3DERR_DEVICENOTRESET){
00082                 if(settings_->isWindowed()){
00083                     // デスクトップディスプレイフォーマットが変更されたので
00084                     // プレゼンテーションパラメータを再構築する
00085                     LampGraphics::getDeviceSelector()->findBestWindowedMode(
00086                         windowHandle_, false, false);
00087                     settings_->buildPresentationParameters(
00088                         &presentationParameter_, windowHandle_);
00089                 }
00090                 if(!reset()){
00091                     ErrorOut("GraphicsDevice::presentation() reset()");
00092                 }
00093             }
00094         }else{
00095             // デバイスロスト解除
00096             deviceLost_ = false;
00097         }
00098     }else{
00099         result = direct3DDevice_->Present(NULL, NULL, NULL, NULL);
00100         // デバイスロストチェック
00101         if(result == D3DERR_DEVICELOST){ deviceLost_ = true; }
00102     }
00103     return deviceLost_;
00104 }
00105 //------------------------------------------------------------------------------
00106 // フルスクリーンモードとウィンドウモードを切り替える
00107 void GraphicsDevice::toggleFullscreen(){
00108     // デバイス情報のバックアップ
00109     GraphicsDeviceInformation* deviceInfoOld =
00110         settings_->getDeviceInformation();
00111     int adapterOrdinalOld = deviceInfoOld->getAdapterOrdinal();
00112     D3DDEVTYPE deviceTypeOld = deviceInfoOld->getDeviceType();
00113     // サイズ変更を無視する
00114     ignoreSizeChange_ = true;
00115     // ウィンドウフラグ反転
00116     settings_->setWindowed(!settings_->isWindowed());
00117     // ウィンドウの調整を行う
00118     adjustWindowForChange();
00119     // 3D環境の再構築
00120     bool result;
00121     GraphicsDeviceInformation* deviceInfo = settings_->getDeviceInformation();
00122     if((deviceInfo->getAdapterOrdinal() == adapterOrdinalOld) &&
00123         (deviceInfo->getDeviceType() == deviceTypeOld)){
00124         // リセットする
00125         settings_->buildPresentationParameters(
00126             &presentationParameter_, windowHandle_);
00127         result = reset();
00128     }else{
00129         // 再構築する
00130         result = rebuild();
00131     }
00132     // 切り替え失敗だったら元に戻す
00133     if(!result){ toggleFullscreen(); }
00134     // サイズ変更を無視しない
00135     ignoreSizeChange_ = false;
00136 }
00137 //------------------------------------------------------------------------------
00138 // 強制的にウィンドウモードにする
00139 void GraphicsDevice::forceWindowed(){
00140     if(settings_->isWindowed()){ return; }
00141     LampGraphics::getDeviceSelector()->findBestWindowedMode(
00142         windowHandle_, false, false);
00143     if(!rebuild()){ ErrorOut("GraphicsDevice::forceWindowed() rebuild()"); }
00144 }
00145 //------------------------------------------------------------------------------
00146 // リビルド
00147 bool GraphicsDevice::rebuild(){
00148     cleanup();
00149     return initialize();
00150 }
00151 //------------------------------------------------------------------------------
00152 // ウィンドウハンドルの初期化
00153 void GraphicsDevice::initializeWindowHandle(HWND windowHandle){
00154     // ウィンドウプロパティの取得
00155     windowHandle_ = windowHandle;
00156     windowStyle_ = ::GetWindowLong(windowHandle_, GWL_STYLE);
00157     ::GetWindowRect(windowHandle_, &windowBoundsSize_);
00158     ::GetClientRect(windowHandle_, &windowClientSize_);
00159     // デバイス設定の取得
00160     settings_ = GraphicsDeviceSettings::getInstance();
00161 }
00162 //------------------------------------------------------------------------------
00163 // 初期化
00164 bool GraphicsDevice::initialize(){
00165     // ウィンドウの調整
00166     adjustWindowForChange();
00167     // プレゼンテーションパラメータの構築
00168     settings_->buildPresentationParameters(
00169         &presentationParameter_, windowHandle_);
00170     // 頂点プロセスフラグの取得
00171     u_int vertexProsessingFlag =
00172         settings_->getVertexProcessingType().getCreateFlag();
00173     // デバイスの作成
00174     HRESULT result;
00175     Direct3D* direct3D = LampGraphics::getDirect3D();
00176     GraphicsDeviceInformation* deviceInfo = settings_->getDeviceInformation();
00177     result = direct3D->CreateDevice(
00178         deviceInfo->getAdapterOrdinal(),    // アダプタ番号
00179         deviceInfo->getDeviceType(),        // デバイスタイプ
00180         windowHandle_,                      // ウィンドウハンドル
00181         vertexProsessingFlag,               // 振る舞いフラグ
00182         &presentationParameter_,            // プレゼンテーションパラメータ
00183         &direct3DDevice_);                  // デバイス
00184     if(DirectXSucceeded(result)){
00185         // デバイスリセットを通知する
00186         LampGraphics::deviceReset();
00187         // カーソルクリップ処理
00188         clipCursor();
00189         // デバイスオブジェクトを再構築する
00190         if(!LampGraphics::initializeDeviceObjects()){
00191             LampGraphics::deleteDeviceObjects();
00192         }else{
00193             if(!LampGraphics::restoreDeviceObjects()){
00194                 LampGraphics::invalidateDeviceObjects();
00195             }else{
00196                 return true;
00197             }
00198         }
00199         cleanup();
00200     }
00201     // リファレンスラスタライザでの起動を試す
00202     if(deviceInfo->getDeviceType() == D3DDEVTYPE_HAL){
00203         if(LampGraphics::getDeviceSelector()->findBestWindowedMode(
00204             windowHandle_, false, true)){
00205             adjustWindowForChange();
00206             AssertMessage(false, "GraphicsDevice::initialize() "
00207                 "Switched to REF");
00208             return initialize();
00209         }
00210     }
00211     return false;
00212 
00213 }
00214 //------------------------------------------------------------------------------
00215 // リセット
00216 bool GraphicsDevice::reset(){
00217     // デバイスオブジェクトを解放する
00218     LampGraphics::invalidateDeviceObjects();
00219     // リセットを行う
00220     direct3DDevice_->Reset(&presentationParameter_);
00221     // デバイスリセットを通知する
00222     LampGraphics::deviceReset();
00223     // カーソルクリップ処理
00224     clipCursor();
00225     // デバイスオブジェクトを再構築する
00226     if(!LampGraphics::restoreDeviceObjects()){
00227         LampGraphics::invalidateDeviceObjects();
00228         return false;
00229     }
00230     return true;
00231 }
00232 //------------------------------------------------------------------------------
00233 // カーソルのクリップ
00234 void GraphicsDevice::clipCursor(){
00235     if(!clipCursor_){ return; }
00236     if(settings_->isWindowed()){
00237         ClipCursor(NULL);
00238     }else{
00239         RECT clipRect;
00240         GetWindowRect(windowHandle_, &clipRect);
00241         ClipCursor(&clipRect);
00242     }
00243 }
00244 //------------------------------------------------------------------------------
00245 // 後始末
00246 void GraphicsDevice::cleanup(){
00247     // デバイスオブジェクトの無効化
00248     LampGraphics::invalidateDeviceObjects();
00249     // デバイスオブジェクトの破棄
00250     LampGraphics::deleteDeviceObjects();
00251     // Direct3DDeviceの解放
00252     SafeRelease(direct3DDevice_);
00253 }
00254 //------------------------------------------------------------------------------
00255 // ウィンドウプロシージャ
00256 LRESULT GraphicsDevice::windowProcedure(
00257     HWND windowHandle, u_int message, WPARAM wParam, LPARAM lParam){
00258     switch(message){
00259     // サイズ変更
00260     case WM_SIZE:
00261         if(settings_->isWindowed() && windowHandle_ != NULL){
00262             windowStyle_ = GetWindowLong(windowHandle_, GWL_STYLE);
00263         }
00264         if(wParam == SIZE_MINIMIZED){
00265             // カーソルのクリップを無効にする
00266             if(clipCursor_ && (!settings_->isWindowed())){
00267                 ClipCursor(NULL);
00268             }
00269             windowMinimized_ = true;
00270             windowMaximized_ = false;
00271         }else if(wParam == SIZE_MAXIMIZED){
00272             windowMaximized_ = true;
00273             windowMinimized_ = false;
00274             handlePossibleSizeChange();
00275         }else if(wParam == SIZE_RESTORED){
00276             if(windowMaximized_){
00277                 windowMaximized_ = false;
00278                 handlePossibleSizeChange();
00279             }else if(windowMinimized_){
00280                 windowMinimized_ = false;
00281                 handlePossibleSizeChange();
00282             }
00283             // ドラッグでのサイズ変更はWM_EXITSIZEMOVEで対処する
00284         }
00285         break;
00286     // サイズ変更終了
00287     case WM_EXITSIZEMOVE:
00288         handlePossibleSizeChange();
00289         break;
00290     // フルスクリーン時にメニュー選択を無効にする
00291     case WM_NCHITTEST:
00292         if(!settings_->isWindowed()){ return HTCLIENT; }
00293         break;
00294     // システムコマンド
00295     case WM_SYSCOMMAND:
00296         switch(wParam){
00297             // フルスクリーン時に以下のイベントが起こらないようにする
00298             case SC_MOVE:
00299             case SC_SIZE:
00300             case SC_MAXIMIZE:
00301             case SC_KEYMENU:
00302             case SC_MONITORPOWER:
00303                 if(!settings_->isWindowed()){ return 1; }
00304                 break;
00305         }
00306         break;
00307     }
00308     return 0;
00309 }
00310 //------------------------------------------------------------------------------
00311 // ウィンドウの調整
00312 void GraphicsDevice::adjustWindowForChange(){
00313     if(settings_->isWindowed()){
00314         // ウィンドウスタイルの設定
00315         SetWindowLong(windowHandle_, GWL_STYLE, windowStyle_);
00316         // メニューハンドルの設定
00317         if(menuHandle_ != NULL){
00318             SetMenu(windowHandle_, menuHandle_);
00319             menuHandle_ = NULL;
00320         }
00321         // ウィンドウサイズの調整
00322         SetWindowPos(windowHandle_, HWND_NOTOPMOST,
00323             windowBoundsSize_.left, windowBoundsSize_.top,
00324             (windowBoundsSize_.right - windowBoundsSize_.left),
00325             (windowBoundsSize_.bottom - windowBoundsSize_.top),
00326             SWP_SHOWWINDOW);
00327     }else{
00328         // ウィンドウスタイルの設定
00329         u_int fullScreenStyle = (WS_POPUP | WS_SYSMENU | WS_VISIBLE);
00330         SetWindowLong(windowHandle_, GWL_STYLE, fullScreenStyle);
00331         // メニューハンドルの設定
00332         if(menuHandle_ == NULL){
00333             menuHandle_ = GetMenu(windowHandle_);
00334             SetMenu(windowHandle_, NULL);
00335         }
00336     }
00337 }
00338 //------------------------------------------------------------------------------
00339 // ウィンドウサイズ変更
00340 void GraphicsDevice::handlePossibleSizeChange(){
00341     // 無視するフラグが立っていれば無視する
00342     if(ignoreSizeChange_){ return; }
00343     // クライアントサイズのバックアップ
00344     RECT windowClientSizeOld =  windowClientSize_;
00345     // 新しいサイズの取得
00346     ::GetWindowRect(windowHandle_, &windowBoundsSize_);
00347     ::GetClientRect(windowHandle_, &windowClientSize_);
00348     // サイズが変わっていなければ無視
00349     int width = (windowClientSize_.right - windowClientSize_.left);
00350     int height = (windowClientSize_.bottom - windowClientSize_.top);
00351     if(((windowClientSizeOld.right - windowClientSizeOld.left) == width) &&
00352         ((windowClientSizeOld.bottom - windowClientSizeOld.top) == height)){
00353         return;
00354     }
00355     settings_->setWindowSize(DimensionI(width, height));
00356     settings_->buildPresentationParameters(
00357         &presentationParameter_, windowHandle_);
00358     if(!reset()){
00359         ErrorOut("GraphicsDevice::handlePossibleSizeChange()");
00360     }
00361     // つぶれた画面の表示を行わないようにする
00362     clear();
00363 }
00364 //------------------------------------------------------------------------------
00365 } // End of namespace Lamp
00366 //------------------------------------------------------------------------------

Generated on Wed Mar 16 10:29:30 2005 for Lamp by doxygen 1.3.2