Removed NioTSO client and server

- NioTSO client isn't needed because we're using RayLib
- Added FreeSO's API server to handle most backend operations
This commit is contained in:
Tony Bark 2024-05-01 02:55:43 -04:00
parent f12ba1502b
commit 22191ce648
591 changed files with 53264 additions and 3362 deletions

View file

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using FSO.Common.Rendering.Framework.Camera;
using FSO.Common.Rendering.Framework.Model;
namespace FSO.Common.Rendering.Framework
{
/// <summary>
/// Base class for scenes with 3D elements.
/// </summary>
public abstract class _3DAbstract : IDisposable
{
public ICamera Camera;
public string ID;
public bool Visible = true;
public abstract List<_3DComponent> GetElements();
public abstract void Add(_3DComponent item);
public abstract void Update(UpdateState Time);
public abstract void Draw(GraphicsDevice device);
protected _3DLayer Parent;
private EventHandler<EventArgs> ResetEvent;
public virtual void PreDraw(GraphicsDevice device)
{
}
public virtual void Initialize(_3DLayer layer)
{
Parent = layer;
}
/// <summary>
/// Creates a new _3DAbstract instance.
/// </summary>
/// <param name="Device">A GraphicsDevice instance.</param>
public _3DAbstract(GraphicsDevice Device)
{
m_Device = Device;
ResetEvent = new EventHandler<EventArgs>(m_Device_DeviceReset);
m_Device.DeviceReset += ResetEvent;
}
/// <summary>
/// Called when m_Device is reset.
/// </summary>
private void m_Device_DeviceReset(object sender, EventArgs e)
{
DeviceReset(m_Device);
}
protected GraphicsDevice m_Device;
public abstract void DeviceReset(GraphicsDevice Device);
public static bool IsInvalidated;
public object Controller { get; internal set; }
public void SetController(object controller)
{
this.Controller = controller;
}
public T FindController<T>()
{
if(Controller is T)
{
return (T)Controller;
}
return default(T);
}
public virtual void Dispose()
{
if (m_Device != null) m_Device.DeviceReset -= ResetEvent;
}
}
}

View file

@ -0,0 +1,161 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using FSO.Common.Rendering.Framework.Model;
namespace FSO.Common.Rendering.Framework
{
public abstract class _3DComponent
{
public _3DScene Scene;
public _3DComponent()
{
}
private Vector3 m_Position = Vector3.Zero;
private Vector3 m_Scale = Vector3.One;
private float m_RotateX = 0.0f;
private float m_RotateY = 0.0f;
private float m_RotateZ = 0.0f;
/// <summary>
/// Gets or the GraphicsDevice instance for this component.
/// </summary>
public GraphicsDevice Device
{
get
{
return Scene.Parent.Device;
}
}
/// <summary>
/// The X component of this 3DComponent's rotation.
/// </summary>
public float RotationX
{
get { return m_RotateX; }
set
{
m_RotateX = value;
m_WorldDirty = true;
}
}
/// <summary>
/// The Y component of this 3DComponent's rotation.
/// </summary>
public float RotationY
{
get { return m_RotateY; }
set
{
m_RotateY = value;
m_WorldDirty = true;
}
}
/// <summary>
/// The Z component of this 3DComponent's rotation.
/// </summary>
public float RotationZ
{
get { return m_RotateZ; }
set
{
m_RotateZ = value;
m_WorldDirty = true;
}
}
/// <summary>
/// This 3DComponent's position.
/// </summary>
public Vector3 Position
{
get { return m_Position; }
set
{
m_Position = value;
m_WorldDirty = true;
}
}
/// <summary>
/// This 3DComponent's scale.
/// </summary>
public Vector3 Scale
{
get { return m_Scale; }
set
{
m_Scale = value;
m_WorldDirty = true;
}
}
private Matrix m_World = Matrix.Identity;
private bool m_WorldDirty = false;
public Matrix World
{
get
{
if (m_WorldDirty)
{
m_World = Matrix.CreateRotationX(m_RotateX) * Matrix.CreateRotationY(m_RotateY) * Matrix.CreateRotationZ(m_RotateZ) * Matrix.CreateScale(m_Scale) * Matrix.CreateTranslation(m_Position);
m_WorldDirty = false;
}
return m_World;
}
}
private string m_StringID;
public string ID
{
get { return m_StringID; }
set { m_StringID = value; }
}
public virtual void Initialize()
{
}
public abstract void Update(UpdateState state);
public abstract void Draw(GraphicsDevice device);
/// <summary>
/// GraphicsDevice was reset.
/// </summary>
public abstract void DeviceReset(GraphicsDevice Device);
public override string ToString()
{
if (m_StringID != null)
{
return m_StringID;
}
return base.ToString();
}
/// <summary>
/// This 3DComponent's camera's view.
/// </summary>
protected Matrix View
{
get
{
return Scene.Camera.View;
}
}
/// <summary>
/// This 3DComponent's camera's projection.
/// </summary>
protected Matrix Projection
{
get
{
return Scene.Camera.Projection;
}
}
}
}

View file

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
namespace FSO.Common.Rendering.Framework
{
public class _3DLayer : IGraphicsLayer
{
public GraphicsDevice Device;
public List<_3DAbstract> Scenes = new List<_3DAbstract>();
public List<_3DAbstract> External = new List<_3DAbstract>();
#region IGraphicsLayer Members
public void Update(FSO.Common.Rendering.Framework.Model.UpdateState state)
{
foreach (var scene in Scenes)
{
scene.Update(state);
}
foreach (var scene in External)
{
scene.Update(state);
}
}
public void PreDraw(Microsoft.Xna.Framework.Graphics.GraphicsDevice device)
{
foreach (var scene in Scenes)
{
if (scene.Visible) scene.PreDraw(device);
}
}
public void Draw(Microsoft.Xna.Framework.Graphics.GraphicsDevice device)
{
foreach (var scene in Scenes)
{
if (scene.Visible) scene.Draw(device);
}
}
public void Initialize(Microsoft.Xna.Framework.Graphics.GraphicsDevice device)
{
this.Device = device;
foreach (var scene in Scenes)
{
scene.Initialize(this);
}
foreach (var scene in External)
{
scene.Initialize(this);
}
}
public void Add(_3DAbstract scene)
{
Scenes.Add(scene);
if (this.Device != null)
{
scene.Initialize(this);
}
}
public void Remove(_3DAbstract scene)
{
Scenes.Remove(scene);
}
public void Clear()
{
foreach (var scene in Scenes)
{
if (scene is IDisposable) ((IDisposable)scene).Dispose();
}
Scenes.Clear();
}
/// <summary>
/// Adds a scene to the draw stack. The system will not call
/// Draw on the scene but it will be initialized and given updates
/// </summary>
/// <param name="scene"></param>
public void AddExternal(_3DAbstract scene){
External.Add(scene);
if (this.Device != null)
{
scene.Initialize(this);
}
}
public void RemoveExternal(_3DAbstract scene)
{
External.Remove(scene);
}
#endregion
}
}

