00001
00002
00003
00004
00005
00006
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
00027
00028 InitializeComponent();
00029
00030
00031 this.pictureBox1.Image = System.Drawing.SystemIcons.Question.ToBitmap();
00032
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
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
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
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
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
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
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
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
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
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
00184 KeyDown = 0x0100,
00185 KeyUp = 0x0101,
00186 Character = 0x0102,
00187 SystemKeyDown = 0x0104,
00188 SystemKeyUp = 0x0105,
00189 SystemCharacter = 0x0106,
00190
00191
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,
00207 MouseLast = XButtonDoubleClick,
00208
00209
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;
00254 public System.Drawing.Rectangle MonitorRectangle;
00255 public System.Drawing.Rectangle WorkRectangle;
00256 public uint Flags;
00257 }
00258 #endregion
00259
00260 #region Windows API calls
00261 [System.Security.SuppressUnmanagedCodeSecurity]
00262 [System.Runtime.InteropServices.DllImport("winmm.dll")]
00263 public static extern IntPtr timeBeginPeriod(uint period);
00264
00265 [System.Security.SuppressUnmanagedCodeSecurity]
00266 [DllImport("kernel32")]
00267 public static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency);
00268
00269 [System.Security.SuppressUnmanagedCodeSecurity]
00270 [DllImport("kernel32")]
00271 public static extern bool QueryPerformanceCounter(ref long PerformanceCount);
00272
00273 [System.Security.SuppressUnmanagedCodeSecurity]
00274 [DllImport("User32.dll", CharSet = CharSet.Auto)]
00275 public static extern bool GetMonitorInfo(IntPtr hWnd, ref MonitorInformation info);
00276
00277 [System.Security.SuppressUnmanagedCodeSecurity]
00278 [DllImport("User32.dll", CharSet = CharSet.Auto)]
00279 public static extern IntPtr MonitorFromWindow(IntPtr hWnd, uint flags);
00280
00281 [System.Security.SuppressUnmanagedCodeSecurity]
00282 [DllImport("User32.dll", CharSet = CharSet.Auto)]
00283 public static extern short GetAsyncKeyState(uint key);
00284
00285 [System.Security.SuppressUnmanagedCodeSecurity]
00286 [DllImport("User32.dll", CharSet = CharSet.Auto)]
00287 public static extern IntPtr SetCapture(IntPtr handle);
00288
00289 [System.Security.SuppressUnmanagedCodeSecurity]
00290 [DllImport("User32.dll", CharSet = CharSet.Auto)]
00291 public static extern bool ReleaseCapture();
00292
00293 [System.Security.SuppressUnmanagedCodeSecurity]
00294 [DllImport("User32.dll", CharSet = CharSet.Auto)]
00295 public static extern int GetCaretBlinkTime();
00296
00297 [System.Security.SuppressUnmanagedCodeSecurity]
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() { }
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() { }
00348 static FrameworkTimer()
00349 {
00350 isTimerStopped = true;
00351 ticksPerSecond = 0;
00352 stopTime = 0;
00353 lastElapsedTime = 0;
00354 baseTime = 0;
00355
00356 isUsingQPF = NativeMethods.QueryPerformanceFrequency(ref ticksPerSecond);
00357 }
00358 #endregion
00359
00363 public static void Reset()
00364 {
00365 if (!isUsingQPF)
00366 return;
00367
00368
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;
00388
00389
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;
00410
00411 if (!isTimerStopped)
00412 {
00413
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;
00433
00434 stopTime += ticksPerSecond / 10;
00435 }
00436
00440 public static double GetAbsoluteTime()
00441 {
00442 if (!isUsingQPF)
00443 return -1.0;
00444
00445
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;
00463
00464
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;
00482
00483
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;
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;
00524 public ShaderFlags Flags;
00525 }
00526
00531 public class ResourceCache
00532 {
00533 #region Creation
00534 private ResourceCache() { }
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();
00546 protected Hashtable effectCache = new Hashtable();
00547 protected Hashtable fontCache = new Hashtable();
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
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
00573 return textureCache[ct] as Texture;
00574 }
00575 }
00576
00577
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
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
00614 return textureCache[ct] as CubeTexture;
00615 }
00616 }
00617
00618
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
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
00656 return textureCache[ct] as VolumeTexture;
00657 }
00658 }
00659
00660
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
00682 foreach (CachedEffect ce in effectCache.Keys)
00683 {
00684 if ((string.Compare(ce.Source, filename, true) == 0) &&
00685 ce.Flags == flags)
00686 {
00687
00688 return effectCache[ce] as Effect;
00689 }
00690 }
00691
00692
00693 Effect e = Effect.FromFile(device, filename, defines, includeFile, null, flags, effectPool);
00694
00695 CachedEffect entry = new CachedEffect();
00696 entry.Flags = flags;
00697 entry.Source = filename;
00698 effectCache.Add(entry, e);
00699
00700
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
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
00722 return CreateFont(device, desc);
00723 }
00725 public Font CreateFont(Device device, FontDescription desc)
00726 {
00727
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
00742 return fontCache[fd] as Font;
00743 }
00744 }
00745
00746
00747 Font f = new Font(device, desc);
00748
00749 fontCache.Add(desc, f);
00750
00751
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
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
00784 foreach (CachedTexture ct in textureCache.Keys)
00785 {
00786 if (ct.Pool == Pool.Default)
00787 {
00788
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
00807 foreach (Font f in fontCache.Values)
00808 f.Dispose();
00809
00810
00811 foreach (Effect e in effectCache.Values)
00812 e.Dispose();
00813
00814
00815 foreach (BaseTexture texture in textureCache.Values)
00816 {
00817 if (texture != null)
00818 texture.Dispose();
00819 }
00820
00821
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;
00839 protected Matrix translation;
00840 protected Matrix translationDelta;
00841
00842 protected int width;
00843 protected int height;
00844 protected Vector2 center;
00845 protected float radius;
00846 protected float radiusTranslation;
00847
00848 protected Quaternion downQuat;
00849 protected Quaternion nowQuat;
00850 protected bool isDragging;
00851
00852 protected System.Drawing.Point lastMousePosition;
00853 protected Vector3 downPt;
00854 protected Vector3 currentPt;
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
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);
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
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
00991 NativeMethods.SetCapture(hWnd);
00992 OnBegin(mouseX, mouseY);
00993 return true;
00994 case NativeMethods.WindowMessage.LeftButtonUp:
00995
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
01005 NativeMethods.SetCapture(hWnd);
01006
01007 lastMousePosition = new System.Drawing.Point(mouseX, mouseY);
01008 return true;
01009
01010 case NativeMethods.WindowMessage.RightButtonUp:
01011 case NativeMethods.WindowMessage.MiddleButtonUp:
01012
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
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
01038 {
01039 translationDelta = Matrix.Translation(0.0f, 0.0f, 5 * deltaY);
01040 translation *= translationDelta;
01041 }
01042
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;
01105 case System.Windows.Forms.Keys.Next: return CameraKeys.MoveDown;
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
01124 return (CameraKeys)byte.MaxValue;
01125 }
01126
01127
01128 #region Instance Data
01129 protected Matrix viewMatrix;
01130 protected Matrix projMatrix;
01131
01132 protected System.Drawing.Point lastMousePosition;
01133 protected bool isMouseLButtonDown;
01134 protected bool isMouseMButtonDown;
01135 protected bool isMouseRButtonDown;
01136 protected int currentButtonMask;
01137 protected int mouseWheelDelta;
01138 protected Vector2 mouseDelta;
01139 protected float framesToSmoothMouseData;
01140
01141 protected Vector3 defaultEye;
01142 protected Vector3 defaultLookAt;
01143 protected Vector3 eye;
01144 protected Vector3 lookAt;
01145 protected float cameraYawAngle;
01146 protected float cameraPitchAngle;
01147
01148 protected System.Drawing.Rectangle dragRectangle;
01149 protected Vector3 velocity;
01150 protected bool isMovementDrag;
01151 protected Vector3 velocityDrag;
01152 protected float dragTimer;
01153 protected float totalDragTimeToZero;
01154 protected Vector2 rotationVelocity;
01155
01156 protected float fieldOfView;
01157 protected float aspectRatio;
01158 protected float nearPlane;
01159 protected float farPlane;
01160
01161 protected float rotationScaler;
01162 protected float moveScaler;
01163
01164 protected bool isInvertPitch;
01165 protected bool isEnablePositionMovement;
01166 protected bool isEnableYAxisMovement;
01167
01168 protected bool isClipToBoundary;
01169 protected Vector3 minBoundary;
01170 protected Vector3 maxBoundary;
01171
01172 protected bool isResetCursorAfterMove;
01173
01174
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
01211 keys = new bool[(int)CameraKeys.MaxKeys];
01212
01213
01214 eye = Vector3.Empty;
01215 lookAt = new Vector3(0.0f, 0.0f, 1.0f);
01216
01217
01218 SetViewParameters(eye, lookAt);
01219
01220
01221 SetProjectionParameters((float)Math.PI / 4, 1.0f, 1.0f, 1000.0f);
01222
01223
01224 lastMousePosition = System.Windows.Forms.Cursor.Position;
01225 isMouseLButtonDown = false;
01226 isMouseRButtonDown = false;
01227 isMouseMButtonDown = false;
01228 mouseWheelDelta = 0;
01229 currentButtonMask = 0;
01230
01231
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
01263 case NativeMethods.WindowMessage.KeyDown:
01264 CameraKeys mappedKeyDown = MapKey(wParam);
01265 if (mappedKeyDown != (CameraKeys)byte.MaxValue)
01266 {
01267
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
01276 keys[(int)mappedKeyUp] = false;
01277 }
01278 break;
01279
01280
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
01289 System.Drawing.Point cursor = new System.Drawing.Point(
01290 NativeMethods.LoWord((uint)lParam.ToInt32()),
01291 NativeMethods.HiWord((uint)lParam.ToInt32()));
01292
01293
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
01314
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
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
01330 if (!isMouseLButtonDown && !isMouseMButtonDown && !isMouseRButtonDown)
01331 {
01332 NativeMethods.ReleaseCapture();
01333 }
01334 }
01335 break;
01336
01337
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
01361 defaultEye = eye = eyePt;
01362 defaultLookAt = lookAt = lookAtPt;
01363
01364
01365 viewMatrix = Matrix.LookAtLeftHanded(eye, lookAt, UpDirection);
01366
01367
01368 Matrix inverseView = Matrix.Invert(viewMatrix);
01369
01370
01371
01372
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
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
01399 System.Drawing.Point current = System.Windows.Forms.Cursor.Position;
01400
01401
01402 System.Drawing.Point delta = new System.Drawing.Point(current.X - lastMousePosition.X,
01403 current.Y - lastMousePosition.Y);
01404
01405
01406 lastMousePosition = current;
01407
01408 if (isResetCursorAfterMove)
01409 {
01410
01411
01412
01413
01414
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
01423
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
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
01459
01460 accel.Normalize();
01461
01462 accel *= moveScaler;
01463
01464 if (isMovementDrag)
01465 {
01466
01467 if (accel.LengthSquared() > 0)
01468 {
01469
01470
01471
01472
01473 velocity = accel;
01474 dragTimer = totalDragTimeToZero;
01475 velocityDrag = accel * (1 / dragTimer);
01476 }
01477 else
01478 {
01479
01480 if (dragTimer > 0)
01481 {
01482 velocity -= (velocityDrag * elapsedTime);
01483 dragTimer -= elapsedTime;
01484 }
01485 else
01486 {
01487
01488 velocity = Vector3.Empty;
01489 }
01490 }
01491 }
01492 else
01493 {
01494
01495 velocity = accel;
01496 }
01497 }
01498
01502 protected void ConstrainToBoundary(ref Vector3 v)
01503 {
01504
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
01525 protected int activeButtonMask = (int)(MouseButtonMask.Left | MouseButtonMask.Middle | MouseButtonMask.Right);
01526
01527 protected Matrix cameraWorld;
01528
01532 public override void FrameMove(float elapsedTime)
01533 {
01534
01535 if (keys[(int)CameraKeys.Reset])
01536 Reset();
01537
01538
01539 if ((activeButtonMask & currentButtonMask) != 0)
01540 UpdateMouseDelta(elapsedTime);
01541
01542
01543 UpdateVelocity(elapsedTime);
01544
01545
01546 Vector3 posDelta = velocity * elapsedTime;
01547
01548
01549 if ((activeButtonMask & currentButtonMask) != 0)
01550 {
01551
01552 float yawDelta = rotationVelocity.X;
01553 float pitchDelta = rotationVelocity.Y;
01554
01555
01556 if (isInvertPitch)
01557 pitchDelta = -pitchDelta;
01558
01559 cameraPitchAngle += pitchDelta;
01560 cameraYawAngle += yawDelta;
01561
01562
01563 cameraPitchAngle = Math.Max(-(float)Math.PI / 2.0f, cameraPitchAngle);
01564 cameraPitchAngle = Math.Min(+(float)Math.PI / 2.0f, cameraPitchAngle);
01565 }
01566
01567
01568 Matrix cameraRotation = Matrix.RotationYawPitchRoll(cameraYawAngle, cameraPitchAngle, 0);
01569
01570
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
01577 Vector3 posDeltaWorld = Vector3.TransformCoordinate(posDelta, cameraRotation);
01578 if (!isEnableYAxisMovement)
01579 posDeltaWorld.Y = 0.0f;
01580
01581
01582 eye += posDeltaWorld;
01583 if (isClipToBoundary)
01584 ConstrainToBoundary(ref eye);
01585
01586
01587 lookAt = eye + worldAhead;
01588
01589
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;
01615 protected Matrix lastCameraRotation;
01616 protected Matrix modelRotation;
01617 protected Matrix world;
01618
01619 protected int rotateModelButtonMask;
01620 protected int zoomButtonMask;
01621 protected int rotateCameraButtonMask;
01622
01623 protected bool isPitchLimited;
01624 protected float radius;
01625 protected float defaultRadius;
01626 protected float minRadius;
01627 protected float maxRadius;
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
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
01690 if (keys[(int)CameraKeys.Reset])
01691 Reset();
01692
01693
01694 if (currentButtonMask != 0)
01695 UpdateMouseDelta(elapsedTime);
01696
01697
01698 UpdateVelocity(elapsedTime);
01699
01700
01701 Vector3 posDelta = velocity * elapsedTime;
01702
01703
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
01711 Matrix cameraRotation = Matrix.Invert(viewArcball.RotationMatrix);
01712
01713
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
01720 Vector3 posDeltaWorld = Vector3.TransformCoordinate(posDelta, cameraRotation);
01721
01722
01723 lookAt += posDeltaWorld;
01724 if (isClipToBoundary)
01725 ConstrainToBoundary(ref lookAt);
01726
01727
01728 eye = lookAt - worldAhead * radius;
01729
01730
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
01737
01738 Matrix localModel = worldArcball.RotationMatrix;
01739 modelRotation *= viewMatrix * modelLastRotInv * localModel * invView;
01740 if (viewArcball.IsBeingDragged && attachCameraToModel && !keys[(int)CameraKeys.ControlDown])
01741 {
01742
01743 Matrix cameraRotInv = Matrix.Invert(lastCameraRotation);
01744 Matrix delta = cameraRotInv * cameraRotation;
01745 modelRotation *= delta;
01746 }
01747 lastCameraRotation = cameraRotation;
01748 lastModelRotation = localModel;
01749
01750
01751
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
01767 modelRotation.M41 = lookAt.X;
01768 modelRotation.M42 = lookAt.Y;
01769 modelRotation.M43 = lookAt.Z;
01770
01771
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
01797 base.SetViewParameters(eyePt, lookAtPt);
01798
01799
01800 Matrix rotation = Matrix.LookAtLeftHanded(eyePt, lookAtPt, UpDirection);
01801 viewArcball.CurrentQuaternion = Quaternion.RotationMatrix(rotation);
01802
01803
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
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
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
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
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;
01869 private Sprite textSprite;
01870 private int color;
01871 private System.Drawing.Point point;
01872 private int lineHeight;
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
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
01900 point.Y += lineHeight;
01901 }
01902
01906 public void DrawStringLine(string text, params object[] args)
01907 {
01908
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
01955 private const string CurrentFolder = @".\";
01956 private const string MediaPath = @"Media\";
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968 private static readonly string[] TypicalFolders = new string[] { CurrentFolder, @"..\",
01969 @"..\..\", @"{0}\", @"{0}\..\", @"{0}\..\..\", @"{0}\..\{1}\", @"{0}\..\..\{1}\" };
01970 private Utility() { }
01971
01978 public static string FindMediaFile(string filename)
01979 {
01980
01981 System.Reflection.Assembly executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
01982
01983
01984 string exeName = System.IO.Path.GetFileNameWithoutExtension(executingAssembly.Location);
01985
01986 string exeFolder = System.IO.Path.GetDirectoryName(executingAssembly.Location);
01987
01988 string filePath;
01989
01990 if (SearchTypicalFolders(filename, exeFolder, exeName, out filePath))
01991 {
01992 return filePath;
01993 }
01994
01995
01996
01997 if (SearchTypicalFolders(filename + MediaPath, exeFolder, exeName, out filePath))
01998 {
01999 return filePath;
02000 }
02001
02002
02003 if (SearchParentFolders(filename, CurrentFolder, "", out filePath))
02004 {
02005 return filePath;
02006 }
02007
02008 if (SearchParentFolders(filename, exeFolder, exeName, out filePath))
02009 {
02010 return filePath;
02011 }
02012
02013
02014 if (SearchParentFolders(filename, CurrentFolder, MediaPath, out filePath))
02015 {
02016 return filePath;
02017 }
02018
02019 if (SearchParentFolders(filename, exeFolder, AppendDirectorySeparator(exeName) + MediaPath, out filePath))
02020 {
02021 return filePath;
02022 }
02023
02024
02025
02026 if (exeName.ToLower().StartsWith("csw"))
02027 {
02028
02029 string newExeName = exeName.Substring(3, exeName.Length - 3);
02030 if (SearchParentFolders(filename, exeFolder, newExeName, out filePath))
02031 {
02032 return filePath;
02033 }
02034
02035 if (SearchParentFolders(filename, exeFolder, AppendDirectorySeparator(newExeName) + MediaPath, out filePath))
02036 {
02037 return filePath;
02038 }
02039 }
02040
02041
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
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
02075 continue;
02076 }
02077 }
02078
02079
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
02095 fullPath = string.Empty;
02096 try
02097 {
02098
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
02109 return false;
02110 }
02111
02112
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
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
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
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 { }
02196 if ((skipWarning == 0) && (firstTime))
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
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
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
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
02253 DirectionWidget.device = device;
02254
02255
02256 string path = Utility.FindMediaFile("UI\\DXUTShared.fx");
02257
02258
02259
02260
02261 effect = Effect.FromFile(device, path, null, null, null, ShaderFlags.NotCloneable, null);
02262
02263
02264
02265
02266
02267 path = Utility.FindMediaFile("UI\\arrow.x");
02268 mesh = new Mesh(device, path, MeshFlags.Managed, null, null, null);
02269
02270
02271
02272
02273
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
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
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
02367
02368 rotation *= (viewMatrix * lastRotationInv * rot * invView);
02369
02370
02371
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
02387 currentDir = Vector3.TransformNormal(defaultDir, rotation);
02388 }
02389
02391 public unsafe void OnRender(ColorValue color, Matrix view, Matrix proj, Vector3 eye)
02392 {
02393
02394 viewMatrix = view;
02395
02396
02397 effect.Technique = "RenderWith1LightNoTexture";
02398 effect.SetValue("g_MaterialDiffuseColor", color);
02399 Vector3 eyePt = Vector3.Normalize(eye);
02400
02401
02402 effect.SetValue("g_LightDir", &eyePt, sizeof(Vector3));
02403
02404
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
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 }