Direct Draw で楕円を描画

C# の Direct Draw で primary Surface に直接楕円を描画します。
3Dに比べてプログラミングも容易で描画速度も速いので、3D機能を使わないのであればお勧めです。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの作成

  1. ウインドウを表示 に習って、空のプロジェクトから作成します。
    次のファイルを格納して下さい。
    /************************************************************/
    /*★ Direct Draw で Front Surface に楕円を描画    前田 稔 ★*/
    /************************************************************/
    using System;
    using System.Drawing;
    using System.ComponentModel;
    using System.Windows.Forms;
    using Microsoft.DirectX;
    using Microsoft.DirectX.DirectDraw;
    
    namespace DXDraw
    {
        public class DXDraw : System.Windows.Forms.Form
        {
            private Device draw = null;         // DrawDevice object.
            private Surface primary = null;     // primary destination surface.
            private Rectangle dest;             // Window Rectangle.
    
            public DXDraw()
            {
                this.Text = "DXDraw";
                this.Resize += new System.EventHandler(this.DXDraw_SizeChanged);
                this.SizeChanged += new System.EventHandler(this.DXDraw_SizeChanged);
                this.Paint += new System.Windows.Forms.PaintEventHandler(this.DXDraw_Paint);
    
                CreateSurfaces();               // Call creates the surface objects.
            }
    
            //☆ Main() メソッド
            static void Main() 
            {
                using(DXDraw mf = new DXDraw())
                {   Application.Run(mf);
                }
            }
    
            private void DXDraw_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
            {
                Draw();
            }
    
            private void DXDraw_SizeChanged(object sender, System.EventArgs e)
            {
                Draw();
            }
    
            // This function Draws the offscreen bitmap surface to the primary visible surface.
            private void Draw()
            {
                if (null == primary)    return;
                if (FormWindowState.Minimized == WindowState)   return;
                try
                {
                    dest = new Rectangle(PointToScreen(new Point(0, 0)), ClientSize);
                    primary.FillColor = Color.White;
                    primary.DrawBox(dest.Left, dest.Top, dest.Right, dest.Bottom);
                    primary.FillColor = Color.Blue;
                    primary.DrawEllipse(dest.Left + 40, dest.Top + 20, dest.Right - 40, dest.Bottom - 20);
                }
                catch(SurfaceLostException)
                {
                    CreateSurfaces(); // Surface was lost. Recreate them.
                }
            }
    
            // This function is where the surfaces and clipper object are created.
            private void CreateSurfaces()
            {
                // Create new Draw Device.
                draw = new Device();
                draw.SetCooperativeLevel(this, CooperativeLevelFlags.Normal);
                // Create new Surface
                SurfaceDescription description = new SurfaceDescription();
                description.SurfaceCaps.PrimarySurface = true;
                primary = new Surface(description, draw);
            }
        }
    }
    
    DirectX のプログラムは、一部を除いて DX.BAT でコンパイルすることも出来ます。
  2. primary surface を取得して、直接図形を描画してみました。
    surface とはウインドウの描画に直接関係するメモリ領域で、高速に描画するためにビデオボード上に確保されます。
    primary surface に直接描画すると Windows Program と同じように多少チラツキます。
    チラツキを無くすにはこの後で説明する「back surface や offscreen surface」を使って下さい。
  3. ソリューションエクスプローラのプロジェクト名を右クリックして [追加][既存項目] からソースファイルを選択して下さい。
  4. ソリューション・エクスプローラーで「参照設定」を右クリックして「参照の追加」を選択します。
    以下のファイル(DLL) を追加して下さい。
    DirectX 関係のファイルは DirectX SDK をインストールすると表示されます。
    Microsoft.DirectX
    Microsoft.DirectX.DirectDraw
    System
    System.Drawing
    System.Windows.Forms

  5. ソリューション・エクスプローラでプロジェクト名を右クリックして「プロパティ」を選択します。
    「出力の種類」を「Windowsアプリケーション」にします。
    またはメニューからプロジェクトのプロパティで「出力の種類」を「Windowsアプリケーション」にします。

  6. メニューの [デバッグ] から [デバッグ開始] または [デバッグなしで開始] を選択すればコンパイルされ、エラーが無ければ実行されます。
    [コンパイル&実行] はツールバーから起動する方が簡単です。