View file

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using FSO.Common.Rendering.Framework.Camera;
using Microsoft.Xna.Framework.Graphics;
using FSO.Common.Rendering.Framework.Model;
namespace FSO.Common.Rendering.Framework
{
/// <summary>
/// A scene capable of rendering 3D elements.
/// </summary>
public class _3DScene : _3DAbstract
{
private List<_3DComponent> m_Elements = new List<_3DComponent>();
public new _3DLayer Parent;
/// <summary>
/// Creates a new _3DScene instance.
/// </summary>
/// <param name="Device">A GraphicsDevice instance used for rendering.</param>
/// <param name="camera">A camera inheriting from ICamera used for rendering.</param>
public _3DScene(GraphicsDevice Device, ICamera camera) : base(Device)
{
this.Camera = camera;
}
/// <summary>
/// Creates a new _3DScene instance.
/// </summary>
/// <param name="Device">A GraphicsDevice instance used for rendering.</param>
public _3DScene(GraphicsDevice Device) : base(Device)
{
}
/// <summary>
/// Graphics device was reset (happens when scene is updated or minimized.)
/// </summary>
void m_Device_DeviceReset(object sender, EventArgs e)
{
throw new NotImplementedException();
}
/// <summary>
/// Returns the _3DComponents that make up this scene.
/// </summary>
/// <returns>A List of _3DComponent instances.</returns>
public override List<_3DComponent> GetElements()
{
return m_Elements;
}
public override void Initialize(_3DLayer layer)
{
this.Parent = layer;
foreach (var element in m_Elements)
{
element.Initialize();
}
}
public override void Update(UpdateState state)
{
for (int i = 0; i < m_Elements.Count; i++)
{
m_Elements[i].Update(state);
}
}
/// <summary>
/// Removes a 3D element from this 3DScene.
/// </summary>
/// <param name="item">The _3DComponent instance to remove.</param>
public void Remove(_3DComponent item)
{
m_Elements.Remove(item);
}
/// <summary>
/// Adds a 3D element to this 3DScene.
/// </summary>
/// <param name="item">The _3DComponent instance to add.</param>
public override void Add(_3DComponent item)
{
m_Elements.Add(item);
item.Scene = this;
if (this.Parent != null)
{
item.Initialize();
}
}
public override void PreDraw(GraphicsDevice device){
}
public override void Draw(GraphicsDevice device)
{
for (int i = 0; i < m_Elements.Count; i++)
{
m_Elements[i].Draw(device);
}
}
public override string ToString()
{
if (ID != null)
{
return ID;
}
return base.ToString();
}
/// <summary>
/// GraphicsDevice was reset.
/// </summary>
/// <param name="Device">The GraphicsDevice instance.</param>
public override void DeviceReset(GraphicsDevice Device)
{
for (int i = 0; i < m_Elements.Count; i++)
m_Elements[i].DeviceReset(Device);
}
}
}

View file

@ -0,0 +1,44 @@
using FSO.Common.Rendering.Framework.Camera;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace FSO.Common.Rendering.Framework
{
public class _3DTargetScene : _3DScene
{
public RenderTarget2D Target;
private GraphicsDevice Device;
private int Multisample = 0;
public Color ClearColor = Color.Transparent;
public _3DTargetScene(GraphicsDevice device, ICamera camera, Point size, int multisample) : this(device, size, multisample) { Camera = camera; }
public _3DTargetScene(GraphicsDevice device, Point size, int multisample) : base(device)
{
Device = device;
Multisample = multisample;
SetSize(size);
}
public void SetSize(Point size)
{
if (Target != null) Target.Dispose();
Target = new RenderTarget2D(Device, size.X, size.Y, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, Multisample, RenderTargetUsage.PreserveContents);
}
public override void Draw(GraphicsDevice device)
{
var oldTargets = device.GetRenderTargets();
device.SetRenderTarget(Target);
device.Clear(ClearColor);
device.DepthStencilState = DepthStencilState.Default;
Camera.ProjectionDirty();
base.Draw(device);
device.SetRenderTargets(oldTargets);
}
public override void Dispose()
{
base.Dispose();
Target.Dispose();
}
}
}

View file

