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, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None,
00555 Format.Unknown, Pool.Managed, (Filter)D3DX.Default, (Filter)D3DX.Default, 0);
00556 }
00558 public Texture CreateTextureFromFileEx(Device device, string filename, int w, int h, int mip, Usage usage, Format fmt, Pool pool, Filter filter, Filter mipfilter, int colorkey)
00559 {
00560
00561 foreach(CachedTexture ct in textureCache.Keys)
00562 {
00563 if ( (string.Compare(ct.Source, filename, true) == 0) &&
00564 ct.Width == w &&
00565 ct.Height == h &&
00566 ct.MipLevels == mip &&
00567 ct.Usage == usage &&
00568 ct.Format == fmt &&
00569 ct.Pool == pool &&
00570 ct.Type == ResourceType.Textures)
00571 {
00572
00573 return textureCache[ct] as Texture;
00574 }
00575 }
00576
00577
00578 Texture t = TextureLoader.FromFile(device, filename, w, h, mip, usage, fmt, pool, filter, mipfilter, colorkey);
00579 CachedTexture entry = new CachedTexture();
00580 entry.Source = filename;
00581 entry.Width = w;
00582 entry.Height = h;
00583 entry.MipLevels = mip;
00584 entry.Usage = usage;
00585 entry.Format = fmt;
00586 entry.Pool = pool;
00587 entry.Type = ResourceType.Textures;
00588
00589 textureCache.Add(entry, t);
00590
00591 return t;
00592 }
00594 public CubeTexture CreateCubeTextureFromFile(Device device, string filename)
00595 {
00596 return CreateCubeTextureFromFileEx(device, filename, D3DX.Default, D3DX.Default, Usage.None,
00597 Format.Unknown, Pool.Managed, (Filter)D3DX.Default, (Filter)D3DX.Default, 0);
00598 }
00600 public CubeTexture CreateCubeTextureFromFileEx(Device device, string filename, int size, int mip, Usage usage, Format fmt, Pool pool, Filter filter, Filter mipfilter, int colorkey)
00601 {
00602
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 = TextureLoader.FromCubeFile(device, filename, size, mip, usage, fmt, pool, filter, mipfilter, colorkey);
00620 CachedTexture entry = new CachedTexture();
00621 entry.Source = filename;
00622 entry.Width = size;
00623 entry.MipLevels = mip;
00624 entry.Usage = usage;
00625 entry.Format = fmt;
00626 entry.Pool = pool;
00627 entry.Type = ResourceType.CubeTexture;
00628
00629 textureCache.Add(entry, t);
00630
00631 return t;
00632 }
00634 public VolumeTexture CreateVolumeTextureFromFile(Device device, string filename)
00635 {
00636 return CreateVolumeTextureFromFileEx(device, filename, D3DX.Default, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None,
00637 Format.Unknown, Pool.Managed, (Filter)D3DX.Default, (Filter)D3DX.Default, 0);
00638 }
00640 public VolumeTexture CreateVolumeTextureFromFileEx(Device device, string filename, int w, int h, int d, int mip, Usage usage, Format fmt, Pool pool, Filter filter, Filter mipfilter, int colorkey)
00641 {
00642
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 = TextureLoader.FromVolumeFile(device, filename, w, h, d, mip, usage, fmt, pool, filter, mipfilter, colorkey);
00662 CachedTexture entry = new CachedTexture();
00663 entry.Source = filename;
00664 entry.Width = w;
00665 entry.Height = h;
00666 entry.Depth = d;
00667 entry.MipLevels = mip;
00668 entry.Usage = usage;
00669 entry.Format = fmt;
00670 entry.Pool = pool;
00671 entry.Type = ResourceType.VolumeTexture;
00672
00673 textureCache.Add(entry, t);
00674
00675 return t;
00676 }
00677
00679 public Effect CreateEffectFromFile(Device device, string filename, Macro[] defines, Include includeFile, ShaderFlags flags, EffectPool effectPool, out string errors)
00680 {
00681
00682 errors = string.Empty;
00683
00684 foreach(CachedEffect ce in effectCache.Keys)
00685 {
00686 if ( (string.Compare(ce.Source, filename, true) == 0) &&
00687 ce.Flags == flags)
00688 {
00689
00690 return effectCache[ce] as Effect;
00691 }
00692 }
00693
00694
00695 Effect e = Effect.FromFile(device, filename, defines, includeFile, null, flags, effectPool, out errors);
00696
00697 CachedEffect entry = new CachedEffect();
00698 entry.Flags = flags;
00699 entry.Source = filename;
00700 effectCache.Add(entry, e);
00701
00702
00703 return e;
00704 }
00705
00707 public Effect CreateEffectFromFile(Device device, string filename, Macro[] defines, Include includeFile, ShaderFlags flags, EffectPool effectPool)
00708 {
00709 string temp; return CreateEffectFromFile(device, filename, defines, includeFile, flags, effectPool, out temp);
00710 }
00712 public Font CreateFont(Device device, int height, int width, FontWeight weight, int mip, bool italic,
00713 CharacterSet charSet, Precision outputPrecision, FontQuality quality, PitchAndFamily pandf, string fontName)
00714 {
00715
00716 FontDescription desc = new FontDescription();
00717 desc.Height = height;
00718 desc.Width = width;
00719 desc.Weight = weight;
00720 desc.MipLevels = mip;
00721 desc.IsItalic = italic;
00722 desc.CharSet = charSet;
00723 desc.OutputPrecision = outputPrecision;
00724 desc.Quality = quality;
00725 desc.PitchAndFamily = pandf;
00726 desc.FaceName = fontName;
00727
00728
00729 return CreateFont(device, desc);
00730 }
00732 public Font CreateFont(Device device, FontDescription desc)
00733 {
00734
00735 foreach(FontDescription fd in fontCache.Keys)
00736 {
00737 if ( (string.Compare(fd.FaceName, desc.FaceName, true) == 0) &&
00738 fd.CharSet == desc.CharSet &&
00739 fd.Height == desc.Height &&
00740 fd.IsItalic == desc.IsItalic &&
00741 fd.MipLevels == desc.MipLevels &&
00742 fd.OutputPrecision == desc.OutputPrecision &&
00743 fd.PitchAndFamily == desc.PitchAndFamily &&
00744 fd.Quality == desc.Quality &&
00745 fd.Weight == desc.Weight &&
00746 fd.Width == desc.Width)
00747 {
00748
00749 return fontCache[fd] as Font;
00750 }
00751 }
00752
00753
00754 Font f = new Font(device, desc);
00755
00756 fontCache.Add(desc, f);
00757
00758
00759 return f;
00760 }
00761
00762 #endregion
00763
00764 #region Device event callbacks
00768 public void OnCreateDevice(Device device) {} // Nothing to do on device create
00772 public void OnResetDevice(Device device)
00773 {
00774
00775 foreach(Font f in fontCache.Values)
00776 f.OnResetDevice();
00777 foreach(Effect e in effectCache.Values)
00778 e.OnResetDevice();
00779 }
00783 public void OnLostDevice()
00784 {
00785 foreach(Font f in fontCache.Values)
00786 f.OnLostDevice();
00787 foreach(Effect e in effectCache.Values)
00788 e.OnLostDevice();
00789
00790
00791 foreach(CachedTexture ct in textureCache.Keys)
00792 {
00793 if (ct.Pool == Pool.Default)
00794 {
00795
00796 switch(ct.Type)
00797 {
00798 case ResourceType.Textures:
00799 (textureCache[ct] as Texture).Dispose(); break;
00800 case ResourceType.CubeTexture:
00801 (textureCache[ct] as CubeTexture).Dispose();break;
00802 case ResourceType.VolumeTexture:
00803 (textureCache[ct] as VolumeTexture).Dispose();break;
00804 }
00805 }
00806 }
00807 }
00811 public void OnDestroyDevice()
00812 {
00813
00814 foreach(Font f in fontCache.Values)
00815 f.Dispose();
00816
00817
00818 foreach(Effect e in effectCache.Values)
00819 e.Dispose();
00820
00821
00822 foreach(BaseTexture texture in textureCache.Values)
00823 {
00824 if (texture != null)
00825 texture.Dispose();
00826 }
00827
00828
00829 textureCache.Clear();
00830 fontCache.Clear();
00831 effectCache.Clear();
00832 }
00833
00834 #endregion
00835 }
00836 #endregion
00837
00838 #region Arcball
00842 public class ArcBall
00843 {
00844 #region Instance Data
00845 protected Matrix rotation;
00846 protected Matrix translation;
00847 protected Matrix translationDelta;
00848
00849 protected int width;
00850 protected int height;
00851 protected Vector2 center;
00852 protected float radius;
00853 protected float radiusTranslation;
00854
00855 protected Quaternion downQuat;
00856 protected Quaternion nowQuat;
00857 protected bool isDragging;
00858
00859 protected System.Drawing.Point lastMousePosition;
00860 protected Vector3 downPt;
00861 protected Vector3 currentPt;
00862 #endregion
00863
00864 #region Simple Properties
00866 public Matrix RotationMatrix { get { return rotation = Matrix.RotationQuaternion(nowQuat); } }
00868 public Matrix TranslationMatrix { get { return translation; } }
00870 public Matrix TranslationDeltaMatrix { get { return translationDelta; } }
00872 public bool IsBeingDragged { get { return isDragging; } }
00874 public Quaternion CurrentQuaternion { get { return nowQuat; } set { nowQuat = value; } }
00875 #endregion
00876
00877
00878
00882 public ArcBall()
00883 {
00884 Reset();
00885 downPt = Vector3.Empty;
00886 currentPt = Vector3.Empty;
00887
00888 System.Windows.Forms.Form active = System.Windows.Forms.Form.ActiveForm;
00889 if (active != null)
00890 {
00891 System.Drawing.Rectangle rect = active.ClientRectangle;
00892 SetWindow(rect.Width, rect.Height);
00893 }
00894 }
00895
00899 public void Reset()
00900 {
00901 downQuat = Quaternion.Identity;
00902 nowQuat = Quaternion.Identity;
00903 rotation = Matrix.Identity;
00904 translation = Matrix.Identity;
00905 translationDelta = Matrix.Identity;
00906 isDragging = false;
00907 radius = 1.0f;
00908 radiusTranslation = 1.0f;
00909 }
00910
00914 public Vector3 ScreenToVector(float screenPointX, float screenPointY)
00915 {
00916 float x = -(screenPointX - width / 2.0f) / (radius * width/2.0f);
00917 float y = (screenPointY - height / 2.0f) / (radius * height/2.0f);
00918 float z = 0.0f;
00919 float mag = (x*x) + (y*y);
00920
00921 if (mag > 1.0f)
00922 {
00923 float scale = 1.0f / (float)Math.Sqrt(mag);
00924 x *= scale;
00925 y *= scale;
00926 }
00927 else
00928 z = (float)Math.Sqrt(1.0f - mag);
00929
00930 return new Vector3(x,y,z);
00931 }
00932
00936 public void SetWindow(int w, int h, float r)
00937 {
00938 width = w; height = h; radius = r;
00939 center = new Vector2(w / 2.0f, h / 2.0f);
00940 }
00941 public void SetWindow(int w, int h)
00942 {
00943 SetWindow(w,h,0.9f);
00944 }
00945
00949 public static Quaternion QuaternionFromBallPoints(Vector3 from, Vector3 to)
00950 {
00951 float dot = Vector3.Dot(from, to);
00952 Vector3 part = Vector3.Cross(from, to);
00953 return new Quaternion(part.X, part.Y, part.Z, dot);
00954 }
00955
00959 public void OnBegin(int x, int y)
00960 {
00961 isDragging = true;
00962 downQuat = nowQuat;
00963 downPt = ScreenToVector((float)x, (float)y);
00964 }
00968 public void OnMove(int x, int y)
00969 {
00970 if (isDragging)
00971 {
00972 currentPt = ScreenToVector((float)x, (float)y);
00973 nowQuat = downQuat * QuaternionFromBallPoints(downPt, currentPt);
00974 }
00975 }
00979 public void OnEnd()
00980 {
00981 isDragging = false;
00982 }
00983
00987 public bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
00988 {
00989
00990 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
00991 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
00992
00993 switch(msg)
00994 {
00995 case NativeMethods.WindowMessage.LeftButtonDown:
00996 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
00997
00998 NativeMethods.SetCapture(hWnd);
00999 OnBegin(mouseX, mouseY);
01000 return true;
01001 case NativeMethods.WindowMessage.LeftButtonUp:
01002
01003 NativeMethods.ReleaseCapture();
01004 OnEnd();
01005 return true;
01006
01007 case NativeMethods.WindowMessage.RightButtonDown:
01008 case NativeMethods.WindowMessage.RightButtonDoubleClick:
01009 case NativeMethods.WindowMessage.MiddleButtonDown:
01010 case NativeMethods.WindowMessage.MiddleButtonDoubleClick:
01011
01012 NativeMethods.SetCapture(hWnd);
01013
01014 lastMousePosition = new System.Drawing.Point(mouseX, mouseY);
01015 return true;
01016
01017 case NativeMethods.WindowMessage.RightButtonUp:
01018 case NativeMethods.WindowMessage.MiddleButtonUp:
01019
01020 NativeMethods.ReleaseCapture();
01021 return true;
01022
01023 case NativeMethods.WindowMessage.MouseMove:
01024 short buttonState = NativeMethods.LoWord((uint)wParam.ToInt32());
01025 bool leftButton = ((buttonState & (short)NativeMethods.MouseButtons.Left) != 0);
01026 bool rightButton = ((buttonState & (short)NativeMethods.MouseButtons.Right) != 0);
01027 bool middleButton = ((buttonState & (short)NativeMethods.MouseButtons.Middle) != 0);
01028
01029 if (leftButton)
01030 {
01031 OnMove(mouseX, mouseY);
01032 }
01033 else if (rightButton || middleButton)
01034 {
01035
01036 float deltaX = (lastMousePosition.X - mouseX) * radiusTranslation / width;
01037 float deltaY = (lastMousePosition.Y - mouseY) * radiusTranslation / height;
01038
01039 if (rightButton)
01040 {
01041 translationDelta = Matrix.Translation(-2*deltaX,2*deltaY, 0.0f);
01042 translation *= translationDelta;
01043 }
01044 else
01045 {
01046 translationDelta = Matrix.Translation(0.0f, 0.0f, 5*deltaY);
01047 translation *= translationDelta;
01048 }
01049
01050 lastMousePosition = new System.Drawing.Point(mouseX, mouseY);
01051 }
01052 return true;
01053 }
01054
01055 return false;
01056 }
01057 }
01058 #endregion
01059
01060 #region Cameras
01064 public enum CameraKeys : byte
01065 {
01066 StrafeLeft,
01067 StrafeRight,
01068 MoveForward,
01069 MoveBackward,
01070 MoveUp,
01071 MoveDown,
01072 Reset,
01073 ControlDown,
01074 MaxKeys,
01075 Unknown=0xff
01076 }
01077
01081 [Flags]
01082 public enum MouseButtonMask : byte
01083 {
01084 None = 0,
01085 Left = 0x01,
01086 Middle = 0x02,
01087 Right = 0x04,
01088 Wheel = 0x08,
01089 }
01090
01096 public abstract class Camera
01097 {
01101 protected static CameraKeys MapKey(IntPtr param)
01102 {
01103 System.Windows.Forms.Keys key = (System.Windows.Forms.Keys)param.ToInt32();
01104 switch(key)
01105 {
01106 case System.Windows.Forms.Keys.ControlKey: return CameraKeys.ControlDown;
01107 case System.Windows.Forms.Keys.Left: return CameraKeys.StrafeLeft;
01108 case System.Windows.Forms.Keys.Right: return CameraKeys.StrafeRight;
01109 case System.Windows.Forms.Keys.Up: return CameraKeys.MoveForward;
01110 case System.Windows.Forms.Keys.Down: return CameraKeys.MoveBackward;
01111 case System.Windows.Forms.Keys.Prior: return CameraKeys.MoveUp;
01112 case System.Windows.Forms.Keys.Next: return CameraKeys.MoveDown;
01113
01114 case System.Windows.Forms.Keys.A: return CameraKeys.StrafeLeft;
01115 case System.Windows.Forms.Keys.D: return CameraKeys.StrafeRight;
01116 case System.Windows.Forms.Keys.W: return CameraKeys.MoveForward;
01117 case System.Windows.Forms.Keys.S: return CameraKeys.MoveBackward;
01118 case System.Windows.Forms.Keys.Q: return CameraKeys.MoveUp;
01119 case System.Windows.Forms.Keys.E: return CameraKeys.MoveDown;
01120
01121 case System.Windows.Forms.Keys.NumPad4: return CameraKeys.StrafeLeft;
01122 case System.Windows.Forms.Keys.NumPad6: return CameraKeys.StrafeRight;
01123 case System.Windows.Forms.Keys.NumPad8: return CameraKeys.MoveForward;
01124 case System.Windows.Forms.Keys.NumPad2: return CameraKeys.MoveBackward;
01125 case System.Windows.Forms.Keys.NumPad9: return CameraKeys.MoveUp;
01126 case System.Windows.Forms.Keys.NumPad3: return CameraKeys.MoveDown;
01127
01128 case System.Windows.Forms.Keys.Home: return CameraKeys.Reset;
01129 }
01130
01131 return (CameraKeys)byte.MaxValue;
01132 }
01133
01134
01135 #region Instance Data
01136 protected Matrix viewMatrix;
01137 protected Matrix projMatrix;
01138
01139 protected System.Drawing.Point lastMousePosition;
01140 protected bool isMouseLButtonDown;
01141 protected bool isMouseMButtonDown;
01142 protected bool isMouseRButtonDown;
01143 protected int currentButtonMask;
01144 protected int mouseWheelDelta;
01145 protected Vector2 mouseDelta;
01146 protected float framesToSmoothMouseData;
01147
01148 protected Vector3 defaultEye;
01149 protected Vector3 defaultLookAt;
01150 protected Vector3 eye;
01151 protected Vector3 lookAt;
01152 protected float cameraYawAngle;
01153 protected float cameraPitchAngle;
01154
01155 protected System.Drawing.Rectangle dragRectangle;
01156 protected Vector3 velocity;
01157 protected bool isMovementDrag;
01158 protected Vector3 velocityDrag;
01159 protected float dragTimer;
01160 protected float totalDragTimeToZero;
01161 protected Vector2 rotationVelocity;
01162
01163 protected float fieldOfView;
01164 protected float aspectRatio;
01165 protected float nearPlane;
01166 protected float farPlane;
01167
01168 protected float rotationScaler;
01169 protected float moveScaler;
01170
01171 protected bool isInvertPitch;
01172 protected bool isEnablePositionMovement;
01173 protected bool isEnableYAxisMovement;
01174
01175 protected bool isClipToBoundary;
01176 protected Vector3 minBoundary;
01177 protected Vector3 maxBoundary;
01178
01179 protected bool isResetCursorAfterMove;
01180
01181
01182 protected bool[] keys;
01183 public static readonly Vector3 UpDirection = new Vector3(0,1,0);
01184 #endregion
01185
01186 #region Simple Properties
01188 public bool IsBeingDragged { get { return (isMouseLButtonDown || isMouseMButtonDown || isMouseRButtonDown); } }
01190 public bool IsMouseLeftButtonDown { get { return isMouseLButtonDown; } }
01192 public bool IsMouseRightButtonDown { get { return isMouseRButtonDown; } }
01194 public bool IsMouseMiddleButtonDown { get { return isMouseMButtonDown; } }
01196 public Matrix ViewMatrix { get { return viewMatrix; } }
01198 public Matrix ProjectionMatrix { get { return projMatrix; } }
01200 public Vector3 EyeLocation { get { return eye; } }
01202 public Vector3 LookAtPoint { get { return lookAt; } }
01204 public bool IsPositionMovementEnabled { get {return isEnablePositionMovement; } set { isEnablePositionMovement = value; } }
01205 #endregion
01206
01210 public abstract void FrameMove(float elapsedTime);
01211
01215 protected Camera()
01216 {
01217
01218 keys = new bool[(int)CameraKeys.MaxKeys];
01219
01220
01221 eye = Vector3.Empty;
01222 lookAt = new Vector3(0.0f, 0.0f, 1.0f);
01223
01224
01225 SetViewParameters(eye, lookAt);
01226
01227
01228 SetProjectionParameters((float)Math.PI / 4, 1.0f, 1.0f, 1000.0f);
01229
01230
01231 lastMousePosition = System.Windows.Forms.Cursor.Position;
01232 isMouseLButtonDown = false;
01233 isMouseRButtonDown = false;
01234 isMouseMButtonDown = false;
01235 mouseWheelDelta = 0;
01236 currentButtonMask = 0;
01237
01238
01239 cameraYawAngle = 0.0f;
01240 cameraPitchAngle = 0.0f;
01241
01242 dragRectangle = new System.Drawing.Rectangle(0, 0, int.MaxValue, int.MaxValue);
01243 velocity = Vector3.Empty;
01244 isMovementDrag = false;
01245 velocityDrag = Vector3.Empty;
01246 dragTimer = 0.0f;
01247 totalDragTimeToZero = 0.25f;
01248 rotationVelocity = Vector2.Empty;
01249 rotationScaler = 0.1f;
01250 moveScaler = 5.0f;
01251 isInvertPitch = false;
01252 isEnableYAxisMovement = true;
01253 isEnablePositionMovement = true;
01254 mouseDelta = Vector2.Empty;
01255 framesToSmoothMouseData = 2.0f;
01256 isClipToBoundary = false;
01257 minBoundary = new Vector3(-1.0f,-1.0f, -1.0f);
01258 maxBoundary = new Vector3(1,1,1);
01259 isResetCursorAfterMove = false;
01260 }
01261
01265 public virtual bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
01266 {
01267 switch(msg)
01268 {
01269
01270 case NativeMethods.WindowMessage.KeyDown:
01271 CameraKeys mappedKeyDown = MapKey(wParam);
01272 if (mappedKeyDown != (CameraKeys)byte.MaxValue)
01273 {
01274
01275 keys[(int)mappedKeyDown] = true;
01276 }
01277 break;
01278 case NativeMethods.WindowMessage.KeyUp:
01279 CameraKeys mappedKeyUp = MapKey(wParam);
01280 if (mappedKeyUp != (CameraKeys)byte.MaxValue)
01281 {
01282
01283 keys[(int)mappedKeyUp] = false;
01284 }
01285 break;
01286
01287
01288 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
01289 case NativeMethods.WindowMessage.LeftButtonDown:
01290 case NativeMethods.WindowMessage.RightButtonDoubleClick:
01291 case NativeMethods.WindowMessage.RightButtonDown:
01292 case NativeMethods.WindowMessage.MiddleButtonDoubleClick:
01293 case NativeMethods.WindowMessage.MiddleButtonDown:
01294 {
01295
01296 System.Drawing.Point cursor = new System.Drawing.Point(
01297 NativeMethods.LoWord((uint)lParam.ToInt32()),
01298 NativeMethods.HiWord((uint)lParam.ToInt32()));
01299
01300
01301 if ( ((msg == NativeMethods.WindowMessage.LeftButtonDown) ||
01302 (msg == NativeMethods.WindowMessage.LeftButtonDoubleClick) )
01303 && dragRectangle.Contains(cursor) )
01304 {
01305 isMouseLButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Left;
01306 }
01307 if ( ((msg == NativeMethods.WindowMessage.MiddleButtonDown) ||
01308 (msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick) )
01309 && dragRectangle.Contains(cursor) )
01310 {
01311 isMouseMButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Middle;
01312 }
01313 if ( ((msg == NativeMethods.WindowMessage.RightButtonDown) ||
01314 (msg == NativeMethods.WindowMessage.RightButtonDoubleClick) )
01315 && dragRectangle.Contains(cursor) )
01316 {
01317 isMouseRButtonDown = true; currentButtonMask |= (int)MouseButtonMask.Right;
01318 }
01319
01320
01321
01322 NativeMethods.SetCapture(hWnd);
01323
01324 lastMousePosition = System.Windows.Forms.Cursor.Position;
01325 return true;
01326 }
01327 case NativeMethods.WindowMessage.LeftButtonUp:
01328 case NativeMethods.WindowMessage.RightButtonUp:
01329 case NativeMethods.WindowMessage.MiddleButtonUp:
01330 {
01331
01332 if (msg == NativeMethods.WindowMessage.LeftButtonUp) { isMouseLButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Left; }
01333 if (msg == NativeMethods.WindowMessage.RightButtonUp) { isMouseRButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Right; }
01334 if (msg == NativeMethods.WindowMessage.MiddleButtonUp) { isMouseMButtonDown = false; currentButtonMask &= ~(int)MouseButtonMask.Middle; }
01335
01336
01337 if (!isMouseLButtonDown && !isMouseMButtonDown && !isMouseRButtonDown)
01338 {
01339 NativeMethods.ReleaseCapture();
01340 }
01341 }
01342 break;
01343
01344
01345 case NativeMethods.WindowMessage.MouseWheel:
01346 mouseWheelDelta = NativeMethods.HiWord((uint)wParam.ToInt32()) / 120;
01347 break;
01348 }
01349
01350 return false;
01351 }
01352
01353
01357 public virtual void Reset()
01358 {
01359 SetViewParameters(defaultEye, defaultLookAt);
01360 }
01361
01365 public unsafe virtual void SetViewParameters(Vector3 eyePt, Vector3 lookAtPt)
01366 {
01367
01368 defaultEye = eye = eyePt;
01369 defaultLookAt = lookAt = lookAtPt;
01370
01371
01372 viewMatrix = Matrix.LookAtLH(eye, lookAt, UpDirection);
01373
01374
01375 Matrix inverseView = Matrix.Invert(viewMatrix);
01376
01377
01378
01379
01380 Vector3* pZBasis = (Vector3*)&inverseView.M31;
01381 cameraYawAngle = (float)Math.Atan2(pZBasis->X, pZBasis->Z);
01382 float len = (float)Math.Sqrt(pZBasis->Z * pZBasis->Z + pZBasis->X * pZBasis->X);
01383 cameraPitchAngle = -(float)Math.Atan2(pZBasis->Y, len);
01384 }
01385
01389 public virtual void SetProjectionParameters(float fov, float aspect, float near, float far)
01390 {
01391
01392 fieldOfView = fov;
01393 aspectRatio = aspect;
01394 nearPlane = near;
01395 farPlane = far;
01396
01397 projMatrix = Matrix.PerspectiveFovLH(fov, aspect, near, far);
01398 }
01399
01403 protected void UpdateMouseDelta(float elapsedTime)
01404 {
01405
01406 System.Drawing.Point current = System.Windows.Forms.Cursor.Position;
01407
01408
01409 System.Drawing.Point delta = new System.Drawing.Point(current.X - lastMousePosition.X,
01410 current.Y - lastMousePosition.Y);
01411
01412
01413 lastMousePosition = current;
01414
01415 if (isResetCursorAfterMove)
01416 {
01417
01418
01419
01420
01421
01422 System.Windows.Forms.Screen activeScreen = System.Windows.Forms.Screen.PrimaryScreen;
01423 System.Drawing.Point center = new System.Drawing.Point(activeScreen.Bounds.Width / 2,
01424 activeScreen.Bounds.Height / 2);
01425 System.Windows.Forms.Cursor.Position = center;
01426 lastMousePosition = center;
01427 }
01428
01429
01430
01431 float percentOfNew = 1.0f / framesToSmoothMouseData;
01432 float percentOfOld = 1.0f - percentOfNew;
01433 mouseDelta.X = mouseDelta.X*percentOfNew + delta.X*percentOfNew;
01434 mouseDelta.Y = mouseDelta.Y*percentOfNew + delta.Y*percentOfNew;
01435
01436 rotationVelocity = mouseDelta * rotationScaler;
01437 }
01438
01442 protected void UpdateVelocity(float elapsedTime)
01443 {
01444 Vector3 accel = Vector3.Empty;
01445
01446 if (isEnablePositionMovement)
01447 {
01448
01449 if (keys[(int)CameraKeys.MoveForward])
01450 accel.Z += 1.0f;
01451 if (keys[(int)CameraKeys.MoveBackward])
01452 accel.Z -= 1.0f;
01453 if (isEnableYAxisMovement)
01454 {
01455 if (keys[(int)CameraKeys.MoveUp])
01456 accel.Y += 1.0f;
01457 if (keys[(int)CameraKeys.MoveDown])
01458 accel.Y -= 1.0f;
01459 }
01460 if (keys[(int)CameraKeys.StrafeRight])
01461 accel.X += 1.0f;
01462 if (keys[(int)CameraKeys.StrafeLeft])
01463 accel.X -= 1.0f;
01464 }
01465
01466
01467 accel.Normalize();
01468
01469 accel *= moveScaler;
01470
01471 if (isMovementDrag)
01472 {
01473
01474 if (accel.LengthSq() > 0)
01475 {
01476
01477
01478
01479
01480 velocity = accel;
01481 dragTimer = totalDragTimeToZero;
01482 velocityDrag = accel * (1 / dragTimer);
01483 }
01484 else
01485 {
01486
01487 if (dragTimer > 0)
01488 {
01489 velocity -= (velocityDrag * elapsedTime);
01490 dragTimer -= elapsedTime;
01491 }
01492 else
01493 {
01494
01495 velocity = Vector3.Empty;
01496 }
01497 }
01498 }
01499 else
01500 {
01501
01502 velocity = accel;
01503 }
01504 }
01505
01509 protected void ConstrainToBoundary(ref Vector3 v)
01510 {
01511
01512 v.X = Math.Max(v.X, minBoundary.X);
01513 v.Y = Math.Max(v.Y, minBoundary.Y);
01514 v.Z = Math.Max(v.Z, minBoundary.Z);
01515
01516 v.X = Math.Min(v.X, maxBoundary.X);
01517 v.Y = Math.Min(v.Y, maxBoundary.Y);
01518 v.Z = Math.Min(v.Z, maxBoundary.Z);
01519
01520 }
01521 }
01522
01529 public class FirstPersonCamera : Camera
01530 {
01531
01532 protected int activeButtonMask = (int)(MouseButtonMask.Left | MouseButtonMask.Middle | MouseButtonMask.Right);
01533
01534 protected Matrix cameraWorld;
01535
01539 public override void FrameMove(float elapsedTime)
01540 {
01541
01542 if (keys[(int)CameraKeys.Reset])
01543 Reset();
01544
01545
01546 if ((activeButtonMask & currentButtonMask) != 0)
01547 UpdateMouseDelta(elapsedTime);
01548
01549
01550 UpdateVelocity(elapsedTime);
01551
01552
01553 Vector3 posDelta = velocity * elapsedTime;
01554
01555
01556 if ((activeButtonMask & currentButtonMask) != 0)
01557 {
01558
01559 float yawDelta = rotationVelocity.X;
01560 float pitchDelta = rotationVelocity.Y;
01561
01562
01563 if (isInvertPitch)
01564 pitchDelta = -pitchDelta;
01565
01566 cameraPitchAngle += pitchDelta;
01567 cameraYawAngle += yawDelta;
01568
01569
01570 cameraPitchAngle = Math.Max(-(float)Math.PI/2.0f, cameraPitchAngle);
01571 cameraPitchAngle = Math.Min(+(float)Math.PI/2.0f, cameraPitchAngle);
01572 }
01573
01574
01575 Matrix cameraRotation = Matrix.RotationYawPitchRoll(cameraYawAngle, cameraPitchAngle, 0 );
01576
01577
01578 Vector3 localUp = new Vector3(0,1,0);
01579 Vector3 localAhead = new Vector3(0,0,1);
01580 Vector3 worldUp = Vector3.TransformCoordinate(localUp, cameraRotation);
01581 Vector3 worldAhead = Vector3.TransformCoordinate(localAhead, cameraRotation);
01582
01583
01584 Vector3 posDeltaWorld = Vector3.TransformCoordinate(posDelta, cameraRotation);
01585 if (!isEnableYAxisMovement)
01586 posDeltaWorld.Y = 0.0f;
01587
01588
01589 eye += posDeltaWorld;
01590 if (isClipToBoundary)
01591 ConstrainToBoundary(ref eye);
01592
01593
01594 lookAt = eye + worldAhead;
01595
01596
01597 viewMatrix = Matrix.LookAtLH(eye, lookAt, worldUp);
01598 cameraWorld = Matrix.Invert(viewMatrix);
01599 }
01600
01604 public void SetRotationButtons(bool left, bool middle, bool right)
01605 {
01606 activeButtonMask = (left ? (int)MouseButtonMask.Left : 0) |
01607 (middle ? (int)MouseButtonMask.Middle : 0) |
01608 (right ? (int)MouseButtonMask.Right : 0);
01609 }
01610 }
01611
01615 public class ModelViewerCamera : Camera
01616 {
01617 #region Instance Data
01618 protected ArcBall worldArcball = new ArcBall();
01619 protected ArcBall viewArcball = new ArcBall();
01620 protected Vector3 modelCenter;
01621 protected Matrix lastModelRotation;
01622 protected Matrix lastCameraRotation;
01623 protected Matrix modelRotation;
01624 protected Matrix world;
01625
01626 protected int rotateModelButtonMask;
01627 protected int zoomButtonMask;
01628 protected int rotateCameraButtonMask;
01629
01630 protected bool isPitchLimited;
01631 protected float radius;
01632 protected float defaultRadius;
01633 protected float minRadius;
01634 protected float maxRadius;
01635 protected bool attachCameraToModel;
01636 #endregion
01637
01638 #region Simple Properties/Set Methods
01640 public float MinimumRadius { get { return minRadius; } set { minRadius = value; } }
01642 public float MaximumRadius { get { return maxRadius; } set { maxRadius = value; } }
01644 public Matrix WorldMatrix { get { return world; } }
01646 public void SetWorldQuat(Quaternion q) { worldArcball.CurrentQuaternion = q; }
01648 public void SetViewQuat(Quaternion q) { viewArcball.CurrentQuaternion = q; }
01650 public void SetIsPitchLimited(bool limit) { isPitchLimited = limit; }
01652 public void SetModelCenter(Vector3 c) { modelCenter = c; }
01654 public void SetRadius(float r, float min, float max) { radius = defaultRadius = r; minRadius = min; maxRadius = max;}
01656 public void SetRadius(float r) { defaultRadius = r; minRadius = 1.0f; maxRadius = float.MaxValue;}
01658 public void SetWindow(int w, int h, float r) { worldArcball.SetWindow(w,h,r); viewArcball.SetWindow(w,h,r); }
01660 public void SetWindow(int w, int h) { worldArcball.SetWindow(w,h,0.9f); viewArcball.SetWindow(w,h,0.9f); }
01662 public void SetButtonMasks(int rotateModel, int zoom, int rotateCamera) { rotateCameraButtonMask = rotateCamera; zoomButtonMask = zoom; rotateModelButtonMask = rotateModel; }
01664 public bool IsAttachedToModel { get { return attachCameraToModel; } set { attachCameraToModel = value; } }
01665 #endregion
01666
01670 public ModelViewerCamera()
01671 {
01672 world = Matrix.Identity;
01673 modelRotation = Matrix.Identity;
01674 lastModelRotation = Matrix.Identity;
01675 lastCameraRotation = Matrix.Identity;
01676 modelCenter = Vector3.Empty;
01677 radius = 5.0f;
01678 defaultRadius = 5.0f;
01679 minRadius = 1.0f;
01680 maxRadius = float.MaxValue;
01681 isPitchLimited = false;
01682 isEnablePositionMovement = false;
01683 attachCameraToModel = false;
01684
01685
01686 rotateModelButtonMask = (int)MouseButtonMask.Left;
01687 zoomButtonMask = (int)MouseButtonMask.Wheel;
01688 rotateCameraButtonMask = (int)MouseButtonMask.Right;
01689 }
01690
01694 public unsafe override void FrameMove(float elapsedTime)
01695 {
01696
01697 if (keys[(int)CameraKeys.Reset])
01698 Reset();
01699
01700
01701 if (currentButtonMask != 0)
01702 UpdateMouseDelta(elapsedTime);
01703
01704
01705 UpdateVelocity(elapsedTime);
01706
01707
01708 Vector3 posDelta = velocity * elapsedTime;
01709
01710
01711 if ( (mouseWheelDelta != 0) && (zoomButtonMask == (int)MouseButtonMask.Wheel) )
01712 radius -= mouseWheelDelta * radius * 0.1f;
01713 radius = Math.Min( maxRadius, radius );
01714 radius = Math.Max( minRadius, radius );
01715 mouseWheelDelta = 0;
01716
01717
01718 Matrix cameraRotation = Matrix.Invert(viewArcball.RotationMatrix);
01719
01720
01721 Vector3 localUp = new Vector3(0,1,0);
01722 Vector3 localAhead = new Vector3(0,0,1);
01723 Vector3 worldUp = Vector3.TransformCoordinate(localUp, cameraRotation);
01724 Vector3 worldAhead = Vector3.TransformCoordinate(localAhead, cameraRotation);
01725
01726
01727 Vector3 posDeltaWorld = Vector3.TransformCoordinate(posDelta, cameraRotation);
01728
01729
01730 lookAt += posDeltaWorld;
01731 if (isClipToBoundary)
01732 ConstrainToBoundary(ref lookAt);
01733
01734
01735 eye = lookAt - worldAhead * radius;
01736
01737
01738 viewMatrix = Matrix.LookAtLH(eye, lookAt, worldUp);
01739 Matrix invView = Matrix.Invert(viewMatrix);
01740 invView.M41 = invView.M42 = invView.M43 = 0;
01741 Matrix modelLastRotInv = Matrix.Invert(lastModelRotation);
01742
01743
01744
01745 Matrix localModel = worldArcball.RotationMatrix;
01746 modelRotation *= viewMatrix * modelLastRotInv * localModel * invView;
01747 if ( viewArcball.IsBeingDragged && attachCameraToModel && !keys[(int)CameraKeys.ControlDown])
01748 {
01749
01750 Matrix cameraRotInv = Matrix.Invert(lastCameraRotation);
01751 Matrix delta = cameraRotInv * cameraRotation;
01752 modelRotation *= delta;
01753 }
01754 lastCameraRotation = cameraRotation;
01755 lastModelRotation = localModel;
01756
01757
01758
01759 fixed(void* pxBasis = &modelRotation.M11)
01760 {
01761 fixed(void* pyBasis = &modelRotation.M21)
01762 {
01763 fixed(void* pzBasis = &modelRotation.M31)
01764 {
01765 UnsafeNativeMethods.Vector3.Normalize((Vector3*)pxBasis, (Vector3*)pxBasis);
01766 UnsafeNativeMethods.Vector3.Cross((Vector3*)pyBasis, (Vector3*)pzBasis, (Vector3*)pxBasis);
01767 UnsafeNativeMethods.Vector3.Normalize((Vector3*)pyBasis, (Vector3*)pyBasis);
01768 UnsafeNativeMethods.Vector3.Cross((Vector3*)pzBasis, (Vector3*)pxBasis, (Vector3*)pyBasis);
01769 }
01770 }
01771 }
01772
01773
01774 modelRotation.M41 = lookAt.X;
01775 modelRotation.M42 = lookAt.Y;
01776 modelRotation.M43 = lookAt.Z;
01777
01778
01779 Matrix trans = Matrix.Translation(-modelCenter.X, -modelCenter.Y, -modelCenter.Z);
01780 world = trans * modelRotation;
01781 }
01782
01786 public override void Reset()
01787 {
01788 base.Reset();
01789 world = Matrix.Identity;
01790 modelRotation = Matrix.Identity;
01791 lastModelRotation = Matrix.Identity;
01792 lastCameraRotation = Matrix.Identity;
01793 radius = defaultRadius;
01794 worldArcball.Reset();
01795 viewArcball.Reset();
01796 }
01797
01801 public override void SetViewParameters(Vector3 eyePt, Vector3 lookAtPt)
01802 {
01803
01804 base.SetViewParameters (eyePt, lookAtPt);
01805
01806
01807 Matrix rotation = Matrix.LookAtLH(eyePt, lookAtPt, UpDirection);
01808 viewArcball.CurrentQuaternion = Quaternion.RotationMatrix(rotation);
01809
01810
01811 Vector3 eyeToPoint = lookAtPt - eyePt;
01812 SetRadius(eyeToPoint.Length());
01813 }
01814
01818 public override bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
01819 {
01820
01821 base.HandleMessages(hWnd, msg, wParam, lParam);
01822
01823 if ( ( (msg == NativeMethods.WindowMessage.LeftButtonDown || msg == NativeMethods.WindowMessage.LeftButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Left) != 0 ) ) ||
01824 ( (msg == NativeMethods.WindowMessage.RightButtonDown || msg == NativeMethods.WindowMessage.RightButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Right) != 0 ) ) ||
01825 ( (msg == NativeMethods.WindowMessage.MiddleButtonDown || msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick) && ((rotateModelButtonMask & (int)MouseButtonMask.Middle) != 0 ) ) )
01826 {
01827
01828 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
01829 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
01830 worldArcball.OnBegin(mouseX, mouseY);
01831 }
01832 if ( ( (msg == NativeMethods.WindowMessage.LeftButtonDown || msg == NativeMethods.WindowMessage.LeftButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Left) != 0 ) ) ||
01833 ( (msg == NativeMethods.WindowMessage.RightButtonDown || msg == NativeMethods.WindowMessage.RightButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Right) != 0 ) ) ||
01834 ( (msg == NativeMethods.WindowMessage.MiddleButtonDown || msg == NativeMethods.WindowMessage.MiddleButtonDoubleClick) && ((rotateCameraButtonMask & (int)MouseButtonMask.Middle) != 0 ) ) )
01835 {
01836
01837 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
01838 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
01839 viewArcball.OnBegin(mouseX, mouseY);
01840 }
01841 if (msg == NativeMethods.WindowMessage.MouseMove)
01842 {
01843
01844 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
01845 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
01846 worldArcball.OnMove(mouseX, mouseY);
01847 viewArcball.OnMove(mouseX, mouseY);
01848 }
01849
01850 if ( (msg == NativeMethods.WindowMessage.LeftButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Left) != 0 ) ||
01851 (msg == NativeMethods.WindowMessage.RightButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Right) != 0 ) ||
01852 (msg == NativeMethods.WindowMessage.MiddleButtonUp) && ((rotateModelButtonMask & (int)MouseButtonMask.Middle) != 0 ) )
01853 {
01854 worldArcball.OnEnd();
01855 }
01856
01857 if ( (msg == NativeMethods.WindowMessage.LeftButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Left) != 0 ) ||
01858 (msg == NativeMethods.WindowMessage.RightButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Right) != 0 ) ||
01859 (msg == NativeMethods.WindowMessage.MiddleButtonUp) && ((rotateCameraButtonMask & (int)MouseButtonMask.Middle) != 0 ) )
01860 {
01861 viewArcball.OnEnd();
01862 }
01863
01864 return false;
01865 }
01866 }
01867 #endregion
01868
01869 #region Text Helper
01873 public struct TextHelper
01874 {
01875 private Font textFont;
01876 private Sprite textSprite;
01877 private int color;
01878 private System.Drawing.Point point;
01879 private int lineHeight;
01880
01884 public TextHelper(Font f, Sprite s, int l)
01885 {
01886 textFont = f;
01887 textSprite = s;
01888 lineHeight = l;
01889 color = unchecked((int)0xffffffff);
01890 point = System.Drawing.Point.Empty;
01891 }
01892
01896 public void DrawTextLine(string text)
01897 {
01898 if (textFont == null)
01899 {
01900 throw new InvalidOperationException("You cannot draw text. There is no font object.");
01901 }
01902
01903 System.Drawing.Rectangle rect = new System.Drawing.Rectangle(point, System.Drawing.Size.Empty);
01904 textFont.DrawText(textSprite, text, rect, DrawTextFormat.NoClip, color);
01905
01906
01907 point.Y += lineHeight;
01908 }
01909
01913 public void DrawTextLine(string text, params object[] args)
01914 {
01915
01916 DrawTextLine(string.Format(text, args));
01917 }
01918
01922 public void SetInsertionPoint(System.Drawing.Point p) { point = p; }
01923 public void SetInsertionPoint(int x, int y) { point.X = x; point.Y = y; }
01924
01928 public void SetForegroundColor(int c) { color = c; }
01929 public void SetForegroundColor(System.Drawing.Color c) { color = c.ToArgb(); }
01930
01934 public void Begin()
01935 {
01936 if (textSprite != null)
01937 {
01938 textSprite.Begin(SpriteFlags.AlphaBlend | SpriteFlags.SortTexture);
01939 }
01940 }
01941
01945 public void End()
01946 {
01947 if (textSprite != null)
01948 {
01949 textSprite.End();
01950 }
01951 }
01952 }
01953 #endregion
01954
01955 #region Utility
01959 public class Utility
01960 {
01961
01962 private const string CurrentFolder = @".\";
01963 private const string MediaPath = @"Media\";
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975 private static readonly string[] TypicalFolders = new string[] { CurrentFolder, @"..\",
01976 @"..\..\", @"{0}\", @"{0}\..\", @"{0}\..\..\", @"{0}\..\{1}\", @"{0}\..\..\{1}\" };
01977 private Utility() { }
01978
01985 public static string FindMediaFile(string filename)
01986 {
01987
01988 System.Reflection.Assembly executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
01989
01990
01991 string exeName = System.IO.Path.GetFileNameWithoutExtension(executingAssembly.Location);
01992
01993 string exeFolder = System.IO.Path.GetDirectoryName(executingAssembly.Location);
01994
01995 string filePath;
01996
01997 if (SearchTypicalFolders(filename, exeFolder, exeName, out filePath))
01998 {
01999 return filePath;
02000 }
02001
02002
02003
02004 if (SearchTypicalFolders(filename + MediaPath, exeFolder, exeName, out filePath))
02005 {
02006 return filePath;
02007 }
02008
02009
02010 if (SearchParentFolders(filename, CurrentFolder, "", out filePath))
02011 {
02012 return filePath;
02013 }
02014
02015 if (SearchParentFolders(filename, exeFolder, exeName, out filePath))
02016 {
02017 return filePath;
02018 }
02019
02020
02021 if (SearchParentFolders(filename, CurrentFolder, MediaPath, out filePath))
02022 {
02023 return filePath;
02024 }
02025
02026 if (SearchParentFolders(filename, exeFolder, AppendDirectorySeparator(exeName) + MediaPath, out filePath))
02027 {
02028 return filePath;
02029 }
02030
02031
02032
02033 if (exeName.ToLower().StartsWith("cs"))
02034 {
02035
02036 string newExeName = exeName.Substring(2, exeName.Length - 2);
02037 if (SearchParentFolders(filename, exeFolder, newExeName, out filePath))
02038 {
02039 return filePath;
02040 }
02041
02042 if (SearchParentFolders(filename, exeFolder, AppendDirectorySeparator(newExeName) + MediaPath, out filePath))
02043 {
02044 return filePath;
02045 }
02046 }
02047
02048
02049 if (File.Exists(filename))
02050 {
02051 return filename;
02052 }
02053
02054 throw new MediaNotFoundException();
02055 }
02056
02065 private static bool SearchTypicalFolders(string filename, string exeFolder, string exeName, out string fullPath)
02066 {
02067
02068 for (int i = 0; i < TypicalFolders.Length; i++)
02069 {
02070 try
02071 {
02072 FileInfo info = new FileInfo(string.Format(TypicalFolders[i], exeFolder, exeName) + filename);
02073 if (info.Exists)
02074 {
02075 fullPath = info.FullName;
02076 return true;
02077 }
02078 }
02079 catch(NotSupportedException)
02080 {
02081
02082 continue;
02083 }
02084 }
02085
02086
02087 fullPath = string.Empty;
02088 return false;
02089 }
02090
02099 private static bool SearchParentFolders(string filename, string rootNode, string leafName, out string fullPath)
02100 {
02101
02102 fullPath = string.Empty;
02103 try
02104 {
02105
02106 FileInfo info = new FileInfo( AppendDirectorySeparator(rootNode) + AppendDirectorySeparator(leafName) + filename);
02107 if (info.Exists)
02108 {
02109 fullPath = info.FullName;
02110 return true;
02111 }
02112 }
02113 catch(NotSupportedException)
02114 {
02115
02116 return false;
02117 }
02118
02119
02120 DirectoryInfo dir = new DirectoryInfo(rootNode);
02121 if (dir.Parent != null)
02122 {
02123 return SearchParentFolders(filename, dir.Parent.FullName, leafName, out fullPath);
02124 }
02125 else
02126 {
02127
02128 return false;
02129 }
02130 }
02131
02135 public static string AppendDirectorySeparator(string pathName)
02136 {
02137 if (!pathName.EndsWith(@"\"))
02138 return pathName + @"\";
02139
02140 return pathName;
02141 }
02142
02144 public static Matrix GetCubeMapViewMatrix(CubeMapFace face)
02145 {
02146 Vector3 vEyePt = new Vector3(0.0f, 0.0f, 0.0f);
02147 Vector3 vLookDir = new Vector3();
02148 Vector3 vUpDir = new Vector3();
02149
02150 switch (face)
02151 {
02152 case CubeMapFace.PositiveX:
02153 vLookDir = new Vector3(1.0f, 0.0f, 0.0f);
02154 vUpDir = new Vector3(0.0f, 1.0f, 0.0f);
02155 break;
02156 case CubeMapFace.NegativeX:
02157 vLookDir = new Vector3(-1.0f, 0.0f, 0.0f);
02158 vUpDir = new Vector3(0.0f, 1.0f, 0.0f);
02159 break;
02160 case CubeMapFace.PositiveY:
02161 vLookDir = new Vector3(0.0f, 1.0f, 0.0f);
02162 vUpDir = new Vector3(0.0f, 0.0f,-1.0f);
02163 break;
02164 case CubeMapFace.NegativeY:
02165 vLookDir = new Vector3(0.0f,-1.0f, 0.0f);
02166 vUpDir = new Vector3(0.0f, 0.0f, 1.0f);
02167 break;
02168 case CubeMapFace.PositiveZ:
02169 vLookDir = new Vector3(0.0f, 0.0f, 1.0f);
02170 vUpDir = new Vector3(0.0f, 1.0f, 0.0f);
02171 break;
02172 case CubeMapFace.NegativeZ:
02173 vLookDir = new Vector3(0.0f, 0.0f,-1.0f);
02174 vUpDir = new Vector3(0.0f, 1.0f, 0.0f);
02175 break;
02176 }
02177
02178
02179 Matrix matView = Matrix.LookAtLH(vEyePt, vLookDir, vUpDir);
02180 return matView;
02181 }
02183 public static Matrix GetCubeMapViewMatrix(int face) { return GetCubeMapViewMatrix((CubeMapFace)face); }
02184
02185 private static bool firstTime = true;
02189 public static void DisplaySwitchingToRefWarning(Framework framework, string sampleTitle)
02190 {
02191 if (framework.IsShowingMsgBoxOnError)
02192 {
02193
02194 int skipWarning = 0;
02195 try
02196 {
02197 using(Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(SwitchRefDialog.KeyLocation))
02198 {
02199 skipWarning = (int)key.GetValue(SwitchRefDialog.KeyValueName, (int)0);
02200 }
02201 }
02202 catch { }
02203 if ( (skipWarning == 0) && (firstTime) )
02204 {
02205 firstTime = false;
02206 using (SwitchRefDialog dialog = new SwitchRefDialog(sampleTitle))
02207 {
02208 System.Windows.Forms.Application.Run(dialog);
02209 if (dialog.DialogResult == System.Windows.Forms.DialogResult.Cancel)
02210 {
02211
02212 framework.Dispose();
02213 }
02214 }
02215 }
02216 }
02217 }
02218 }
02219 #endregion
02220
02221 #region Widgets
02222
02223 #region Direction Widget
02225 public class DirectionWidget
02226 {
02227 #region Class level data (Instance/Static)
02228
02229 private float widgetRadius = 1.0f;
02230 private ArcBall arc = new ArcBall();
02231 private Vector3 defaultDir = new Vector3(0,1,0);
02232 private Vector3 currentDir = new Vector3(0,1,0);
02233 private Matrix viewMatrix = Matrix.Identity;
02234 private Matrix rotation = Matrix.Identity;
02235 private Matrix rotationSnapshot = Matrix.Identity;
02236 private MouseButtonMask rotateMask = MouseButtonMask.Right;
02237
02238
02239 private static Device device = null;
02240 private static Effect effect = null;
02241 private static Mesh mesh = null;
02242 #endregion
02243
02244 #region Properties
02246 public float Radius { get { return widgetRadius; } set { widgetRadius = value; } }
02248 public Vector3 LightDirection { get { return currentDir; } set { currentDir = defaultDir = value; } }
02250 public bool IsBeingDragged{ get { return arc.IsBeingDragged; } }
02252 public MouseButtonMask RotateButtonMask{ get { return rotateMask; } set { rotateMask = value; }}
02253 #endregion
02254
02255 #region Device handlers
02257 public static void OnCreateDevice(Device device)
02258 {
02259
02260 DirectionWidget.device = device;
02261
02262
02263 string path = Utility.FindMediaFile("UI\\DXUTShared.fx");
02264
02265
02266
02267
02268 effect = Effect.FromFile(device, path, null, null, ShaderFlags.NotCloneable, null);
02269
02270
02271
02272
02273
02274 path = Utility.FindMediaFile("UI\\arrow.x");
02275 mesh = Mesh.FromFile(path, MeshFlags.Managed, device);
02276
02277
02278
02279
02280
02281 int[] adj = new int[mesh.NumberFaces * 3];
02282 mesh.GenerateAdjacency(1e-6f, adj);
02283 mesh.OptimizeInPlace(MeshFlags.OptimizeVertexCache, adj);
02284 }
02285
02287 public void OnResetDevice(SurfaceDescription desc)
02288 {
02289 arc.SetWindow(desc.Width, desc.Height);
02290 }
02291
02293 public static void OnLostDevice()
02294 {
02295 if (effect != null)
02296 effect.OnLostDevice();
02297 }
02298
02300 public static void OnDestroyDevice()
02301 {
02302 if (effect != null)
02303 effect.Dispose();
02304 if (mesh != null)
02305 mesh.Dispose();
02306 effect = null;
02307 mesh = null;
02308 }
02309 #endregion
02310
02312 public bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
02313 {
02314
02315 short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
02316 short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
02317
02318 switch(msg)
02319 {
02320 case NativeMethods.WindowMessage.LeftButtonDown:
02321 case NativeMethods.WindowMessage.MiddleButtonDown:
02322 case NativeMethods.WindowMessage.RightButtonDown:
02323 {
02324 if ( ((rotateMask & MouseButtonMask.Left) == MouseButtonMask.Left && msg == NativeMethods.WindowMessage.LeftButtonDown) ||
02325 ((rotateMask & MouseButtonMask.Right) == MouseButtonMask.Right && msg == NativeMethods.WindowMessage.RightButtonDown) ||
02326 ((rotateMask & MouseButtonMask.Middle) == MouseButtonMask.Middle && msg == NativeMethods.WindowMessage.MiddleButtonDown) )
02327 {
02328 arc.OnBegin(mouseX, mouseY);
02329 NativeMethods.SetCapture(hWnd);
02330 }
02331 return true;
02332 }
02333 case NativeMethods.WindowMessage.MouseMove:
02334 {
02335 if (arc.IsBeingDragged)
02336 {
02337 arc.OnMove(mouseX, mouseY);
02338 UpdateLightDirection();
02339 }
02340 return true;
02341 }
02342 case NativeMethods.WindowMessage.LeftButtonUp:
02343 case NativeMethods.WindowMessage.RightButtonUp:
02344 case NativeMethods.WindowMessage.MiddleButtonUp:
02345 {
02346 if ( ((rotateMask & MouseButtonMask.Left) == MouseButtonMask.Left && msg == NativeMethods.WindowMessage.LeftButtonUp) ||
02347 ((rotateMask & MouseButtonMask.Right) == MouseButtonMask.Right && msg == NativeMethods.WindowMessage.RightButtonUp) ||
02348 ((rotateMask & MouseButtonMask.Middle) == MouseButtonMask.Middle && msg == NativeMethods.WindowMessage.MiddleButtonUp) )
02349 {
02350 arc.OnEnd();
02351 NativeMethods.ReleaseCapture();
02352 }
02353
02354 UpdateLightDirection();
02355 return true;
02356 }
02357 }
02358
02359
02360 return false;
02361 }
02362
02364 private unsafe void UpdateLightDirection()
02365 {
02366 Matrix invView = Matrix.Invert(viewMatrix);
02367 invView.M41 = invView.M42 = invView.M43 = 0;
02368
02369 Matrix lastRotationInv = Matrix.Invert(rotationSnapshot);
02370 Matrix rot = arc.RotationMatrix;
02371 rotationSnapshot = rot;
02372
02373
02374
02375 rotation *= (viewMatrix * lastRotationInv * rot * invView);
02376
02377
02378
02379 fixed(void* pxBasis = &rotation.M11)
02380 {
02381 fixed(void* pyBasis = &rotation.M21)
02382 {
02383 fixed(void* pzBasis = &rotation.M31)
02384 {
02385 UnsafeNativeMethods.Vector3.Normalize((Vector3*)pxBasis, (Vector3*)pxBasis);
02386 UnsafeNativeMethods.Vector3.Cross((Vector3*)pyBasis, (Vector3*)pzBasis, (Vector3*)pxBasis);
02387 UnsafeNativeMethods.Vector3.Normalize((Vector3*)pyBasis, (Vector3*)pyBasis);
02388 UnsafeNativeMethods.Vector3.Cross((Vector3*)pzBasis, (Vector3*)pxBasis, (Vector3*)pyBasis);
02389 }
02390 }
02391 }
02392
02393
02394 currentDir = Vector3.TransformNormal(defaultDir, rotation);
02395 }
02396
02398 public unsafe void OnRender(ColorValue color, Matrix view, Matrix proj, Vector3 eye)
02399 {
02400
02401 viewMatrix = view;
02402
02403
02404 effect.Technique = "RenderWith1LightNoTexture";
02405 effect.SetValue("g_MaterialDiffuseColor", color);
02406 Vector3 eyePt = Vector3.Normalize(eye);
02407
02408
02409 effect.SetValue("g_LightDir", &eyePt, sizeof(Vector3));
02410
02411
02412 Vector3 at = Vector3.Empty;
02413 Vector3 up = new Vector3(0,1,0);
02414 Matrix rotateB = Matrix.RotationX((float)Math.PI);
02415 Matrix rotateA = Matrix.LookAtLH(currentDir, at, up);
02416 rotateA.Invert();
02417 Matrix rotate = rotateB * rotateA;
02418 Vector3 l = currentDir * widgetRadius * 1.0f;
02419 Matrix trans = Matrix.Translation(l);
02420 Matrix scale = Matrix.Scaling(widgetRadius * 0.2f, widgetRadius * 0.2f, widgetRadius * 0.2f);
02421
02422 Matrix world = rotate * scale * trans;
02423 Matrix worldViewProj = world * viewMatrix * proj;
02424
02425 effect.SetValue("g_mWorldViewProjection", worldViewProj);
02426 effect.SetValue("g_mWorld", world);
02427
02428
02429 for (int subset = 0; subset < 2; subset++)
02430 {
02431 int passes = effect.Begin(0);
02432 for (int pass = 0; pass < passes; pass++)
02433 {
02434 effect.BeginPass(pass);
02435 mesh.DrawSubset(subset);
02436 effect.EndPass();
02437 }
02438 effect.End();
02439 }
02440
02441 }
02442 }
02443 #endregion
02444
02445 #endregion
02446 }