- Main Page
- Packages
- Classes
- Files

- File List
- File Members

# D:/guillaume/guillara/3D/DXGfx/Backup/DXCommon/dxmutmisc.cs

Go to the documentation of this file.

    00001 //--------------------------------------------------------------------------------------
    00002 // File: DXMUTMisc.cs
    00003 //
    00004 // Shortcut and helper functions for using DX Code
    00005 //
    00006 // Copyright (c) Microsoft Corporation. All rights reserved.
    00007 //--------------------------------------------------------------------------------------
    00008 using System;
    00009 using System.IO;
    00010 using System.Collections;
    00011 using System.Runtime.InteropServices;
    00012 using Microsoft.DirectX;
    00013 using Microsoft.DirectX.Direct3D;
    00014
    00015 namespace Microsoft.Samples.DirectX.UtilityToolkit
    00016 {
    00017     #region RefWarningDialog Form
    00018     internal class SwitchRefDialog : System.Windows.Forms.Form
    00019     {
    00020         internal const string KeyLocation = @"Software\Microsoft\DirectX 9.0 SDK\ManagedSamples";
    00021         internal const string KeyValueName = "SkipWarning";
    00022
    00023         public SwitchRefDialog(string title)
    00024         {
    00025             //
    00026             // Required for Windows Form Designer support
    00027             //
    00028             InitializeComponent();
    00029
    00030             // Use the 'question' icon
    00031             this.pictureBox1.Image = System.Drawing.SystemIcons.Question.ToBitmap();
    00032             // Include text
    00033             this.lblInfo.Text = "Switching to the Direct3D reference rasterizer, a software device that implements the entire Direct3D feature set, but runs very slowly.\r\nDo you wish to continue?";
    00034             // UPdate title
    00035             this.Text = title;
    00036         }
    00037
    00038         #region Windows Form Designer generated code
    00039         private System.Windows.Forms.PictureBox pictureBox1;
    00040         private System.Windows.Forms.Label lblInfo;
    00041         private System.Windows.Forms.CheckBox chkShowAgain;
    00042         private System.Windows.Forms.Button btnYes;
    00043         private System.Windows.Forms.Button btnNo;
    00048         private void InitializeComponent()
    00049         {
    00050             this.pictureBox1 = new System.Windows.Forms.PictureBox();
    00051             this.lblInfo = new System.Windows.Forms.Label();
    00052             this.chkShowAgain = new System.Windows.Forms.CheckBox();
    00053             this.btnYes = new System.Windows.Forms.Button();
    00054             this.btnNo = new System.Windows.Forms.Button();
    00055             this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
    00056             this.SuspendLayout();
    00057             //
    00058             // pictureBox1
    00059             //
    00060             this.pictureBox1.Location = new System.Drawing.Point(16, 16);
    00061             this.pictureBox1.Name = "pictureBox1";
    00062             this.pictureBox1.Size = new System.Drawing.Size(32, 32);
    00063             this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
    00064             this.pictureBox1.TabIndex = 0;
    00065             this.pictureBox1.TabStop = false;
    00066             //
    00067             // lblInfo
    00068             //
    00069             this.lblInfo.FlatStyle = System.Windows.Forms.FlatStyle.System;
    00070             this.lblInfo.Location = new System.Drawing.Point(64, 16);
    00071             this.lblInfo.Name = "lblInfo";
    00072             this.lblInfo.Size = new System.Drawing.Size(328, 48);
    00073             this.lblInfo.TabIndex = 99;
    00074             //
    00075             // chkShowAgain
    00076             //
    00077             this.chkShowAgain.FlatStyle = System.Windows.Forms.FlatStyle.System;
    00078             this.chkShowAgain.Location = new System.Drawing.Point(8, 104);
    00079             this.chkShowAgain.Name = "chkShowAgain";
    00080             this.chkShowAgain.Size = new System.Drawing.Size(224, 16);
    00081             this.chkShowAgain.TabIndex = 2;
    00082             this.chkShowAgain.Text = "&Don\'t show again";
    00083             //
    00084             // btnYes
    00085             //
    00086             this.btnYes.DialogResult = System.Windows.Forms.DialogResult.OK;
    00087             this.btnYes.FlatStyle = System.Windows.Forms.FlatStyle.System;
    00088             this.btnYes.Location = new System.Drawing.Point(117, 72);
    00089             this.btnYes.Name = "btnYes";
    00090             this.btnYes.Size = new System.Drawing.Size(80, 24);
    00091             this.btnYes.TabIndex = 0;
    00092             this.btnYes.Text = "&Yes";
    00093             this.btnYes.Click += new EventHandler(OnYes);
    00094             //
    00095             // btnNo
    00096             //
    00097             this.btnNo.DialogResult = System.Windows.Forms.DialogResult.Cancel;
    00098             this.btnNo.FlatStyle = System.Windows.Forms.FlatStyle.System;
    00099             this.btnNo.Location = new System.Drawing.Point(205, 72);
    00100             this.btnNo.Name = "btnNo";
    00101             this.btnNo.Size = new System.Drawing.Size(80, 24);
    00102             this.btnNo.TabIndex = 1;
    00103             this.btnNo.Text = "&No";
    00104             this.btnNo.Click += new EventHandler(OnNo);
    00105             //
    00106             // SwitchRefDialog
    00107             //
    00108             this.AcceptButton = this.btnYes;
    00109             this.CancelButton = this.btnNo;
    00110             this.ClientSize = new System.Drawing.Size(402, 134);
    00111             this.Controls.Add(this.btnNo);
    00112             this.Controls.Add(this.btnYes);
    00113             this.Controls.Add(this.chkShowAgain);
    00114             this.Controls.Add(this.lblInfo);
    00115             this.Controls.Add(this.pictureBox1);
    00116             this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
    00117             this.Name = "SwitchRefDialog";
    00118             this.Text = "SampleName";
    00119             this.ResumeLayout(false);
    00120
    00121         }
    00125         private void OnYes(object sender, EventArgs e)
    00126         {
    00127             this.DialogResult = System.Windows.Forms.DialogResult.OK;
    00128             this.Close();
    00129         }
    00133         private void OnNo(object sender, EventArgs e)
    00134         {
    00135             this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
    00136             this.Close();
    00137         }
    00138         #endregion
    00139
    00144         protected override void OnClosed(EventArgs e)
    00145         {
    00146             // Is the box checked?
    00147             if (chkShowAgain.Checked)
    00148             {
    00149                 using(Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(KeyLocation))
    00150                 {
    00151                     key.SetValue(KeyValueName, (int)1);
    00152                 }
    00153             }
    00154         }
    00155     }
    00156     #endregion
    00157
    00158     #region Native Methods
    00162     public class NativeMethods
    00163     {
    00164         #region Win32 User Messages / Structures
    00165
    00167         public enum WindowMessage : uint
    00168         {
    00169             // Misc messages
    00170             Destroy = 0x0002,
    00171             Close = 0x0010,
    00172             Quit = 0x0012,
    00173             Paint = 0x000F,
    00174             SetCursor = 0x0020,
    00175             ActivateApplication = 0x001C,
    00176             EnterMenuLoop = 0x0211,
    00177             ExitMenuLoop = 0x0212,
    00178             NonClientHitTest = 0x0084,
    00179             PowerBroadcast = 0x0218,
    00180             SystemCommand = 0x0112,
    00181             GetMinMax = 0x0024,
    00182
    00183             // Keyboard messages
    00184             KeyDown = 0x0100,
    00185             KeyUp = 0x0101,
    00186             Character = 0x0102,
    00187             SystemKeyDown = 0x0104,
    00188             SystemKeyUp = 0x0105,
    00189             SystemCharacter = 0x0106,
    00190
    00191             // Mouse messages
    00192             MouseMove = 0x0200,
    00193             LeftButtonDown = 0x0201,
    00194             LeftButtonUp = 0x0202,
    00195             LeftButtonDoubleClick = 0x0203,
    00196             RightButtonDown = 0x0204,
    00197             RightButtonUp = 0x0205,
    00198             RightButtonDoubleClick = 0x0206,
    00199             MiddleButtonDown = 0x0207,
    00200             MiddleButtonUp = 0x0208,
    00201             MiddleButtonDoubleClick = 0x0209,
    00202             MouseWheel = 0x020a,
    00203             XButtonDown = 0x020B,
    00204             XButtonUp = 0x020c,
    00205             XButtonDoubleClick = 0x020d,
    00206             MouseFirst = LeftButtonDown, // Skip mouse move, it happens a lot and there is another message for that
    00207             MouseLast = XButtonDoubleClick,
    00208
    00209             // Sizing
    00210             EnterSizeMove = 0x0231,
    00211             ExitSizeMove = 0x0232,
    00212             Size = 0x0005,
    00213
    00214         }
    00215
    00217         public enum MouseButtons
    00218         {
    00219             Left = 0x0001,
    00220             Right = 0x0002,
    00221             Middle = 0x0010,
    00222             Side1 = 0x0020,
    00223             Side2 = 0x0040,
    00224         }
    00225
    00227         [StructLayout(LayoutKind.Sequential)]
    00228         public struct Message
    00229         {
    00230             public IntPtr hWnd;
    00231             public WindowMessage msg;
    00232             public IntPtr wParam;
    00233             public IntPtr lParam;
    00234             public uint time;
    00235             public System.Drawing.Point p;
    00236         }
    00237
    00239         [StructLayout(LayoutKind.Sequential)]
    00240         public struct MinMaxInformation
    00241         {
    00242             public System.Drawing.Point reserved;
    00243             public System.Drawing.Point MaxSize;
    00244             public System.Drawing.Point MaxPosition;
    00245             public System.Drawing.Point MinTrackSize;
    00246             public System.Drawing.Point MaxTrackSize;
    00247         }
    00248
    00250         [StructLayout(LayoutKind.Sequential)]
    00251         public struct MonitorInformation
    00252         {
    00253             public uint Size; // Size of this structure
    00254             public System.Drawing.Rectangle MonitorRectangle;
    00255             public System.Drawing.Rectangle WorkRectangle;
    00256             public uint Flags; // Possible flags
    00257         }
    00258         #endregion
    00259
    00260         #region Windows API calls
    00261         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00262         [System.Runtime.InteropServices.DllImport("winmm.dll")]
    00263         public static extern IntPtr timeBeginPeriod(uint period);
    00264
    00265         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00266         [DllImport("kernel32")]
    00267         public static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency);
    00268
    00269         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00270         [DllImport("kernel32")]
    00271         public static extern bool QueryPerformanceCounter(ref long PerformanceCount);
    00272
    00273         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00274         [DllImport("User32.dll", CharSet=CharSet.Auto)]
    00275         public static extern bool GetMonitorInfo(IntPtr hWnd, ref MonitorInformation info);
    00276
    00277         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00278         [DllImport("User32.dll", CharSet=CharSet.Auto)]
    00279         public static extern IntPtr MonitorFromWindow(IntPtr hWnd, uint flags);
    00280
    00281         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00282         [DllImport("User32.dll", CharSet=CharSet.Auto)]
    00283         public static extern short GetAsyncKeyState(uint key);
    00284
    00285         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00286         [DllImport("User32.dll", CharSet=CharSet.Auto)]
    00287         public static extern IntPtr SetCapture(IntPtr handle);
    00288
    00289         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00290         [DllImport("User32.dll", CharSet=CharSet.Auto)]
    00291         public static extern bool ReleaseCapture();
    00292
    00293         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00294         [DllImport("User32.dll", CharSet=CharSet.Auto)]
    00295         public static extern int GetCaretBlinkTime();
    00296
    00297         [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    00298         [DllImport("User32.dll", CharSet=CharSet.Auto)]
    00299         public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
    00300         #endregion
    00301
    00302         #region Class Methods
    00303         private NativeMethods() {} // No creation
    00305         public static short LoWord(uint l)
    00306         {
    00307             return (short)(l & 0xffff);
    00308         }
    00310         public static short HiWord(uint l)
    00311         {
    00312             return (short)(l >> 16);
    00313         }
    00314
    00316         public static uint MakeUInt32(short l, short r)
    00317         {
    00318             return (uint)((l & 0xffff) | ((r & 0xffff) << 16));
    00319         }
    00320
    00322         public static bool IsKeyDown(System.Windows.Forms.Keys key)
    00323         {
    00324             return (GetAsyncKeyState((int)System.Windows.Forms.Keys.ShiftKey) & 0x8000) != 0;
    00325         }
    00326         #endregion
    00327     }
    00328
    00329     #endregion
    00330
    00331     #region Timer
    00332     public class FrameworkTimer
    00333     {
    00334         #region Instance Data
    00335         private static bool isUsingQPF;
    00336         private static bool isTimerStopped;
    00337         private static long ticksPerSecond;
    00338         private static long stopTime;
    00339         private static long lastElapsedTime;
    00340         private static long baseTime;
    00341         #endregion
    00342
    00343         #region Creation
    00344         private FrameworkTimer() { } // No creation
    00348         static FrameworkTimer()
    00349         {
    00350             isTimerStopped = true;
    00351             ticksPerSecond = 0;
    00352             stopTime = 0;
    00353             lastElapsedTime = 0;
    00354             baseTime = 0;
    00355             // Use QueryPerformanceFrequency to get frequency of the timer
    00356             isUsingQPF = NativeMethods.QueryPerformanceFrequency(ref ticksPerSecond);
    00357         }
    00358         #endregion
    00359
    00363         public static void Reset()
    00364         {
    00365             if (!isUsingQPF)
    00366                 return; // Nothing to do
    00367
    00368             // Get either the current time or the stop time
    00369             long time = 0;
    00370             if (stopTime != 0)
    00371                 time = stopTime;
    00372             else
    00373                 NativeMethods.QueryPerformanceCounter(ref time);
    00374
    00375             baseTime = time;
    00376             lastElapsedTime = time;
    00377             stopTime = 0;
    00378             isTimerStopped = false;
    00379         }
    00380
    00384         public static void Start()
    00385         {
    00386             if (!isUsingQPF)
    00387                 return; // Nothing to do
    00388
    00389             // Get either the current time or the stop time
    00390             long time = 0;
    00391             if (stopTime != 0)
    00392                 time = stopTime;
    00393             else
    00394                 NativeMethods.QueryPerformanceCounter(ref time);
    00395
    00396             if (isTimerStopped)
    00397                 baseTime += (time - stopTime);
    00398             stopTime = 0;
    00399             lastElapsedTime = time;
    00400             isTimerStopped = false;
    00401         }
    00402
    00406         public static void Stop()
    00407         {
    00408             if (!isUsingQPF)
    00409                 return; // Nothing to do
    00410
    00411             if (!isTimerStopped)
    00412             {
    00413                 // Get either the current time or the stop time
    00414                 long time = 0;
    00415                 if (stopTime != 0)
    00416                     time = stopTime;
    00417                 else
    00418                     NativeMethods.QueryPerformanceCounter(ref time);
    00419
    00420                 stopTime = time;
    00421                 lastElapsedTime = time;
    00422                 isTimerStopped = true;
    00423             }
    00424         }
    00425
    00429         public static void Advance()
    00430         {
    00431             if (!isUsingQPF)
    00432                 return; // Nothing to do
    00433
    00434             stopTime += ticksPerSecond / 10;
    00435         }
    00436
    00440         public static double GetAbsoluteTime()
    00441         {
    00442             if (!isUsingQPF)
    00443                 return -1.0; // Nothing to do
    00444
    00445             // Get either the current time or the stop time
    00446             long time = 0;
    00447             if (stopTime != 0)
    00448                 time = stopTime;
    00449             else
    00450                 NativeMethods.QueryPerformanceCounter(ref time);
    00451
    00452             double absolueTime = time / (double)ticksPerSecond;
    00453             return absolueTime;
    00454         }
    00455
    00459         public static double GetTime()
    00460         {
    00461             if (!isUsingQPF)
    00462                 return -1.0; // Nothing to do
    00463
    00464             // Get either the current time or the stop time
    00465             long time = 0;
    00466             if (stopTime != 0)
    00467                 time = stopTime;
    00468             else
    00469                 NativeMethods.QueryPerformanceCounter(ref time);
    00470
    00471             double appTime = (double)(time - baseTime) / (double)ticksPerSecond;
    00472             return appTime;
    00473         }
    00474
    00478         public static double GetElapsedTime()
    00479         {
    00480             if (!isUsingQPF)
    00481                 return -1.0; // Nothing to do
    00482
    00483             // Get either the current time or the stop time
    00484             long time = 0;
    00485             if (stopTime != 0)
    00486                 time = stopTime;
    00487             else
    00488                 NativeMethods.QueryPerformanceCounter(ref time);
    00489
    00490             double elapsedTime = (double)(time - lastElapsedTime) / (double)ticksPerSecond;
    00491             lastElapsedTime = time;
    00492             return elapsedTime;
    00493         }
    00494
    00498         public static bool IsStopped
    00499         {
    00500             get { return isTimerStopped; }
    00501         }
    00502     }
    00503     #endregion
    00504
    00505     #region Resource Cache
    00507     struct CachedTexture
    00508     {
    00509         public string Source; // Data source
    00510         public int Width;
    00511         public int Height;
    00512         public int Depth;
    00513         public int MipLevels;
    00514         public Usage Usage;
    00515         public Format Format;
    00516         public Pool Pool;
    00517         public ResourceType Type;
    00518     }
    00519
    00521     struct CachedEffect
    00522     {
    00523         public string Source; // Data source
    00524         public ShaderFlags Flags;
    00525     }
    00526
    00531     public class ResourceCache
    00532     {
    00533         #region Creation
    00534         private ResourceCache() { } // Don't allow creation
    00535         private static ResourceCache localObject = null;
    00536         public static ResourceCache GetGlobalInstance()
    00537         {
    00538             if (localObject == null)
    00539                 localObject = new ResourceCache();
    00540
    00541             return localObject;
    00542         }
    00543         #endregion
    00544
    00545         protected Hashtable textureCache = new Hashtable(); // Cache of textures
    00546         protected Hashtable effectCache = new Hashtable(); // Cache of effects
    00547         protected Hashtable fontCache = new Hashtable(); // Cache of fonts
    00548
    00549         #region Cache Creation Methods
    00550
    00552         public Texture CreateTextureFromFile(Device device, string filename)
    00553         {
    00554             return CreateTextureFromFileEx(device, filename, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None,
    00555                 Format.Unknown, Pool.Managed, (Filter)D3DX.Default, (Filter)D3DX.Default, 0);
    00556         }
    00558         public Texture CreateTextureFromFileEx(Device device, string filename, int w, int h, int mip, Usage usage, Format fmt, Pool pool, Filter filter, Filter mipfilter, int colorkey)
    00559         {
    00560             // Search the cache first
    00561             foreach(CachedTexture ct in textureCache.Keys)
    00562             {
    00563                 if ( (string.Compare(ct.Source, filename, true) == 0) &&
    00564                     ct.Width == w &&
    00565                     ct.Height == h &&
    00566                     ct.MipLevels == mip &&
    00567                     ct.Usage == usage &&
    00568                     ct.Format == fmt &&
    00569                     ct.Pool == pool &&
    00570                     ct.Type == ResourceType.Textures)
    00571                 {
    00572                     // A match was found, return that
    00573                     return textureCache[ct] as Texture;
    00574                 }
    00575             }
    00576
    00577             // No matching entry, load the resource and add it to the cache
    00578             Texture t = TextureLoader.FromFile(device, filename, w, h, mip, usage, fmt, pool, filter, mipfilter, colorkey);
    00579             CachedTexture entry = new CachedTexture();
    00580             entry.Source = filename;
    00581             entry.Width = w;
    00582             entry.Height = h;
    00583             entry.MipLevels = mip;
    00584             entry.Usage = usage;
    00585             entry.Format = fmt;
    00586             entry.Pool = pool;
    00587             entry.Type = ResourceType.Textures;
    00588
    00589             textureCache.Add(entry, t);
    00590
    00591             return t;
    00592         }
    00594         public CubeTexture CreateCubeTextureFromFile(Device device, string filename)
    00595         {
    00596             return CreateCubeTextureFromFileEx(device, filename, D3DX.Default, D3DX.Default, Usage.None,
    00597                 Format.Unknown, Pool.Managed, (Filter)D3DX.Default, (Filter)D3DX.Default, 0);
    00598         }
    00600         public CubeTexture CreateCubeTextureFromFileEx(Device device, string filename, int size, int mip, Usage usage, Format fmt, Pool pool, Filter filter, Filter mipfilter, int colorkey)
    00601         {
    00602             // Search the cache first
    00603             foreach(CachedTexture ct in textureCache.Keys)
    00604             {
    00605                 if ( (string.Compare(ct.Source, filename, true) == 0) &&
    00606                     ct.Width == size &&
    00607                     ct.MipLevels == mip &&
    00608                     ct.Usage == usage &&
    00609                     ct.Format == fmt &&
    00610                     ct.Pool == pool &&
    00611                     ct.Type == ResourceType.CubeTexture)
    00612                 {
    00613                     // A match was found, return that
    00614                     return textureCache[ct] as CubeTexture;
    00615                 }
    00616             }
    00617
    00618             // No matching entry, load the resource and add it to the cache
    00619             CubeTexture t = TextureLoader.FromCubeFile(device, filename, size, mip, usage, fmt, pool, filter, mipfilter, colorkey);
    00620             CachedTexture entry = new CachedTexture();
    00621             entry.Source = filename;
    00622             entry.Width = size;
    00623             entry.MipLevels = mip;
    00624             entry.Usage = usage;
    00625             entry.Format = fmt;
    00626             entry.Pool = pool;
    00627             entry.Type = ResourceType.CubeTexture;
    00628
    00629             textureCache.Add(entry, t);
    00630
    00631             return t;
    00632         }
    00634         public VolumeTexture CreateVolumeTextureFromFile(Device device, string filename)
    00635         {
    00636             return CreateVolumeTextureFromFileEx(device, filename, D3DX.Default, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None,
    00637                 Format.Unknown, Pool.Managed, (Filter)D3DX.Default, (Filter)D3DX.Default, 0);
    00638         }
    00640         public VolumeTexture CreateVolumeTextureFromFileEx(Device device, string filename, int w, int h, int d, int mip, Usage usage, Format fmt, Pool pool, Filter filter, Filter mipfilter, int colorkey)
    00641         {
    00642             // Search the cache first
    00643             foreach(CachedTexture ct in textureCache.Keys)
    00644             {
    00645                 if ( (string.Compare(ct.Source, filename, true) == 0) &&
    00646                     ct.Width == w &&
    00647                     ct.Height == h &&
    00648                     ct.Depth == d &&
    00649                     ct.MipLevels == mip &&
    00650                     ct.Usage == usage &&
    00651                     ct.Format == fmt &&
    00652                     ct.Pool == pool &&
    00653                     ct.Type == ResourceType.VolumeTexture)
    00654                 {
    00655                     // A match was found, return that
    00656                     return textureCache[ct] as VolumeTexture;
    00657                 }
    00658             }
    00659
    00660             // No matching entry, load the resource and add it to the cache
    00661             VolumeTexture t = TextureLoader.FromVolumeFile(device, filename, w, h, d, mip, usage, fmt, pool, filter, mipfilter, colorkey);
    00662             CachedTexture entry = new CachedTexture();
    00663             entry.Source = filename;
    00664             entry.Width = w;
    00665             entry.Height = h;
    00666             entry.Depth = d;
    00667             entry.MipLevels = mip;
    00668             entry.Usage = usage;
    00669             entry.Format = fmt;
    00670             entry.Pool = pool;
    00671             entry.Type = ResourceType.VolumeTexture;
    00672
    00673             textureCache.Add(entry, t);
    00674
    00675             return t;
    00676         }
    00677
    00679         public Effect CreateEffectFromFile(Device device, string filename, Macro[] defines, Include includeFile, ShaderFlags flags, EffectPool effectPool, out string errors)
    00680         {
    00681             // No errors at first!
    00682             errors = string.Empty;
    00683             // Search the cache first
    00684             foreach(CachedEffect ce in effectCache.Keys)
    00685             {
    00686                 if ( (string.Compare(ce.Source, filename, true) == 0) &&
    00687                     ce.Flags == flags)
    00688                 {
    00689                     // A match was found, return that
    00690                     return effectCache[ce] as Effect;
    00691                 }
    00692             }
    00693
    00694             // Nothing found in the cache
    00695             Effect e = Effect.FromFile(device, filename, defines, includeFile, null, flags, effectPool, out errors);
    00696             // Add this to the cache
    00697             CachedEffect entry = new CachedEffect();
    00698             entry.Flags = flags;
    00699             entry.Source = filename;
    00700             effectCache.Add(entry, e);
    00701
    00702             // Return the new effect
    00703             return e;
    00704         }
    00705
    00707         public Effect CreateEffectFromFile(Device device, string filename, Macro[] defines, Include includeFile, ShaderFlags flags, EffectPool effectPool)
    00708         {
    00709             string temp; return CreateEffectFromFile(device, filename, defines, includeFile, flags, effectPool, out temp);
    00710         }
    00712         public Font CreateFont(Device device, int height, int width, FontWeight weight, int mip, bool italic,
    00713             CharacterSet charSet, Precision outputPrecision, FontQuality quality, PitchAndFamily pandf, string fontName)
    00714         {
    00715             // Create the font description
    00716             FontDescription desc = new FontDescription();
    00717             desc.Height = height;
    00718             desc.Width = width;
    00719             desc.Weight = weight;
    00720             desc.MipLevels = mip;
    00721             desc.IsItalic = italic;
    00722             desc.CharSet = charSet;
    00723             desc.OutputPrecision = outputPrecision;
    00724             desc.Quality = quality;
    00725             desc.PitchAndFamily = pandf;
    00726             desc.FaceName = fontName;
    00727
    00728             // return the font
    00729             return CreateFont(device, desc);
    00730         }
    00732         public Font CreateFont(Device device, FontDescription desc)
    00733         {
    00734             // Search the cache first
    00735             foreach(FontDescription fd in fontCache.Keys)
    00736             {
    00737                 if ( (string.Compare(fd.FaceName, desc.FaceName, true) == 0) &&
    00738                     fd.CharSet == desc.CharSet &&
    00739                     fd.Height == desc.Height &&
    00740                     fd.IsItalic == desc.IsItalic &&
    00741                     fd.MipLevels == desc.MipLevels &&
    00742                     fd.OutputPrecision == desc.OutputPrecision &&
    00743                     fd.PitchAndFamily == desc.PitchAndFamily &&
    00744                     fd.Quality == desc.Quality &&
    00745                     fd.Weight == desc.Weight &&
    00746                     fd.Width == desc.Width)
    00747                 {
    00748                     // A match was found, return that
    00749                     return fontCache[fd] as Font;
    00750                 }
    00751             }
    00752
    00753             // Couldn't find anything in the cache, create one
    00754             Font f = new Font(device, desc);
    00755             // Create a new entry
    00756             fontCache.Add(desc, f);
    00757
    00758             // return the new font
    00759             return f;
    00760         }
    00761
    00762         #endregion
    00763
    00764         #region Device event callbacks
    00768         public void OnCreateDevice(Device device) {} // Nothing to do on device create
    00772         public void OnResetDevice(Device device)
    00773         {
    00774             // Call OnResetDevice on all effect and font objects
    00775             foreach(Font f in fontCache.Values)
    00776                 f.OnResetDevice();
    00777             foreach(Effect e in effectCache.Values)
    00778                 e.OnResetDevice();
    00779         }
    00783         public void OnLostDevice()
    00784         {
    00785             foreach(Font f in fontCache.Values)
    00786                 f.OnLostDevice();
    00787             foreach(Effect e in effectCache.Values)
    00788                 e.OnLostDevice();
    00789
    00790             // Search the texture cache
    00791             foreach(CachedTexture ct in textureCache.Keys)
    00792             {
    00793                 if (ct.Pool == Pool.Default)
    00794                 {
    00795                     // A match was found, get rid of it
    00796                     switch(ct.Type)
    00797                     {
    00798                         case ResourceType.Textures:
    00799                             (textureCache[ct] as Texture).Dispose(); break;
    00800                         case ResourceType.CubeTexture:
    00801                             (textureCache[ct] as CubeTexture).Dispose();break;
    00802                         case ResourceType.VolumeTexture:
    00803                             (textureCache[ct] as VolumeTexture).Dispose();break;
    00804                     }
    00805                 }
    00806             }
    00807         }
    00811         public void OnDestroyDevice()
    00812         {
    00813             // Cleanup the fonts
    00814             foreach(Font f in fontCache.Values)
    00815                 f.Dispose();
    00816
    00817             // Cleanup the effects
    00818             foreach(Effect e in effectCache.Values)
    00819                 e.Dispose();
    00820
    00821             // Dispose of any items in the caches
    00822             foreach(BaseTexture texture in textureCache.Values)
    00823             {
    00824                 if (texture != null)
    00825                     texture.Dispose();
    00826             }
    00827
    00828             // Clear all of the caches
    00829             textureCache.Clear();
    00830             fontCache.Clear();
    00831             effectCache.Clear();
    00832         }
    00833
    00834         #endregion
    00835     }
    00836     #endregion
    00837
    00838     #region Arcball
    00842     public class ArcBall
    00843     {
    00844         #region Instance Data
    00845         protected Matrix rotation; // Matrix for arc ball's orientation
    00846         protected Matrix translation; // Matrix for arc ball's position
    00847         protected Matrix translationDelta; // Matrix for arc ball's position
    00848
    00849         protected int width; // arc ball's window width
    00850         protected int height; // arc ball's window height
    00851         protected Vector2 center;  // center of arc ball
    00852         protected float radius; // arc ball's radius in screen coords
    00853         protected float radiusTranslation; // arc ball's radius for translating the target
    00854
    00855         protected Quaternion downQuat; // Quaternion before button down
    00856         protected Quaternion nowQuat; // Composite quaternion for current drag
    00857         protected bool isDragging; // Whether user is dragging arc ball
    00858
    00859         protected System.Drawing.Point lastMousePosition; // position of last mouse point
    00860         protected Vector3 downPt; // starting point of rotation arc
    00861         protected Vector3 currentPt; // current point of rotation arc
    00862         #endregion
    00863
    00864         #region Simple Properties
    00866         public Matrix RotationMatrix { get { return rotation = Matrix.RotationQuaternion(nowQuat); } }
    00868         public Matrix TranslationMatrix { get { return translation; } }
    00870         public Matrix TranslationDeltaMatrix { get { return translationDelta; } }
    00872         public bool IsBeingDragged { get { return isDragging; } }
    00874         public Quaternion CurrentQuaternion { get { return nowQuat; } set { nowQuat = value; } }
    00875         #endregion
    00876
    00877         // Class methods
    00878
    00882         public ArcBall()
    00883         {
    00884             Reset();
    00885             downPt = Vector3.Empty;
    00886             currentPt = Vector3.Empty;
    00887
    00888             System.Windows.Forms.Form active = System.Windows.Forms.Form.ActiveForm;
    00889             if (active != null)
    00890             {
    00891                 System.Drawing.Rectangle rect = active.ClientRectangle;
    00892                 SetWindow(rect.Width, rect.Height);
    00893             }
    00894         }
    00895
    00899         public void Reset()
    00900         {
    00901             downQuat = Quaternion.Identity;
    00902             nowQuat = Quaternion.Identity;
    00903             rotation = Matrix.Identity;
    00904             translation = Matrix.Identity;
    00905             translationDelta = Matrix.Identity;
    00906             isDragging = false;
    00907             radius = 1.0f;
    00908             radiusTranslation = 1.0f;
    00909         }
    00910
    00914         public Vector3 ScreenToVector(float screenPointX, float screenPointY)
    00915         {
    00916             float x = -(screenPointX - width / 2.0f) / (radius * width/2.0f);
    00917             float y = (screenPointY - height / 2.0f) / (radius * height/2.0f);
    00918             float z = 0.0f;
    00919             float mag = (x*x) + (y*y);
    00920
    00921             if (mag > 1.0f)
    00922             {
    00923                 float scale = 1.0f / (float)Math.Sqrt(mag);
    00924                 x *= scale;
    00925                 y *= scale;
    00926             }
    00927             else
    00928                 z = (float)Math.Sqrt(1.0f - mag);
    00929
    00930             return new Vector3(x,y,z);
    00931         }
    00932
    00936         public void SetWindow(int w, int h, float r)
    00937         {
    00938             width = w; height = h; radius = r;
    00939             center = new Vector2(w / 2.0f, h / 2.0f);
    00940         }
    00941         public void SetWindow(int w, int h)
    00942         {
    00943             SetWindow(w,h,0.9f); // default radius
    00944         }
    00945
    00949         public static Quaternion QuaternionFromBallPoints(Vector3 from, Vector3 to)
    00950         {
    00951             float dot = Vector3.Dot(from, to);
    00952             Vector3 part = Vector3.Cross(from, to);
    00953             return new Quaternion(part.X, part.Y, part.Z, dot);
    00954         }
    00955
    00959         public void OnBegin(int x, int y)
    00960         {
    00961             isDragging = true;
    00962             downQuat = nowQuat;
    00963             downPt = ScreenToVector((float)x, (float)y);
    00964         }
    00968         public void OnMove(int x, int y)
    00969         {
    00970             if (isDragging)
    00971             {
    00972                 currentPt = ScreenToVector((float)x, (float)y);
    00973                 nowQuat = downQuat * QuaternionFromBallPoints(downPt, currentPt);
    00974             }
    00975         }
    00979         public void OnEnd()
    00980         {
    00981             isDragging = false;
    00982         }
    00983
    00987         public bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
    00988         {
    00989             // Current mouse position
    00990             short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    00991             short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    00992
    00993             switch(msg)
    00994             {
    00995                 case NativeMethods.WindowMessage.LeftButtonDown:
    00996                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
    00997                     // Set capture
    00998                     NativeMethods.SetCapture(hWnd);
    00999                     OnBegin(mouseX, mouseY);
    01000                     return true;
    01001                 case NativeMethods.WindowMessage.LeftButtonUp:
    01002                     // Release capture
    01003                     NativeMethods.ReleaseCapture();
    01004                     OnEnd();
    01005                     return true;
    01006
    01007                 case NativeMethods.WindowMessage.RightButtonDown:
    01008                 case NativeMethods.WindowMessage.RightButtonDoubleClick:
    01009                 case NativeMethods.WindowMessage.MiddleButtonDown:
    01010                 case NativeMethods.WindowMessage.MiddleButtonDoubleClick:
    01011                     // Set capture
    01012                     NativeMethods.SetCapture(hWnd);
    01013                     // Store off the position of the cursor
    01014                     lastMousePosition = new System.Drawing.Point(mouseX, mouseY);
    01015                     return true;
    01016
    01017                 case NativeMethods.WindowMessage.RightButtonUp:
    01018                 case NativeMethods.WindowMessage.MiddleButtonUp:
    01019                     // Release capture
    01020                     NativeMethods.ReleaseCapture();
    01021                     return true;
    01022
    01023                 case NativeMethods.WindowMessage.MouseMove:
    01024                     short buttonState = NativeMethods.LoWord((uint)wParam.ToInt32());
    01025                     bool leftButton = ((buttonState & (short)NativeMethods.MouseButtons.Left) != 0);
    01026                     bool rightButton = ((buttonState & (short)NativeMethods.MouseButtons.Right) != 0);
    01027                     bool middleButton = ((buttonState & (short)NativeMethods.MouseButtons.Middle) != 0);
    01028
    01029                     if (leftButton)
    01030                     {
    01031                         OnMove(mouseX, mouseY);
    01032                     }
    01033                     else if (rightButton || middleButton)
    01034                     {
    01035                         // Normalize based on size of window and bounding sphere radius
    01036                         float deltaX = (lastMousePosition.X - mouseX) * radiusTranslation / width;
    01037                         float deltaY = (lastMousePosition.Y - mouseY) * radiusTranslation / height;
    01038
    01039                         if (rightButton)
    01040                         {
    01041                             translationDelta = Matrix.Translation(-2*deltaX,2*deltaY, 0.0f);
    01042                             translation *= translationDelta;
    01043                         }
    01044                         else // Middle button
    01045                         {
    01046                             translationDelta = Matrix.Translation(0.0f, 0.0f, 5*deltaY);
    01047                             translation *= translationDelta;
    01048                         }
    01049                         // Store off the position of the cursor
    01050                         lastMousePosition = new System.Drawing.Point(mouseX, mouseY);
    01051                     }
    01052                     return true;
    01053             }
    01054
    01055             return false;
    01056         }
    01057     }
    01058     #endregion
    01059
    01060     #region Cameras
    01064     public enum CameraKeys : byte
    01065     {
    01066         StrafeLeft,
    01067         StrafeRight,
    01068         MoveForward,
    01069         MoveBackward,
    01070         MoveUp,
    01071         MoveDown,
    01072         Reset,
    01073         ControlDown,
    01074         MaxKeys,
    01075         Unknown=0xff
    01076     }
    01077
    01081     [Flags]
    01082     public enum MouseButtonMask : byte
    01083     {
    01084         None = 0,
    01085         Left = 0x01,
    01086         Middle = 0x02,
    01087         Right = 0x04,
    01088         Wheel = 0x08,
    01089     }
    01090
    01096     public abstract class Camera
    01097     {
    01101         protected static CameraKeys MapKey(IntPtr param)
    01102         {
    01103             System.Windows.Forms.Keys key = (System.Windows.Forms.Keys)param.ToInt32();
    01104             switch(key)
    01105             {
    01106                 case System.Windows.Forms.Keys.ControlKey: return CameraKeys.ControlDown;
    01107                 case System.Windows.Forms.Keys.Left: return CameraKeys.StrafeLeft;
    01108                 case System.Windows.Forms.Keys.Right: return CameraKeys.StrafeRight;
    01109                 case System.Windows.Forms.Keys.Up: return CameraKeys.MoveForward;
    01110                 case System.Windows.Forms.Keys.Down: return CameraKeys.MoveBackward;
    01111                 case System.Windows.Forms.Keys.Prior: return CameraKeys.MoveUp; // pgup
    01112                 case System.Windows.Forms.Keys.Next: return CameraKeys.MoveDown; // pgdn
    01113
    01114                 case System.Windows.Forms.Keys.A: return CameraKeys.StrafeLeft;
    01115                 case System.Windows.Forms.Keys.D: return CameraKeys.StrafeRight;
    01116                 case System.Windows.Forms.Keys.W: return CameraKeys.MoveForward;
    01117                 case System.Windows.Forms.Keys.S: return CameraKeys.MoveBackward;
    01118                 case System.Windows.Forms.Keys.Q: return CameraKeys.MoveUp;
    01119                 case System.Windows.Forms.Keys.E: return CameraKeys.MoveDown;
    01120
    01121                 case System.Windows.Forms.Keys.NumPad4: return CameraKeys.StrafeLeft;
    01122                 case System.Windows.Forms.Keys.NumPad6: return CameraKeys.StrafeRight;
    01123                 case System.Windows.Forms.Keys.NumPad8: return CameraKeys.MoveForward;
    01124                 case System.Windows.Forms.Keys.NumPad2: return CameraKeys.MoveBackward;
    01125                 case System.Windows.Forms.Keys.NumPad9: return CameraKeys.MoveUp;
    01126                 case System.Windows.Forms.Keys.NumPad3: return CameraKeys.MoveDown;
    01127
    01128                 case System.Windows.Forms.Keys.Home: return CameraKeys.Reset;
    01129             }
    01130             // No idea
    01131             return (CameraKeys)byte.MaxValue;
    01132         }
    01133
    01134
    01135         #region Instance Data
    01136         protected Matrix viewMatrix; // View Matrix
    01137         protected Matrix projMatrix; // Projection matrix
    01138
    01139         protected System.Drawing.Point lastMousePosition;  // Last absolute position of mouse cursor
    01140         protected bool isMouseLButtonDown;    // True if left button is down
    01141         protected bool isMouseMButtonDown;    // True if middle button is down
    01142         protected bool isMouseRButtonDown;    // True if right button is down
    01143         protected int currentButtonMask;   // mask of which buttons are down
    01144         protected int mouseWheelDelta;     // Amount of middle wheel scroll (+/-)
    01145         protected Vector2 mouseDelta;          // Mouse relative delta smoothed over a few frames
    01146         protected float framesToSmoothMouseData; // Number of frames to smooth mouse data over
    01147
    01148         protected Vector3 defaultEye;          // Default camera eye position
    01149         protected Vector3 defaultLookAt;       // Default LookAt position
    01150         protected Vector3 eye;                 // Camera eye position
    01151         protected Vector3 lookAt;              // LookAt position
    01152         protected float cameraYawAngle;      // Yaw angle of camera
    01153         protected float cameraPitchAngle;    // Pitch angle of camera
    01154
    01155         protected System.Drawing.Rectangle dragRectangle; // Rectangle within which a drag can be initiated.
    01156         protected Vector3 velocity;            // Velocity of camera
    01157         protected bool isMovementDrag;        // If true, then camera movement will slow to a stop otherwise movement is instant
    01158         protected Vector3 velocityDrag;        // Velocity drag force
    01159         protected float dragTimer;           // Countdown timer to apply drag
    01160         protected float totalDragTimeToZero; // Time it takes for velocity to go from full to 0
    01161         protected Vector2 rotationVelocity;         // Velocity of camera
    01162
    01163         protected float fieldOfView;                 // Field of view
    01164         protected float aspectRatio;              // Aspect ratio
    01165         protected float nearPlane;           // Near plane
    01166         protected float farPlane;            // Far plane
    01167
    01168         protected float rotationScaler;      // Scaler for rotation
    01169         protected float moveScaler;          // Scaler for movement
    01170
    01171         protected bool isInvertPitch;         // Invert the pitch axis
    01172         protected bool isEnablePositionMovement; // If true, then the user can translate the camera/model
    01173         protected bool isEnableYAxisMovement; // If true, then camera can move in the y-axis
    01174
    01175         protected bool isClipToBoundary;      // If true, then the camera will be clipped to the boundary
    01176         protected Vector3 minBoundary;         // Min point in clip boundary
    01177         protected Vector3 maxBoundary;         // Max point in clip boundary
    01178
    01179         protected bool isResetCursorAfterMove;// If true, the class will reset the cursor position so that the cursor always has space to move
    01180
    01181         // State of the input
    01182         protected bool[] keys;
    01183         public static readonly Vector3 UpDirection = new Vector3(0,1,0);
    01184         #endregion
    01185
    01186         #region Simple Properties
    01188         public bool IsBeingDragged { get { return (isMouseLButtonDown || isMouseMButtonDown || isMouseRButtonDown); } }
    01190         public bool IsMouseLeftButtonDown { get { return isMouseLButtonDown; } }
    01192         public bool IsMouseRightButtonDown { get { return isMouseRButtonDown; } }
    01194         public bool IsMouseMiddleButtonDown { get { return isMouseMButtonDown; } }
    01196         public Matrix ViewMatrix { get { return viewMatrix; } }
    01198         public Matrix ProjectionMatrix { get { return projMatrix; } }
    01200         public Vector3 EyeLocation { get { return eye; } }
    01202         public Vector3 LookAtPoint { get { return lookAt; } }
    01204         public bool IsPositionMovementEnabled { get {return isEnablePositionMovement; } set { isEnablePositionMovement = value; } }
    01205         #endregion
    01206
    01210         public abstract void FrameMove(float elapsedTime);
    01211
    01215         protected Camera()
    01216         {
    01217             // Create the keys
    01218             keys = new bool[(int)CameraKeys.MaxKeys];
    01219
    01220             // Set attributes for the view matrix
    01221             eye = Vector3.Empty;
    01222             lookAt = new Vector3(0.0f, 0.0f, 1.0f);
    01223
    01224             // Setup the view matrix
    01225             SetViewParameters(eye, lookAt);
    01226
    01227             // Setup the projection matrix
    01228             SetProjectionParameters((float)Math.PI / 4, 1.0f, 1.0f, 1000.0f);
    01229
    01230             // Store mouse information
    01231             lastMousePosition = System.Windows.Forms.Cursor.Position;
    01232             isMouseLButtonDown = false;
    01233             isMouseRButtonDown = false;
    01234             isMouseMButtonDown = false;
    01235             mouseWheelDelta = 0;
    01236             currentButtonMask = 0;
    01237
    01238             // Setup camera rotations
    01239             cameraYawAngle = 0.0f;
    01240             cameraPitchAngle = 0.0f;
    01241
    01242             dragRectangle = new System.Drawing.Rectangle(0, 0, int.MaxValue, int.MaxValue);
    01243             velocity = Vector3.Empty;
    01244             isMovementDrag = false;
    01245             velocityDrag = Vector3.Empty;
    01246             dragTimer = 0.0f;
    01247             totalDragTimeToZero = 0.25f;
    01248             rotationVelocity = Vector2.Empty;
    01249             rotationScaler = 0.1f;
    01250             moveScaler = 5.0f;
    01251             isInvertPitch = false;
    01252             isEnableYAxisMovement = true;
    01253             isEnablePositionMovement = true;
    01254             mouseDelta = Vector2.Empty;
    01255             framesToSmoothMouseData = 2.0f;
    01256             isClipToBoundary = false;
    01257             minBoundary = new Vector3(-1.0f,-1.0f, -1.0f);
    01258             maxBoundary = new Vector3(1,1,1);
    01259             isResetCursorAfterMove = false;
    01260         }
    01261
    01265         public virtual bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
    01266         {
    01267             switch(msg)
    01268             {
    01269                 // Handle the keyboard
    01270                 case NativeMethods.WindowMessage.KeyDown:
    01271                     CameraKeys mappedKeyDown = MapKey(wParam);
    01272                     if (mappedKeyDown != (CameraKeys)byte.MaxValue)
    01273                     {
    01274                         // Valid key was pressed, mark it as 'down'
    01275                         keys[(int)mappedKeyDown] = true;
    01276                     }
    01277                     break;
    01278                 case NativeMethods.WindowMessage.KeyUp:
    01279                     CameraKeys mappedKeyUp = MapKey(wParam);
    01280                     if (mappedKeyUp != (CameraKeys)byte.MaxValue)
    01281                     {
    01282                         // Valid key was let go, mark it as 'up'
    01283                         keys[(int)mappedKeyUp] = false;
    01284                     }
    01285                     break;
    01286
    01287                 // Handle the mouse
    01288                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
    01289                 case NativeMethods.WindowMessage.LeftButtonDown:
    01290                 case NativeMethods.WindowMessage.RightButtonDoubleClick:
    01291                 case NativeMethods.WindowMessage.RightButtonDown:
    01292                 case NativeMethods.WindowMessage.MiddleButtonDoubleClick:
    01293                 case NativeMethods.WindowMessage.MiddleButtonDown:
    01294                 {
    01295                     // Compute the drag rectangle in screen coord.
    01296                     System.Drawing.Point cursor = new System.Drawing.Point(
    01297                         NativeMethods.LoWord((uint)lParam.ToInt32()),
    01298                         NativeMethods.HiWord((uint)lParam.ToInt32()));
    01299
    01300                     // Update the variable state
    01301                     if ( ((msg == NativeMethods.WindowMessage.LeftButtonDown) ||
    01302                         (msg == NativeMethods.WindowMessage.LeftButtonDoubleClick) )
    01303                         && dragRectangle.Contains(cursor) )
    01304                     {
    01305                         isMouseLButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Left;
    01306                     }
    01307                     if ( ((msg == NativeMethods.WindowMessage.MiddleButtonDown) ||
    01308                         (msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick) )
    01309                         && dragRectangle.Contains(cursor) )
    01310                     {
    01311                         isMouseMButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Middle;
    01312                     }
    01313                     if ( ((msg == NativeMethods.WindowMessage.RightButtonDown) ||
    01314                         (msg == NativeMethods.WindowMessage.RightButtonDoubleClick) )
    01315                         && dragRectangle.Contains(cursor) )
    01316                     {
    01317                         isMouseRButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Right;
    01318                     }
    01319
    01320                     // Capture the mouse, so if the mouse button is
    01321                     // released outside the window, we'll get the button up messages
    01322                     NativeMethods.SetCapture(hWnd);
    01323
    01324                     lastMousePosition = System.Windows.Forms.Cursor.Position;
    01325                     return true;
    01326                 }
    01327                 case NativeMethods.WindowMessage.LeftButtonUp:
    01328                 case NativeMethods.WindowMessage.RightButtonUp:
    01329                 case NativeMethods.WindowMessage.MiddleButtonUp:
    01330                 {
    01331                     // Update member var state
    01332                     if (msg == NativeMethods.WindowMessage.LeftButtonUp) { isMouseLButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Left; }
    01333                     if (msg == NativeMethods.WindowMessage.RightButtonUp) { isMouseRButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Right; }
    01334                     if (msg == NativeMethods.WindowMessage.MiddleButtonUp) { isMouseMButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Middle; }
    01335
    01336                     // Release the capture if no mouse buttons are down
    01337                     if (!isMouseLButtonDown && !isMouseMButtonDown && !isMouseRButtonDown)
    01338                     {
    01339                         NativeMethods.ReleaseCapture();
    01340                     }
    01341                 }
    01342                     break;
    01343
    01344                 // Handle the mouse wheel
    01345                 case NativeMethods.WindowMessage.MouseWheel:
    01346                     mouseWheelDelta = NativeMethods.HiWord((uint)wParam.ToInt32()) / 120;
    01347                     break;
    01348             }
    01349
    01350             return false;
    01351         }
    01352
    01353
    01357         public virtual void Reset()
    01358         {
    01359             SetViewParameters(defaultEye, defaultLookAt);
    01360         }
    01361
    01365         public unsafe virtual void SetViewParameters(Vector3 eyePt, Vector3 lookAtPt)
    01366         {
    01367             // Store the data
    01368             defaultEye = eye = eyePt;
    01369             defaultLookAt = lookAt = lookAtPt;
    01370
    01371             // Calculate the view matrix
    01372             viewMatrix = Matrix.LookAtLH(eye, lookAt, UpDirection);
    01373
    01374             // Get the inverted matrix
    01375             Matrix inverseView = Matrix.Invert(viewMatrix);
    01376
    01377             // The axis basis vectors and camera position are stored inside the
    01378             // position matrix in the 4 rows of the camera's world matrix.
    01379             // To figure out the yaw/pitch of the camera, we just need the Z basis vector
    01380             Vector3* pZBasis = (Vector3*)&inverseView.M31;
    01381             cameraYawAngle = (float)Math.Atan2(pZBasis->X, pZBasis->Z);
    01382             float len = (float)Math.Sqrt(pZBasis->Z * pZBasis->Z + pZBasis->X * pZBasis->X);
    01383             cameraPitchAngle = -(float)Math.Atan2(pZBasis->Y, len);
    01384         }
    01385
    01389         public virtual void SetProjectionParameters(float fov, float aspect, float near, float far)
    01390         {
    01391             // Set attributes for the projection matrix
    01392             fieldOfView = fov;
    01393             aspectRatio = aspect;
    01394             nearPlane = near;
    01395             farPlane = far;
    01396
    01397             projMatrix = Matrix.PerspectiveFovLH(fov, aspect, near, far);
    01398         }
    01399
    01403         protected void UpdateMouseDelta(float elapsedTime)
    01404         {
    01405             // Get the current mouse position
    01406             System.Drawing.Point current = System.Windows.Forms.Cursor.Position;
    01407
    01408             // Calculate how far it's moved since the last frame
    01409             System.Drawing.Point delta = new System.Drawing.Point(current.X - lastMousePosition.X,
    01410                 current.Y - lastMousePosition.Y);
    01411
    01412             // Record the current position for next time
    01413             lastMousePosition = current;
    01414
    01415             if (isResetCursorAfterMove)
    01416             {
    01417                 // Set position of camera to center of desktop,
    01418                 // so it always has room to move.  This is very useful
    01419                 // if the cursor is hidden.  If this isn't done and cursor is hidden,
    01420                 // then invisible cursor will hit the edge of the screen
    01421                 // and the user can't tell what happened
    01422                 System.Windows.Forms.Screen activeScreen = System.Windows.Forms.Screen.PrimaryScreen;
    01423                 System.Drawing.Point center = new System.Drawing.Point(activeScreen.Bounds.Width / 2,
    01424                     activeScreen.Bounds.Height / 2);
    01425                 System.Windows.Forms.Cursor.Position = center;
    01426                 lastMousePosition = center;
    01427             }
    01428
    01429             // Smooth the relative mouse data over a few frames so it isn't
    01430             // jerky when moving slowly at low frame rates.
    01431             float percentOfNew = 1.0f / framesToSmoothMouseData;
    01432             float percentOfOld = 1.0f - percentOfNew;
    01433             mouseDelta.X = mouseDelta.X*percentOfNew + delta.X*percentOfNew;
    01434             mouseDelta.Y = mouseDelta.Y*percentOfNew + delta.Y*percentOfNew;
    01435
    01436             rotationVelocity = mouseDelta * rotationScaler;
    01437         }
    01438
    01442         protected void UpdateVelocity(float elapsedTime)
    01443         {
    01444             Vector3 accel = Vector3.Empty;
    01445
    01446             if (isEnablePositionMovement)
    01447             {
    01448                 // Update acceleration vector based on keyboard state
    01449                 if (keys[(int)CameraKeys.MoveForward])
    01450                     accel.Z += 1.0f;
    01451                 if (keys[(int)CameraKeys.MoveBackward])
    01452                     accel.Z -= 1.0f;
    01453                 if (isEnableYAxisMovement)
    01454                 {
    01455                     if (keys[(int)CameraKeys.MoveUp])
    01456                         accel.Y += 1.0f;
    01457                     if (keys[(int)CameraKeys.MoveDown])
    01458                         accel.Y -= 1.0f;
    01459                 }
    01460                 if (keys[(int)CameraKeys.StrafeRight])
    01461                     accel.X += 1.0f;
    01462                 if (keys[(int)CameraKeys.StrafeLeft])
    01463                     accel.X -= 1.0f;
    01464             }
    01465             // Normalize vector so if moving 2 dirs (left & forward),
    01466             // the camera doesn't move faster than if moving in 1 dir
    01467             accel.Normalize();
    01468             // Scale the acceleration vector
    01469             accel *= moveScaler;
    01470
    01471             if (isMovementDrag)
    01472             {
    01473                 // Is there any acceleration this frame?
    01474                 if (accel.LengthSq() > 0)
    01475                 {
    01476                     // If so, then this means the user has pressed a movement key
    01477                     // so change the velocity immediately to acceleration
    01478                     // upon keyboard input.  This isn't normal physics
    01479                     // but it will give a quick response to keyboard input
    01480                     velocity = accel;
    01481                     dragTimer = totalDragTimeToZero;
    01482                     velocityDrag = accel * (1 / dragTimer);
    01483                 }
    01484                 else
    01485                 {
    01486                     // If no key being pressed, then slowly decrease velocity to 0
    01487                     if (dragTimer > 0)
    01488                     {
    01489                         velocity -= (velocityDrag * elapsedTime);
    01490                         dragTimer -= elapsedTime;
    01491                     }
    01492                     else
    01493                     {
    01494                         // Zero velocity
    01495                         velocity = Vector3.Empty;
    01496                     }
    01497                 }
    01498             }
    01499             else
    01500             {
    01501                 // No drag, so immediately change the velocity
    01502                 velocity = accel;
    01503             }
    01504         }
    01505
    01509         protected void ConstrainToBoundary(ref Vector3 v)
    01510         {
    01511             // Constrain vector to a bounding box
    01512             v.X = Math.Max(v.X, minBoundary.X);
    01513             v.Y = Math.Max(v.Y, minBoundary.Y);
    01514             v.Z = Math.Max(v.Z, minBoundary.Z);
    01515
    01516             v.X = Math.Min(v.X, maxBoundary.X);
    01517             v.Y = Math.Min(v.Y, maxBoundary.Y);
    01518             v.Z = Math.Min(v.Z, maxBoundary.Z);
    01519
    01520         }
    01521     }
    01522
    01529     public class FirstPersonCamera : Camera
    01530     {
    01531         // Mask to determine which button to enable for rotation
    01532         protected int activeButtonMask = (int)(MouseButtonMask.Left | MouseButtonMask.Middle | MouseButtonMask.Right);
    01533         // World matrix of the camera (inverse of the view matrix)
    01534         protected Matrix cameraWorld;
    01535
    01539         public override void FrameMove(float elapsedTime)
    01540         {
    01541             // Reset the camera if necessary
    01542             if (keys[(int)CameraKeys.Reset])
    01543                 Reset();
    01544
    01545             // Get the mouse movement (if any) if the mouse buttons are down
    01546             if ((activeButtonMask & currentButtonMask) != 0)
    01547                 UpdateMouseDelta(elapsedTime);
    01548
    01549             // Get amount of velocity based on the keyboard input and drag (if any)
    01550             UpdateVelocity(elapsedTime);
    01551
    01552             // Simple euler method to calculate position delta
    01553             Vector3 posDelta = velocity * elapsedTime;
    01554
    01555             // If rotating the camera
    01556             if ((activeButtonMask & currentButtonMask) != 0)
    01557             {
    01558                 // Update the pitch & yaw angle based on mouse movement
    01559                 float yawDelta   = rotationVelocity.X;
    01560                 float pitchDelta = rotationVelocity.Y;
    01561
    01562                 // Invert pitch if requested
    01563                 if (isInvertPitch)
    01564                     pitchDelta = -pitchDelta;
    01565
    01566                 cameraPitchAngle += pitchDelta;
    01567                 cameraYawAngle   += yawDelta;
    01568
    01569                 // Limit pitch to straight up or straight down
    01570                 cameraPitchAngle = Math.Max(-(float)Math.PI/2.0f,  cameraPitchAngle);
    01571                 cameraPitchAngle = Math.Min(+(float)Math.PI/2.0f,  cameraPitchAngle);
    01572             }
    01573
    01574             // Make a rotation matrix based on the camera's yaw & pitch
    01575             Matrix cameraRotation = Matrix.RotationYawPitchRoll(cameraYawAngle, cameraPitchAngle, 0 );
    01576
    01577             // Transform vectors based on camera's rotation matrix
    01578             Vector3 localUp = new Vector3(0,1,0);
    01579             Vector3 localAhead = new Vector3(0,0,1);
    01580             Vector3 worldUp = Vector3.TransformCoordinate(localUp, cameraRotation);
    01581             Vector3 worldAhead = Vector3.TransformCoordinate(localAhead, cameraRotation);
    01582
    01583             // Transform the position delta by the camera's rotation
    01584             Vector3 posDeltaWorld = Vector3.TransformCoordinate(posDelta, cameraRotation);
    01585             if (!isEnableYAxisMovement)
    01586                 posDeltaWorld.Y = 0.0f;
    01587
    01588             // Move the eye position
    01589             eye += posDeltaWorld;
    01590             if (isClipToBoundary)
    01591                 ConstrainToBoundary(ref eye);
    01592
    01593             // Update the lookAt position based on the eye position
    01594             lookAt = eye + worldAhead;
    01595
    01596             // Update the view matrix
    01597             viewMatrix = Matrix.LookAtLH(eye, lookAt, worldUp);
    01598             cameraWorld = Matrix.Invert(viewMatrix);
    01599         }
    01600
    01604         public void SetRotationButtons(bool left, bool middle, bool right)
    01605         {
    01606             activeButtonMask = (left ? (int)MouseButtonMask.Left : 0) |
    01607                 (middle ? (int)MouseButtonMask.Middle : 0) |
    01608                 (right ? (int)MouseButtonMask.Right : 0);
    01609         }
    01610     }
    01611
    01615     public class ModelViewerCamera : Camera
    01616     {
    01617         #region Instance Data
    01618         protected ArcBall worldArcball = new ArcBall();
    01619         protected ArcBall viewArcball = new ArcBall();
    01620         protected Vector3 modelCenter;
    01621         protected Matrix lastModelRotation; // Last arcball rotation matrix for model
    01622         protected Matrix lastCameraRotation; // Last rotation matrix for camera
    01623         protected Matrix modelRotation; // Rotation matrix of model
    01624         protected Matrix world; // World Matrix of model
    01625
    01626         protected int rotateModelButtonMask;
    01627         protected int zoomButtonMask;
    01628         protected int rotateCameraButtonMask;
    01629
    01630         protected bool isPitchLimited;
    01631         protected float radius; // Distance from the camera to model
    01632         protected float defaultRadius; // Distance from the camera to model
    01633         protected float minRadius; // Min radius
    01634         protected float maxRadius; // Max radius
    01635         protected bool attachCameraToModel;
    01636         #endregion
    01637
    01638         #region Simple Properties/Set Methods
    01640         public float MinimumRadius { get { return minRadius; } set { minRadius = value; } }
    01642         public float MaximumRadius { get { return maxRadius; } set { maxRadius = value; } }
    01644         public Matrix WorldMatrix { get { return world; } }
    01646         public void SetWorldQuat(Quaternion q) { worldArcball.CurrentQuaternion = q; }
    01648         public void SetViewQuat(Quaternion q) { viewArcball.CurrentQuaternion = q; }
    01650         public void SetIsPitchLimited(bool limit) { isPitchLimited = limit; }
    01652         public void SetModelCenter(Vector3 c) { modelCenter = c; }
    01654         public void SetRadius(float r, float min, float max) { radius = defaultRadius = r; minRadius = min; maxRadius = max;}
    01656         public void SetRadius(float r) { defaultRadius = r; minRadius = 1.0f; maxRadius = float.MaxValue;}
    01658         public void SetWindow(int w, int h, float r) { worldArcball.SetWindow(w,h,r); viewArcball.SetWindow(w,h,r); }
    01660         public void SetWindow(int w, int h) { worldArcball.SetWindow(w,h,0.9f); viewArcball.SetWindow(w,h,0.9f); }
    01662         public void SetButtonMasks(int rotateModel, int zoom, int rotateCamera) { rotateCameraButtonMask = rotateCamera; zoomButtonMask = zoom; rotateModelButtonMask = rotateModel; }
    01664         public bool IsAttachedToModel { get { return attachCameraToModel; } set { attachCameraToModel = value; } }
    01665         #endregion
    01666
    01670         public ModelViewerCamera()
    01671         {
    01672             world = Matrix.Identity;
    01673             modelRotation = Matrix.Identity;
    01674             lastModelRotation = Matrix.Identity;
    01675             lastCameraRotation = Matrix.Identity;
    01676             modelCenter = Vector3.Empty;
    01677             radius = 5.0f;
    01678             defaultRadius = 5.0f;
    01679             minRadius = 1.0f;
    01680             maxRadius = float.MaxValue;
    01681             isPitchLimited = false;
    01682             isEnablePositionMovement = false;
    01683             attachCameraToModel = false;
    01684
    01685             // Set button masks
    01686             rotateModelButtonMask = (int)MouseButtonMask.Left;
    01687             zoomButtonMask = (int)MouseButtonMask.Wheel;
    01688             rotateCameraButtonMask = (int)MouseButtonMask.Right;
    01689         }
    01690
    01694         public unsafe override void FrameMove(float elapsedTime)
    01695         {
    01696             // Reset the camera if necessary
    01697             if (keys[(int)CameraKeys.Reset])
    01698                 Reset();
    01699
    01700             // Get the mouse movement (if any) if the mouse buttons are down
    01701             if (currentButtonMask != 0)
    01702                 UpdateMouseDelta(elapsedTime);
    01703
    01704             // Get amount of velocity based on the keyboard input and drag (if any)
    01705             UpdateVelocity(elapsedTime);
    01706
    01707             // Simple euler method to calculate position delta
    01708             Vector3 posDelta = velocity * elapsedTime;
    01709
    01710             // Change the radius from the camera to the model based on wheel scrolling
    01711             if ( (mouseWheelDelta != 0) && (zoomButtonMask == (int)MouseButtonMask.Wheel) )
    01712                 radius -= mouseWheelDelta * radius * 0.1f;
    01713             radius = Math.Min( maxRadius, radius );
    01714             radius = Math.Max( minRadius, radius );
    01715             mouseWheelDelta = 0;
    01716
    01717             // Get the inverse of the arcball's rotation matrix
    01718             Matrix cameraRotation = Matrix.Invert(viewArcball.RotationMatrix);
    01719
    01720             // Transform vectors based on camera's rotation matrix
    01721             Vector3 localUp = new Vector3(0,1,0);
    01722             Vector3 localAhead = new Vector3(0,0,1);
    01723             Vector3 worldUp = Vector3.TransformCoordinate(localUp, cameraRotation);
    01724             Vector3 worldAhead = Vector3.TransformCoordinate(localAhead, cameraRotation);
    01725
    01726             // Transform the position delta by the camera's rotation
    01727             Vector3 posDeltaWorld = Vector3.TransformCoordinate(posDelta, cameraRotation);
    01728
    01729             // Move the lookAt position
    01730             lookAt += posDeltaWorld;
    01731             if (isClipToBoundary)
    01732                 ConstrainToBoundary(ref lookAt);
    01733
    01734             // Update the eye point based on a radius away from the lookAt position
    01735             eye = lookAt - worldAhead * radius;
    01736
    01737             // Update the view matrix
    01738             viewMatrix = Matrix.LookAtLH(eye, lookAt, worldUp);
    01739             Matrix invView = Matrix.Invert(viewMatrix);
    01740             invView.M41 = invView.M42 = invView.M43 = 0;
    01741             Matrix modelLastRotInv = Matrix.Invert(lastModelRotation);
    01742
    01743             // Accumulate the delta of the arcball's rotation in view space.
    01744             // Note that per-frame delta rotations could be problematic over long periods of time.
    01745             Matrix localModel = worldArcball.RotationMatrix;
    01746             modelRotation *= viewMatrix * modelLastRotInv * localModel * invView;
    01747             if ( viewArcball.IsBeingDragged && attachCameraToModel && !keys[(int)CameraKeys.ControlDown])
    01748             {
    01749                 // Attah camera to model by inverse of the model rotation
    01750                 Matrix cameraRotInv = Matrix.Invert(lastCameraRotation);
    01751                 Matrix delta = cameraRotInv * cameraRotation; // local to world matrix
    01752                 modelRotation *= delta;
    01753             }
    01754             lastCameraRotation = cameraRotation;
    01755             lastModelRotation = localModel;
    01756
    01757             // Since we're accumulating delta rotations, we need to orthonormalize
    01758             // the matrix to prevent eventual matrix skew
    01759             fixed(void* pxBasis = &modelRotation.M11)
    01760             {
    01761                 fixed(void* pyBasis = &modelRotation.M21)
    01762                 {
    01763                     fixed(void* pzBasis = &modelRotation.M31)
    01764                     {
    01765                         UnsafeNativeMethods.Vector3.Normalize((Vector3*)pxBasis, (Vector3*)pxBasis);
    01766                         UnsafeNativeMethods.Vector3.Cross((Vector3*)pyBasis, (Vector3*)pzBasis, (Vector3*)pxBasis);
    01767                         UnsafeNativeMethods.Vector3.Normalize((Vector3*)pyBasis, (Vector3*)pyBasis);
    01768                         UnsafeNativeMethods.Vector3.Cross((Vector3*)pzBasis, (Vector3*)pxBasis, (Vector3*)pyBasis);
    01769                     }
    01770                 }
    01771             }
    01772
    01773             // Translate the rotation matrix to the same position as the lookAt position
    01774             modelRotation.M41 = lookAt.X;
    01775             modelRotation.M42 = lookAt.Y;
    01776             modelRotation.M43 = lookAt.Z;
    01777
    01778             // Translate world matrix so its at the center of the model
    01779             Matrix trans = Matrix.Translation(-modelCenter.X, -modelCenter.Y, -modelCenter.Z);
    01780             world = trans * modelRotation;
    01781         }
    01782
    01786         public override void Reset()
    01787         {
    01788             base.Reset();
    01789             world = Matrix.Identity;
    01790             modelRotation = Matrix.Identity;
    01791             lastModelRotation = Matrix.Identity;
    01792             lastCameraRotation = Matrix.Identity;
    01793             radius = defaultRadius;
    01794             worldArcball.Reset();
    01795             viewArcball.Reset();
    01796         }
    01797
    01801         public override void SetViewParameters(Vector3 eyePt, Vector3 lookAtPt)
    01802         {
    01803             // Call base first
    01804             base.SetViewParameters (eyePt, lookAtPt);
    01805
    01806             // Propogate changes to the member arcball
    01807             Matrix rotation = Matrix.LookAtLH(eyePt, lookAtPt, UpDirection);
    01808             viewArcball.CurrentQuaternion = Quaternion.RotationMatrix(rotation);
    01809
    01810             // Set the radius according to the distance
    01811             Vector3 eyeToPoint = lookAtPt - eyePt;
    01812             SetRadius(eyeToPoint.Length());
    01813         }
    01814
    01818         public override bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
    01819         {
    01820             // Call base first
    01821             base.HandleMessages(hWnd, msg, wParam, lParam);
    01822
    01823             if ( ( (msg == NativeMethods.WindowMessage.LeftButtonDown || msg == NativeMethods.WindowMessage.LeftButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Left) != 0 ) ) ||
    01824                 ( (msg == NativeMethods.WindowMessage.RightButtonDown || msg == NativeMethods.WindowMessage.RightButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Right) != 0 ) ) ||
    01825                 ( (msg == NativeMethods.WindowMessage.MiddleButtonDown || msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Middle) != 0 ) ) )
    01826             {
    01827                 // Current mouse position
    01828                 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    01829                 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    01830                 worldArcball.OnBegin(mouseX, mouseY);
    01831             }
    01832             if ( ( (msg == NativeMethods.WindowMessage.LeftButtonDown || msg == NativeMethods.WindowMessage.LeftButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Left) != 0 ) ) ||
    01833                 ( (msg == NativeMethods.WindowMessage.RightButtonDown || msg == NativeMethods.WindowMessage.RightButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Right) != 0 ) ) ||
    01834                 ( (msg == NativeMethods.WindowMessage.MiddleButtonDown || msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Middle) != 0 ) ) )
    01835             {
    01836                 // Current mouse position
    01837                 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    01838                 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    01839                 viewArcball.OnBegin(mouseX, mouseY);
    01840             }
    01841             if (msg == NativeMethods.WindowMessage.MouseMove)
    01842             {
    01843                 // Current mouse position
    01844                 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    01845                 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    01846                 worldArcball.OnMove(mouseX, mouseY);
    01847                 viewArcball.OnMove(mouseX, mouseY);
    01848             }
    01849
    01850             if ( (msg == NativeMethods.WindowMessage.LeftButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Left) != 0 ) ||
    01851                 (msg == NativeMethods.WindowMessage.RightButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Right) != 0 ) ||
    01852                 (msg == NativeMethods.WindowMessage.MiddleButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Middle) != 0 ) )
    01853             {
    01854                 worldArcball.OnEnd();
    01855             }
    01856
    01857             if ( (msg == NativeMethods.WindowMessage.LeftButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Left) != 0 ) ||
    01858                 (msg == NativeMethods.WindowMessage.RightButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Right) != 0 ) ||
    01859                 (msg == NativeMethods.WindowMessage.MiddleButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Middle) != 0 ) )
    01860             {
    01861                 viewArcball.OnEnd();
    01862             }
    01863
    01864             return false;
    01865         }
    01866     }
    01867     #endregion
    01868
    01869     #region Text Helper
    01873     public struct TextHelper
    01874     {
    01875         private Font textFont; // Used to draw the text
    01876         private Sprite textSprite; // Used to cache the drawn text
    01877         private int color; // Color to draw the text
    01878         private System.Drawing.Point point; // Where to draw the text
    01879         private int lineHeight; // Height of the lines
    01880
    01884         public TextHelper(Font f, Sprite s, int l)
    01885         {
    01886             textFont = f;
    01887             textSprite = s;
    01888             lineHeight = l;
    01889             color = unchecked((int)0xffffffff);
    01890             point = System.Drawing.Point.Empty;
    01891         }
    01892
    01896         public void DrawTextLine(string text)
    01897         {
    01898             if (textFont == null)
    01899             {
    01900                 throw new InvalidOperationException("You cannot draw text.  There is no font object.");
    01901             }
    01902             // Create the rectangle to draw to
    01903             System.Drawing.Rectangle rect = new System.Drawing.Rectangle(point, System.Drawing.Size.Empty);
    01904             textFont.DrawText(textSprite, text, rect, DrawTextFormat.NoClip, color);
    01905
    01906             // Increase the line height
    01907             point.Y += lineHeight;
    01908         }
    01909
    01913         public void DrawTextLine(string text, params object[] args)
    01914         {
    01915             // Simply format the string and pass it on
    01916             DrawTextLine(string.Format(text, args));
    01917         }
    01918
    01922         public void SetInsertionPoint(System.Drawing.Point p) { point = p; }
    01923         public void SetInsertionPoint(int x, int y) { point.X = x; point.Y = y; }
    01924
    01928         public void SetForegroundColor(int c) { color = c; }
    01929         public void SetForegroundColor(System.Drawing.Color c) { color = c.ToArgb(); }
    01930
    01934         public void Begin()
    01935         {
    01936             if (textSprite != null)
    01937             {
    01938                 textSprite.Begin(SpriteFlags.AlphaBlend | SpriteFlags.SortTexture);
    01939             }
    01940         }
    01941
    01945         public void End()
    01946         {
    01947             if (textSprite != null)
    01948             {
    01949                 textSprite.End();
    01950             }
    01951         }
    01952     }
    01953         #endregion
    01954
    01955     #region Utility
    01959         public class Utility
    01960         {
    01961             // Constants for search folders
    01962             private const string CurrentFolder = @".\";
    01963             private const string MediaPath = @"Media\";
    01964
    01965             // Typical folder locations
    01966             //      .\
    01967             //      ..\
    01968             //      ..\..\
    01969             //      %EXE_DIR%\
    01970             //      %EXE_DIR%\..\
    01971             //      %EXE_DIR%\..\..\
    01972             //      %EXE_DIR%\..\%EXE_NAME%
    01973             //      %EXE_DIR%\..\..\%EXE_NAME%
    01974             //      DXSDK media path
    01975             private static readonly string[] TypicalFolders = new string[] { CurrentFolder, @"..\",
    01976                                                                                @"..\..\", @"{0}\", @"{0}\..\", @"{0}\..\..\", @"{0}\..\{1}\", @"{0}\..\..\{1}\" };
    01977             private Utility() { /* Private Constructor */ }
    01978
    01985             public static string FindMediaFile(string filename)
    01986             {
    01987                 // Find out the executing assembly information
    01988                 System.Reflection.Assembly executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
    01989                 // Now check the typical folders, before you can do that you'll need to get
    01990                 // the executable name
    01991                 string exeName = System.IO.Path.GetFileNameWithoutExtension(executingAssembly.Location);
    01992                 // And the executable folder
    01993                 string exeFolder = System.IO.Path.GetDirectoryName(executingAssembly.Location);
    01994
    01995                 string filePath;
    01996                 // Now you can search the typical folders
    01997                 if (SearchTypicalFolders(filename, exeFolder, exeName, out filePath))
    01998                 {
    01999                     return filePath;
    02000                 }
    02001
    02002                 // The file wasn't found again, search the folders with \media on them
    02003                 // Now you can search the typical folders
    02004                 if (SearchTypicalFolders(filename + MediaPath, exeFolder, exeName, out filePath))
    02005                 {
    02006                     return filePath;
    02007                 }
    02008
    02009                 // We still haven't found the file yet, we should search the parents folders now
    02010                 if (SearchParentFolders(filename, CurrentFolder, "", out filePath))
    02011                 {
    02012                     return filePath;
    02013                 }
    02014                 // We still haven't found the file yet, now search from the exe folder
    02015                 if (SearchParentFolders(filename, exeFolder, exeName, out filePath))
    02016                 {
    02017                     return filePath;
    02018                 }
    02019
    02020                 // We still haven't found the file yet, we should search the parents folders now, but append media
    02021                 if (SearchParentFolders(filename, CurrentFolder, MediaPath, out filePath))
    02022                 {
    02023                     return filePath;
    02024                 }
    02025                 // We still haven't found the file yet, now search from the exe folder and append media
    02026                 if (SearchParentFolders(filename, exeFolder, AppendDirectorySeparator(exeName) + MediaPath, out filePath))
    02027                 {
    02028                     return filePath;
    02029                 }
    02030
    02031
    02032                 // We still haven't found the file yet, the built samples are prefixed with 'cs', so see if that's the case
    02033                 if (exeName.ToLower().StartsWith("cs"))
    02034                 {
    02035                     // Build the new exe name by stripping off the 'cs' prefix and doing the searches again
    02036                     string newExeName = exeName.Substring(2, exeName.Length - 2);
    02037                     if (SearchParentFolders(filename, exeFolder, newExeName, out filePath))
    02038                     {
    02039                         return filePath;
    02040                     }
    02041                     // We still haven't found the file yet, now search from the exe folder and append media
    02042                     if (SearchParentFolders(filename, exeFolder, AppendDirectorySeparator(newExeName) + MediaPath, out filePath))
    02043                     {
    02044                         return filePath;
    02045                     }
    02046                 }
    02047
    02048                 // Before throwing an exception, girst check to see if the file exists as is
    02049                 if (File.Exists(filename))
    02050                 {
    02051                     return filename;
    02052                 }
    02053
    02054                 throw new MediaNotFoundException();
    02055             }
    02056
    02065             private static bool SearchTypicalFolders(string filename, string exeFolder, string exeName, out string fullPath)
    02066             {
    02067                 // First scan through each typical folder and see if we found the file
    02068                 for (int i = 0; i < TypicalFolders.Length; i++)
    02069                 {
    02070                     try
    02071                     {
    02072                         FileInfo info = new FileInfo(string.Format(TypicalFolders[i], exeFolder, exeName) + filename);
    02073                         if (info.Exists)
    02074                         {
    02075                             fullPath = info.FullName;
    02076                             return true;
    02077                         }
    02078                     }
    02079                     catch(NotSupportedException)
    02080                     {
    02081                         // This exception will be fired if the filename is not supported
    02082                         continue;
    02083                     }
    02084                 }
    02085
    02086                 // We never found any of the files
    02087                 fullPath = string.Empty;
    02088                 return false;
    02089             }
    02090
    02099             private static bool SearchParentFolders(string filename, string rootNode, string leafName, out string fullPath)
    02100             {
    02101                 // Set the out parameter first
    02102                 fullPath = string.Empty;
    02103                 try
    02104                 {
    02105                     // Search the root node first
    02106                     FileInfo info = new FileInfo( AppendDirectorySeparator(rootNode) + AppendDirectorySeparator(leafName) + filename);
    02107                     if (info.Exists)
    02108                     {
    02109                         fullPath = info.FullName;
    02110                         return true;
    02111                     }
    02112                 }
    02113                 catch(NotSupportedException)
    02114                 {
    02115                     // The arguments passed in are not supported, fail now
    02116                     return false;
    02117                 }
    02118
    02119                 // Are we in the root yet?
    02120                 DirectoryInfo dir = new DirectoryInfo(rootNode);
    02121                 if (dir.Parent != null)
    02122                 {
    02123                     return SearchParentFolders(filename, dir.Parent.FullName, leafName, out fullPath);
    02124                 }
    02125                 else
    02126                 {
    02127                     // We never found any of the files
    02128                     return false;
    02129                 }
    02130             }
    02131
    02135             public static string AppendDirectorySeparator(string pathName)
    02136             {
    02137                 if (!pathName.EndsWith(@"\"))
    02138                     return pathName + @"\";
    02139
    02140                 return pathName;
    02141             }
    02142
    02144             public static Matrix GetCubeMapViewMatrix(CubeMapFace face)
    02145             {
    02146                 Vector3 vEyePt = new Vector3(0.0f, 0.0f, 0.0f);
    02147                 Vector3 vLookDir = new Vector3();
    02148                 Vector3 vUpDir = new Vector3();
    02149
    02150                 switch (face)
    02151                 {
    02152                     case CubeMapFace.PositiveX:
    02153                         vLookDir = new Vector3(1.0f, 0.0f, 0.0f);
    02154                         vUpDir   = new Vector3(0.0f, 1.0f, 0.0f);
    02155                         break;
    02156                     case CubeMapFace.NegativeX:
    02157                         vLookDir = new Vector3(-1.0f, 0.0f, 0.0f);
    02158                         vUpDir   = new Vector3(0.0f, 1.0f, 0.0f);
    02159                         break;
    02160                     case CubeMapFace.PositiveY:
    02161                         vLookDir = new Vector3(0.0f, 1.0f, 0.0f);
    02162                         vUpDir   = new Vector3(0.0f, 0.0f,-1.0f);
    02163                         break;
    02164                     case CubeMapFace.NegativeY:
    02165                         vLookDir = new Vector3(0.0f,-1.0f, 0.0f);
    02166                         vUpDir   = new Vector3(0.0f, 0.0f, 1.0f);
    02167                         break;
    02168                     case CubeMapFace.PositiveZ:
    02169                         vLookDir = new Vector3(0.0f, 0.0f, 1.0f);
    02170                         vUpDir   = new Vector3(0.0f, 1.0f, 0.0f);
    02171                         break;
    02172                     case CubeMapFace.NegativeZ:
    02173                         vLookDir = new Vector3(0.0f, 0.0f,-1.0f);
    02174                         vUpDir   = new Vector3(0.0f, 1.0f, 0.0f);
    02175                         break;
    02176                 }
    02177
    02178                 // Set the view transform for this cubemap surface
    02179                 Matrix matView = Matrix.LookAtLH(vEyePt, vLookDir, vUpDir);
    02180                 return matView;
    02181             }
    02183             public static Matrix GetCubeMapViewMatrix(int face) { return GetCubeMapViewMatrix((CubeMapFace)face); }
    02184
    02185             private static bool firstTime = true;
    02189             public static void DisplaySwitchingToRefWarning(Framework framework, string sampleTitle)
    02190             {
    02191                 if (framework.IsShowingMsgBoxOnError)
    02192                 {
    02193                     // Read the registry key to see if the warning should be skipped
    02194                     int skipWarning = 0;
    02195                     try
    02196                     {
    02197                         using(Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(SwitchRefDialog.KeyLocation))
    02198                         {
    02199                             skipWarning = (int)key.GetValue(SwitchRefDialog.KeyValueName, (int)0);
    02200                         }
    02201                     }
    02202                     catch { } // Ignore any errors
    02203                     if ( (skipWarning == 0) && (firstTime) ) // Show dialog
    02204                     {
    02205                         firstTime = false;
    02206                         using (SwitchRefDialog dialog = new SwitchRefDialog(sampleTitle))
    02207                         {
    02208                             System.Windows.Forms.Application.Run(dialog);
    02209                             if (dialog.DialogResult == System.Windows.Forms.DialogResult.Cancel)
    02210                             {
    02211                                 // Shutdown the application
    02212                                 framework.Dispose();
    02213                             }
    02214                         }
    02215                     }
    02216                 }
    02217             }
    02218         }
    02219     #endregion
    02220
    02221     #region Widgets
    02222
    02223     #region Direction Widget
    02225     public class DirectionWidget
    02226     {
    02227         #region Class level data (Instance/Static)
    02228         // Instance members
    02229         private float widgetRadius = 1.0f;
    02230         private ArcBall arc = new ArcBall();
    02231         private Vector3 defaultDir = new Vector3(0,1,0);
    02232         private Vector3 currentDir = new Vector3(0,1,0);
    02233         private Matrix viewMatrix = Matrix.Identity;
    02234         private Matrix rotation = Matrix.Identity;
    02235         private Matrix rotationSnapshot = Matrix.Identity;
    02236         private MouseButtonMask rotateMask = MouseButtonMask.Right;
    02237
    02238         // Static members
    02239         private static Device device = null;
    02240         private static Effect effect = null;
    02241         private static Mesh mesh = null;
    02242         #endregion
    02243
    02244         #region Properties
    02246         public float Radius { get { return widgetRadius; } set { widgetRadius = value; } }
    02248         public Vector3 LightDirection { get { return currentDir; } set { currentDir = defaultDir = value; } }
    02250         public bool IsBeingDragged{ get { return arc.IsBeingDragged; } }
    02252         public MouseButtonMask RotateButtonMask{ get { return rotateMask; } set { rotateMask = value; }}
    02253         #endregion
    02254
    02255         #region Device handlers
    02257         public static void OnCreateDevice(Device device)
    02258         {
    02259             // Store the device
    02260             DirectionWidget.device = device;
    02261
    02262             // Read the effect file
    02263             string path = Utility.FindMediaFile("UI\\DXUTShared.fx");
    02264
    02265             // If this fails, there should be debug output as to
    02266             // why the .fx file failed to compile (assuming you have dbmon running).
    02267             // If you do not, you can turn on unmanaged debugging for this project.
    02268             effect = Effect.FromFile(device, path, null, null, ShaderFlags.NotCloneable, null);
    02269
    02270             // Load the mesh with D3DX and get back a Mesh.  For this
    02271             // sample we'll ignore the X file's embedded materials since we know
    02272             // exactly the model we're loading.  See the mesh samples such as
    02273             // "OptimizedMesh" for a more generic mesh loading example.
    02274             path = Utility.FindMediaFile("UI\\arrow.x");
    02275             mesh = Mesh.FromFile(path, MeshFlags.Managed, device);
    02276
    02277             // Optimize the mesh for this graphics card's vertex cache
    02278             // so when rendering the mesh's triangle list the vertices will
    02279             // cache hit more often so it won't have to re-execute the vertex shader
    02280             // on those vertices so it will improve perf.
    02281             int[] adj = new int[mesh.NumberFaces * 3];
    02282             mesh.GenerateAdjacency(1e-6f, adj);
    02283             mesh.OptimizeInPlace(MeshFlags.OptimizeVertexCache, adj);
    02284         }
    02285
    02287         public void OnResetDevice(SurfaceDescription desc)
    02288         {
    02289             arc.SetWindow(desc.Width, desc.Height);
    02290         }
    02291
    02293         public static void OnLostDevice()
    02294         {
    02295             if (effect != null)
    02296                 effect.OnLostDevice();
    02297         }
    02298
    02300         public static void OnDestroyDevice()
    02301         {
    02302             if (effect != null)
    02303                 effect.Dispose();
    02304             if (mesh != null)
    02305                 mesh.Dispose();
    02306             effect = null;
    02307             mesh = null;
    02308         }
    02309         #endregion
    02310
    02312         public bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
    02313         {
    02314             // Current mouse position
    02315             short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    02316             short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    02317
    02318             switch(msg)
    02319             {
    02320                 case NativeMethods.WindowMessage.LeftButtonDown:
    02321                 case NativeMethods.WindowMessage.MiddleButtonDown:
    02322                 case NativeMethods.WindowMessage.RightButtonDown:
    02323                 {
    02324                     if ( ((rotateMask & MouseButtonMask.Left) == MouseButtonMask.Left && msg == NativeMethods.WindowMessage.LeftButtonDown) ||
    02325                         ((rotateMask & MouseButtonMask.Right) == MouseButtonMask.Right && msg == NativeMethods.WindowMessage.RightButtonDown) ||
    02326                         ((rotateMask & MouseButtonMask.Middle) == MouseButtonMask.Middle && msg == NativeMethods.WindowMessage.MiddleButtonDown) )
    02327                     {
    02328                         arc.OnBegin(mouseX, mouseY);
    02329                         NativeMethods.SetCapture(hWnd);
    02330                     }
    02331                     return true;
    02332                 }
    02333                 case NativeMethods.WindowMessage.MouseMove:
    02334                 {
    02335                     if (arc.IsBeingDragged)
    02336                     {
    02337                         arc.OnMove(mouseX, mouseY);
    02338                         UpdateLightDirection();
    02339                     }
    02340                     return true;
    02341                 }
    02342                 case NativeMethods.WindowMessage.LeftButtonUp:
    02343                 case NativeMethods.WindowMessage.RightButtonUp:
    02344                 case NativeMethods.WindowMessage.MiddleButtonUp:
    02345                 {
    02346                     if ( ((rotateMask & MouseButtonMask.Left) == MouseButtonMask.Left && msg == NativeMethods.WindowMessage.LeftButtonUp) ||
    02347                         ((rotateMask & MouseButtonMask.Right) == MouseButtonMask.Right && msg == NativeMethods.WindowMessage.RightButtonUp) ||
    02348                         ((rotateMask & MouseButtonMask.Middle) == MouseButtonMask.Middle && msg == NativeMethods.WindowMessage.MiddleButtonUp) )
    02349                     {
    02350                         arc.OnEnd();
    02351                         NativeMethods.ReleaseCapture();
    02352                     }
    02353
    02354                     UpdateLightDirection();
    02355                     return true;
    02356                 }
    02357             }
    02358
    02359             // Didn't handle the message
    02360             return false;
    02361         }
    02362
    02364         private unsafe void UpdateLightDirection()
    02365         {
    02366             Matrix invView = Matrix.Invert(viewMatrix);
    02367             invView.M41 = invView.M42 = invView.M43 = 0;
    02368
    02369             Matrix lastRotationInv = Matrix.Invert(rotationSnapshot);
    02370             Matrix rot = arc.RotationMatrix;
    02371             rotationSnapshot = rot;
    02372
    02373             // Accumulate the delta of the arcball's rotation in view space.
    02374             // Note that per-frame delta rotations could be problematic over long periods of time.
    02375             rotation *= (viewMatrix * lastRotationInv * rot * invView);
    02376
    02377             // Since we're accumulating delta rotations, we need to orthonormalize
    02378             // the matrix to prevent eventual matrix skew
    02379             fixed(void* pxBasis = &rotation.M11)
    02380             {
    02381                 fixed(void* pyBasis = &rotation.M21)
    02382                 {
    02383                     fixed(void* pzBasis = &rotation.M31)
    02384                     {
    02385                         UnsafeNativeMethods.Vector3.Normalize((Vector3*)pxBasis, (Vector3*)pxBasis);
    02386                         UnsafeNativeMethods.Vector3.Cross((Vector3*)pyBasis, (Vector3*)pzBasis, (Vector3*)pxBasis);
    02387                         UnsafeNativeMethods.Vector3.Normalize((Vector3*)pyBasis, (Vector3*)pyBasis);
    02388                         UnsafeNativeMethods.Vector3.Cross((Vector3*)pzBasis, (Vector3*)pxBasis, (Vector3*)pyBasis);
    02389                     }
    02390                 }
    02391             }
    02392
    02393             // Transform the default direction vector by the light's rotation matrix
    02394             currentDir = Vector3.TransformNormal(defaultDir, rotation);
    02395         }
    02396
    02398         public unsafe void OnRender(ColorValue color, Matrix view, Matrix proj, Vector3 eye)
    02399         {
    02400             // Store the view matrix
    02401             viewMatrix = view;
    02402
    02403             // Render the light arrows so the user can visually see the light direction
    02404             effect.Technique = "RenderWith1LightNoTexture";
    02405             effect.SetValue("g_MaterialDiffuseColor", color);
    02406             Vector3 eyePt = Vector3.Normalize(eye);
    02407
    02408             // Set the light direction value
    02409             effect.SetValue("g_LightDir", &eyePt, sizeof(Vector3));
    02410
    02411             // Rotate arrow model to point towards origin
    02412             Vector3 at = Vector3.Empty;
    02413             Vector3 up = new Vector3(0,1,0);
    02414             Matrix rotateB = Matrix.RotationX((float)Math.PI);
    02415             Matrix rotateA = Matrix.LookAtLH(currentDir, at, up);
    02416             rotateA.Invert();
    02417             Matrix rotate = rotateB * rotateA;
    02418             Vector3 l = currentDir * widgetRadius * 1.0f;
    02419             Matrix trans = Matrix.Translation(l);
    02420             Matrix scale = Matrix.Scaling(widgetRadius * 0.2f, widgetRadius * 0.2f, widgetRadius * 0.2f);
    02421
    02422             Matrix world = rotate * scale * trans;
    02423             Matrix worldViewProj = world * viewMatrix * proj;
    02424
    02425             effect.SetValue("g_mWorldViewProjection", worldViewProj);
    02426             effect.SetValue("g_mWorld", world);
    02427
    02428             // Render the arrows
    02429             for (int subset = 0; subset < 2; subset++)
    02430             {
    02431                 int passes = effect.Begin(0);
    02432                 for (int pass = 0; pass < passes; pass++)
    02433                 {
    02434                     effect.BeginPass(pass);
    02435                     mesh.DrawSubset(subset);
    02436                     effect.EndPass();
    02437                 }
    02438                 effect.End();
    02439             }
    02440
    02441         }
    02442     }
    02443     #endregion
    02444
    02445     #endregion
    02446 }