@ -0,0 +1,273 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.ComponentModel;
namespace FSO.Common.Rendering.Framework.Camera
{
/// <summary>
/// A basic camera for the game.
/// </summary>
[DisplayName("BasicCamera")]
public class BasicCamera : ICamera
{
public float NearPlane { get; set; }
public float FarPlane { get; set; }
public float AspectRatioMultiplier { get; set; }
protected Vector3 m_Position;
protected Vector3 m_Target;
protected Vector3 m_Up;
protected GraphicsDevice m_Device;
/// <summary>
/// Creates a new BasicCamera instance. Assumes projection is full screen!
/// </summary>
/// <param name="device">A GraphicsDevice instance used for rendering.</param>
/// <param name="Position">Camera's initial position.</param>
/// <param name="Target">Camera's initial target.</param>
/// <param name="Up">Camera's initial up vector.</param>
public BasicCamera(GraphicsDevice device, Vector3 Position, Vector3 Target, Vector3 Up)
{
m_Device = device;
AspectRatioMultiplier = 1.0f;
NearPlane = 1.0f;
FarPlane = 800.0f;
m_Position = Position;
m_Target = Target;
m_Up = Up;
m_ViewDirty = true;
/**
* Assume the projection is full screen, center origin
*/
ProjectionOrigin = new Vector2(
m_Device.Viewport.Width / 2.0f,
m_Device.Viewport.Height / 2.0f
);
}
protected Vector2 m_ProjectionOrigin = Vector2.Zero;
/// <summary>
/// Gets or sets this BasicCamera's projection origin.
/// </summary>
public Vector2 ProjectionOrigin
{
get
{
return m_ProjectionOrigin;
}
set
{
m_ProjectionOrigin = value;
m_ProjectionDirty = true;
}
}
protected Matrix m_Projection;
protected bool m_ProjectionDirty;
public void ProjectionDirty()
{
m_ProjectionDirty = true;
}
/// <summary>
/// Gets this camera's projection.
/// </summary>
[Browsable(false)]
public Matrix Projection
{
get
{
if (m_ProjectionDirty)
{
CalculateProjection();
m_ProjectionDirty = false;
}
return m_Projection;
}
}
private float _FOV = (float)Math.PI / 4f;
public float FOV
{
get
{
return _FOV;
}
set
{
_FOV = value;
ProjectionDirty();
}
}
protected virtual void CalculateProjection()
{
var device = m_Device;
var aspect = device.Viewport.AspectRatio * AspectRatioMultiplier;
var ratioX = m_ProjectionOrigin.X / device.Viewport.Width;
var ratioY = m_ProjectionOrigin.Y / device.Viewport.Height;
var projectionX = 0.0f - (1.0f * ratioX);
var projectionY = (1.0f * ratioY);
m_Projection = Matrix.CreatePerspectiveFieldOfView(FOV, aspect, NearPlane, FarPlane);
/*m_Projection = Matrix.CreatePerspectiveOffCenter(
projectionX, projectionX + 1.0f,
((projectionY-1.0f) / aspect), (projectionY) / aspect,
NearPlane, FarPlane
);*/
m_Projection = Matrix.CreateScale(Zoom, Zoom, 1.0f) * m_Projection;
}
protected virtual void CalculateView()
{
var translate = Matrix.CreateTranslation(m_Translation);
var position = Vector3.Transform(m_Position, translate);
var target = Vector3.Transform(m_Target, translate);
m_View = Matrix.CreateLookAt(position, target, m_Up);
}
protected bool m_ViewDirty = false;
protected Matrix m_View = Matrix.Identity;
[Browsable(false)]
public Matrix View
{
get
{
if (m_ViewDirty)
{
m_ViewDirty = false;
CalculateView();
}
return m_View;
}
}
protected float m_Zoom = 1.0f;
/// <summary>
/// Gets or sets this BasicCamera's zoom level.
/// </summary>
public float Zoom
{
get { return m_Zoom; }
set
{
m_Zoom = value;
m_ViewDirty = true;
m_ProjectionDirty = true;
}
}
protected Vector3 m_Translation;
/// <summary>
/// Gets or sets this BasicCamera's translation.
/// </summary>
public Vector3 Translation
{
get
{
return m_Translation;
}
set
{
m_Translation = value;
m_ViewDirty = true;
}
}
/// <summary>
/// Gets or sets this BasicCamera's position.
/// </summary>
public Vector3 Position
{
get
{
return m_Position;
}
set
{
m_Position = value;
m_ViewDirty = true;
}
}
/// <summary>
/// Gets or sets this BasicCamera's target.
/// </summary>
public Vector3 Target
{
get
{
return m_Target;
}
set
{
m_Target = value;
m_ViewDirty = true;
}
}
/// <summary>
/// Gets or sets this BasicCamera's up vector.
/// </summary>
public Vector3 Up
{
get
{
return m_Up;
}
set
{
m_Up = value;
m_ViewDirty = true;
}
}
public bool DrawCamera = false;
public void Draw(GraphicsDevice device)
{
/*
device.RasterizerState.PointSize = 30.0f;
device.VertexDeclaration = new VertexDeclaration(device, VertexPositionColor.VertexElements);
var effect = new BasicEffect(device);
effect.World = Matrix.Identity;
effect.View = View;
effect.Projection = Projection;
effect.VertexColorEnabled = true;
foreach (var pass in effect.Techniques[0].Passes)
{
pass.Apply();
var vertex = new VertexPositionColor(Position, Color.Green);
var vertexList = new VertexPositionColor[1] { vertex };
device.DrawUserPrimitives(PrimitiveType.PointList, vertexList, 0, 1);
vertex.Color = Color.Red;
vertex.Position = Target;
device.DrawUserPrimitives(PrimitiveType.PointList, vertexList, 0, 1);
}
* XNA4 no longer has support for point primitives.
*/
}
}
}

View file

@ -0,0 +1,24 @@
using Microsoft.Xna.Framework;
namespace FSO.Common.Rendering.Framework.Camera
{
public interface ICamera
{
Matrix View { get; }
Matrix Projection { get; }
Vector3 Position { get; set; }
Vector3 Target { get; set; }
Vector3 Up { get; set; }
Vector3 Translation { get; set; }
Vector2 ProjectionOrigin { get; set; }
float NearPlane { get; set; }
float FarPlane { get; set; }
float Zoom { get; set; }
float AspectRatioMultiplier { get; set; }
void ProjectionDirty();
}
}

View file

@ -0,0 +1,35 @@
namespace FSO.Common.Rendering.Framework.Camera
{
public class ManualCamera : ICamera
{
#region ICamera Members
public Microsoft.Xna.Framework.Matrix View { get; set; }
public Microsoft.Xna.Framework.Matrix Projection { get; set; }
public Microsoft.Xna.Framework.Vector3 Position { get; set; }
public Microsoft.Xna.Framework.Vector3 Target { get; set; }
public Microsoft.Xna.Framework.Vector3 Up { get; set; }
public Microsoft.Xna.Framework.Vector3 Translation { get; set; }
public Microsoft.Xna.Framework.Vector2 ProjectionOrigin { get; set; }
public float NearPlane { get; set; }
public float FarPlane { get; set; }
public float Zoom { get; set; }
public float AspectRatioMultiplier { get; set; }
public void ProjectionDirty()
{
}
#endregion
}
}

View file

@ -0,0 +1,37 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace FSO.Common.Rendering.Framework.Camera
{
/// <summary>
/// Orthographic camera for the game. Used for rendering lots.
/// </summary>
public class OrthographicCamera : BasicCamera
{
public OrthographicCamera(GraphicsDevice device, Vector3 Position, Vector3 Target, Vector3 Up)
: base(device, Position, Target, Up)
{
}
protected override void CalculateProjection()
{
var device = m_Device;
var aspect = device.Viewport.AspectRatio * AspectRatioMultiplier;
var ratioX = m_ProjectionOrigin.X / device.Viewport.Width;
var ratioY = m_ProjectionOrigin.Y / device.Viewport.Height;
var projectionX = 0.0f - (1.0f * ratioX);
var projectionY = (1.0f * ratioY);
m_Projection = Matrix.CreateOrthographicOffCenter(
projectionX, projectionX + 1.0f,
((projectionY - 1.0f) / aspect), (projectionY) / aspect,
NearPlane, FarPlane
);
var zoom = 1 / m_Zoom;
m_Projection = m_Projection * Matrix.CreateScale(zoom);
}
}
}

View file

