カウンタ

  フルスクリーン表示

Google
▲探し物はこちら

 市販PCゲームでよく見られる全画面表示を行います。それ以外の動作は前回と同じです。
 実行すると下のように表示されます。わかりづらいかもしれませんが、全画面の時の画面キャプチャです。(枠がありません。

フルスクリーン表示

 下のリンクから今回のプロジェクトをダウンロードできます。

ファイル名 言語 サイズ バージョン
fullscreen_cs_1_1.zip C# 58KB 1.1
fullscreen_vb_1_1.zip VB.NET 64KB 1.1
fullscreen_cpp_1_1.zip C++/CLI 30KB 1.1

 今回のメインコードファイルを載せます。重要なコードを赤色で表示させています

MainSample.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace MDXSample
{
    /// <summary>
    /// メインサンプルクラス
    /// </summary>
    public partial class MainSample : IDisposable
    {
        /// <summary>
        /// モデルの位置情報
        /// </summary>
        private Vector3 _trans = Vector3.Empty;

        /// <summary>
        /// モデルの回転情報(degree)
        /// </summary>
        private float _rotate = 0.0f;

        /// <summary>
        /// モデルの拡大縮小情報
        /// </summary>
        private Vector3 _scale = new Vector3(1.0f, 1.0f, 1.0f);


        /// <summary>
        /// アプリケーションの初期化
        /// </summary>
        /// <param name="topLevelForm">トップレベルウインドウ</param>
        /// <returns>全ての初期化がOKなら true, ひとつでも失敗したら false を返すようにする</returns>
        /// <remarks>
        /// false を返した場合は、自動的にアプリケーションが終了するようになっている
        /// </remarks>
        public bool InitializeApplication(MainForm topLevelForm)
        {
            // フォームの参照を保持
            this._form = topLevelForm;

            // 入力イベント作成
            this.CreateInputEvent(topLevelForm);


            // PresentParameters。デバイスを作成する際に必須
            PresentParameters pp = new PresentParameters();

            // ウインドウモードなら true、フルスクリーンモードなら false を指定
            pp.Windowed = false;

            // スワップ効果
            pp.SwapEffect = SwapEffect.Discard;

            // 深度ステンシルバッファ
            pp.EnableAutoDepthStencil = true;

            // 自動深度ステンシル サーフェイスのフォーマット
            pp.AutoDepthStencilFormat = DepthFormat.D16;


            // 使用できるディスプレイモードを検索し、目的のモードを探す
            bool flag = false;

            // ディプレイモードを列挙し、サイズが「640×480」かつ
            // リフレッシュレートが「60」のモードを探す
            // (条件はアプリケーションの内容によって変えてください)
            foreach (DisplayMode i in Manager.Adapters[0].SupportedDisplayModes)
            {
                if (i.Width == 640 && i.Height == 480 && i.RefreshRate == 60)
                {
                    // 条件に見合えば使用する
                    pp.BackBufferWidth = 640;
                    pp.BackBufferHeight = 480;
                    pp.BackBufferFormat = i.Format;
                    pp.FullScreenRefreshRateInHz = 60;
                    // 見つかったことを示すフラグを立てる
                    flag = true;
                    break;
                }
            }
            if (!flag)
            {
                // 目的のモードがなければそのまま終了
                MessageBox.Show("指定したディプレイモードは見つかりませんでした。",
                    "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            try
            {
                // Direct3D デバイス作成
                this.CreateDevice(topLevelForm, pp);

                // フォントの作成
                this.CreateFont();

                // Xファイルからメッシュ作成
                this.LoadXFileMesh("Deruderu.x");
            }
            catch (DirectXException ex)
            {
                // 例外発生
                MessageBox.Show(ex.ToString(), "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            // XYZライン作成
            this.CreateXYZLine();

            // ライトを設定
            this.SettingLight();

            // カメラ空間にトランスフォームされた後で頂点法線の正規化
            this._device.RenderState.NormalizeNormals = true;

            return true;
        }

        /// <summary>
        /// メインループ処理
        /// </summary>
        public void MainLoop()
        {
            // カメラの設定
            this.SettingCamera();


            // キー操作で移動パラメータを変化
            if (this._keys[(int)Keys.Down])
            {
                // 後へ移動
                this._trans -= Vector3.TransformCoordinate(new Vector3(0.0f, 0.0f, -0.3f),
                    Matrix.RotationY(Geometry.DegreeToRadian(this._rotate)));
            }
            if (this._keys[(int)Keys.Up])
            {
                // 前へ移動
                this._trans += Vector3.TransformCoordinate(new Vector3(0.0f, 0.0f, -0.3f),
                    Matrix.RotationY(Geometry.DegreeToRadian(this._rotate)));
            }
            if (this._keys[(int)Keys.Left])
            {
                // 左回転
                this._rotate -= 5.0f;
            }
            if (this._keys[(int)Keys.Right])
            {
                // 右回転
                this._rotate += 5.0f;
            }
            if (this._keys[(int)Keys.Z])
            {
                // 縮小
                this._scale.X /= 1.01f;
                this._scale.Y /= 1.01f;
                this._scale.Z /= 1.01f;
                //this._scale *= 1.0f / 1.01f;
            }
            if (this._keys[(int)Keys.A])
            {
                // 拡大
                this._scale *= 1.01f;
            }


            // モデル座標変換用マトリックスを初期化
            Matrix modelTransform = Matrix.Identity;

            // 最初に拡大縮小
            modelTransform *= Matrix.Scaling(this._scale);

            // 回転
            modelTransform *= Matrix.RotationY(Geometry.DegreeToRadian(this._rotate));

            // 最後に移動
            modelTransform *= Matrix.Translation(this._trans);


            // 描画内容を単色でクリアし、Zバッファもクリア
            this._device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkBlue, 1.0f, 0);

            // 「BeginScene」と「EndScene」の間に描画内容を記述する
            this._device.BeginScene();


            // ライトを無効
            this._device.RenderState.Lighting = false;

            // 原点に配置
            this._device.SetTransform(TransformType.World, Matrix.Identity);

            // XYZラインを描画
            this.RenderXYZLine();


            // ライトを有効
            this._device.RenderState.Lighting = true;

            // 計算したマトリックスで座標変換
            this._device.SetTransform(TransformType.World, modelTransform);

            // メッシュの描画
            this.RenderMesh();


            // 文字列の描画
            this._font.DrawText(null, "[Escape]終了", 0, 0, Color.White);
            this._font.DrawText(null, "[←→]回転 [↑↓]移動 [ZA]拡大縮小", 0, 12, Color.White);
            this._font.DrawText(null, "θ:" + this._lensPosTheta, 0, 24, Color.White);
            this._font.DrawText(null, "φ:" + this._lensPosPhi, 0, 36, Color.White);
            this._font.DrawText(null,
                "移動:"+this._trans.X+","+this._trans.Y+","+this._trans.Z, 0, 48, Color.White);
            this._font.DrawText(null, "回転:" + this._rotate, 0, 60, Color.White);
            this._font.DrawText(null, "拡大:" + this._scale.X, 0, 72, Color.White);

            // 描画はここまで
            this._device.EndScene();

            // 実際のディスプレイに描画
            this._device.Present();

            // アプリケーションの終了操作
            if (this._keys[(int)Keys.Escape])
            {
                this._form.Close();
            }
        }

        /// <summary>
        /// リソースの破棄をするために呼ばれる
        /// </summary>
        public void Dispose()
        {
            // メッシュの破棄
            this.DisposeMesh();

            // XYZラインの破棄
            this.DisposeXYZLine();

            // フォントのリソースを解放
            if (this._font != null)
            {
                this._font.Dispose();
            }

            // Direct3D デバイスのリソース解放
            if (this._device != null)
            {
                this._device.Dispose();
            }
        }
    }
}

 では、赤文字の部分を説明していきます。MainSamplePartial.cs ファイルのコードはこちらです。


 最初のころにやったコードを引っ張ってきました。

 実は「フルスクリーン」にするには「PresentParameter」構造体のパラメータを5つ変更するだけでできてしまいます。

  • Windowed を false に設定
  • BackBufferFormat を Format.R5G6B5 に設定
  • BackBufferWidth を 640 に設定
  • BackBufferHeight を 480 に設定
  • FullScreenRefreshRateInHz を 60 に設定

 しかし、フルスクリーンで作成する場合は、いろいろとパラメータに制限があり、また実際作成したアプリケーションを使う人がどんなビデオカードやチップセットを使うかをプログラマが知る方法はありません(使うビデオカードを指定すれば別ですが)。
 高いクオリティで設定すると、ソフトが使えないPCが出てきますし、逆に低スペックなPCでも使えるように作るとクオリティをどうしても低くしないといけません。

 また、クオリティに関わらずPCの環境によって使用できる画面サイズやフォーマットなど違うこともあるので、そこら辺をうまく考えて設定しなければなりません。

 そのため、今回はアダプタビデオカードなどのこと)の「ディスプレイモード」を列挙し、使用できる画面サイズやフォーマットなど調べて設定するようにします。


// PresentParameters。デバイスを作成する際に必須
PresentParameters pp = new PresentParameters();

// ウインドウモードなら true、フルスクリーンモードなら false を指定
pp.Windowed = true;

// スワップ効果
pp.SwapEffect = SwapEffect.Discard;

// 深度ステンシルバッファ
pp.EnableAutoDepthStencil = true;

// 自動深度ステンシル サーフェイスのフォーマット
pp.AutoDepthStencilFormat = DepthFormat.D16;

 フルスクリーンなので「Windowed」パラメータは false に設定しておきます


// 使用できるディスプレイモードを検索し、目的のモードを探す
bool flag = false;

// ディプレイモードを列挙し、サイズが「640×480」かつ
// リフレッシュレートが「60」のモードを探す
// (条件はアプリケーションの内容によって変えてください)
foreach (DisplayMode i in Manager.Adapters[0].SupportedDisplayModes)
{
    if (i.Width == 640 && i.Height == 480 && i.RefreshRate == 60)
    {
        // 条件に見合えば使用する
        pp.BackBufferWidth = 640;
        pp.BackBufferHeight = 480;
        pp.BackBufferFormat = i.Format;
        pp.FullScreenRefreshRateInHz = 60;
        // 見つかったことを示すフラグを立てる
        flag = true;
        break;
    }
}

 「Manager」クラスにアダプタコレクションがあるので、0番��アダ��タ�����用で��る����ィスプレイモードを列挙しています。

 アダプタのインデックスですが、ビデオカードなどが複数ある場合、1以降のインデックスも使用できます
 逆にアダプタが1個も無いということはほとんどないので、今回は直接「0」を指定しています。実際にアプリケーションを作るときは一応アダプタの数も調べておいたほうがいいです。

 今回は「幅が 640」「高さが 480」「リフレッシュレートが 60」という条件に当てはまるディスプレイモードが存在するか調べて、あればその条件で使用するようにしています。
 ちなみにこれはディスプレイモードの調べ方の一例ですので、実際に作るときは、高いクオリティを使用できるように調べたりユーザーに選択させたりできるような形にしてみてください。これは多くのユーザーにソフトを使っていただける条件にもなります。


if (!flag)
{
    // 目的のモードがなければそのまま終了
    MessageBox.Show("指定したディプレイモードは見つかりませんでした。",
        "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
    return false;
}

 条件に見合わなければメッセージボックスを出して終了します。


// Direct3D デバイス作成
this.CreateDevice(topLevelForm, pp);

 新しく設定した PresentParameters をデバイス作成メソッドに渡しています。


// アプリケーションの終了操作
if (this._keys[(int)Keys.Escape])
{
    this._form.Close();
}

 フルスクリーンではウインドウの「×」ボタンによる終了が出来ないので、「ESC」キーでフォームを閉じるようにしています。

 また、他にもディフォルトで「Alt + F4」でもアプリケーションを終了させることができます。

その他の関連情報です▼