X-FILE 入力メニュー

X-FILE の入力メニューを設定します。

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

プログラムの説明

  1. プログラムメニューを設定して、メニュー選択で X-FILE を入力します。
    DirectX 3D で Form を表示する に習って、空のプロジェクトから作成します。
    次のファイルを格納して、プロジェクトに取り込んで下さい。
    /**********************************/
    /*★ File Open Menu     前田 稔 ★*/
    /**********************************/
    using System;
    using System.Drawing;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.IO;
    using Microsoft.DirectX;
    using Microsoft.DirectX.Direct3D;
    using Direct3D=Microsoft.DirectX.Direct3D;
    
    namespace MeshesTutorial
    {
        public class Meshes : Form
        {
            Device device = null;                   // Our rendering device
            Mesh mesh = null;                       // Our mesh object in sysmem
            Direct3D.Material[] meshMaterials;      // Materials for our mesh
            Texture[] meshTextures;                 // Textures for our mesh
            PresentParameters presentParams = new PresentParameters();
            bool pause = true;
            string XFilePath = "C:\\DATA\\XFILE\\";
            string XFileName = "cone.x";
            static  MainMenu menu = null;
    
            public Meshes()
            {
                this.ClientSize = new System.Drawing.Size(400,300);
                this.Text = "Direct3D File Menu";
                // メインメニューを生成
                menu = new MainMenu();
                MenuItem item = menu.MenuItems.Add("ファイル(&F)");
                item.MenuItems.Add(new MenuItem("開く(&O)", new EventHandler(this.OpenMesh)));
                item.MenuItems.Add(new MenuItem("終了(&X)", new EventHandler(this.FileExit), Shortcut.CtrlQ));
                item = menu.MenuItems.Add("ヘルプ(&H)");
                item.MenuItems.Add(new MenuItem("バージョン情報(&A)...", new EventHandler(this.HelpAbout)));
                this.Menu = menu;
            }
    
            bool InitializeGraphics()
            {
                try
                {
                    // Set up the structure used to create the D3DDevice. Since we are now
                    presentParams.Windowed = true;
                    presentParams.SwapEffect = SwapEffect.Discard;
                    presentParams.EnableAutoDepthStencil = true;
                    presentParams.AutoDepthStencilFormat = DepthFormat.D16;
    
                    // Create the D3DDevice
                    device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
                    device.DeviceReset += new System.EventHandler(this.OnResetDevice);
                    pause = false;
                }
                catch (DirectXException)
                {   return false;  }
                return true;
            }
    
            // X-FILE を入力して、描画の準備を整える
            public void OnResetDevice(object sender, EventArgs e)
            {
                Device dev = (Device)sender;
                // Turn on the zbuffer
                dev.RenderState.ZBufferEnable = true;
    
                // Load the mesh from the specified file
                ExtendedMaterial[] materials = null;
                Directory.SetCurrentDirectory(XFilePath);
                mesh = Mesh.FromFile(XFileName, MeshFlags.SystemMemory, device, out materials);
    
                // Allocate a material/texture arrays
                meshMaterials = new Material[materials.Length];
                meshTextures = new Texture[materials.Length];
    
                // Copy the materials and load the textures
                for(int i = 0; i < meshMaterials.Length; i++)
                {
                    meshMaterials[i] = materials[i].Material3D;
                    meshMaterials[i].AmbientColor = meshMaterials[i].DiffuseColor;
    
                    if ( (materials[i].TextureFilename != null) && (materials[i].TextureFilename.Length > 0) )
                    {
                        // Create the texture
                        meshTextures[i] = TextureLoader.FromFile(dev, materials[i].TextureFilename);
                    }
                }
    
                // 法線情報がなければ計算して作成
                if ((mesh.VertexFormat & VertexFormats.Normal) == 0)
                {
                    Mesh temporaryMesh = mesh.Clone(mesh.Options.Value,
                        mesh.VertexFormat | VertexFormats.Normal, device);
                    // 法線を計算
                    temporaryMesh.ComputeNormals();
                    // 古いメッシュを破棄し、置き換える
                    mesh.Dispose();
                    mesh = temporaryMesh;
                }
            }
    
            void SetupMatrices()
            {
                device.Transform.World = Matrix.RotationY(Environment.TickCount/1000.0f );
                device.Transform.View = Matrix.LookAtLH(new Vector3( 0.0f, 0.0f,-5.0f ), 
                    new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) );
                device.Transform.Projection = Matrix.PerspectiveFovLH( (float)(Math.PI / 4),
                    (float)this.Width / (float)this.Height, 0.1f, 5000.0f );
            }
    
            private void SetupLights()
            {
                System.Drawing.Color col = System.Drawing.Color.White;
                Direct3D.Material mtrl = new Direct3D.Material();
                mtrl.Diffuse = col;
                mtrl.Ambient = col;
                device.Material = mtrl;
                
                device.Lights[0].Type = LightType.Directional;
                device.Lights[0].Diffuse = System.Drawing.Color.White;
                device.Lights[0].Direction = new Vector3(50.0f, -40.0f, 100.0f);
                device.Lights[0].Enabled = true;//turn it on
                device.RenderState.Ambient = System.Drawing.Color.FromArgb(0x202020);
            }
    
            private void Render()
            {
                if (device == null) return;
                if (pause)          return;
    
                //Clear the backbuffer to a blue color 
                device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.LightGray, 1.0f, 0);
                //Begin the scene
                device.BeginScene();
                SetupLights();
                // Setup the world, view, and projection matrices
                SetupMatrices();
    
                if (mesh != null)
                {   // Meshes are divided into subsets, one for each material. Render them in
                    for (int i = 0; i < meshMaterials.Length; i++)
                    {
                        // Set the material and texture for this subset
                        device.Material = meshMaterials[i];
                        device.SetTexture(0, meshTextures[i]);
                        // Draw the mesh subset
                        mesh.DrawSubset(i);
                    }
                }
    
                //End the scene
                device.EndScene();
                device.Present();
            }
    
            protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
            {
                this.Render(); // Render on painting
            }
            protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
            {
                if ((int)(byte)e.KeyChar == (int)System.Windows.Forms.Keys.Escape)
                    this.Dispose(); // Esc was pressed
            }
    
            protected override void OnResize(System.EventArgs e)
            {
                pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);
            }
    
            // ファイル/終了メニューのイベントハンドラ
            private void FileExit(object sender, EventArgs e)
            {
                this.Dispose();
            }
    
            // ヘルプ/バージョン情報メニューのイベントハンドラ
            private void HelpAbout(object sender, EventArgs e)
            {
                MessageBox.Show("Project Menu Ver 1.0   Maeda Minoru");
            }
    
            // ファイル/オープンのイベントハンドラ
            private void OpenMesh(object sender, EventArgs e)
            {
                System.Windows.Forms.OpenFileDialog ofn = new OpenFileDialog();
                ofn.Filter = ".X Files (*.x)|*.x";
                ofn.FileName = XFileName;
                ofn.InitialDirectory = XFilePath;
                ofn.Title = "Open Mesh File";
                ofn.CheckFileExists = true;
                ofn.Multiselect = false;
                ofn.ShowReadOnly = false;
                ofn.ShowDialog();
    
                System.IO.FileInfo fo = new System.IO.FileInfo(ofn.FileName);
                XFileName = fo.Name;
                System.IO.Directory.SetCurrentDirectory(fo.DirectoryName);
                XFilePath = fo.DirectoryName;
    
                // メッシュを解放
                if (mesh != null)
                {
                    for(int i = 0; i < meshMaterials.Length; i++)
                    {
                        if (meshTextures[i] != null)    meshTextures[i].Dispose();
                    }
                    meshMaterials = null;
                    mesh.Dispose();
                }
                // 新しいメッシュを生成
                OnResetDevice(device, null);
            }
    
            //☆ Main() メソッド
            [STAThread]
            static void Main() 
            {
                using (Meshes frm = new Meshes())
                {
                    if (!frm.InitializeGraphics()) // Initialize Direct3D
                    {
                        MessageBox.Show("Could not initialize Direct3D.  This tutorial will exit.");
                        return;
                    }
                    frm.Show();
    
                    // While the form is still valid, render and process messages
                    while(frm.Created)
                    {
                        frm.Render();
                        Application.DoEvents();
                    }
                }
            }
        }
    }
    
  2. XFilePath は X-FILE が置かれているフォルダです。
    XFileName には、適当な X-FILE 名を初期値として設定しました。
    MainMenu menu がメニューの領域です。
            string XFilePath = "C:\\DATA\\XFILE\\";
            string XFileName = "cone.x";
            static  MainMenu menu = null;
        
  3. OpenFileDialog を使うので、Main()メソッドに [STAThread] を設定して下さい。
    using で Meshes Class を生成して、レンダリングループに入ります。
            //☆ Main() メソッド
            [STAThread]
            static void Main() 
            {
                using (Meshes frm = new Meshes())
                {
                    if (!frm.InitializeGraphics()) // Initialize Direct3D
                    {
                        MessageBox.Show("Could not initialize Direct3D.  This tutorial will exit.");
                        return;
                    }
                    frm.Show();
    
                    // While the form is still valid, render and process messages
                    while(frm.Created)
                    {
                        frm.Render();
                        Application.DoEvents();
                    }
                }
            }
        
  4. Meshes Class の Constructor で、メニューを生成します。
    X-FILE のオープンとプログラムの終了とバージョンの表示メニューを設定しました。
    this.Menu = menu; でウインドウにメニューを登録します。
            public Meshes()
            {
                this.ClientSize = new System.Drawing.Size(400,300);
                this.Text = "Direct3D File Menu";
                // メインメニューを生成
                menu = new MainMenu();
                MenuItem item = menu.MenuItems.Add("ファイル(&F)");
                item.MenuItems.Add(new MenuItem("開く(&O)", new EventHandler(this.OpenMesh)));
                item.MenuItems.Add(new MenuItem("終了(&X)", new EventHandler(this.FileExit), Shortcut.CtrlQ));
                item = menu.MenuItems.Add("ヘルプ(&H)");
                item.MenuItems.Add(new MenuItem("バージョン情報(&A)...", new EventHandler(this.HelpAbout)));
                this.Menu = menu;
            }
        
  5. プログラムの終了とバージョン表示のイベントハンドラです。
            // ファイル/終了メニューのイベントハンドラ
            private void FileExit(object sender, EventArgs e)
            {
                this.Close();
            }
    
            // ヘルプ/バージョン情報メニューのイベントハンドラ
            private void HelpAbout(object sender, EventArgs e)
            {
                MessageBox.Show("Project Menu Ver 1.0   Maeda Minoru");
            }
        
  6. X-FILE オープンのイベントハンドラです。
    OpenFileDialog を使って X-FILE を選択します。
    現在表示しているメッシュがあれば、これを解放します。
    OnResetDevice(device, null); で新しいメッシュを生成します。
            // ファイル/オープンのイベントハンドラ
            private void OpenMesh(object sender, EventArgs e)
            {
                System.Windows.Forms.OpenFileDialog ofn = new OpenFileDialog();
                ofn.Filter = ".X Files (*.x)|*.x";
                ofn.FileName = XFileName;
                ofn.InitialDirectory = XFilePath;
                ofn.Title = "Open Mesh File";
                ofn.CheckFileExists = true;
                ofn.Multiselect = false;
                ofn.ShowReadOnly = false;
                ofn.ShowDialog();
    
                System.IO.FileInfo fo = new System.IO.FileInfo(ofn.FileName);
                XFileName = fo.Name;
                System.IO.Directory.SetCurrentDirectory(fo.DirectoryName);
                XFilePath = fo.DirectoryName;
    
                // メッシュを解放
                if (mesh != null)
                {
                    for(int i = 0; i < meshMaterials.Length; i++)
                    {
                        if (meshTextures[i] != null)    meshTextures[i].Dispose();
                    }
                    meshMaterials = null;
                    mesh.Dispose();
                }
                // 新しいメッシュを生成
                OnResetDevice(device, null);
            }
        
  7. これ以外の部分は従来と同じです。詳細はソースコードを参照して下さい。
    Xファイルを表示するプログラムは コーンのメッシュ(cone.x)を描画する を参照して下さい。