@ -0,0 +1,137 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using FSO.Common.Utils;
namespace FSO.Common.Rendering.Framework
{
public enum CursorType
{
Normal,
ArrowUp,
ArrowUpLeft,
ArrowUpRight,
ArrowDown,
ArrowDownLeft,
ArrowDownRight,
ArrowLeft,
ArrowRight,
LiveNothing,
LiveObjectUnavail,
LivePerson,
IBeam,
SimsRotate,
SimsRotateNE,
SimsRotateSE,
SimsRotateSW,
SimsRotateNW,
SimsMove,
SimsPlace,
Hourglass,
LiveObjectAvail,
LiveObject1Star,
LiveObject2Star,
LiveObject3Star,
LiveObject4Star,
LiveObject5Star,
LiveObjectSpecial,
}
/// <summary>
/// Manages cursors in the game.
/// </summary>
public class CursorManager
{
public static CursorManager INSTANCE;
private Dictionary<CursorType, MouseCursor> m_CursorMap;
private GraphicsDevice GD;
public CursorType CurrentCursor { get; internal set;} = CursorType.Normal;
public CursorManager(GraphicsDevice gd)
{
INSTANCE = this;
m_CursorMap = new Dictionary<CursorType, MouseCursor>();
this.GD = gd;
}
public void SetCursor(CursorType type)
{
if (m_CursorMap.ContainsKey(type))
{
CurrentCursor = type;
Mouse.SetCursor(m_CursorMap[type]);
}
}
public Dictionary<CursorType, string> GenMap()
{
return new Dictionary< CursorType, string> (){
//{CursorType.Normal, "arrow.cur"},
{ CursorType.ArrowUp, "up.cur"},
{ CursorType.ArrowUpLeft, "upleft.cur"},
{ CursorType.ArrowUpRight, "upright.cur"},
{ CursorType.ArrowDown, "down.cur"},
{ CursorType.ArrowDownLeft, "downleft.cur"},
{ CursorType.ArrowDownRight, "downright.cur"},
{ CursorType.ArrowLeft, "left.cur"},
{ CursorType.ArrowRight, "right.cur"},
{ CursorType.LiveNothing, "livenothing.cur"},
{ CursorType.LiveObjectAvail, "liveobjectavail.cur"},
{ CursorType.LiveObjectUnavail, "liveobjectunavail.cur"},
{ CursorType.LivePerson, "liveperson.cur"},
{ CursorType.SimsRotate, "simsrotate.cur" },
{ CursorType.SimsRotateNE, "simsrotatene.cur" },
{ CursorType.SimsRotateNW, "simsrotatenw.cur" },
{ CursorType.SimsRotateSE, "simsrotatese.cur" },
{ CursorType.SimsRotateSW, "simsrotatesw.cur" },
{ CursorType.SimsMove, "simsmove.cur" },
{ CursorType.SimsPlace, "simsplace.cur" },
{ CursorType.Hourglass, "hourglass.cur" }
};
}
public void Init(string basepath, bool ts1)
{
var map = GenMap();
var curPath = "UIGraphics/Shared/cursors/";
if (!ts1) curPath = curPath.ToLowerInvariant();
foreach (var item in map)
{
m_CursorMap.Add(item.Key,
LoadCustomCursor(
Path.Combine(basepath, curPath, item.Value)
));
}
var starMax = 5;
var stars = LoadUpgradeCursors(Path.Combine(basepath, curPath, "liveobjectavail.cur"), starMax);
for (int i=0; i<starMax; i++)
{
m_CursorMap.Add(CursorType.LiveObject1Star + i, stars[i]);
}
m_CursorMap.Add(CursorType.IBeam, MouseCursor.IBeam);
//m_CursorMap.Add(CursorType.Hourglass, MouseCursor.Wait);
m_CursorMap.Add(CursorType.Normal, MouseCursor.Arrow);
}
private MouseCursor[] LoadUpgradeCursors(string path, int maxStars)
{
return CurLoader.LoadUpgradeCursors(GD, File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read), maxStars);
}
private MouseCursor LoadCustomCursor(string path)
{
return CurLoader.LoadMonoCursor(GD, File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read));
}
}
}

View file

@ -0,0 +1,30 @@
using Microsoft.Xna.Framework;
namespace FSO.Common.Rendering.Framework
{
public abstract class Game : Microsoft.Xna.Framework.Game
{
protected GraphicsDeviceManager Graphics;
protected GameScreen Screen;
public Game() : base()
{
Graphics = new GraphicsDeviceManager(this);
}
protected override void Initialize(){
base.Initialize();
Screen = new GameScreen(GraphicsDevice);
}
protected override void Update(GameTime gameTime){
Screen.Update(gameTime, IsActive);
}
protected override void Draw(GameTime gameTime){
base.Draw(gameTime);
Screen.Draw(gameTime);
}
}
}

View file

@ -0,0 +1,225 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using FSO.Common.Rendering.Framework.Model;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
namespace FSO.Common.Rendering.Framework
{
/// <summary>
/// A screen used for drawing.
/// </summary>
public class GameScreen
{
public List<IGraphicsLayer> Layers = new List<IGraphicsLayer>();
public GraphicsDevice Device;
public UpdateState State;
public static Color ClearColor = new Color(0x72, 0x72, 0x72);
private int touchedFrames;
private int lastTouchCount;
private MouseState lastMouseState;
private Vector2? prevTouchAvg;
private const int TOUCH_ACCEPT_TIME = 5;
public GameScreen(GraphicsDevice device)
{
this.Device = device;
State = new UpdateState();
}
private static List<char> TextCharacters = new List<char>();
public static void TextInput(object sender, TextInputEventArgs e)
{
TextCharacters.Add(e.Character);
}
/// <summary>
/// Adds a graphical element to this scene.
/// </summary>
/// <param name="layer">Element inheriting from IGraphicsLayer.</param>
public void Add(IGraphicsLayer layer)
{
layer.Initialize(Device);
Layers.Add(layer);
}
public void Update(GameTime time, bool hasFocus)
{
State.Time = time;
State.PreviousKeyboardState = State.KeyboardState;
State.FrameTextInput = TextCharacters;
var touchMode = FSOEnvironment.SoftwareKeyboard;
if (touchMode)
{
if (FSOEnvironment.SoftwareDepth) State.KeyboardState = new KeyboardState();
TouchCollection touches = TouchPanel.GetState();
var missing = new HashSet<MultiMouse>(State.MouseStates);
//relate touches to their last virtual mouse
foreach (var touch in touches)
{
var mouse = State.MouseStates.FirstOrDefault(x => x.ID == touch.Id);
if (mouse == null)
{
mouse = new MultiMouse { ID = touch.Id };
State.MouseStates.Add(mouse);
}
missing.Remove(mouse);
mouse.MouseState = new MouseState(
(int)touch.Position.X, (int)touch.Position.Y, 0,
ButtonState.Pressed,
ButtonState.Released,
ButtonState.Released,
ButtonState.Released,
ButtonState.Released
);
}
//if virtual mouses no longer have their touch, they are performing a "mouse up"
//if the state has mouseovers, we should record the mouse state as being lifted.
foreach (var miss in missing)
{
if (miss.LastMouseOver == null && miss.LastMouseDown == null)
{
State.MouseStates.Remove(miss);
} else
{
miss.MouseState = new MouseState(miss.MouseState.X, miss.MouseState.Y, 0, ButtonState.Released, ButtonState.Released, ButtonState.Released, ButtonState.Released, ButtonState.Released);
miss.Dead = true;
}
}
}
else
{
//single mouse state
if (hasFocus)
{
State.MouseState = Mouse.GetState();
State.KeyboardState = Keyboard.GetState();
}
else
{
State.MouseState = new MouseState();
State.KeyboardState = new KeyboardState();
}
if (State.KeyboardState.IsKeyDown(Keys.LeftAlt) && State.MouseState.LeftButton == ButtonState.Pressed)
{
//emulated middle click with alt
var ms = State.MouseState;
State.MouseState = new MouseState(ms.X, ms.Y, ms.ScrollWheelValue, ButtonState.Released, ButtonState.Pressed, ms.RightButton, ms.XButton1, ms.XButton2);
}
if (State.MouseStates.Count == 0)
{
State.MouseStates.Add(new MultiMouse { ID = 1 });
}
State.MouseStates[0].MouseState = State.MouseState;
}
State.SharedData.Clear();
State.Update();
foreach (var layer in Layers){
layer.Update(State);
}
TextCharacters.Clear();
}
private void TouchStub(UpdateState state)
{
var test = TouchPanel.EnableMouseTouchPoint;
TouchCollection touches = TouchPanel.GetState();
if (touches.Count != lastTouchCount) touchedFrames = 0;
lastTouchCount = touches.Count;
if (touches.Count > 0)
{
Vector2 avg = new Vector2();
for (int i = 0; i < touches.Count; i++)
{
avg += touches[i].Position;
}
avg /= touches.Count;
if (touchedFrames < TOUCH_ACCEPT_TIME)
{
avg = prevTouchAvg ?? avg;
state.MouseState = new MouseState(
(int)avg.X, (int)avg.Y, state.MouseState.ScrollWheelValue,
ButtonState.Released,
ButtonState.Released,
ButtonState.Released,
ButtonState.Released,
ButtonState.Released
);
touchedFrames++;
}
else
{
state.MouseState = new MouseState(
(int)avg.X, (int)avg.Y, state.MouseState.ScrollWheelValue,
(touches.Count > 1) ? ButtonState.Released : ButtonState.Pressed,
(touches.Count > 1) ? ButtonState.Pressed : ButtonState.Released,
(touches.Count > 1) ? ButtonState.Pressed : ButtonState.Released,
ButtonState.Released,
ButtonState.Released
);
prevTouchAvg = avg;
state.TouchMode = true;
}
}
else
{
prevTouchAvg = null;
touchedFrames = 0;
if (state.TouchMode) state.MouseState = new MouseState(
lastMouseState.X, lastMouseState.Y, state.MouseState.ScrollWheelValue,
ButtonState.Released,
ButtonState.Released,
ButtonState.Released,
ButtonState.Released,
ButtonState.Released
);
//state.TouchMode = false;
}
lastMouseState = state.MouseState;
}
public void Draw(GameTime time)
{
lock (Device)
{
foreach (var layer in Layers.Reverse<IGraphicsLayer>())
{
layer.PreDraw(Device);
}
}
Device.SetRenderTarget(null);
Device.BlendState = BlendState.AlphaBlend;
Device.Clear(ClearColor);
//Device.RasterizerState.AlphaBlendEnable = true;
//Device.DepthStencilState.DepthBufferEnable = true;
lock (Device)
{
foreach (var layer in Layers)
{
layer.Draw(Device);
}
}
}
}
}

