using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.DirectX.Direct3D; using Microsoft.DirectX; using Microsoft.DirectX.DirectInput; namespace SalsaModel { public class View3D : UserControl { private Microsoft.DirectX.Direct3D.Device device = null; public View3D() { //this.ClientSize = new System.Drawing.Size(640, 480); this.Text = "SalsaModel"; this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true); } bool Animating = false; bool TopView = false; protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { this.Render(); if (Animating || Rotating) { System.Threading.Thread.Sleep(10); this.Invalidate(); this.ReadKeyboard(); } } bool UsePerspective = true; public delegate void CloseHandler(); public event CloseHandler CloseApplication; protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e) { switch (e.KeyCode) { case System.Windows.Forms.Keys.Escape: //this.Dispose(); if (CloseApplication != null) { CloseApplication(); } break; case System.Windows.Forms.Keys.A: ViewAngle -= (float)Math.PI * 0.05f; this.Invalidate(); Rotating = false; break; case System.Windows.Forms.Keys.D: ViewAngle += (float)Math.PI * 0.05f; this.Invalidate(); Rotating = false; break; case System.Windows.Forms.Keys.R: StartRotating(); this.Invalidate(); break; case System.Windows.Forms.Keys.W: CameraHeight += 5; System.Diagnostics.Debug.WriteLine("Camera height: " + CameraHeight.ToString() + "cm"); this.Invalidate(); break; case System.Windows.Forms.Keys.S: CameraHeight -= 5; System.Diagnostics.Debug.WriteLine("Camera height: " + CameraHeight.ToString() + "cm"); this.Invalidate(); break; case System.Windows.Forms.Keys.Z: CameraRadius += 5; System.Diagnostics.Debug.WriteLine("Camera Radius: " + CameraRadius.ToString() + "cm"); this.Invalidate(); break; case System.Windows.Forms.Keys.X: CameraRadius -= 5; System.Diagnostics.Debug.WriteLine("Camera Radius: " + CameraRadius.ToString() + "cm"); this.Invalidate(); break; case System.Windows.Forms.Keys.T: TopView = !TopView; this.Invalidate(); break; case System.Windows.Forms.Keys.P: UsePerspective = !UsePerspective; this.Invalidate(); break; case System.Windows.Forms.Keys.I: Animator.Timing.BeatLength = Animator.Timing.BeatLength + 100.0; break; case System.Windows.Forms.Keys.O: Animator.Timing.BeatLength = Animator.Timing.BeatLength - 100.0; break; case System.Windows.Forms.Keys.Space: Animating = !Animating; if (Animating) { Animator.Timing.Unpause(); this.Invalidate(); } else { Animator.Timing.Pause(); } break; case System.Windows.Forms.Keys.F: foreach (IScene scene in Scenes) { SalsaScene ss = scene as SalsaScene; if (ss != null) { ss.DrawFootprints = !ss.DrawFootprints; } } break; } } protected override void Dispose(bool disposing) { base.Dispose(disposing); } /// /// This method basically creates and initialize the Direct3D device and /// anything else that doens't need to be recreated after a device /// reset. /// public void Init() { // Does the hardware support a 16-bit z-buffer? if (!Microsoft.DirectX.Direct3D.Manager.CheckDeviceFormat(Microsoft.DirectX.Direct3D.Manager.Adapters.Default.Adapter, Microsoft.DirectX.Direct3D.DeviceType.Hardware, Microsoft.DirectX.Direct3D.Manager.Adapters.Default.CurrentDisplayMode.Format, Usage.DepthStencil, ResourceType.Surface, DepthFormat.D16)) { // POTENTIAL PROBLEM: We need at least a 16-bit z-buffer! return; } // // Do we support hardware vertex processing? if so, use it. // If not, downgrade to software. // Caps caps = Microsoft.DirectX.Direct3D.Manager.GetDeviceCaps(Microsoft.DirectX.Direct3D.Manager.Adapters.Default.Adapter, Microsoft.DirectX.Direct3D.DeviceType.Hardware); CreateFlags flags; if (caps.DeviceCaps.SupportsHardwareTransformAndLight) flags = CreateFlags.HardwareVertexProcessing; else flags = CreateFlags.SoftwareVertexProcessing; // // Everything checks out - create a simple, windowed device. // PresentParameters d3dpp = new PresentParameters(); d3dpp.BackBufferFormat = Format.Unknown; d3dpp.SwapEffect = SwapEffect.Discard; d3dpp.Windowed = true; d3dpp.EnableAutoDepthStencil = true; d3dpp.AutoDepthStencilFormat = DepthFormat.D16; d3dpp.PresentationInterval = PresentInterval.Immediate; d3dpp.MultiSample = MultiSampleType.FourSamples; device = new Microsoft.DirectX.Direct3D.Device(0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this, flags, d3dpp); // Register an event-handler for DeviceReset and call it to continue // our setup. device.DeviceReset += new System.EventHandler(this.OnResetDevice); OnResetDevice(device, null); // this doesn't work when we're a user control, but we weren't really using it // anyway. //InitializeKeyboard(); // we only do this on initialisation, otherwise it gets enabled // at design time, and all heck breaks loose Animating = true; StartRotating(); } BasicDrawing Helper = new BasicDrawing(); protected void SetupLights() { // Use a white, directional light coming from over our right shoulder device.Lights[0].Diffuse = Color.White; device.Lights[0].Specular = Color.White; device.Lights[0].Type = LightType.Directional; device.Lights[0].Direction = new Vector3(-3, -1, -3); device.Lights[0].Update(); device.Lights[0].Enabled = true; // Add a little ambient light to the scene device.RenderState.Ambient = Color.FromArgb(0x80, 0x80, 0x80); //device.RenderState.Ambient = Color.White; } public void InitializeKeyboard() { keyb = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard); keyb.SetCooperativeLevel(this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive); keyb.Acquire(); } private Microsoft.DirectX.DirectInput.Device keyb; private void ReadKeyboard() { if (keyb == null) { return; } KeyboardState keys = keyb.GetCurrentKeyboardState(); if (keys[Key.Delete]) { ViewAngle += 0.003f; } if (keys[Key.Next]) { ViewAngle -= 0.003f; } } /// /// This event-handler is a good place to create and initialize any /// Direct3D related objects, which may become invalid during a /// device reset. /// public void OnResetDevice(object sender, EventArgs e) { // this switches off lighting support. Switch it back on to use // lighting! //device.RenderState.Lighting = false; SetupLights(); foreach (IScene s in Scenes) { s.Setup(device); } Helper.Setup(device); } float ViewAngle = (float) -Math.PI / 2.0f; float CameraHeight = 250; float CameraRadius = 300; private void Render() { if (device == null) { // this happens at design time. We should probably do // something to make it clear, in case it happens at // runtime too. return; } //angle += 0.005f; if (UsePerspective) { // NB the near plane can't be 0! device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 100f, 1000f); } else { device.Transform.Projection = Matrix.OrthoLH(250, 250, -500f, 500f); } //device.Transform.Projection = Matrix.PerspectiveLH(650, 650, 2000f, -000f); //device.Transform.Projection = Matrix.PerspectiveLH(650, 650, 2000f, -000f); //device.Transform.Projection = Matrix.OrthoLH(650, 650, 000f, 2000f); //float cameraRadius = 30; if (TopView) { device.Transform.View = Matrix.LookAtLH(new Vector3(0,0,450), new Vector3(0,0,0), new Vector3((float)(CameraRadius * Math.Cos(ViewAngle)), (float)(CameraRadius * Math.Sin(ViewAngle)), 0)); } else { device.Transform.View = Matrix.LookAtLH(new Vector3((float)(CameraRadius * Math.Cos(ViewAngle)), (float)(CameraRadius * Math.Sin(ViewAngle)), CameraHeight), new Vector3(0, 0, 100), new Vector3(0, 0, 1)); } //SetOrigin(); device.Transform.World = Matrix.Identity; device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0); device.BeginScene(); RenderGeometry(); device.EndScene(); device.Present(); } public List Scenes = new List(); public ISequence Animator; bool Rotating = false; double BaseRotationAngle; long BaseRotationTicks; private void StartRotating() { Rotating = true; BaseRotationAngle = ViewAngle; BaseRotationTicks = System.Environment.TickCount; } long SavedTicks = -1; int FramesRendered; double CurrentFPS; private void RenderGeometry() { //System.Threading.Thread.Sleep(1000); if (Animating && Animator != null) { Animator.Update(); } if (Rotating) { double RotateTime = 50000; double fraction = ((System.Environment.TickCount - BaseRotationTicks) % RotateTime) / RotateTime; ViewAngle = (float)(fraction * Math.PI * 2) + (float)BaseRotationAngle; } foreach (IScene s in Scenes) { s.Draw(); } StringBuilder sb = new StringBuilder(); sb.AppendLine("$Rev$"); sb.AppendFormat("(T)op view, (P)erspective, (R)otate, (SPACE) pause, (F)ootprints, (ESC) close\n"); sb.AppendFormat("Camera: radius {0} (Z/X), height {1} (W/S), angle {2} deg (A/D)\n", CameraRadius, CameraHeight, (int)(ViewAngle * 180.0 / Math.PI)); //sb.AppendFormat("Perspective: {0}\n", UsePerspective ? "on" : "off"); sb.AppendFormat("Beat length: {0} (I/O)\n", Animator.Timing.BeatLength); long timeNow = DateTime.Now.Ticks; ++FramesRendered; if (timeNow - SavedTicks > 10000000) { if (SavedTicks != -1) { long ticks = timeNow - SavedTicks; CurrentFPS = FramesRendered * ticks / 10000000.0; } SavedTicks = timeNow; FramesRendered = 0; } sb.AppendFormat("FPS: {0}\n", CurrentFPS); sb.Append(Animator.Status()); Helper.Status(sb.ToString()); } private void InitializeComponent() { this.SuspendLayout(); // // View3D // this.ClientSize = new System.Drawing.Size(292, 266); this.Name = "View3D"; this.ResumeLayout(false); } } }