port from perforce
This commit is contained in:
407
aiwaz/Aiwaz.Editor/Controls/AiwazViewControl.xaml.cs
Normal file
407
aiwaz/Aiwaz.Editor/Controls/AiwazViewControl.xaml.cs
Normal file
@@ -0,0 +1,407 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using Aiwaz.Resources;
|
||||
using System.Windows.Threading;
|
||||
using Aiwaz.Core;
|
||||
using Aiwaz.Contracts;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using SlimDX;
|
||||
|
||||
namespace Aiwaz.Editor.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for AiwazViewControl.xaml
|
||||
/// </summary>
|
||||
public partial class AiwazViewControl : System.Windows.Controls.UserControl
|
||||
{
|
||||
#region Win32
|
||||
|
||||
public static Point CorrectGetPosition(Visual relativeTo)
|
||||
{
|
||||
Win32Point w32Mouse = new Win32Point();
|
||||
GetCursorPos(ref w32Mouse);
|
||||
return relativeTo.PointFromScreen(new Point(w32Mouse.X, w32Mouse.Y));
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct Win32Point
|
||||
{
|
||||
public Int32 X;
|
||||
public Int32 Y;
|
||||
};
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool GetCursorPos(ref Win32Point pt);
|
||||
|
||||
#endregion
|
||||
|
||||
private DateTime lastPerformCalledTime = DateTime.UtcNow;
|
||||
private bool rightButtonPressed;
|
||||
private bool leftButtonPressed;
|
||||
private bool moveThresholdReached;
|
||||
private Point lastMousePosition;
|
||||
private int desiredFPS = 30;
|
||||
private DispatcherTimer renderTimer;
|
||||
|
||||
private RenderCommandNode mainRootNode;
|
||||
private RenderCommandNode rootNode;
|
||||
|
||||
private Shader selectionShader;
|
||||
private RenderCommandNode selectionMarkerNode;
|
||||
private PickableResourceInfo selectedResourceInfo;
|
||||
|
||||
public delegate void PerformCalledDelegate(object sender, TimeSpan elapsedTime);
|
||||
public delegate void SelectedResourceChangedDelegate(object sender, PickableResourceInfo newSelectedResourceInfo);
|
||||
|
||||
public event PerformCalledDelegate PerformCalled;
|
||||
public event SelectedResourceChangedDelegate SelectedResourceChanged;
|
||||
|
||||
public AiwazViewControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
|
||||
return;
|
||||
|
||||
this.SwapChain = new SwapChain(RenderTarget.Handle);
|
||||
this.SwapChain.HasDepthStencilBuffer = true;
|
||||
|
||||
MainRootNode.Children.Add(this.SwapChain);
|
||||
MainRootNode.Children.Add(RootNode);
|
||||
|
||||
renderTimer = new DispatcherTimer();
|
||||
renderTimer.Tick += new EventHandler(delegate(object s, EventArgs a)
|
||||
{
|
||||
this.Perform();
|
||||
});
|
||||
renderTimer.Interval = TimeSpan.FromMilliseconds(1000 / 60.0);
|
||||
renderTimer.Start();
|
||||
|
||||
selectionMarkerNode = new RenderCommandNode();
|
||||
selectionShader = new Shader(new ShaderParams() { FileName = "Resources/SelectionHighlight.fx" });
|
||||
selectionShader.Priority = 128;
|
||||
MainRootNode.Children.Add(selectionMarkerNode);
|
||||
|
||||
this.RenderTarget.MouseDown += new System.Windows.Forms.MouseEventHandler(RenderTarget_MouseButtonDown);
|
||||
this.RenderTarget.MouseUp += new System.Windows.Forms.MouseEventHandler(RenderTarget_MouseButtonUp);
|
||||
}
|
||||
|
||||
public ICamera MainCamera
|
||||
{
|
||||
get
|
||||
{
|
||||
return FindLastAvailableCamera(MainRootNode);
|
||||
}
|
||||
}
|
||||
|
||||
public PickableResourcesDataSource PickableResources { get; set; }
|
||||
|
||||
public RenderCommandNode MainRootNode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mainRootNode == null)
|
||||
{
|
||||
mainRootNode = new RenderCommandNode();
|
||||
}
|
||||
return mainRootNode;
|
||||
}
|
||||
set
|
||||
{
|
||||
mainRootNode = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SwapChain SwapChain { get; protected set; }
|
||||
|
||||
public RenderCommandNode RootNode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (rootNode == null)
|
||||
{
|
||||
rootNode = new RenderCommandNode();
|
||||
}
|
||||
return rootNode;
|
||||
}
|
||||
set
|
||||
{
|
||||
mainRootNode.Children.Remove(rootNode);
|
||||
rootNode = value;
|
||||
mainRootNode.Children.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan RenderInterval
|
||||
{
|
||||
get { return renderTimer.Interval; }
|
||||
set { renderTimer.Interval = value; }
|
||||
}
|
||||
|
||||
public PickableResourceInfo SelectedResourceInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return selectedResourceInfo;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (selectedResourceInfo != null)
|
||||
{
|
||||
selectionMarkerNode.Children.Clear();
|
||||
selectionMarkerNode.MarkDirty();
|
||||
}
|
||||
|
||||
selectedResourceInfo = value;
|
||||
|
||||
if (selectedResourceInfo != null)
|
||||
{
|
||||
selectionMarkerNode.Children.Add(selectionShader);
|
||||
if (selectedResourceInfo.Transformation != null)
|
||||
selectionMarkerNode.Children.Add(selectedResourceInfo.Transformation);
|
||||
if (selectedResourceInfo.Resource != null)
|
||||
selectionMarkerNode.Children.Add(selectedResourceInfo.Resource);
|
||||
}
|
||||
|
||||
if (SelectedResourceChanged != null)
|
||||
SelectedResourceChanged(this, selectedResourceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public int DesiredFPS
|
||||
{
|
||||
get
|
||||
{
|
||||
return desiredFPS;
|
||||
}
|
||||
set
|
||||
{
|
||||
desiredFPS = value;
|
||||
if (desiredFPS <= 0)
|
||||
renderTimer.Interval = TimeSpan.FromMilliseconds(0);
|
||||
else
|
||||
renderTimer.Interval = TimeSpan.FromMilliseconds(1000 / (double)desiredFPS);
|
||||
}
|
||||
}
|
||||
|
||||
private ICamera FindLastAvailableCamera(Resource rootNode)
|
||||
{
|
||||
ICamera lastFoundCamera = null;
|
||||
if (rootNode.Children != null)
|
||||
foreach (var child in rootNode.Children)
|
||||
{
|
||||
if (child is ICamera)
|
||||
lastFoundCamera = child as ICamera;
|
||||
if (child is Resource)
|
||||
lastFoundCamera = this.FindLastAvailableCamera(child as Resource) ?? lastFoundCamera;
|
||||
}
|
||||
return lastFoundCamera;
|
||||
}
|
||||
|
||||
protected void Perform()
|
||||
{
|
||||
mainRootNode.Update(false);
|
||||
mainRootNode.ProcessCommands();
|
||||
this.SwapChain.Present();
|
||||
|
||||
var deltaTime = DateTime.UtcNow - lastPerformCalledTime;
|
||||
this.PerformCalledInternal(deltaTime);
|
||||
if (PerformCalled != null)
|
||||
PerformCalled(this, deltaTime);
|
||||
|
||||
lastPerformCalledTime = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private void RenderTarget_Resize(object sender, EventArgs e)
|
||||
{
|
||||
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
|
||||
return;
|
||||
this.SwapChain.Resize((int)this.Width, (int)this.Height);
|
||||
}
|
||||
|
||||
private void RenderTarget_MouseButtonUp(object sender, System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
rightButtonPressed = false;
|
||||
else if (e.Button == MouseButtons.Left)
|
||||
leftButtonPressed = false;
|
||||
|
||||
lastMousePosition = CorrectGetPosition(this);
|
||||
if (!moveThresholdReached)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
if (this.ContextMenu != null)
|
||||
this.ContextMenu.IsOpen = true;
|
||||
}
|
||||
else if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
if (PickableResources != null)
|
||||
{
|
||||
var mainCamera = this.MainCamera;
|
||||
|
||||
int width = this.SwapChain.ViewPort.Width;
|
||||
int height = this.SwapChain.ViewPort.Height;
|
||||
|
||||
var viewProj = mainCamera.ViewMatrix * mainCamera.ProjectionMatrix;
|
||||
|
||||
Vector3 ZNearPlane = Vector3.Unproject(new Vector3((float)lastMousePosition.X, (float)lastMousePosition.Y, 0), 0, 0, width, height,
|
||||
this.SwapChain.ViewPort.MinDepth, this.SwapChain.ViewPort.MaxDepth, viewProj);
|
||||
Vector3 ZFarPlane = Vector3.Unproject(new Vector3((float)lastMousePosition.X, (float)lastMousePosition.Y, 1), 0, 0, width, height,
|
||||
this.SwapChain.ViewPort.MinDepth, this.SwapChain.ViewPort.MaxDepth, viewProj);
|
||||
|
||||
Vector3 direction = ZFarPlane - ZNearPlane;
|
||||
direction.Normalize();
|
||||
|
||||
Ray ray = new Ray(ZNearPlane, direction);
|
||||
|
||||
PickableResourceInfo winnerResourceInfo = this.SelectedResourceInfo;
|
||||
float distance = float.MaxValue;
|
||||
foreach (var pickable in PickableResources)
|
||||
{
|
||||
float newDistance;
|
||||
if (pickable.PickHull.TryPick(ray, pickable.Transformation.WorldMatrix, out newDistance)
|
||||
&& newDistance < distance)
|
||||
{
|
||||
winnerResourceInfo = pickable;
|
||||
distance = newDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.SelectedResourceInfo != null && winnerResourceInfo != null && this.SelectedResourceInfo.Resource == winnerResourceInfo.Resource)
|
||||
winnerResourceInfo = null;
|
||||
|
||||
this.SelectedResourceInfo = winnerResourceInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!leftButtonPressed && !rightButtonPressed)
|
||||
{
|
||||
renderTimer.Interval = TimeSpan.FromMilliseconds(1000 / (double)desiredFPS);
|
||||
moveThresholdReached = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderTarget_MouseButtonDown(object sender, System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
rightButtonPressed = true;
|
||||
else if (e.Button == MouseButtons.Left)
|
||||
leftButtonPressed = true;
|
||||
|
||||
if (leftButtonPressed || rightButtonPressed)
|
||||
renderTimer.Interval = TimeSpan.FromMilliseconds(0);
|
||||
|
||||
lastMousePosition = CorrectGetPosition(this);
|
||||
}
|
||||
|
||||
private void PerformCalledInternal(TimeSpan elapsedTime)
|
||||
{
|
||||
var currentMousePosition = CorrectGetPosition(this);
|
||||
var deltaTime = Math.Max(1.0, elapsedTime.TotalSeconds);
|
||||
var deltaMouse = currentMousePosition - lastMousePosition;
|
||||
lastMousePosition = currentMousePosition;
|
||||
|
||||
var power = 1.7;
|
||||
if (rightButtonPressed && !leftButtonPressed)
|
||||
power = 1.25;
|
||||
|
||||
deltaMouse.X = Math.Pow(Math.Abs(deltaMouse.X), power) * Math.Sign(deltaMouse.X) * deltaTime;
|
||||
deltaMouse.Y = Math.Pow(Math.Abs(deltaMouse.Y), power) * Math.Sign(deltaMouse.Y) * deltaTime;
|
||||
|
||||
if (!leftButtonPressed && !rightButtonPressed)
|
||||
return;
|
||||
|
||||
moveThresholdReached = moveThresholdReached || deltaMouse.Length >= 3.0;
|
||||
if (!moveThresholdReached)
|
||||
return;
|
||||
|
||||
var mainCamera = this.MainCamera as Transformation;
|
||||
|
||||
if (rightButtonPressed && leftButtonPressed)
|
||||
{
|
||||
mainCamera.LocalPosition += mainCamera.LocalUpDirection * -(float)deltaMouse.Y * 0.005f +
|
||||
mainCamera.LocalRightDirection * (float)deltaMouse.X * 0.005f;
|
||||
}
|
||||
else if (leftButtonPressed)
|
||||
{
|
||||
mainCamera.LocalPosition += mainCamera.LocalDirection * -(float)deltaMouse.Y * 0.005f +
|
||||
mainCamera.LocalRightDirection * (float)deltaMouse.X * 0.005f;
|
||||
}
|
||||
else if (rightButtonPressed)
|
||||
{
|
||||
var yawPitchRoll = mainCamera.LocalRotationYPR;
|
||||
yawPitchRoll.X += (float)deltaMouse.X * 0.005f;
|
||||
yawPitchRoll.Y += (float)deltaMouse.Y * 0.005f;
|
||||
if (yawPitchRoll.Y > Math.PI / 2)
|
||||
yawPitchRoll.Y = (float)Math.PI / 2;
|
||||
else if (yawPitchRoll.Y < -Math.PI / 2)
|
||||
yawPitchRoll.Y = -(float)Math.PI / 2;
|
||||
mainCamera.LocalRotationYPR = yawPitchRoll;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PickableResourcesDataSource : List<PickableResourceInfo>
|
||||
{
|
||||
public static PickableResourcesDataSource CreateFromResource(Resource rootNode)
|
||||
{
|
||||
var pickablesDataResource = new PickableResourcesDataSource();
|
||||
|
||||
List<KeyValuePair<Transformation, IGeometryBuffer>> pickables = new List<KeyValuePair<Transformation, IGeometryBuffer>>();
|
||||
FindAllPickables(rootNode, null, pickables);
|
||||
|
||||
foreach (var pickable in pickables)
|
||||
{
|
||||
pickablesDataResource.Add(new PickableResourceInfo()
|
||||
{
|
||||
PickHull = pickable.Value.PickHull,
|
||||
Transformation = pickable.Key,
|
||||
Resource = pickable.Value as IResource
|
||||
});
|
||||
}
|
||||
return pickablesDataResource;
|
||||
}
|
||||
|
||||
private static void FindAllPickables(Resource rootNode, Transformation lastTransformation, List<KeyValuePair<Transformation, IGeometryBuffer>> pickables)
|
||||
{
|
||||
if (rootNode.Children != null)
|
||||
foreach (var child in rootNode.Children)
|
||||
{
|
||||
if (child is Transformation)
|
||||
lastTransformation = child as Transformation;
|
||||
if (child is IGeometryBuffer && lastTransformation != null)
|
||||
{
|
||||
var geoBuffer = child as IGeometryBuffer;
|
||||
if (geoBuffer.IsPickable)
|
||||
pickables.Add(new KeyValuePair<Transformation, IGeometryBuffer>(lastTransformation, geoBuffer));
|
||||
}
|
||||
if (child is Resource)
|
||||
FindAllPickables(child as Resource, lastTransformation, pickables);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class PickableResourceInfo
|
||||
{
|
||||
public IResource Resource;
|
||||
public Transformation Transformation;
|
||||
public IPickHull PickHull;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user