View file

@ -0,0 +1,8 @@
using Microsoft.Xna.Framework.Graphics;
namespace FSO.Common.Rendering.Framework
{
public interface I3DGeometry {
void DrawGeometry(GraphicsDevice gd);
}
}

View file

@ -0,0 +1,13 @@
using FSO.Common.Rendering.Framework.Model;
using Microsoft.Xna.Framework.Graphics;
namespace FSO.Common.Rendering.Framework
{
public interface IGraphicsLayer
{
void Initialize(GraphicsDevice device);
void Update(UpdateState state);
void PreDraw(GraphicsDevice device);
void Draw(GraphicsDevice device);
}
}

View file

@ -0,0 +1,10 @@
namespace FSO.Common.Rendering.Framework.IO
{
public class ClipboardHandler
{
public static ClipboardHandler Default = new ClipboardHandler();
public virtual string Get() { return ""; }
public virtual void Set(string text) { }
}
}

View file

@ -0,0 +1,10 @@
namespace FSO.Common.Rendering.Framework.IO
{
/// <summary>
/// Represents an object that has depth
/// </summary>
public interface IDepthProvider
{
float Depth { get; }
}
}

View file

@ -0,0 +1,13 @@
namespace FSO.Common.Rendering.Framework.IO
{
public interface IFocusableUI
{
void OnFocusChanged(FocusEvent newFocus);
}
public enum FocusEvent
{
FocusIn,
FocusOut
}
}

View file