コマンドラインから指定

  1. Xファイルの名前をコマンドラインから指定できるように改造します。
    コマンドラインのプログラムは Command Line 引数 を参照して下さい。
  2. XFilePath は X-FILE が置かれているフォルダです。
    XFileName は領域を定義するだけです。
            static  string XFilePath = "C:\\DATA\\XFILE\\";
            static  string XFileName;
        
  3. Main() メソッドでコマンドラインから指定された X-FILE名を取得します。
    args[0] にはドラッグ&ドロップした X-FILE の名前がフルパスで格納されています。
            //☆ Main() メソッド
            [STAThread]
            static void Main(string[] args)
            {
                if (args.Length>0)
                {
                    System.IO.FileInfo info = new System.IO.FileInfo(args[0]);
                    XFilePath = info.Directory.FullName;
                    XFileName = info.Name;
                }
        
  4. InitializeGraphics() で XFileName にファイル名が設定されているときはロードします。
            bool InitializeGraphics()
            {         ・
                      ・
                    if (XFileName!=null)    this.OnResetDevice(device, null);
                    pause = false;
                }
                catch (DirectXException)
                {      ・
                       ・
        
  5. ウインドウエクスプローラーを開いて DXMenu.exe を表示して下さい。
    適当な X-FILE を選択して DXMenu.exe にドラッグ&ドロップするとモデルが描画されます。
    普通に起動したときはメニュー選択で X-FILE を入力して下さい。

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