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);
}
}
}