@ -0,0 +1,571 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using System.Runtime.InteropServices;
using FSO.Common.Rendering.Framework.Model;
namespace FSO.Common.Rendering.Framework.IO
{
/// <summary>
/// Manages input for the game.
/// </summary>
public class InputManager
{
private IFocusableUI LastFocus;
public bool RequireWindowFocus = false;
public void SetFocus(IFocusableUI ui)
{
/** No change **/
if (ui == LastFocus) { return; }
if (LastFocus != null)
{
LastFocus.OnFocusChanged(FocusEvent.FocusOut);
}
LastFocus = ui;
if (ui != null)
{
LastFocus.OnFocusChanged(FocusEvent.FocusIn);
}
}
public IFocusableUI GetFocus()
{
return LastFocus;
}
[DllImport("user32.dll")]
static extern int MapVirtualKey(uint uCode, uint uMapType);
/// <summary>
/// Utility to apply the result of pressing keys against a buffer
/// </summary>
/// <param name="buffer"></param>
/// <param name="keys"></param>
public KeyboardInputResult ApplyKeyboardInput(StringBuilder m_SBuilder, UpdateState state, int cursorIndex, int cursorEndIndex, bool allowInput)
{
if (!state.WindowFocused && RequireWindowFocus) { return null; }
var PressedKeys = state.KeyboardState.GetPressedKeys();
int charCount = 0;
if (state.FrameTextInput == null) charCount = 0;
else charCount = state.FrameTextInput.Count;
if (PressedKeys.Length + charCount == 0) { return null; }
//bit of a legacy thing going on here
//we support both "pressed keys" and the keyboard event system.
//todo: clean up a bit
var didChange = false;
var result = new KeyboardInputResult();
var m_CurrentKeyState = state.KeyboardState;
var m_OldKeyState = state.PreviousKeyboardState;
result.ShiftDown = PressedKeys.Contains(Keys.LeftShift) || PressedKeys.Contains(Keys.RightShift);
result.CapsDown = state.KeyboardState.CapsLock;
result.NumLockDown = state.KeyboardState.NumLock;
// Right alt aka AltGr is treated as Ctrl+Alt. It is used to type accented letters and other unusual characters so pressing that key cannot cause special actions.
result.CtrlDown = (PressedKeys.Contains(Keys.LeftControl) && !PressedKeys.Contains(Keys.RightAlt)) || PressedKeys.Contains(Keys.RightControl);
for (int j = 0; j < state.NewKeys.Count + charCount; j++)
{
var key = (j<state.NewKeys.Count)?state.NewKeys[j]:Keys.None;
bool processChar = true;
if (key != Keys.None)
{
processChar = false;
if (key == Keys.Back || key == Keys.Delete)
{
if (m_SBuilder.Length > 0)
{
/**
* Delete previous character or delete selection
*/
if (cursorEndIndex == -1 && result.CtrlDown)
{
/** Delete up until the previous whitespace char **/
int newEndIndex = cursorIndex;
if (newEndIndex == -1)
{
newEndIndex = m_SBuilder.Length;
cursorIndex = m_SBuilder.Length;
}
int dir = (key == Keys.Delete) ? 1 : -1;
int ws = (key == Keys.Delete) ? 0 : -1;
while (newEndIndex+ws >= 0 && newEndIndex+ws < m_SBuilder.Length)
{
if (Char.IsWhiteSpace(m_SBuilder[newEndIndex+ws]))
{
/** Keep the whitespace char **/
break;
}
newEndIndex += dir;
}
if (cursorIndex > newEndIndex)
{
cursorEndIndex = cursorIndex;
cursorIndex = newEndIndex;
}
else
cursorEndIndex = newEndIndex;
if (cursorEndIndex == cursorIndex)
cursorIndex = cursorEndIndex = -1;
}
if (cursorEndIndex == -1)
{
/** Previous character **/
var index = cursorIndex == -1 ? m_SBuilder.Length : cursorIndex;
if ((key == Keys.Back) && (index > 0))
{
var numToDelete = 1;
if (index > 1 && m_SBuilder[index - 1] == '\n' && m_SBuilder[index - 2] == '\r')
{
numToDelete = 2;
}
m_SBuilder.Remove(index - numToDelete, numToDelete);
result.NumDeletes += numToDelete;
if (cursorIndex != -1)
{
cursorIndex -= numToDelete;
}
}
else if ((key == Keys.Delete) && (index < m_SBuilder.Length))
{
/** Guys, delete removes the next character, not the last!! **/
var numToDelete = 1;
if ((index < m_SBuilder.Length - 1) && m_SBuilder[index] == '\r' && m_SBuilder[index + 1] == '\n')
{
numToDelete = 2;
}
m_SBuilder.Remove(index, numToDelete);
result.NumDeletes += numToDelete;
}
}
else
{
DeleteSelectedText(m_SBuilder, ref cursorIndex, ref cursorEndIndex, ref didChange, result);
}
result.SelectionChanged = true;
didChange = true;
}
}
else if (key == Keys.Enter)
{
if (allowInput)
{
/** Line break **/
if (cursorEndIndex != -1)
{
/** Delete selected text **/
DeleteSelectedText(m_SBuilder, ref cursorIndex, ref cursorEndIndex, ref didChange, result);
}
if (cursorIndex == -1)
{
m_SBuilder.Append("\n");
}
else
{
cursorIndex = Math.Min(m_SBuilder.Length, cursorIndex);
m_SBuilder.Insert(cursorIndex, "\n");
cursorIndex += 1;
}
result.NumInsertions += 1;
didChange = true;
result.EnterPressed = true;
}
}
else if (key == Keys.Tab)
{
result.TabPressed = true;
}
else if (result.CtrlDown)
{
switch (key)
{
case Keys.A:
/** Select all **/
cursorIndex = 0;
cursorEndIndex = m_SBuilder.Length;
result.SelectionChanged = true;
break;
case Keys.C:
case Keys.X:
/** Copy text to clipboard **/
if (cursorEndIndex > 0)
{
var selectionStart = Math.Max(0, cursorIndex);
var selectionEnd = cursorEndIndex;
GetSelectionRange(ref selectionStart, ref selectionEnd);
var str = m_SBuilder.ToString().Substring(selectionStart, selectionEnd - selectionStart);
ClipboardHandler.Default.Set(str);
if (key == Keys.X)
{
DeleteSelectedText(m_SBuilder, ref cursorIndex, ref cursorEndIndex, ref didChange, result);
}
}
break;
case Keys.V:
/** Paste text in **/
var clipboardText = ClipboardHandler.Default.Get();
if (clipboardText != null)
{
/** TODO: Cleanup the clipboard text to make sure its valid **/
/** If i have selection, delete it **/
if (cursorEndIndex != -1)
{
DeleteSelectedText(m_SBuilder, ref cursorIndex, ref cursorEndIndex, ref didChange, result);
}
/** Paste **/
if (cursorIndex == -1)
{
m_SBuilder.Append(clipboardText);
}
else
{
m_SBuilder.Insert(Math.Min(cursorIndex, m_SBuilder.Length), clipboardText);
cursorIndex += clipboardText.Length;
}
result.NumInsertions += clipboardText.Length;
didChange = true;
}
break;
}
} else {
result.UnhandledKeys.Add(key);
processChar = true;
}
}
if (processChar)
{
char value;
if (j >= state.NewKeys.Count) value = state.FrameTextInput[j - state.NewKeys.Count];
else if (state.FrameTextInput != null) continue;
else value = TranslateChar(key, result.ShiftDown, result.CapsDown, result.NumLockDown);
/** For now we dont support tabs in text **/
if (!char.IsControl(value) && value != '\0' && value != '\t' && value != '\b' && value != '\r')
{
if (allowInput)
{
if (cursorEndIndex != -1)
{
/** Delete selected text **/
DeleteSelectedText(m_SBuilder, ref cursorIndex, ref cursorEndIndex, ref didChange, result);
}
if (cursorIndex == -1)
{
m_SBuilder.Append(value);
}
else
{
m_SBuilder.Insert(cursorIndex, value);
cursorIndex++;
}
result.NumInsertions++;
didChange = true;
}
}
else
{
result.UnhandledKeys.Add(key);
}
}
}
result.SelectionStart = cursorIndex;
result.SelectionEnd = cursorEndIndex;
result.ContentChanged = didChange;
return result;
}
private void DeleteSelectedText(StringBuilder m_SBuilder, ref int cursorIndex, ref int cursorEndIndex, ref bool didChange, KeyboardInputResult result)
{
/** Remove selected text **/
var index = cursorIndex == -1 ? m_SBuilder.Length : cursorIndex;
var end = cursorEndIndex;
if (end < index)
{
var temp = index;
index = end;
end = temp;
}
m_SBuilder.Remove(index, end - index);
cursorIndex = index;
if (cursorIndex >= m_SBuilder.Length)
{
cursorIndex = -1;
}
cursorEndIndex = -1;
result.SelectionChanged = true;
didChange = true;
}
public void GetSelectionRange(ref int start, ref int end)
{
if (end < start)
{
var temp = start;
start = end;
end = temp;
}
}
public static char TranslateChar(Keys key, bool shift, bool capsLock, bool numLock)
{
switch (key)
{
case Keys.A: return TranslateAlphabetic('a', shift, capsLock);
case Keys.B: return TranslateAlphabetic('b', shift, capsLock);
case Keys.C: return TranslateAlphabetic('c', shift, capsLock);
case Keys.D: return TranslateAlphabetic('d', shift, capsLock);
case Keys.E: return TranslateAlphabetic('e', shift, capsLock);
case Keys.F: return TranslateAlphabetic('f', shift, capsLock);
case Keys.G: return TranslateAlphabetic('g', shift, capsLock);
case Keys.H: return TranslateAlphabetic('h', shift, capsLock);
case Keys.I: return TranslateAlphabetic('i', shift, capsLock);
case Keys.J: return TranslateAlphabetic('j', shift, capsLock);
case Keys.K: return TranslateAlphabetic('k', shift, capsLock);
case Keys.L: return TranslateAlphabetic('l', shift, capsLock);
case Keys.M: return TranslateAlphabetic('m', shift, capsLock);
case Keys.N: return TranslateAlphabetic('n', shift, capsLock);
case Keys.O: return TranslateAlphabetic('o', shift, capsLock);
case Keys.P: return TranslateAlphabetic('p', shift, capsLock);
case Keys.Q: return TranslateAlphabetic('q', shift, capsLock);
case Keys.R: return TranslateAlphabetic('r', shift, capsLock);
case Keys.S: return TranslateAlphabetic('s', shift, capsLock);
case Keys.T: return TranslateAlphabetic('t', shift, capsLock);
case Keys.U: return TranslateAlphabetic('u', shift, capsLock);
case Keys.V: return TranslateAlphabetic('v', shift, capsLock);
case Keys.W: return TranslateAlphabetic('w', shift, capsLock);
case Keys.X: return TranslateAlphabetic('x', shift, capsLock);
case Keys.Y: return TranslateAlphabetic('y', shift, capsLock);
case Keys.Z: return TranslateAlphabetic('z', shift, capsLock);
case Keys.D0: return (shift) ? ')' : '0';
case Keys.D1: return (shift) ? '!' : '1';
case Keys.D2: return (shift) ? '@' : '2';
case Keys.D3: return (shift) ? '#' : '3';
case Keys.D4: return (shift) ? '$' : '4';
case Keys.D5: return (shift) ? '%' : '5';
case Keys.D6: return (shift) ? '^' : '6';
case Keys.D7: return (shift) ? '&' : '7';
case Keys.D8: return (shift) ? '*' : '8';
case Keys.D9: return (shift) ? '(' : '9';
case Keys.Add: return '+';
case Keys.Divide: return '/';
case Keys.Multiply: return '*';
case Keys.Subtract: return '-';
case Keys.Space: return ' ';
case Keys.Tab: return '\t';
case Keys.Decimal: if (numLock && !shift) return '.'; break;
case Keys.NumPad0: if (numLock && !shift) return '0'; break;
case Keys.NumPad1: if (numLock && !shift) return '1'; break;
case Keys.NumPad2: if (numLock && !shift) return '2'; break;
case Keys.NumPad3: if (numLock && !shift) return '3'; break;
case Keys.NumPad4: if (numLock && !shift) return '4'; break;
case Keys.NumPad5: if (numLock && !shift) return '5'; break;
case Keys.NumPad6: if (numLock && !shift) return '6'; break;
case Keys.NumPad7: if (numLock && !shift) return '7'; break;
case Keys.NumPad8: if (numLock && !shift) return '8'; break;
case Keys.NumPad9: if (numLock && !shift) return '9'; break;
case Keys.OemBackslash: return shift ? '|' : '\\';
case Keys.OemCloseBrackets: return shift ? '}' : ']';
case Keys.OemComma: return shift ? '<' : ',';
case Keys.OemMinus: return shift ? '_' : '-';
case Keys.OemOpenBrackets: return shift ? '{' : '[';
case Keys.OemPeriod: return shift ? '>' : '.';
case Keys.OemPipe: return shift ? '|' : '\\';
case Keys.OemPlus: return shift ? '+' : '=';
case Keys.OemQuestion: return shift ? '?' : '/';
case Keys.OemQuotes: return shift ? '"' : '\'';
case Keys.OemSemicolon: return shift ? ':' : ';';
case Keys.OemTilde: return shift ? '~' : '`';
}
return (char)0;
}
public static char TranslateAlphabetic(char baseChar, bool shift, bool capsLock)
{
return (capsLock ^ shift) ? char.ToUpper(baseChar) : baseChar;
}
public void HandleMouseEvents(UpdateState state)
{
foreach (var mouse in state.MouseStates) {
var mouseBtnDown = mouse.MouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed;
var mouseDif = mouseBtnDown != mouse.LastMouseDownState;
if (mouse.NewMultiMouse) mouse.NewMultiMouse = false;
else
mouse.LastMouseDownState = mouseBtnDown;
state.MouseState = mouse.MouseState; //make sure each event uses the mouse state for this mouse.
state.CurrentMouseID = mouse.ID;
//if anyone accesses vanilla mouse state during the update loop, it will be the last mouse that was present.
var topMost =
state.MouseEvents.Where(x => x.Item1 == mouse.ID).OrderByDescending(x => x.Item2.Element.Depth).FirstOrDefault();
if (topMost != null && !mouse.Dead)
{
/** different element? **/
if (mouse.LastMouseOver != topMost.Item2)
{
if (mouse.LastMouseOver != null)
{
mouse.LastMouseOver.Callback(UIMouseEventType.MouseOut, state);
}
topMost.Item2.Callback(UIMouseEventType.MouseOver, state);
mouse.LastMouseOver = topMost.Item2;
}
}
else
{
if (mouse.LastMouseOver != null)
{
mouse.LastMouseOver.Callback(UIMouseEventType.MouseOut, state);
mouse.LastMouseOver = null;
}
}
if (mouseDif)
{
if (mouseBtnDown)
{
if (mouse.LastMouseDown != null)
{
/** We already have mouse down on an object **/
return;
}
if (mouse.LastMouseOver != null)
{
mouse.LastMouseDown = mouse.LastMouseOver;
mouse.LastMouseDown.Callback(UIMouseEventType.MouseDown, state);
}
}
else
{
if (mouse.LastMouseDown != null)
{
mouse.LastMouseDown.Callback(UIMouseEventType.MouseUp, state);
mouse.LastMouseDown = null;
}
}
}
}
}
}
public class KeyboardInputResult
{
public List<Keys> UnhandledKeys = new List<Keys>();
public bool ContentChanged;
public bool ShiftDown;
public bool CapsDown;
public bool NumLockDown;
public bool CtrlDown;
public bool EnterPressed;
public bool TabPressed;
public int NumDeletes;
public int NumInsertions;
public int SelectionStart;
public int SelectionEnd;
public bool SelectionChanged;
}
}

