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 //------------------------------------------------------------------------------