プログラムの説明

  1. Main() メソッドで DXDraw Object Class を生成して制御を渡します。
    using は DXDraw Object Class の範囲を指定して、範囲から出ると資源を解放するためのコードです。
        static void Main() 
        {
            using(DXDraw mf = new DXDraw())
            {   Application.Run(mf);
            }
        }
        
  2. draw は Direct Draw Device の定義です。
    primary は primary surface の定義です。
    dest はウインドウのサイズを取得する矩形領域です。
        private Device draw = null;         // DrawDevice object.
        private Surface primary = null;     // primary destination surface.
        private Rectangle dest;             // Window Rectangle.
        
  3. DXDraw の Constructor でキャプションを設定します。
    DXDraw_SizeChanged はウインドウサイズが変更されたときに呼び出されるイベントハンドラです。
    DXDraw_Paint はウインドウの描画を行うイベントハンドラです。
    CreateSurfaces() で Direct Draw Object を取得します。
        public DXDraw()
        {
            this.Text = "DXDraw";
            this.Resize += new System.EventHandler(this.DXDraw_SizeChanged);
            this.SizeChanged += new System.EventHandler(this.DXDraw_SizeChanged);
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.DXDraw_Paint);
    
            CreateSurfaces();               // Call creates the surface objects.
        }
        
  4. Direct Draw Object を取得する CreateSurfaces です。
    new Device() で Direct Draw の Device を生成します。
    SetCooperativeLevel で Windowed Mode に設定します。
    new SurfaceDescription() で Description を生成して、Surface の形式を定義します。
    new Surface() で primary surface を取得します。
    このメソッドは Surface を消失したときにも呼び出されます。
        private void CreateSurfaces()
        {
            // Create new Draw Device.
            draw = new Device();
            draw.SetCooperativeLevel(this, CooperativeLevelFlags.Normal);
            // Create new Surface
            SurfaceDescription description = new SurfaceDescription();
            description.SurfaceCaps.PrimarySurface = true;
            primary = new Surface(description, draw);
        }
        
  5. primary surface に図形を直接描画する Draw() メソッドです。
    primary が null のときやウインドウが最小化されているときはパスします。
    dest にウインドウサイズを取得して White でクリアします。
    クリアする専用の関数「primary.ColorFill(Color.White);」があるのですが、primary には使えないようです。
    ウインドウのサイズに合わせて Blue で楕円を描画します。
    try{ } と catch (SurfaceLostException){ } で、Surface が消失したときは CreateSurfaces() を呼び出します。
    これが無いと失敗したときにエラーが表示されて異常終了します。
        private void Draw()
        {
            if (null == primary)    return;
            if (FormWindowState.Minimized == WindowState)   return;
            try
            {
                dest = new Rectangle(PointToScreen(new Point(0, 0)), ClientSize);
                primary.FillColor = Color.White;
                primary.DrawBox(dest.Left, dest.Top, dest.Right, dest.Bottom);
                primary.FillColor = Color.Blue;
                primary.DrawEllipse(dest.Left + 40, dest.Top + 20, dest.Right - 40, dest.Bottom - 20);
            }
            catch(SurfaceLostException)
            {
                CreateSurfaces(); // Surface was lost. Recreate them.
            }
        }
        

【演習】

  1. ウインドウよりやや小さめの塗りつぶした矩形を描画して下さい。
  2. ウインドウよりやや小さめの矩形を線(Line)を使って描画して下さい。

超初心者のプログラム入門(C# Frame Work)