View file

@ -0,0 +1,25 @@
using FSO.Common.Rendering.Framework.Model;
using Microsoft.Xna.Framework;
namespace FSO.Common.Rendering.Framework.IO
{
public enum UIMouseEventType
{
MouseOver,
MouseOut,
MouseDown,
MouseUp
}
public delegate void UIMouseEvent(UIMouseEventType type, UpdateState state);
public class UIMouseEventRef
{
public UIMouseEvent Callback;
public Rectangle Region;
//public UIElement Element;
public UIMouseEventType LastState;
public IDepthProvider Element;
}
}

View file

@ -0,0 +1,21 @@
using Microsoft.Xna.Framework;
namespace FSO.Common.Rendering.Framework.Model
{
public class UIState
{
public int Width;
public int Height;
public UITooltipProperties TooltipProperties = new UITooltipProperties();
public string Tooltip;
}
public class UITooltipProperties
{
public float Opacity;
public Vector2 Position;
public bool Show;
public Color Color = Color.Black;
public bool UpdateDead;
}
}

View file

@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using FSO.Common.Rendering.Framework.IO;
namespace FSO.Common.Rendering.Framework.Model
{
public class MultiMouse
{
public int ID;
public MouseState MouseState;
public UIMouseEventRef LastMouseDown;
public UIMouseEventRef LastMouseOver;
public bool LastMouseDownState = false;
public bool NewMultiMouse = true;
public bool Dead = false;
}
/// <summary>
/// Contains common information used in the update loop
/// </summary>
public class UpdateState
{
public GameTime Time;
public List<MultiMouse> MouseStates = new List<MultiMouse>();
public MouseState MouseState;
public int CurrentMouseID;
public KeyboardState KeyboardState;
public bool ShiftDown
{
get { return KeyboardState.IsKeyDown(Keys.LeftShift) || KeyboardState.IsKeyDown(Keys.RightShift); }
}
/// <summary>
/// Right alt is treated as LeftCtrl+RightAlt so while right Alt is down, you cannot predict if left Ctrl is also down.
/// For that reason, this variable is false when left Ctrl and right Alt are down, and right Ctrl is not down.
/// </summary>
public bool CtrlDown
{
get { return (KeyboardState.IsKeyDown(Keys.LeftControl) && !KeyboardState.IsKeyDown(Keys.RightAlt)) || KeyboardState.IsKeyDown(Keys.RightControl); }
}
public bool AltDown
{
get { return KeyboardState.IsKeyDown(Keys.LeftAlt) || KeyboardState.IsKeyDown(Keys.RightAlt); }
}
public UIState UIState = new UIState();
public InputManager InputManager;
public bool TouchMode;
public KeyboardState PreviousKeyboardState;
public List<char> FrameTextInput;
/** A Place to keep shared variables, clears every update cycle **/
public Dictionary<string, object> SharedData = new Dictionary<string, object>();
public List<Tuple<int, UIMouseEventRef>> MouseEvents = new List<Tuple<int, UIMouseEventRef>>();
private Dictionary<Keys, long> KeyDownTime = new Dictionary<Keys, long>();
private List<Keys> KeyInRepeatMode = new List<Keys>();
public List<Keys> NewKeys = new List<Keys>();
public int Depth;
public bool WindowFocused;
public bool MouseOverWindow;
public bool ProcessMouseEvents
{
get
{
return WindowFocused && MouseOverWindow;
}
}
public void Update()
{
NewKeys.Clear();
Depth = 0;
/**
* If a key has been held down for X duration, treat it as if it is newly
* pressed
*/
for(var i=0; i < KeyInRepeatMode.Count; i++){
if (!KeyboardState.IsKeyDown(KeyInRepeatMode[i]))
{
KeyInRepeatMode.RemoveAt(i);
i--;
}
}
var now = Time.TotalGameTime.Ticks;
var keys = KeyboardState.GetPressedKeys();
foreach (var key in keys)
{
var newPress = PreviousKeyboardState.IsKeyUp(key);
if (newPress)
{
KeyDownTime[key] = now;
NewKeys.Add(key);
}
else
{
if (KeyInRepeatMode.Contains(key))
{
/** How long has it been down? **/
if (now - KeyDownTime[key] > 400000)
{
/** Its been down long enough, consider it a new key **/
KeyDownTime[key] = now;
NewKeys.Add(key);
}
}
else
{
/** How long has it been down? **/
if (now - KeyDownTime[key] > 9000000)
{
/** Its been down long enough, consider it in repeat mode **/
KeyDownTime[key] = now;
KeyInRepeatMode.Add(key);
}
}
}
}
}
}
}

