- Main Page
- Packages
- Classes
- Files

- File List
- File Members

# D:/guillaume/guillara/3D/DXGfx/DXCommon/wdxmutmisc.cs

Go to the documentation of this file.

    00001 //--------------------------------------------------------------------------------------
    00002 // File: WDXMUTMisc.cs
    00003 //
    00004 // Shortcut and helper functions for using Managed DirectX for Whidbey 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, Constants.Default, Constants.Default, Constants.Default, Usage.None,
    00555                 Format.Unknown, Pool.Managed, (Filter)Constants.Default, (Filter)Constants.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.Texture)
    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 = new Texture(device, filename, w, h, mip, usage, fmt, pool, filter, mipfilter, colorkey, false, null);
    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.Texture;
    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, Constants.Default, Constants.Default, Usage.None,
    00597                 Format.Unknown, Pool.Managed, (Filter)Constants.Default, (Filter)Constants.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 = new CubeTexture(device, filename, size, mip, usage, fmt, pool, filter, mipfilter, colorkey, false, null);
    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, Constants.Default, Constants.Default, Constants.Default, Constants.Default, Usage.None,
    00637                 Format.Unknown, Pool.Managed, (Filter)Constants.Default, (Filter)Constants.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 = new VolumeTexture(device, filename, w, h, d, mip, usage, fmt, pool, filter, mipfilter, colorkey, false, null);
    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)
    00680         {
    00681             // Search the cache first
    00682             foreach (CachedEffect ce in effectCache.Keys)
    00683             {
    00684                 if ((string.Compare(ce.Source, filename, true) == 0) &&
    00685                     ce.Flags == flags)
    00686                 {
    00687                     // A match was found, return that
    00688                     return effectCache[ce] as Effect;
    00689                 }
    00690             }
    00691
    00692             // Nothing found in the cache
    00693             Effect e = Effect.FromFile(device, filename, defines, includeFile, null, flags, effectPool);
    00694             // Add this to the cache
    00695             CachedEffect entry = new CachedEffect();
    00696             entry.Flags = flags;
    00697             entry.Source = filename;
    00698             effectCache.Add(entry, e);
    00699
    00700             // Return the new effect
    00701             return e;
    00702         }
    00703
    00705         public Font CreateFont(Device device, int height, int width, FontWeight weight, int mip, bool italic,
    00706             CharacterSet charSet, Precision outputPrecision, FontQuality quality, PitchAndFamily pandf, string fontName)
    00707         {
    00708             // Create the font description
    00709             FontDescription desc = new FontDescription();
    00710             desc.Height = height;
    00711             desc.Width = width;
    00712             desc.Weight = weight;
    00713             desc.MipLevels = mip;
    00714             desc.IsItalic = italic;
    00715             desc.CharacterSet = charSet;
    00716             desc.OutputPrecision = outputPrecision;
    00717             desc.Quality = quality;
    00718             desc.PitchAndFamily = pandf;
    00719             desc.FaceName = fontName;
    00720
    00721             // return the font
    00722             return CreateFont(device, desc);
    00723         }
    00725         public Font CreateFont(Device device, FontDescription desc)
    00726         {
    00727             // Search the cache first
    00728             foreach (FontDescription fd in fontCache.Keys)
    00729             {
    00730                 if ((string.Compare(fd.FaceName, desc.FaceName, true) == 0) &&
    00731                     fd.CharacterSet == desc.CharacterSet &&
    00732                     fd.Height == desc.Height &&
    00733                     fd.IsItalic == desc.IsItalic &&
    00734                     fd.MipLevels == desc.MipLevels &&
    00735                     fd.OutputPrecision == desc.OutputPrecision &&
    00736                     fd.PitchAndFamily == desc.PitchAndFamily &&
    00737                     fd.Quality == desc.Quality &&
    00738                     fd.Weight == desc.Weight &&
    00739                     fd.Width == desc.Width)
    00740                 {
    00741                     // A match was found, return that
    00742                     return fontCache[fd] as Font;
    00743                 }
    00744             }
    00745
    00746             // Couldn't find anything in the cache, create one
    00747             Font f = new Font(device, desc);
    00748             // Create a new entry
    00749             fontCache.Add(desc, f);
    00750
    00751             // return the new font
    00752             return f;
    00753         }
    00754
    00755         #endregion
    00756
    00757         #region Device event callbacks
    00761         public void OnCreateDevice(Device device) { } // Nothing to do on device create
    00765         public void OnResetDevice(Device device)
    00766         {
    00767             // Call OnResetDevice on all effect and font objects
    00768             foreach (Font f in fontCache.Values)
    00769                 f.OnResetDevice();
    00770             foreach (Effect e in effectCache.Values)
    00771                 e.OnResetDevice();
    00772         }
    00776         public void OnLostDevice()
    00777         {
    00778             foreach (Font f in fontCache.Values)
    00779                 f.OnLostDevice();
    00780             foreach (Effect e in effectCache.Values)
    00781                 e.OnLostDevice();
    00782
    00783             // Search the texture cache
    00784             foreach (CachedTexture ct in textureCache.Keys)
    00785             {
    00786                 if (ct.Pool == Pool.Default)
    00787                 {
    00788                     // A match was found, get rid of it
    00789                     switch (ct.Type)
    00790                     {
    00791                         case ResourceType.Texture:
    00792                             (textureCache[ct] as Texture).Dispose(); break;
    00793                         case ResourceType.CubeTexture:
    00794                             (textureCache[ct] as CubeTexture).Dispose(); break;
    00795                         case ResourceType.VolumeTexture:
    00796                             (textureCache[ct] as VolumeTexture).Dispose(); break;
    00797                     }
    00798                 }
    00799             }
    00800         }
    00804         public void OnDestroyDevice()
    00805         {
    00806             // Cleanup the fonts
    00807             foreach (Font f in fontCache.Values)
    00808                 f.Dispose();
    00809
    00810             // Cleanup the effects
    00811             foreach (Effect e in effectCache.Values)
    00812                 e.Dispose();
    00813
    00814             // Dispose of any items in the caches
    00815             foreach (BaseTexture texture in textureCache.Values)
    00816             {
    00817                 if (texture != null)
    00818                     texture.Dispose();
    00819             }
    00820
    00821             // Clear all of the caches
    00822             textureCache.Clear();
    00823             fontCache.Clear();
    00824             effectCache.Clear();
    00825         }
    00826
    00827         #endregion
    00828     }
    00829     #endregion
    00830
    00831     #region Arcball
    00835     public class ArcBall
    00836     {
    00837         #region Instance Data
    00838         protected Matrix rotation; // Matrix for arc ball's orientation
    00839         protected Matrix translation; // Matrix for arc ball's position
    00840         protected Matrix translationDelta; // Matrix for arc ball's position
    00841
    00842         protected int width; // arc ball's window width
    00843         protected int height; // arc ball's window height
    00844         protected Vector2 center;  // center of arc ball
    00845         protected float radius; // arc ball's radius in screen coords
    00846         protected float radiusTranslation; // arc ball's radius for translating the target
    00847
    00848         protected Quaternion downQuat; // Quaternion before button down
    00849         protected Quaternion nowQuat; // Composite quaternion for current drag
    00850         protected bool isDragging; // Whether user is dragging arc ball
    00851
    00852         protected System.Drawing.Point lastMousePosition; // position of last mouse point
    00853         protected Vector3 downPt; // starting point of rotation arc
    00854         protected Vector3 currentPt; // current point of rotation arc
    00855         #endregion
    00856
    00857         #region Simple Properties
    00859         public Matrix RotationMatrix { get { return rotation = Matrix.RotationQuaternion(nowQuat); } }
    00861         public Matrix TranslationMatrix { get { return translation; } }
    00863         public Matrix TranslationDeltaMatrix { get { return translationDelta; } }
    00865         public bool IsBeingDragged { get { return isDragging; } }
    00867         public Quaternion CurrentQuaternion { get { return nowQuat; } set { nowQuat = value; } }
    00868         #endregion
    00869
    00870         // Class methods
    00871
    00875         public ArcBall()
    00876         {
    00877             Reset();
    00878             downPt = Vector3.Empty;
    00879             currentPt = Vector3.Empty;
    00880
    00881             System.Windows.Forms.Form active = System.Windows.Forms.Form.ActiveForm;
    00882             if (active != null)
    00883             {
    00884                 System.Drawing.Rectangle rect = active.ClientRectangle;
    00885                 SetWindow(rect.Width, rect.Height);
    00886             }
    00887         }
    00888
    00892         public void Reset()
    00893         {
    00894             downQuat = Quaternion.Identity;
    00895             nowQuat = Quaternion.Identity;
    00896             rotation = Matrix.Identity;
    00897             translation = Matrix.Identity;
    00898             translationDelta = Matrix.Identity;
    00899             isDragging = false;
    00900             radius = 1.0f;
    00901             radiusTranslation = 1.0f;
    00902         }
    00903
    00907         public Vector3 ScreenToVector(float screenPointX, float screenPointY)
    00908         {
    00909             float x = -(screenPointX - width / 2.0f) / (radius * width / 2.0f);
    00910             float y = (screenPointY - height / 2.0f) / (radius * height / 2.0f);
    00911             float z = 0.0f;
    00912             float mag = (x * x) + (y * y);
    00913
    00914             if (mag > 1.0f)
    00915             {
    00916                 float scale = 1.0f / (float)Math.Sqrt(mag);
    00917                 x *= scale;
    00918                 y *= scale;
    00919             }
    00920             else
    00921                 z = (float)Math.Sqrt(1.0f - mag);
    00922
    00923             return new Vector3(x, y, z);
    00924         }
    00925
    00929         public void SetWindow(int w, int h, float r)
    00930         {
    00931             width = w; height = h; radius = r;
    00932             center = new Vector2(w / 2.0f, h / 2.0f);
    00933         }
    00934         public void SetWindow(int w, int h)
    00935         {
    00936             SetWindow(w, h, 0.9f); // default radius
    00937         }
    00938
    00942         public static Quaternion QuaternionFromBallPoints(Vector3 from, Vector3 to)
    00943         {
    00944             float dot = Vector3.DotProduct(from, to);
    00945             Vector3 part = Vector3.CrossProduct(from, to);
    00946             return new Quaternion(part.X, part.Y, part.Z, dot);
    00947         }
    00948
    00952         public void OnBegin(int x, int y)
    00953         {
    00954             isDragging = true;
    00955             downQuat = nowQuat;
    00956             downPt = ScreenToVector((float)x, (float)y);
    00957         }
    00961         public void OnMove(int x, int y)
    00962         {
    00963             if (isDragging)
    00964             {
    00965                 currentPt = ScreenToVector((float)x, (float)y);
    00966                 nowQuat = downQuat * QuaternionFromBallPoints(downPt, currentPt);
    00967             }
    00968         }
    00972         public void OnEnd()
    00973         {
    00974             isDragging = false;
    00975         }
    00976
    00980         public bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
    00981         {
    00982             // Current mouse position
    00983             short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    00984             short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    00985
    00986             switch (msg)
    00987             {
    00988                 case NativeMethods.WindowMessage.LeftButtonDown:
    00989                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
    00990                     // Set capture
    00991                     NativeMethods.SetCapture(hWnd);
    00992                     OnBegin(mouseX, mouseY);
    00993                     return true;
    00994                 case NativeMethods.WindowMessage.LeftButtonUp:
    00995                     // Release capture
    00996                     NativeMethods.ReleaseCapture();
    00997                     OnEnd();
    00998                     return true;
    00999
    01000                 case NativeMethods.WindowMessage.RightButtonDown:
    01001                 case NativeMethods.WindowMessage.RightButtonDoubleClick:
    01002                 case NativeMethods.WindowMessage.MiddleButtonDown:
    01003                 case NativeMethods.WindowMessage.MiddleButtonDoubleClick:
    01004                     // Set capture
    01005                     NativeMethods.SetCapture(hWnd);
    01006                     // Store off the position of the cursor
    01007                     lastMousePosition = new System.Drawing.Point(mouseX, mouseY);
    01008                     return true;
    01009
    01010                 case NativeMethods.WindowMessage.RightButtonUp:
    01011                 case NativeMethods.WindowMessage.MiddleButtonUp:
    01012                     // Release capture
    01013                     NativeMethods.ReleaseCapture();
    01014                     return true;
    01015
    01016                 case NativeMethods.WindowMessage.MouseMove:
    01017                     short buttonState = NativeMethods.LoWord((uint)wParam.ToInt32());
    01018                     bool leftButton = ((buttonState & (short)NativeMethods.MouseButtons.Left) != 0);
    01019                     bool rightButton = ((buttonState & (short)NativeMethods.MouseButtons.Right) != 0);
    01020                     bool middleButton = ((buttonState & (short)NativeMethods.MouseButtons.Middle) != 0);
    01021
    01022                     if (leftButton)
    01023                     {
    01024                         OnMove(mouseX, mouseY);
    01025                     }
    01026                     else if (rightButton || middleButton)
    01027                     {
    01028                         // Normalize based on size of window and bounding sphere radius
    01029                         float deltaX = (lastMousePosition.X - mouseX) * radiusTranslation / width;
    01030                         float deltaY = (lastMousePosition.Y - mouseY) * radiusTranslation / height;
    01031
    01032                         if (rightButton)
    01033                         {
    01034                             translationDelta = Matrix.Translation(-2 * deltaX, 2 * deltaY, 0.0f);
    01035                             translation *= translationDelta;
    01036                         }
    01037                         else // Middle button
    01038                         {
    01039                             translationDelta = Matrix.Translation(0.0f, 0.0f, 5 * deltaY);
    01040                             translation *= translationDelta;
    01041                         }
    01042                         // Store off the position of the cursor
    01043                         lastMousePosition = new System.Drawing.Point(mouseX, mouseY);
    01044                     }
    01045                     return true;
    01046             }
    01047
    01048             return false;
    01049         }
    01050     }
    01051     #endregion
    01052
    01053     #region Cameras
    01057     public enum CameraKeys : byte
    01058     {
    01059         StrafeLeft,
    01060         StrafeRight,
    01061         MoveForward,
    01062         MoveBackward,
    01063         MoveUp,
    01064         MoveDown,
    01065         Reset,
    01066         ControlDown,
    01067         MaxKeys,
    01068         Unknown = 0xff
    01069     }
    01070
    01074     [Flags]
    01075     public enum MouseButtonMask : byte
    01076     {
    01077         None = 0,
    01078         Left = 0x01,
    01079         Middle = 0x02,
    01080         Right = 0x04,
    01081         Wheel = 0x08,
    01082     }
    01083
    01089     public abstract class Camera
    01090     {
    01094         protected static CameraKeys MapKey(IntPtr param)
    01095         {
    01096             System.Windows.Forms.Keys key = (System.Windows.Forms.Keys)param.ToInt32();
    01097             switch (key)
    01098             {
    01099                 case System.Windows.Forms.Keys.ControlKey: return CameraKeys.ControlDown;
    01100                 case System.Windows.Forms.Keys.Left: return CameraKeys.StrafeLeft;
    01101                 case System.Windows.Forms.Keys.Right: return CameraKeys.StrafeRight;
    01102                 case System.Windows.Forms.Keys.Up: return CameraKeys.MoveForward;
    01103                 case System.Windows.Forms.Keys.Down: return CameraKeys.MoveBackward;
    01104                 case System.Windows.Forms.Keys.Prior: return CameraKeys.MoveUp; // pgup
    01105                 case System.Windows.Forms.Keys.Next: return CameraKeys.MoveDown; // pgdn
    01106
    01107                 case System.Windows.Forms.Keys.A: return CameraKeys.StrafeLeft;
    01108                 case System.Windows.Forms.Keys.D: return CameraKeys.StrafeRight;
    01109                 case System.Windows.Forms.Keys.W: return CameraKeys.MoveForward;
    01110                 case System.Windows.Forms.Keys.S: return CameraKeys.MoveBackward;
    01111                 case System.Windows.Forms.Keys.Q: return CameraKeys.MoveUp;
    01112                 case System.Windows.Forms.Keys.E: return CameraKeys.MoveDown;
    01113
    01114                 case System.Windows.Forms.Keys.NumPad4: return CameraKeys.StrafeLeft;
    01115                 case System.Windows.Forms.Keys.NumPad6: return CameraKeys.StrafeRight;
    01116                 case System.Windows.Forms.Keys.NumPad8: return CameraKeys.MoveForward;
    01117                 case System.Windows.Forms.Keys.NumPad2: return CameraKeys.MoveBackward;
    01118                 case System.Windows.Forms.Keys.NumPad9: return CameraKeys.MoveUp;
    01119                 case System.Windows.Forms.Keys.NumPad3: return CameraKeys.MoveDown;
    01120
    01121                 case System.Windows.Forms.Keys.Home: return CameraKeys.Reset;
    01122             }
    01123             // No idea
    01124             return (CameraKeys)byte.MaxValue;
    01125         }
    01126
    01127
    01128         #region Instance Data
    01129         protected Matrix viewMatrix; // View Matrix
    01130         protected Matrix projMatrix; // Projection matrix
    01131
    01132         protected System.Drawing.Point lastMousePosition;  // Last absolute position of mouse cursor
    01133         protected bool isMouseLButtonDown;    // True if left button is down
    01134         protected bool isMouseMButtonDown;    // True if middle button is down
    01135         protected bool isMouseRButtonDown;    // True if right button is down
    01136         protected int currentButtonMask;   // mask of which buttons are down
    01137         protected int mouseWheelDelta;     // Amount of middle wheel scroll (+/-)
    01138         protected Vector2 mouseDelta;          // Mouse relative delta smoothed over a few frames
    01139         protected float framesToSmoothMouseData; // Number of frames to smooth mouse data over
    01140
    01141         protected Vector3 defaultEye;          // Default camera eye position
    01142         protected Vector3 defaultLookAt;       // Default LookAt position
    01143         protected Vector3 eye;                 // Camera eye position
    01144         protected Vector3 lookAt;              // LookAt position
    01145         protected float cameraYawAngle;      // Yaw angle of camera
    01146         protected float cameraPitchAngle;    // Pitch angle of camera
    01147
    01148         protected System.Drawing.Rectangle dragRectangle; // Rectangle within which a drag can be initiated.
    01149         protected Vector3 velocity;            // Velocity of camera
    01150         protected bool isMovementDrag;        // If true, then camera movement will slow to a stop otherwise movement is instant
    01151         protected Vector3 velocityDrag;        // Velocity drag force
    01152         protected float dragTimer;           // Countdown timer to apply drag
    01153         protected float totalDragTimeToZero; // Time it takes for velocity to go from full to 0
    01154         protected Vector2 rotationVelocity;         // Velocity of camera
    01155
    01156         protected float fieldOfView;                 // Field of view
    01157         protected float aspectRatio;              // Aspect ratio
    01158         protected float nearPlane;           // Near plane
    01159         protected float farPlane;            // Far plane
    01160
    01161         protected float rotationScaler;      // Scaler for rotation
    01162         protected float moveScaler;          // Scaler for movement
    01163
    01164         protected bool isInvertPitch;         // Invert the pitch axis
    01165         protected bool isEnablePositionMovement; // If true, then the user can translate the camera/model
    01166         protected bool isEnableYAxisMovement; // If true, then camera can move in the y-axis
    01167
    01168         protected bool isClipToBoundary;      // If true, then the camera will be clipped to the boundary
    01169         protected Vector3 minBoundary;         // Min point in clip boundary
    01170         protected Vector3 maxBoundary;         // Max point in clip boundary
    01171
    01172         protected bool isResetCursorAfterMove;// If true, the class will reset the cursor position so that the cursor always has space to move
    01173
    01174         // State of the input
    01175         protected bool[] keys;
    01176         public static readonly Vector3 UpDirection = new Vector3(0, 1, 0);
    01177         #endregion
    01178
    01179         #region Simple Properties
    01181         public bool IsBeingDragged { get { return (isMouseLButtonDown || isMouseMButtonDown || isMouseRButtonDown); } }
    01183         public bool IsMouseLeftButtonDown { get { return isMouseLButtonDown; } }
    01185         public bool IsMouseRightButtonDown { get { return isMouseRButtonDown; } }
    01187         public bool IsMouseMiddleButtonDown { get { return isMouseMButtonDown; } }
    01189         public Matrix ViewMatrix { get { return viewMatrix; } }
    01191         public Matrix ProjectionMatrix { get { return projMatrix; } }
    01193         public Vector3 EyeLocation { get { return eye; } }
    01195         public Vector3 LookAtPoint { get { return lookAt; } }
    01197         public bool IsPositionMovementEnabled { get { return isEnablePositionMovement; } set { isEnablePositionMovement = value; } }
    01198         #endregion
    01199
    01203         public abstract void FrameMove(float elapsedTime);
    01204
    01208         protected Camera()
    01209         {
    01210             // Create the keys
    01211             keys = new bool[(int)CameraKeys.MaxKeys];
    01212
    01213             // Set attributes for the view matrix
    01214             eye = Vector3.Empty;
    01215             lookAt = new Vector3(0.0f, 0.0f, 1.0f);
    01216
    01217             // Setup the view matrix
    01218             SetViewParameters(eye, lookAt);
    01219
    01220             // Setup the projection matrix
    01221             SetProjectionParameters((float)Math.PI / 4, 1.0f, 1.0f, 1000.0f);
    01222
    01223             // Store mouse information
    01224             lastMousePosition = System.Windows.Forms.Cursor.Position;
    01225             isMouseLButtonDown = false;
    01226             isMouseRButtonDown = false;
    01227             isMouseMButtonDown = false;
    01228             mouseWheelDelta = 0;
    01229             currentButtonMask = 0;
    01230
    01231             // Setup camera rotations
    01232             cameraYawAngle = 0.0f;
    01233             cameraPitchAngle = 0.0f;
    01234
    01235             dragRectangle = new System.Drawing.Rectangle(0, 0, int.MaxValue, int.MaxValue);
    01236             velocity = Vector3.Empty;
    01237             isMovementDrag = false;
    01238             velocityDrag = Vector3.Empty;
    01239             dragTimer = 0.0f;
    01240             totalDragTimeToZero = 0.25f;
    01241             rotationVelocity = Vector2.Empty;
    01242             rotationScaler = 0.1f;
    01243             moveScaler = 5.0f;
    01244             isInvertPitch = false;
    01245             isEnableYAxisMovement = true;
    01246             isEnablePositionMovement = true;
    01247             mouseDelta = Vector2.Empty;
    01248             framesToSmoothMouseData = 2.0f;
    01249             isClipToBoundary = false;
    01250             minBoundary = new Vector3(-1.0f, -1.0f, -1.0f);
    01251             maxBoundary = new Vector3(1, 1, 1);
    01252             isResetCursorAfterMove = false;
    01253         }
    01254
    01258         public virtual bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
    01259         {
    01260             switch (msg)
    01261             {
    01262                 // Handle the keyboard
    01263                 case NativeMethods.WindowMessage.KeyDown:
    01264                     CameraKeys mappedKeyDown = MapKey(wParam);
    01265                     if (mappedKeyDown != (CameraKeys)byte.MaxValue)
    01266                     {
    01267                         // Valid key was pressed, mark it as 'down'
    01268                         keys[(int)mappedKeyDown] = true;
    01269                     }
    01270                     break;
    01271                 case NativeMethods.WindowMessage.KeyUp:
    01272                     CameraKeys mappedKeyUp = MapKey(wParam);
    01273                     if (mappedKeyUp != (CameraKeys)byte.MaxValue)
    01274                     {
    01275                         // Valid key was let go, mark it as 'up'
    01276                         keys[(int)mappedKeyUp] = false;
    01277                     }
    01278                     break;
    01279
    01280                 // Handle the mouse
    01281                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
    01282                 case NativeMethods.WindowMessage.LeftButtonDown:
    01283                 case NativeMethods.WindowMessage.RightButtonDoubleClick:
    01284                 case NativeMethods.WindowMessage.RightButtonDown:
    01285                 case NativeMethods.WindowMessage.MiddleButtonDoubleClick:
    01286                 case NativeMethods.WindowMessage.MiddleButtonDown:
    01287                     {
    01288                         // Compute the drag rectangle in screen coord.
    01289                         System.Drawing.Point cursor = new System.Drawing.Point(
    01290                             NativeMethods.LoWord((uint)lParam.ToInt32()),
    01291                             NativeMethods.HiWord((uint)lParam.ToInt32()));
    01292
    01293                         // Update the variable state
    01294                         if (((msg == NativeMethods.WindowMessage.LeftButtonDown) ||
    01295                             (msg == NativeMethods.WindowMessage.LeftButtonDoubleClick))
    01296                             && dragRectangle.Contains(cursor))
    01297                         {
    01298                             isMouseLButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Left;
    01299                         }
    01300                         if (((msg == NativeMethods.WindowMessage.MiddleButtonDown) ||
    01301                             (msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick))
    01302                             && dragRectangle.Contains(cursor))
    01303                         {
    01304                             isMouseMButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Middle;
    01305                         }
    01306                         if (((msg == NativeMethods.WindowMessage.RightButtonDown) ||
    01307                             (msg == NativeMethods.WindowMessage.RightButtonDoubleClick))
    01308                             && dragRectangle.Contains(cursor))
    01309                         {
    01310                             isMouseRButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Right;
    01311                         }
    01312
    01313                         // Capture the mouse, so if the mouse button is
    01314                         // released outside the window, we'll get the button up messages
    01315                         NativeMethods.SetCapture(hWnd);
    01316
    01317                         lastMousePosition = System.Windows.Forms.Cursor.Position;
    01318                         return true;
    01319                     }
    01320                 case NativeMethods.WindowMessage.LeftButtonUp:
    01321                 case NativeMethods.WindowMessage.RightButtonUp:
    01322                 case NativeMethods.WindowMessage.MiddleButtonUp:
    01323                     {
    01324                         // Update member var state
    01325                         if (msg == NativeMethods.WindowMessage.LeftButtonUp) { isMouseLButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Left; }
    01326                         if (msg == NativeMethods.WindowMessage.RightButtonUp) { isMouseRButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Right; }
    01327                         if (msg == NativeMethods.WindowMessage.MiddleButtonUp) { isMouseMButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Middle; }
    01328
    01329                         // Release the capture if no mouse buttons are down
    01330                         if (!isMouseLButtonDown && !isMouseMButtonDown && !isMouseRButtonDown)
    01331                         {
    01332                             NativeMethods.ReleaseCapture();
    01333                         }
    01334                     }
    01335                     break;
    01336
    01337                 // Handle the mouse wheel
    01338                 case NativeMethods.WindowMessage.MouseWheel:
    01339                     mouseWheelDelta = NativeMethods.HiWord((uint)wParam.ToInt32()) / 120;
    01340                     break;
    01341             }
    01342
    01343             return false;
    01344         }
    01345
    01346
    01350         public virtual void Reset()
    01351         {
    01352             SetViewParameters(defaultEye, defaultLookAt);
    01353         }
    01354
    01358         public unsafe virtual void SetViewParameters(Vector3 eyePt, Vector3 lookAtPt)
    01359         {
    01360             // Store the data
    01361             defaultEye = eye = eyePt;
    01362             defaultLookAt = lookAt = lookAtPt;
    01363
    01364             // Calculate the view matrix
    01365             viewMatrix = Matrix.LookAtLeftHanded(eye, lookAt, UpDirection);
    01366
    01367             // Get the inverted matrix
    01368             Matrix inverseView = Matrix.Invert(viewMatrix);
    01369
    01370             // The axis basis vectors and camera position are stored inside the
    01371             // position matrix in the 4 rows of the camera's world matrix.
    01372             // To figure out the yaw/pitch of the camera, we just need the Z basis vector
    01373             Vector3* pZBasis = (Vector3*)&inverseView.M31;
    01374             cameraYawAngle = (float)Math.Atan2(pZBasis->X, pZBasis->Z);
    01375             float len = (float)Math.Sqrt(pZBasis->Z * pZBasis->Z + pZBasis->X * pZBasis->X);
    01376             cameraPitchAngle = -(float)Math.Atan2(pZBasis->Y, len);
    01377         }
    01378
    01382         public virtual void SetProjectionParameters(float fov, float aspect, float near, float far)
    01383         {
    01384             // Set attributes for the projection matrix
    01385             fieldOfView = fov;
    01386             aspectRatio = aspect;
    01387             nearPlane = near;
    01388             farPlane = far;
    01389
    01390             projMatrix = Matrix.PerspectiveFieldOfViewLeftHanded(fov, aspect, near, far);
    01391         }
    01392
    01396         protected void UpdateMouseDelta(float elapsedTime)
    01397         {
    01398             // Get the current mouse position
    01399             System.Drawing.Point current = System.Windows.Forms.Cursor.Position;
    01400
    01401             // Calculate how far it's moved since the last frame
    01402             System.Drawing.Point delta = new System.Drawing.Point(current.X - lastMousePosition.X,
    01403                 current.Y - lastMousePosition.Y);
    01404
    01405             // Record the current position for next time
    01406             lastMousePosition = current;
    01407
    01408             if (isResetCursorAfterMove)
    01409             {
    01410                 // Set position of camera to center of desktop,
    01411                 // so it always has room to move.  This is very useful
    01412                 // if the cursor is hidden.  If this isn't done and cursor is hidden,
    01413                 // then invisible cursor will hit the edge of the screen
    01414                 // and the user can't tell what happened
    01415                 System.Windows.Forms.Screen activeScreen = System.Windows.Forms.Screen.PrimaryScreen;
    01416                 System.Drawing.Point center = new System.Drawing.Point(activeScreen.Bounds.Width / 2,
    01417                     activeScreen.Bounds.Height / 2);
    01418                 System.Windows.Forms.Cursor.Position = center;
    01419                 lastMousePosition = center;
    01420             }
    01421
    01422             // Smooth the relative mouse data over a few frames so it isn't
    01423             // jerky when moving slowly at low frame rates.
    01424             float percentOfNew = 1.0f / framesToSmoothMouseData;
    01425             float percentOfOld = 1.0f - percentOfNew;
    01426             mouseDelta.X = mouseDelta.X * percentOfNew + delta.X * percentOfNew;
    01427             mouseDelta.Y = mouseDelta.Y * percentOfNew + delta.Y * percentOfNew;
    01428
    01429             rotationVelocity = mouseDelta * rotationScaler;
    01430         }
    01431
    01435         protected void UpdateVelocity(float elapsedTime)
    01436         {
    01437             Vector3 accel = Vector3.Empty;
    01438
    01439             if (isEnablePositionMovement)
    01440             {
    01441                 // Update acceleration vector based on keyboard state
    01442                 if (keys[(int)CameraKeys.MoveForward])
    01443                     accel.Z += 1.0f;
    01444                 if (keys[(int)CameraKeys.MoveBackward])
    01445                     accel.Z -= 1.0f;
    01446                 if (isEnableYAxisMovement)
    01447                 {
    01448                     if (keys[(int)CameraKeys.MoveUp])
    01449                         accel.Y += 1.0f;
    01450                     if (keys[(int)CameraKeys.MoveDown])
    01451                         accel.Y -= 1.0f;
    01452                 }
    01453                 if (keys[(int)CameraKeys.StrafeRight])
    01454                     accel.X += 1.0f;
    01455                 if (keys[(int)CameraKeys.StrafeLeft])
    01456                     accel.X -= 1.0f;
    01457             }
    01458             // Normalize vector so if moving 2 dirs (left & forward),
    01459             // the camera doesn't move faster than if moving in 1 dir
    01460             accel.Normalize();
    01461             // Scale the acceleration vector
    01462             accel *= moveScaler;
    01463
    01464             if (isMovementDrag)
    01465             {
    01466                 // Is there any acceleration this frame?
    01467                 if (accel.LengthSquared() > 0)
    01468                 {
    01469                     // If so, then this means the user has pressed a movement key
    01470                     // so change the velocity immediately to acceleration
    01471                     // upon keyboard input.  This isn't normal physics
    01472                     // but it will give a quick response to keyboard input
    01473                     velocity = accel;
    01474                     dragTimer = totalDragTimeToZero;
    01475                     velocityDrag = accel * (1 / dragTimer);
    01476                 }
    01477                 else
    01478                 {
    01479                     // If no key being pressed, then slowly decrease velocity to 0
    01480                     if (dragTimer > 0)
    01481                     {
    01482                         velocity -= (velocityDrag * elapsedTime);
    01483                         dragTimer -= elapsedTime;
    01484                     }
    01485                     else
    01486                     {
    01487                         // Zero velocity
    01488                         velocity = Vector3.Empty;
    01489                     }
    01490                 }
    01491             }
    01492             else
    01493             {
    01494                 // No drag, so immediately change the velocity
    01495                 velocity = accel;
    01496             }
    01497         }
    01498
    01502         protected void ConstrainToBoundary(ref Vector3 v)
    01503         {
    01504             // Constrain vector to a bounding box
    01505             v.X = Math.Max(v.X, minBoundary.X);
    01506             v.Y = Math.Max(v.Y, minBoundary.Y);
    01507             v.Z = Math.Max(v.Z, minBoundary.Z);
    01508
    01509             v.X = Math.Min(v.X, maxBoundary.X);
    01510             v.Y = Math.Min(v.Y, maxBoundary.Y);
    01511             v.Z = Math.Min(v.Z, maxBoundary.Z);
    01512
    01513         }
    01514     }
    01515
    01522     public class FirstPersonCamera : Camera
    01523     {
    01524         // Mask to determine which button to enable for rotation
    01525         protected int activeButtonMask = (int)(MouseButtonMask.Left | MouseButtonMask.Middle | MouseButtonMask.Right);
    01526         // World matrix of the camera (inverse of the view matrix)
    01527         protected Matrix cameraWorld;
    01528
    01532         public override void FrameMove(float elapsedTime)
    01533         {
    01534             // Reset the camera if necessary
    01535             if (keys[(int)CameraKeys.Reset])
    01536                 Reset();
    01537
    01538             // Get the mouse movement (if any) if the mouse buttons are down
    01539             if ((activeButtonMask & currentButtonMask) != 0)
    01540                 UpdateMouseDelta(elapsedTime);
    01541
    01542             // Get amount of velocity based on the keyboard input and drag (if any)
    01543             UpdateVelocity(elapsedTime);
    01544
    01545             // Simple euler method to calculate position delta
    01546             Vector3 posDelta = velocity * elapsedTime;
    01547
    01548             // If rotating the camera
    01549             if ((activeButtonMask & currentButtonMask) != 0)
    01550             {
    01551                 // Update the pitch & yaw angle based on mouse movement
    01552                 float yawDelta = rotationVelocity.X;
    01553                 float pitchDelta = rotationVelocity.Y;
    01554
    01555                 // Invert pitch if requested
    01556                 if (isInvertPitch)
    01557                     pitchDelta = -pitchDelta;
    01558
    01559                 cameraPitchAngle += pitchDelta;
    01560                 cameraYawAngle += yawDelta;
    01561
    01562                 // Limit pitch to straight up or straight down
    01563                 cameraPitchAngle = Math.Max(-(float)Math.PI / 2.0f, cameraPitchAngle);
    01564                 cameraPitchAngle = Math.Min(+(float)Math.PI / 2.0f, cameraPitchAngle);
    01565             }
    01566
    01567             // Make a rotation matrix based on the camera's yaw & pitch
    01568             Matrix cameraRotation = Matrix.RotationYawPitchRoll(cameraYawAngle, cameraPitchAngle, 0);
    01569
    01570             // Transform vectors based on camera's rotation matrix
    01571             Vector3 localUp = new Vector3(0, 1, 0);
    01572             Vector3 localAhead = new Vector3(0, 0, 1);
    01573             Vector3 worldUp = Vector3.TransformCoordinate(localUp, cameraRotation);
    01574             Vector3 worldAhead = Vector3.TransformCoordinate(localAhead, cameraRotation);
    01575
    01576             // Transform the position delta by the camera's rotation
    01577             Vector3 posDeltaWorld = Vector3.TransformCoordinate(posDelta, cameraRotation);
    01578             if (!isEnableYAxisMovement)
    01579                 posDeltaWorld.Y = 0.0f;
    01580
    01581             // Move the eye position
    01582             eye += posDeltaWorld;
    01583             if (isClipToBoundary)
    01584                 ConstrainToBoundary(ref eye);
    01585
    01586             // Update the lookAt position based on the eye position
    01587             lookAt = eye + worldAhead;
    01588
    01589             // Update the view matrix
    01590             viewMatrix = Matrix.LookAtLeftHanded(eye, lookAt, worldUp);
    01591             cameraWorld = Matrix.Invert(viewMatrix);
    01592         }
    01593
    01597         public void SetRotationButtons(bool left, bool middle, bool right)
    01598         {
    01599             activeButtonMask = (left ? (int)MouseButtonMask.Left : 0) |
    01600                 (middle ? (int)MouseButtonMask.Middle : 0) |
    01601                 (right ? (int)MouseButtonMask.Right : 0);
    01602         }
    01603     }
    01604
    01608     public class ModelViewerCamera : Camera
    01609     {
    01610         #region Instance Data
    01611         protected ArcBall worldArcball = new ArcBall();
    01612         protected ArcBall viewArcball = new ArcBall();
    01613         protected Vector3 modelCenter;
    01614         protected Matrix lastModelRotation; // Last arcball rotation matrix for model
    01615         protected Matrix lastCameraRotation; // Last rotation matrix for camera
    01616         protected Matrix modelRotation; // Rotation matrix of model
    01617         protected Matrix world; // World Matrix of model
    01618
    01619         protected int rotateModelButtonMask;
    01620         protected int zoomButtonMask;
    01621         protected int rotateCameraButtonMask;
    01622
    01623         protected bool isPitchLimited;
    01624         protected float radius; // Distance from the camera to model
    01625         protected float defaultRadius; // Distance from the camera to model
    01626         protected float minRadius; // Min radius
    01627         protected float maxRadius; // Max radius
    01628         protected bool attachCameraToModel;
    01629         #endregion
    01630
    01631         #region Simple Properties/Set Methods
    01633         public float MinimumRadius { get { return minRadius; } set { minRadius = value; } }
    01635         public float MaximumRadius { get { return maxRadius; } set { maxRadius = value; } }
    01637         public Matrix WorldMatrix { get { return world; } }
    01639         public void SetWorldQuat(Quaternion q) { worldArcball.CurrentQuaternion = q; }
    01641         public void SetViewQuat(Quaternion q) { viewArcball.CurrentQuaternion = q; }
    01643         public void SetIsPitchLimited(bool limit) { isPitchLimited = limit; }
    01645         public void SetModelCenter(Vector3 c) { modelCenter = c; }
    01647         public void SetRadius(float r, float min, float max) { radius = defaultRadius = r; minRadius = min; maxRadius = max; }
    01649         public void SetRadius(float r) { defaultRadius = r; minRadius = 1.0f; maxRadius = float.MaxValue; }
    01651         public void SetWindow(int w, int h, float r) { worldArcball.SetWindow(w, h, r); viewArcball.SetWindow(w, h, r); }
    01653         public void SetWindow(int w, int h) { worldArcball.SetWindow(w, h, 0.9f); viewArcball.SetWindow(w, h, 0.9f); }
    01655         public void SetButtonMasks(int rotateModel, int zoom, int rotateCamera) { rotateCameraButtonMask = rotateCamera; zoomButtonMask = zoom; rotateModelButtonMask = rotateModel; }
    01657         public bool IsAttachedToModel { get { return attachCameraToModel; } set { attachCameraToModel = value; } }
    01658         #endregion
    01659
    01663         public ModelViewerCamera()
    01664         {
    01665             world = Matrix.Identity;
    01666             modelRotation = Matrix.Identity;
    01667             lastModelRotation = Matrix.Identity;
    01668             lastCameraRotation = Matrix.Identity;
    01669             modelCenter = Vector3.Empty;
    01670             radius = 5.0f;
    01671             defaultRadius = 5.0f;
    01672             minRadius = 1.0f;
    01673             maxRadius = float.MaxValue;
    01674             isPitchLimited = false;
    01675             isEnablePositionMovement = false;
    01676             attachCameraToModel = false;
    01677
    01678             // Set button masks
    01679             rotateModelButtonMask = (int)MouseButtonMask.Left;
    01680             zoomButtonMask = (int)MouseButtonMask.Wheel;
    01681             rotateCameraButtonMask = (int)MouseButtonMask.Right;
    01682         }
    01683
    01687         public unsafe override void FrameMove(float elapsedTime)
    01688         {
    01689             // Reset the camera if necessary
    01690             if (keys[(int)CameraKeys.Reset])
    01691                 Reset();
    01692
    01693             // Get the mouse movement (if any) if the mouse buttons are down
    01694             if (currentButtonMask != 0)
    01695                 UpdateMouseDelta(elapsedTime);
    01696
    01697             // Get amount of velocity based on the keyboard input and drag (if any)
    01698             UpdateVelocity(elapsedTime);
    01699
    01700             // Simple euler method to calculate position delta
    01701             Vector3 posDelta = velocity * elapsedTime;
    01702
    01703             // Change the radius from the camera to the model based on wheel scrolling
    01704             if ((mouseWheelDelta != 0) && (zoomButtonMask == (int)MouseButtonMask.Wheel))
    01705                 radius -= mouseWheelDelta * radius * 0.1f;
    01706             radius = Math.Min(maxRadius, radius);
    01707             radius = Math.Max(minRadius, radius);
    01708             mouseWheelDelta = 0;
    01709
    01710             // Get the inverse of the arcball's rotation matrix
    01711             Matrix cameraRotation = Matrix.Invert(viewArcball.RotationMatrix);
    01712
    01713             // Transform vectors based on camera's rotation matrix
    01714             Vector3 localUp = new Vector3(0, 1, 0);
    01715             Vector3 localAhead = new Vector3(0, 0, 1);
    01716             Vector3 worldUp = Vector3.TransformCoordinate(localUp, cameraRotation);
    01717             Vector3 worldAhead = Vector3.TransformCoordinate(localAhead, cameraRotation);
    01718
    01719             // Transform the position delta by the camera's rotation
    01720             Vector3 posDeltaWorld = Vector3.TransformCoordinate(posDelta, cameraRotation);
    01721
    01722             // Move the lookAt position
    01723             lookAt += posDeltaWorld;
    01724             if (isClipToBoundary)
    01725                 ConstrainToBoundary(ref lookAt);
    01726
    01727             // Update the eye point based on a radius away from the lookAt position
    01728             eye = lookAt - worldAhead * radius;
    01729
    01730             // Update the view matrix
    01731             viewMatrix = Matrix.LookAtLeftHanded(eye, lookAt, worldUp);
    01732             Matrix invView = Matrix.Invert(viewMatrix);
    01733             invView.M41 = invView.M42 = invView.M43 = 0;
    01734             Matrix modelLastRotInv = Matrix.Invert(lastModelRotation);
    01735
    01736             // Accumulate the delta of the arcball's rotation in view space.
    01737             // Note that per-frame delta rotations could be problematic over long periods of time.
    01738             Matrix localModel = worldArcball.RotationMatrix;
    01739             modelRotation *= viewMatrix * modelLastRotInv * localModel * invView;
    01740             if (viewArcball.IsBeingDragged && attachCameraToModel && !keys[(int)CameraKeys.ControlDown])
    01741             {
    01742                 // Attah camera to model by inverse of the model rotation
    01743                 Matrix cameraRotInv = Matrix.Invert(lastCameraRotation);
    01744                 Matrix delta = cameraRotInv * cameraRotation; // local to world matrix
    01745                 modelRotation *= delta;
    01746             }
    01747             lastCameraRotation = cameraRotation;
    01748             lastModelRotation = localModel;
    01749
    01750             // Since we're accumulating delta rotations, we need to orthonormalize
    01751             // the matrix to prevent eventual matrix skew
    01752             fixed (void* pxBasis = &modelRotation.M11)
    01753             {
    01754                 fixed (void* pyBasis = &modelRotation.M21)
    01755                 {
    01756                     fixed (void* pzBasis = &modelRotation.M31)
    01757                     {
    01758                         UnsafeNativeMethods.Vector3.Normalize((Vector3*)pxBasis, (Vector3*)pxBasis);
    01759                         UnsafeNativeMethods.Vector3.Cross((Vector3*)pyBasis, (Vector3*)pzBasis, (Vector3*)pxBasis);
    01760                         UnsafeNativeMethods.Vector3.Normalize((Vector3*)pyBasis, (Vector3*)pyBasis);
    01761                         UnsafeNativeMethods.Vector3.Cross((Vector3*)pzBasis, (Vector3*)pxBasis, (Vector3*)pyBasis);
    01762                     }
    01763                 }
    01764             }
    01765
    01766             // Translate the rotation matrix to the same position as the lookAt position
    01767             modelRotation.M41 = lookAt.X;
    01768             modelRotation.M42 = lookAt.Y;
    01769             modelRotation.M43 = lookAt.Z;
    01770
    01771             // Translate world matrix so its at the center of the model
    01772             Matrix trans = Matrix.Translation(-modelCenter.X, -modelCenter.Y, -modelCenter.Z);
    01773             world = trans * modelRotation;
    01774         }
    01775
    01779         public override void Reset()
    01780         {
    01781             base.Reset();
    01782             world = Matrix.Identity;
    01783             modelRotation = Matrix.Identity;
    01784             lastModelRotation = Matrix.Identity;
    01785             lastCameraRotation = Matrix.Identity;
    01786             radius = defaultRadius;
    01787             worldArcball.Reset();
    01788             viewArcball.Reset();
    01789         }
    01790
    01794         public override void SetViewParameters(Vector3 eyePt, Vector3 lookAtPt)
    01795         {
    01796             // Call base first
    01797             base.SetViewParameters(eyePt, lookAtPt);
    01798
    01799             // Propogate changes to the member arcball
    01800             Matrix rotation = Matrix.LookAtLeftHanded(eyePt, lookAtPt, UpDirection);
    01801             viewArcball.CurrentQuaternion = Quaternion.RotationMatrix(rotation);
    01802
    01803             // Set the radius according to the distance
    01804             Vector3 eyeToPoint = lookAtPt - eyePt;
    01805             SetRadius(eyeToPoint.Length());
    01806         }
    01807
    01811         public override bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
    01812         {
    01813             // Call base first
    01814             base.HandleMessages(hWnd, msg, wParam, lParam);
    01815
    01816             if (((msg == NativeMethods.WindowMessage.LeftButtonDown || msg == NativeMethods.WindowMessage.LeftButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Left) != 0)) ||
    01817                 ((msg == NativeMethods.WindowMessage.RightButtonDown || msg == NativeMethods.WindowMessage.RightButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Right) != 0)) ||
    01818                 ((msg == NativeMethods.WindowMessage.MiddleButtonDown || msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Middle) != 0)))
    01819             {
    01820                 // Current mouse position
    01821                 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    01822                 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    01823                 worldArcball.OnBegin(mouseX, mouseY);
    01824             }
    01825             if (((msg == NativeMethods.WindowMessage.LeftButtonDown || msg == NativeMethods.WindowMessage.LeftButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Left) != 0)) ||
    01826                 ((msg == NativeMethods.WindowMessage.RightButtonDown || msg == NativeMethods.WindowMessage.RightButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Right) != 0)) ||
    01827                 ((msg == NativeMethods.WindowMessage.MiddleButtonDown || msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Middle) != 0)))
    01828             {
    01829                 // Current mouse position
    01830                 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    01831                 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    01832                 viewArcball.OnBegin(mouseX, mouseY);
    01833             }
    01834             if (msg == NativeMethods.WindowMessage.MouseMove)
    01835             {
    01836                 // Current mouse position
    01837                 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    01838                 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    01839                 worldArcball.OnMove(mouseX, mouseY);
    01840                 viewArcball.OnMove(mouseX, mouseY);
    01841             }
    01842
    01843             if ((msg == NativeMethods.WindowMessage.LeftButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Left) != 0) ||
    01844                 (msg == NativeMethods.WindowMessage.RightButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Right) != 0) ||
    01845                 (msg == NativeMethods.WindowMessage.MiddleButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Middle) != 0))
    01846             {
    01847                 worldArcball.OnEnd();
    01848             }
    01849
    01850             if ((msg == NativeMethods.WindowMessage.LeftButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Left) != 0) ||
    01851                 (msg == NativeMethods.WindowMessage.RightButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Right) != 0) ||
    01852                 (msg == NativeMethods.WindowMessage.MiddleButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Middle) != 0))
    01853             {
    01854                 viewArcball.OnEnd();
    01855             }
    01856
    01857             return false;
    01858         }
    01859     }
    01860     #endregion
    01861
    01862     #region Text Helper
    01866     public struct TextHelper
    01867     {
    01868         private Font textFont; // Used to draw the text
    01869         private Sprite textSprite; // Used to cache the drawn text
    01870         private int color; // Color to draw the text
    01871         private System.Drawing.Point point; // Where to draw the text
    01872         private int lineHeight; // Height of the lines
    01873
    01877         public TextHelper(Font f, Sprite s, int l)
    01878         {
    01879             textFont = f;
    01880             textSprite = s;
    01881             lineHeight = l;
    01882             color = unchecked((int)0xffffffff);
    01883             point = System.Drawing.Point.Empty;
    01884         }
    01885
    01889         public void DrawStringLine(string text)
    01890         {
    01891             if (textFont == null)
    01892             {
    01893                 throw new InvalidOperationException("You cannot draw text.  There is no font object.");
    01894             }
    01895             // Create the rectangle to draw to
    01896             System.Drawing.Rectangle rect = new System.Drawing.Rectangle(point, System.Drawing.Size.Empty);
    01897             textFont.DrawString(textSprite, text, rect, DrawStringFormat.NoClip, color);
    01898
    01899             // Increase the line height
    01900             point.Y += lineHeight;
    01901         }
    01902
    01906         public void DrawStringLine(string text, params object[] args)
    01907         {
    01908             // Simply format the string and pass it on
    01909             DrawStringLine(string.Format(text, args));
    01910         }
    01911
    01915         public void SetInsertionPoint(System.Drawing.Point p) { point = p; }
    01916         public void SetInsertionPoint(int x, int y) { point.X = x; point.Y = y; }
    01917
    01921         public void SetForegroundColor(int c) { color = c; }
    01922         public void SetForegroundColor(System.Drawing.Color c) { color = c.ToArgb(); }
    01923
    01927         public void Begin()
    01928         {
    01929             if (textSprite != null)
    01930             {
    01931                 textSprite.Begin(SpriteFlags.AlphaBlend | SpriteFlags.SortTexture);
    01932             }
    01933         }
    01934
    01938         public void End()
    01939         {
    01940             if (textSprite != null)
    01941             {
    01942                 textSprite.End();
    01943             }
    01944         }
    01945     }
    01946     #endregion
    01947
    01948     #region Utility
    01952     public class Utility
    01953     {
    01954         // Constants for search folders
    01955         private const string CurrentFolder = @".\";
    01956         private const string MediaPath = @"Media\";
    01957
    01958         // Typical folder locations
    01959         //      .\
    01960         //      ..\
    01961         //      ..\..\
    01962         //      %EXE_DIR%\
    01963         //      %EXE_DIR%\..\
    01964         //      %EXE_DIR%\..\..\
    01965         //      %EXE_DIR%\..\%EXE_NAME%
    01966         //      %EXE_DIR%\..\..\%EXE_NAME%
    01967         //      DXSDK media path
    01968         private static readonly string[] TypicalFolders = new string[] { CurrentFolder, @"..\",
    01969                                                                                @"..\..\", @"{0}\", @"{0}\..\", @"{0}\..\..\", @"{0}\..\{1}\", @"{0}\..\..\{1}\" };
    01970         private Utility() { /* Private Constructor */ }
    01971
    01978         public static string FindMediaFile(string filename)
    01979         {
    01980             // Find out the executing assembly information
    01981             System.Reflection.Assembly executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
    01982             // Now check the typical folders, before you can do that you'll need to get
    01983             // the executable name
    01984             string exeName = System.IO.Path.GetFileNameWithoutExtension(executingAssembly.Location);
    01985             // And the executable folder
    01986             string exeFolder = System.IO.Path.GetDirectoryName(executingAssembly.Location);
    01987
    01988             string filePath;
    01989             // Now you can search the typical folders
    01990             if (SearchTypicalFolders(filename, exeFolder, exeName, out filePath))
    01991             {
    01992                 return filePath;
    01993             }
    01994
    01995             // The file wasn't found again, search the folders with \media on them
    01996             // Now you can search the typical folders
    01997             if (SearchTypicalFolders(filename + MediaPath, exeFolder, exeName, out filePath))
    01998             {
    01999                 return filePath;
    02000             }
    02001
    02002             // We still haven't found the file yet, we should search the parents folders now
    02003             if (SearchParentFolders(filename, CurrentFolder, "", out filePath))
    02004             {
    02005                 return filePath;
    02006             }
    02007             // We still haven't found the file yet, now search from the exe folder
    02008             if (SearchParentFolders(filename, exeFolder, exeName, out filePath))
    02009             {
    02010                 return filePath;
    02011             }
    02012
    02013             // We still haven't found the file yet, we should search the parents folders now, but append media
    02014             if (SearchParentFolders(filename, CurrentFolder, MediaPath, out filePath))
    02015             {
    02016                 return filePath;
    02017             }
    02018             // We still haven't found the file yet, now search from the exe folder and append media
    02019             if (SearchParentFolders(filename, exeFolder, AppendDirectorySeparator(exeName) + MediaPath, out filePath))
    02020             {
    02021                 return filePath;
    02022             }
    02023
    02024
    02025             // We still haven't found the file yet, the built samples are prefixed with 'csw', so see if that's the case
    02026             if (exeName.ToLower().StartsWith("csw"))
    02027             {
    02028                 // Build the new exe name by stripping off the 'csw' prefix and doing the searches again
    02029                 string newExeName = exeName.Substring(3, exeName.Length - 3);
    02030                 if (SearchParentFolders(filename, exeFolder, newExeName, out filePath))
    02031                 {
    02032                     return filePath;
    02033                 }
    02034                 // We still haven't found the file yet, now search from the exe folder and append media
    02035                 if (SearchParentFolders(filename, exeFolder, AppendDirectorySeparator(newExeName) + MediaPath, out filePath))
    02036                 {
    02037                     return filePath;
    02038                 }
    02039             }
    02040
    02041             // Before throwing an exception, girst check to see if the file exists as is
    02042             if (File.Exists(filename))
    02043             {
    02044                 return filename;
    02045             }
    02046
    02047             throw new MediaNotFoundException();
    02048         }
    02049
    02058         private static bool SearchTypicalFolders(string filename, string exeFolder, string exeName, out string fullPath)
    02059         {
    02060             // First scan through each typical folder and see if we found the file
    02061             for (int i = 0; i < TypicalFolders.Length; i++)
    02062             {
    02063                 try
    02064                 {
    02065                     FileInfo info = new FileInfo(string.Format(TypicalFolders[i], exeFolder, exeName) + filename);
    02066                     if (info.Exists)
    02067                     {
    02068                         fullPath = info.FullName;
    02069                         return true;
    02070                     }
    02071                 }
    02072                 catch (NotSupportedException)
    02073                 {
    02074                     // This exception will be fired if the filename is not supported
    02075                     continue;
    02076                 }
    02077             }
    02078
    02079             // We never found any of the files
    02080             fullPath = string.Empty;
    02081             return false;
    02082         }
    02083
    02092         private static bool SearchParentFolders(string filename, string rootNode, string leafName, out string fullPath)
    02093         {
    02094             // Set the out parameter first
    02095             fullPath = string.Empty;
    02096             try
    02097             {
    02098                 // Search the root node first
    02099                 FileInfo info = new FileInfo(AppendDirectorySeparator(rootNode) + AppendDirectorySeparator(leafName) + filename);
    02100                 if (info.Exists)
    02101                 {
    02102                     fullPath = info.FullName;
    02103                     return true;
    02104                 }
    02105             }
    02106             catch (NotSupportedException)
    02107             {
    02108                 // The arguments passed in are not supported, fail now
    02109                 return false;
    02110             }
    02111
    02112             // Are we in the root yet?
    02113             DirectoryInfo dir = new DirectoryInfo(rootNode);
    02114             if (dir.Parent != null)
    02115             {
    02116                 return SearchParentFolders(filename, dir.Parent.FullName, leafName, out fullPath);
    02117             }
    02118             else
    02119             {
    02120                 // We never found any of the files
    02121                 return false;
    02122             }
    02123         }
    02124
    02128         public static string AppendDirectorySeparator(string pathName)
    02129         {
    02130             if (!pathName.EndsWith(@"\"))
    02131                 return pathName + @"\";
    02132
    02133             return pathName;
    02134         }
    02135
    02137         public static Matrix GetCubeMapViewMatrix(CubeMapFace face)
    02138         {
    02139             Vector3 vEyePt = new Vector3(0.0f, 0.0f, 0.0f);
    02140             Vector3 vLookDir = new Vector3();
    02141             Vector3 vUpDir = new Vector3();
    02142
    02143             switch (face)
    02144             {
    02145                 case CubeMapFace.PositiveX:
    02146                     vLookDir = new Vector3(1.0f, 0.0f, 0.0f);
    02147                     vUpDir = new Vector3(0.0f, 1.0f, 0.0f);
    02148                     break;
    02149                 case CubeMapFace.NegativeX:
    02150                     vLookDir = new Vector3(-1.0f, 0.0f, 0.0f);
    02151                     vUpDir = new Vector3(0.0f, 1.0f, 0.0f);
    02152                     break;
    02153                 case CubeMapFace.PositiveY:
    02154                     vLookDir = new Vector3(0.0f, 1.0f, 0.0f);
    02155                     vUpDir = new Vector3(0.0f, 0.0f, -1.0f);
    02156                     break;
    02157                 case CubeMapFace.NegativeY:
    02158                     vLookDir = new Vector3(0.0f, -1.0f, 0.0f);
    02159                     vUpDir = new Vector3(0.0f, 0.0f, 1.0f);
    02160                     break;
    02161                 case CubeMapFace.PositiveZ:
    02162                     vLookDir = new Vector3(0.0f, 0.0f, 1.0f);
    02163                     vUpDir = new Vector3(0.0f, 1.0f, 0.0f);
    02164                     break;
    02165                 case CubeMapFace.NegativeZ:
    02166                     vLookDir = new Vector3(0.0f, 0.0f, -1.0f);
    02167                     vUpDir = new Vector3(0.0f, 1.0f, 0.0f);
    02168                     break;
    02169             }
    02170
    02171             // Set the view transform for this cubemap surface
    02172             Matrix matView = Matrix.LookAtLeftHanded(vEyePt, vLookDir, vUpDir);
    02173             return matView;
    02174         }
    02176         public static Matrix GetCubeMapViewMatrix(int face) { return GetCubeMapViewMatrix((CubeMapFace)face); }
    02177
    02178         private static bool firstTime = true;
    02182         public static void DisplaySwitchingToRefWarning(Framework framework, string sampleTitle)
    02183         {
    02184             if (framework.IsShowingMsgBoxOnError)
    02185             {
    02186                 // Read the registry key to see if the warning should be skipped
    02187                 int skipWarning = 0;
    02188                 try
    02189                 {
    02190                     using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(SwitchRefDialog.KeyLocation))
    02191                     {
    02192                         skipWarning = (int)key.GetValue(SwitchRefDialog.KeyValueName, (int)0);
    02193                     }
    02194                 }
    02195                 catch { } // Ignore any errors
    02196                 if ((skipWarning == 0) && (firstTime)) // Show dialog
    02197                 {
    02198                     firstTime = false;
    02199                     using (SwitchRefDialog dialog = new SwitchRefDialog(sampleTitle))
    02200                     {
    02201                         System.Windows.Forms.Application.Run(dialog);
    02202                         if (dialog.DialogResult == System.Windows.Forms.DialogResult.Cancel)
    02203                         {
    02204                             // Shutdown the application
    02205                             framework.Dispose();
    02206                         }
    02207                     }
    02208                 }
    02209             }
    02210         }
    02211     }
    02212     #endregion
    02213
    02214     #region Widgets
    02215
    02216     #region Direction Widget
    02218     public class DirectionWidget
    02219     {
    02220         #region Class level data (Instance/Static)
    02221         // Instance members
    02222         private float widgetRadius = 1.0f;
    02223         private ArcBall arc = new ArcBall();
    02224         private Vector3 defaultDir = new Vector3(0, 1, 0);
    02225         private Vector3 currentDir = new Vector3(0, 1, 0);
    02226         private Matrix viewMatrix = Matrix.Identity;
    02227         private Matrix rotation = Matrix.Identity;
    02228         private Matrix rotationSnapshot = Matrix.Identity;
    02229         private MouseButtonMask rotateMask = MouseButtonMask.Right;
    02230
    02231         // Static members
    02232         private static Device device = null;
    02233         private static Effect effect = null;
    02234         private static Mesh mesh = null;
    02235         #endregion
    02236
    02237         #region Properties
    02239         public float Radius { get { return widgetRadius; } set { widgetRadius = value; } }
    02241         public Vector3 LightDirection { get { return currentDir; } set { currentDir = defaultDir = value; } }
    02243         public bool IsBeingDragged { get { return arc.IsBeingDragged; } }
    02245         public MouseButtonMask RotateButtonMask { get { return rotateMask; } set { rotateMask = value; } }
    02246         #endregion
    02247
    02248         #region Device handlers
    02250         public static void OnCreateDevice(Device device)
    02251         {
    02252             // Store the device
    02253             DirectionWidget.device = device;
    02254
    02255             // Read the effect file
    02256             string path = Utility.FindMediaFile("UI\\DXUTShared.fx");
    02257
    02258             // If this fails, there should be debug output as to
    02259             // why the .fx file failed to compile (assuming you have dbmon running).
    02260             // If you do not, you can turn on unmanaged debugging for this project.
    02261             effect = Effect.FromFile(device, path, null, null, null, ShaderFlags.NotCloneable, null);
    02262
    02263             // Load the mesh with D3DX and get back a Mesh.  For this
    02264             // sample we'll ignore the X file's embedded materials since we know
    02265             // exactly the model we're loading.  See the mesh samples such as
    02266             // "OptimizedMesh" for a more generic mesh loading example.
    02267             path = Utility.FindMediaFile("UI\\arrow.x");
    02268             mesh = new Mesh(device, path, MeshFlags.Managed, null, null, null);
    02269
    02270             // Optimize the mesh for this graphics card's vertex cache
    02271             // so when rendering the mesh's triangle list the vertices will
    02272             // cache hit more often so it won't have to re-execute the vertex shader
    02273             // on those vertices so it will improve perf.
    02274             Microsoft.DirectX.Generic.GraphicsBuffer<int> adj = new Microsoft.DirectX.Generic.GraphicsBuffer<int>(mesh.FaceCount * 3);
    02275             mesh.GenerateAdjacency(1e-6f, adj);
    02276             mesh.OptimizeInPlace(MeshFlags.OptimizeVertexCache, adj);
    02277         }
    02278
    02280         public void OnResetDevice(SurfaceDescription desc)
    02281         {
    02282             arc.SetWindow(desc.Width, desc.Height);
    02283         }
    02284
    02286         public static void OnLostDevice()
    02287         {
    02288             if (effect != null)
    02289                 effect.OnLostDevice();
    02290         }
    02291
    02293         public static void OnDestroyDevice()
    02294         {
    02295             if (effect != null)
    02296                 effect.Dispose();
    02297             if (mesh != null)
    02298                 mesh.Dispose();
    02299             effect = null;
    02300             mesh = null;
    02301         }
    02302         #endregion
    02303
    02305         public bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
    02306         {
    02307             // Current mouse position
    02308             short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
    02309             short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
    02310
    02311             switch (msg)
    02312             {
    02313                 case NativeMethods.WindowMessage.LeftButtonDown:
    02314                 case NativeMethods.WindowMessage.MiddleButtonDown:
    02315                 case NativeMethods.WindowMessage.RightButtonDown:
    02316                     {
    02317                         if (((rotateMask & MouseButtonMask.Left) == MouseButtonMask.Left && msg == NativeMethods.WindowMessage.LeftButtonDown) ||
    02318                             ((rotateMask & MouseButtonMask.Right) == MouseButtonMask.Right && msg == NativeMethods.WindowMessage.RightButtonDown) ||
    02319                             ((rotateMask & MouseButtonMask.Middle) == MouseButtonMask.Middle && msg == NativeMethods.WindowMessage.MiddleButtonDown))
    02320                         {
    02321                             arc.OnBegin(mouseX, mouseY);
    02322                             NativeMethods.SetCapture(hWnd);
    02323                         }
    02324                         return true;
    02325                     }
    02326                 case NativeMethods.WindowMessage.MouseMove:
    02327                     {
    02328                         if (arc.IsBeingDragged)
    02329                         {
    02330                             arc.OnMove(mouseX, mouseY);
    02331                             UpdateLightDirection();
    02332                         }
    02333                         return true;
    02334                     }
    02335                 case NativeMethods.WindowMessage.LeftButtonUp:
    02336                 case NativeMethods.WindowMessage.RightButtonUp:
    02337                 case NativeMethods.WindowMessage.MiddleButtonUp:
    02338                     {
    02339                         if (((rotateMask & MouseButtonMask.Left) == MouseButtonMask.Left && msg == NativeMethods.WindowMessage.LeftButtonUp) ||
    02340                             ((rotateMask & MouseButtonMask.Right) == MouseButtonMask.Right && msg == NativeMethods.WindowMessage.RightButtonUp) ||
    02341                             ((rotateMask & MouseButtonMask.Middle) == MouseButtonMask.Middle && msg == NativeMethods.WindowMessage.MiddleButtonUp))
    02342                         {
    02343                             arc.OnEnd();
    02344                             NativeMethods.ReleaseCapture();
    02345                         }
    02346
    02347                         UpdateLightDirection();
    02348                         return true;
    02349                     }
    02350             }
    02351
    02352             // Didn't handle the message
    02353             return false;
    02354         }
    02355
    02357         private unsafe void UpdateLightDirection()
    02358         {
    02359             Matrix invView = Matrix.Invert(viewMatrix);
    02360             invView.M41 = invView.M42 = invView.M43 = 0;
    02361
    02362             Matrix lastRotationInv = Matrix.Invert(rotationSnapshot);
    02363             Matrix rot = arc.RotationMatrix;
    02364             rotationSnapshot = rot;
    02365
    02366             // Accumulate the delta of the arcball's rotation in view space.
    02367             // Note that per-frame delta rotations could be problematic over long periods of time.
    02368             rotation *= (viewMatrix * lastRotationInv * rot * invView);
    02369
    02370             // Since we're accumulating delta rotations, we need to orthonormalize
    02371             // the matrix to prevent eventual matrix skew
    02372             fixed (void* pxBasis = &rotation.M11)
    02373             {
    02374                 fixed (void* pyBasis = &rotation.M21)
    02375                 {
    02376                     fixed (void* pzBasis = &rotation.M31)
    02377                     {
    02378                         UnsafeNativeMethods.Vector3.Normalize((Vector3*)pxBasis, (Vector3*)pxBasis);
    02379                         UnsafeNativeMethods.Vector3.Cross((Vector3*)pyBasis, (Vector3*)pzBasis, (Vector3*)pxBasis);
    02380                         UnsafeNativeMethods.Vector3.Normalize((Vector3*)pyBasis, (Vector3*)pyBasis);
    02381                         UnsafeNativeMethods.Vector3.Cross((Vector3*)pzBasis, (Vector3*)pxBasis, (Vector3*)pyBasis);
    02382                     }
    02383                 }
    02384             }
    02385
    02386             // Transform the default direction vector by the light's rotation matrix
    02387             currentDir = Vector3.TransformNormal(defaultDir, rotation);
    02388         }
    02389
    02391         public unsafe void OnRender(ColorValue color, Matrix view, Matrix proj, Vector3 eye)
    02392         {
    02393             // Store the view matrix
    02394             viewMatrix = view;
    02395
    02396             // Render the light arrows so the user can visually see the light direction
    02397             effect.Technique = "RenderWith1LightNoTexture";
    02398             effect.SetValue("g_MaterialDiffuseColor", color);
    02399             Vector3 eyePt = Vector3.Normalize(eye);
    02400
    02401             // Set the light direction value
    02402             effect.SetValue("g_LightDir", &eyePt, sizeof(Vector3));
    02403
    02404             // Rotate arrow model to point towards origin
    02405             Vector3 at = Vector3.Empty;
    02406             Vector3 up = new Vector3(0, 1, 0);
    02407             Matrix rotateB = Matrix.RotationX((float)Math.PI);
    02408             Matrix rotateA = Matrix.LookAtLeftHanded(currentDir, at, up);
    02409             rotateA.Invert();
    02410             Matrix rotate = rotateB * rotateA;
    02411             Vector3 l = currentDir * widgetRadius * 1.0f;
    02412             Matrix trans = Matrix.Translation(l);
    02413             Matrix scale = Matrix.Scaling(widgetRadius * 0.2f, widgetRadius * 0.2f, widgetRadius * 0.2f);
    02414
    02415             Matrix world = rotate * scale * trans;
    02416             Matrix worldViewProj = world * viewMatrix * proj;
    02417
    02418             effect.SetValue("g_mWorldViewProjection", worldViewProj);
    02419             effect.SetValue("g_mWorld", world);
    02420
    02421             // Render the arrows
    02422             for (int subset = 0; subset < 2; subset++)
    02423             {
    02424                 int passes = effect.Begin(0);
    02425                 for (int pass = 0; pass < passes; pass++)
    02426                 {
    02427                     effect.BeginPass(pass);
    02428                     mesh.DrawSubset(subset);
    02429                     effect.EndPass();
    02430                 }
    02431                 effect.End();
    02432             }
    02433
    02434         }
    02435     }
    02436     #endregion
    02437
    02438     #endregion
    02439 }