View file

@ -0,0 +1,86 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace FSO.Common.Rendering.Framework.Shapes
{
public class _3DCube : _3DComponent
{
private BasicEffect Effect;
private VertexPositionColor[] Geom;
private List<VertexPositionColor> GeomList;
private Color Color;
private Vector3 Size;
public _3DCube(Color color, Vector3 size)
{
this.Color = color;
this.Size = size;
}
public override void Initialize(){
Effect = new BasicEffect(Device);
/** Bottom Face **/
var btmTL = new Vector3(0.0f, 0.0f, 0.0f);
var btmTR = new Vector3(Size.X, 0.0f, 0.0f);
var btmBR = new Vector3(Size.X, 0.0f, Size.Z);
var btmBL = new Vector3(0.0f, 0.0f, Size.Z);
/** Top face **/
var topTL = new Vector3(0.0f, Size.Y, 0.0f);
var topTR = new Vector3(Size.X, Size.Y, 0.0f);
var topBR = new Vector3(Size.X, Size.Y, Size.Z);
var topBL = new Vector3(0.0f, Size.Y, Size.Z);
GeomList = new List<VertexPositionColor>();
AddQuad(Color, topTL, topTR, topBR, topBL);
AddQuad(Color.Yellow, btmTL, btmTR, btmBR, btmBL);
AddQuad(Color.Green, topTL, topTR, btmTR, btmTL);
AddQuad(Color.Blue, topBL, topTL, btmTL, btmBL);
AddQuad(Color.Orange, topBR, topTR, btmTR, btmBR);
AddQuad(Color.White, topBL, topBR, btmBR, btmBL);
Geom = GeomList.ToArray();
}
private void AddQuad(Color color, Vector3 tl, Vector3 tr, Vector3 br, Vector3 bl)
{
GeomList.Add(new VertexPositionColor(tl, color));
GeomList.Add(new VertexPositionColor(tr, color));
GeomList.Add(new VertexPositionColor(br, color));
GeomList.Add(new VertexPositionColor(br, color));
GeomList.Add(new VertexPositionColor(bl, color));
GeomList.Add(new VertexPositionColor(tl, color));
}
public override void Draw(GraphicsDevice device)
{
Effect.World = World;
Effect.View = View;
Effect.Projection = Projection;
Effect.VertexColorEnabled = true;
//Effect.EnableDefaultLighting();
foreach (var pass in Effect.CurrentTechnique.Passes)
{
pass.Apply();
device.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, Geom, 0, Geom.Length / 3);
}
}
public override void Update(FSO.Common.Rendering.Framework.Model.UpdateState state)
{
}
public override void DeviceReset(GraphicsDevice Device)
{
}
}
}

View file

@ -0,0 +1,6 @@
using FSO.Common.Rendering.Framework.Model;
namespace FSO.Common.Rendering.Framework
{
public delegate void UpdateHookDelegate(UpdateState state);
}