diff --git a/Blarg.GameFramework/Blarg.GameFramework.csproj b/Blarg.GameFramework/Blarg.GameFramework.csproj
index a8477c5..1a7b5da 100644
--- a/Blarg.GameFramework/Blarg.GameFramework.csproj
+++ b/Blarg.GameFramework/Blarg.GameFramework.csproj
@@ -135,7 +135,6 @@
-
@@ -225,6 +224,8 @@
+
+
diff --git a/Blarg.GameFramework/Graphics/BillboardSpriteBatch.cs b/Blarg.GameFramework/Graphics/BillboardSpriteBatch.cs
index 32f902d..5f6464e 100644
--- a/Blarg.GameFramework/Graphics/BillboardSpriteBatch.cs
+++ b/Blarg.GameFramework/Graphics/BillboardSpriteBatch.cs
@@ -127,7 +127,7 @@ namespace Blarg.GameFramework.Graphics
throw new InvalidOperationException();
_cameraPosition = GraphicsDevice.ViewContext.Camera.Position;
- _cameraForward = GraphicsDevice.ViewContext.Camera.Forward;
+ _cameraForward = GraphicsDevice.ViewContext.Camera.Direction;
if (shader == null)
_shader = GraphicsDevice.Sprite3DShader;
diff --git a/Blarg.GameFramework/Graphics/Camera.cs b/Blarg.GameFramework/Graphics/Camera.cs
index 29a047d..d64b785 100644
--- a/Blarg.GameFramework/Graphics/Camera.cs
+++ b/Blarg.GameFramework/Graphics/Camera.cs
@@ -2,100 +2,58 @@ using System;
namespace Blarg.GameFramework.Graphics
{
- public class Camera
+ public abstract class Camera
{
- ViewContext _viewContext;
- float _nearHeight;
- float _nearWidth;
-
public readonly Frustum Frustum;
public Matrix4x4 LookAt;
public Matrix4x4 Projection;
- public Vector3 Forward;
- public Vector3 Up;
-
- public Vector3 Orientation;
public Vector3 Position;
+ public Vector3 Direction;
+ public Vector3 Up;
+ public float Near;
+ public float Far;
- public int ViewportWidth { get; private set; }
- public int ViewportHeight { get; private set; }
- public float AspectRatio { get; private set; }
- public float Near { get; private set; }
- public float Far { get; private set; }
- public float FieldOfViewAngle { get; private set; }
+ public int ViewportWidth { get; protected set; }
+ public int ViewportHeight { get; protected set; }
- public Camera(ViewContext viewContext, float near = 1.0f, float far = 50.0f, float fieldOfView = MathConstants.Radians60)
+ protected readonly ViewContext ViewContext;
+ protected float NearWidth;
+ protected float NearHeight;
+
+ public Camera(ViewContext viewContext, float near = 1.0f, float far = 50.0f)
{
if (viewContext == null)
throw new ArgumentNullException("viewContext");
- _viewContext = viewContext;
+ ViewContext = viewContext;
Frustum = new Frustum(this);
Position = Vector3.Zero;
- Orientation = Vector3.Zero;
- Forward = Vector3.Zero;
+ Direction = Vector3.Forward;
Up = Vector3.Up;
LookAt = Matrix4x4.Identity;
- FieldOfViewAngle = fieldOfView;
Near = near;
Far = far;
- CalculateDefaultProjection(
- _viewContext.ViewportLeft,
- _viewContext.ViewportTop,
- _viewContext.ViewportRight,
- _viewContext.ViewportBottom
- );
+ Update();
}
- public virtual void OnUpdate(float delta)
- {
- }
-
- public virtual void OnRender(float delta)
- {
- Vector3 movement = Vector3.Zero;
- UpdateLookAtMatrix(ref movement);
- _viewContext.ModelViewMatrix = LookAt;
- Frustum.Calculate();
- }
-
- public virtual void OnResize(ref Rect size)
- {
- CalculateDefaultProjection(size.Left, size.Top, size.Right, size.Bottom);
- _viewContext.ProjectionMatrix = Projection;
- }
-
- public virtual void UpdateProjectionMatrix()
- {
- CalculateDefaultProjection(
- _viewContext.ViewportLeft,
- _viewContext.ViewportTop,
- _viewContext.ViewportRight,
- _viewContext.ViewportBottom
- );
- }
-
- public virtual void UpdateLookAtMatrix(ref Vector3 movement)
- {
- CalculateDefaultLookAt(ref movement);
- }
+ public abstract void Update();
public Ray Pick(int screenX, int screenY)
{
- float nx = 2.0f * ((float)(screenX - (_viewContext.ViewportWidth / 2))) / ((float)_viewContext.ViewportWidth);
- float ny = 2.0f * -((float)(screenY - (_viewContext.ViewportHeight / 2))) / ((float)_viewContext.ViewportHeight);
+ float nx = 2.0f * ((float)(screenX - (ViewContext.ViewportWidth / 2))) / ((float)ViewContext.ViewportWidth);
+ float ny = 2.0f * -((float)(screenY - (ViewContext.ViewportHeight / 2))) / ((float)ViewContext.ViewportHeight);
// pick ray calculation method copied from http://code.google.com/p/libgdx/
- Vector3 vz = Vector3.Normalize(Forward * -1.0f);
+ Vector3 vz = Vector3.Normalize(Direction * -1.0f);
Vector3 vx = Vector3.Normalize(Vector3.Cross(Vector3.Up, vz));
Vector3 vy = Vector3.Normalize(Vector3.Cross(vz, vx));
Vector3 near_center = Position - (vz * Near);
- Vector3 a = (vx * _nearWidth) * nx;
- Vector3 b = (vy * _nearHeight) * ny;
+ Vector3 a = (vx * NearWidth) * nx;
+ Vector3 b = (vy * NearHeight) * ny;
Vector3 near_point = a + b + near_center;
Vector3 dir = Vector3.Normalize(near_point - Position);
@@ -105,8 +63,8 @@ namespace Blarg.GameFramework.Graphics
public Point2 Project(ref Vector3 objectPosition)
{
- Matrix4x4 modelview = _viewContext.ModelViewMatrix;
- Matrix4x4 projection = _viewContext.ProjectionMatrix;
+ Matrix4x4 modelview = ViewContext.ModelViewMatrix;
+ Matrix4x4 projection = ViewContext.ProjectionMatrix;
return Project(ref objectPosition, ref modelview, ref projection);
}
@@ -137,44 +95,14 @@ namespace Blarg.GameFramework.Graphics
// map to 2D viewport coordinates (ignoring Z)
Point2 result;
- result.X = (int)(((transformedX * 0.5f) + 0.5f) * (float)_viewContext.PixelScaler.ScaledWidth + (float)_viewContext.PixelScaler.ScaledViewport.Left);
- result.Y = (int)(((transformedY * 0.5f) + 0.5f) * (float)_viewContext.PixelScaler.ScaledHeight + (float)_viewContext.PixelScaler.ScaledViewport.Top);
+ result.X = (int)(((transformedX * 0.5f) + 0.5f) * (float)ViewContext.PixelScaler.ScaledWidth + (float)ViewContext.PixelScaler.ScaledViewport.Left);
+ result.Y = (int)(((transformedY * 0.5f) + 0.5f) * (float)ViewContext.PixelScaler.ScaledHeight + (float)ViewContext.PixelScaler.ScaledViewport.Top);
// float z = (1.0f + transformedZ) * 0.5f; // would be between 0.0f and 1.0f
// adjust Y coordinate so that 0 is at the top of the screen instead of the bottom
- result.Y = (int)_viewContext.PixelScaler.ScaledHeight - result.Y;
+ result.Y = (int)ViewContext.PixelScaler.ScaledHeight - result.Y;
return result;
}
-
- protected void CalculateDefaultProjection(int left, int top, int right, int bottom)
- {
- ViewportWidth = right - left;
- ViewportHeight = bottom - top;
-
- AspectRatio = (float)ViewportWidth / (float)ViewportHeight;
-
- _nearHeight = Near * (float)Math.Tan(FieldOfViewAngle / 2.0f);
- _nearWidth = _nearHeight * AspectRatio;
-
- Projection = Matrix4x4.CreatePerspectiveFieldOfView(FieldOfViewAngle, AspectRatio, Near, Far);
- }
-
- protected void CalculateDefaultLookAt(ref Vector3 movement)
- {
- // final camera orientation. angles must be negative (or rather, inverted) for the camera matrix. also the matrix concatenation order is important!
- Matrix4x4 rotation = Matrix4x4.CreateRotationY(-Orientation.Y) * Matrix4x4.CreateRotationX(-Orientation.X);
-
- // apply orientation to forward, movement and up vectors so they're pointing in the right direction
- Forward = Matrix4x4.Transform(rotation, Vector3.Forward);
- Up = Matrix4x4.Transform(rotation, Vector3.Up);
- Vector3 orientedMovement = Matrix4x4.Transform(rotation, movement);
-
- // move the camera position
- Position += orientedMovement;
-
- Vector3 target = Forward + Position;
- LookAt = Matrix4x4.CreateLookAt(Position, target, Vector3.Up);
- }
}
}
diff --git a/Blarg.GameFramework/Graphics/EulerPerspectiveCamera.cs b/Blarg.GameFramework/Graphics/EulerPerspectiveCamera.cs
new file mode 100644
index 0000000..c67cab6
--- /dev/null
+++ b/Blarg.GameFramework/Graphics/EulerPerspectiveCamera.cs
@@ -0,0 +1,37 @@
+using System;
+using Blarg.GameFramework.TileMap;
+
+namespace Blarg.GameFramework.Graphics
+{
+ public class EulerPerspectiveCamera : PerspectiveCamera
+ {
+ public float Yaw;
+ public float Pitch;
+
+ public Quaternion Rotation;
+
+ public EulerPerspectiveCamera(ViewContext viewContext, float near = 1.0f, float far = 50.0f, float fieldOfView = MathConstants.Radians60)
+ : base(viewContext, near, far, fieldOfView)
+ {
+ }
+
+ public override void Update()
+ {
+ UpdateRotation();
+
+ CalculateProjection();
+ CalculateLookAt();
+ }
+
+ public void UpdateRotation()
+ {
+ var rotationX = Quaternion.CreateFromAxisAngle(-Pitch, Vector3.XAxis);
+ var rotationY = Quaternion.CreateFromAxisAngle(-Yaw, Vector3.YAxis);
+ Rotation = rotationY * rotationX;
+
+ Direction = Quaternion.Transform(Rotation, Vector3.Forward);
+ Up = Quaternion.Transform(Rotation, Vector3.Up);
+ }
+ }
+}
+
diff --git a/Blarg.GameFramework/Graphics/PerspectiveCamera.cs b/Blarg.GameFramework/Graphics/PerspectiveCamera.cs
new file mode 100644
index 0000000..5449948
--- /dev/null
+++ b/Blarg.GameFramework/Graphics/PerspectiveCamera.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace Blarg.GameFramework.Graphics
+{
+ public class PerspectiveCamera : Camera
+ {
+ public float FieldOfViewAngle;
+
+ public PerspectiveCamera(ViewContext viewContext, float near = 1.0f, float far = 50.0f, float fieldOfView = MathConstants.Radians60)
+ : base(viewContext, near, far)
+ {
+ FieldOfViewAngle = fieldOfView;
+ }
+
+ public override void Update()
+ {
+ CalculateProjection();
+ CalculateLookAt();
+ }
+
+ protected void CalculateLookAt()
+ {
+ var target = Position + Direction;
+ Matrix4x4.CreateLookAt(ref Position, ref target, ref Up, out LookAt);
+ ViewContext.ModelViewMatrix = LookAt;
+ }
+
+ protected void CalculateProjection()
+ {
+ ViewportWidth = ViewContext.ViewportRight - ViewContext.ViewportLeft;
+ ViewportHeight = ViewContext.ViewportBottom - ViewContext.ViewportTop;
+
+ float aspectRatio = (float)ViewportWidth / (float)ViewportHeight;
+
+ NearHeight = Near * (float)Math.Tan(FieldOfViewAngle / 2.0f);
+ NearWidth = NearHeight * aspectRatio;
+
+ Matrix4x4.CreatePerspectiveFieldOfView(FieldOfViewAngle, aspectRatio, Near, Far, out Projection);
+ ViewContext.ProjectionMatrix = Projection;
+ }
+ }
+}
+
diff --git a/Blarg.GameFramework/Graphics/ViewContext.cs b/Blarg.GameFramework/Graphics/ViewContext.cs
index 9c9a7f2..1280e8d 100644
--- a/Blarg.GameFramework/Graphics/ViewContext.cs
+++ b/Blarg.GameFramework/Graphics/ViewContext.cs
@@ -55,7 +55,7 @@ namespace Blarg.GameFramework.Graphics
// not using the default camera, and clearing ("nulling") the camera
else if (!_isUsingDefaultCamera && value == null)
{
- _camera = new Camera(this);
+ _camera = new PerspectiveCamera(this);
_isUsingDefaultCamera = true;
cameraWasChanged = true;
}
@@ -183,7 +183,7 @@ namespace Blarg.GameFramework.Graphics
_viewport = viewport;
_viewportIsFixedSize = isFixedSizeViewport;
_screenOrientation = ScreenOrientation.Rotation0;
- _camera = new Camera(this);
+ _camera = new PerspectiveCamera(this);
_isUsingDefaultCamera = true;
_pixelScaler = new NoScaleOrthoPixelScaler();
_isUsingDefaultPixelScaler = true;
@@ -207,18 +207,12 @@ namespace Blarg.GameFramework.Graphics
public void OnRender(float delta)
{
if (_camera != null)
- _camera.OnRender(delta);
+ _camera.Update();
}
public void OnApply(ref Rect size, ScreenOrientation screenOrientation = ScreenOrientation.Rotation0)
{
SetupViewport(ref size, screenOrientation);
-
- // ensures it's set up for rendering immediately when this call returns
- // NOTE: we assume OnApply() is going to be called in some other class's
- // OnRender() event only (like, e.g. if a new framebuffer is bound)
- if (_camera != null)
- _camera.OnRender(0.0f);
}
private void SetupViewport(ref Rect size, ScreenOrientation screenOrientation)
@@ -257,7 +251,7 @@ namespace Blarg.GameFramework.Graphics
// we also **don't** want the camera to work with a rotated viewport
if (_camera != null)
- _camera.OnResize(ref _viewport);
+ _camera.Update();
}
}
}
diff --git a/Blarg.GameFramework/Support/FreeMovementCamera.cs b/Blarg.GameFramework/Support/FreeMovementCamera.cs
deleted file mode 100644
index de150c1..0000000
--- a/Blarg.GameFramework/Support/FreeMovementCamera.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using System;
-using Blarg.GameFramework.Graphics;
-using Blarg.GameFramework.Input;
-
-namespace Blarg.GameFramework.Support
-{
- public class FreeMovementCamera : Camera
- {
- Vector3 _movement;
-
- public FreeMovementCamera(ViewContext viewContext)
- : base(viewContext)
- {
- }
-
- public void Move(float x, float y, float z)
- {
- Position = new Vector3(Position.X + x, Position.Y + y, Position.Z + z);
- }
-
- public void Orient(float x, float y, float z)
- {
- Orientation = new Vector3(Orientation.X + x, Orientation.Y + y, Orientation.Z + z);
- }
-
- public override void OnUpdate(float delta)
- {
- float pointerDeltaX = 0.0f;
- float pointerDeltaY = 0.0f;
- bool isPointerTouching = false;
-
- if (Framework.Mouse != null && Framework.Mouse.IsDown(MouseButton.Left))
- {
- pointerDeltaX = Framework.Mouse.DeltaX;
- pointerDeltaY = Framework.Mouse.DeltaY;
- isPointerTouching = true;
- }
- else if (Framework.TouchScreen != null && Framework.TouchScreen.IsTouching)
- {
- pointerDeltaX = Framework.TouchScreen.PrimaryPointer.DeltaX;
- pointerDeltaY = Framework.TouchScreen.PrimaryPointer.DeltaY;
- isPointerTouching = true;
- }
-
-
- if (isPointerTouching)
- {
- var orientation = Orientation;
-
- orientation.Y += pointerDeltaX * 0.01f;
- orientation.X += pointerDeltaY * 0.01f;
-
- orientation.Y = MathHelpers.RolloverClamp(orientation.Y, MathConstants.Radians0, MathConstants.Radians360);
- orientation.X = MathHelpers.RolloverClamp(orientation.X, MathConstants.Radians0, MathConstants.Radians360);
-
- Orientation = orientation;
- }
-
- _movement = Vector3.Zero;
-
- if (Framework.Keyboard.IsDown(Key.Up))
- _movement.Z -= delta * 6.0f;
- if (Framework.Keyboard.IsDown(Key.Down))
- _movement.Z += delta * 6.0f;
- if (Framework.Keyboard.IsDown(Key.Left))
- _movement.X -= delta * 6.0f;
- if (Framework.Keyboard.IsDown(Key.Right))
- _movement.X += delta * 6.0f;
-
- UpdateLookAtMatrix(ref _movement);
- }
- }
-}
diff --git a/Game.Core/TestGameState.cs b/Game.Core/TestGameState.cs
index ac15591..fe68c25 100644
--- a/Game.Core/TestGameState.cs
+++ b/Game.Core/TestGameState.cs
@@ -4,6 +4,7 @@ using Blarg.GameFramework.Events;
using Blarg.GameFramework.Graphics;
using Blarg.GameFramework.Graphics.Helpers;
using Blarg.GameFramework.Graphics.ScreenEffects;
+using Blarg.GameFramework.Input;
using Blarg.GameFramework.States;
using Blarg.GameFramework.Support;
@@ -12,7 +13,7 @@ namespace Game
public class TestGameState : GameState
{
FlatWireframeGrid _grid;
- FreeMovementCamera _camera;
+ EulerPerspectiveCamera _camera;
public TestGameState(StateManager stateManager, EventManager eventManager)
: base(stateManager, eventManager)
@@ -21,7 +22,7 @@ namespace Game
public override void OnPush()
{
- _camera = new FreeMovementCamera(Framework.GraphicsDevice.ViewContext);
+ _camera = new EulerPerspectiveCamera(Framework.GraphicsDevice.ViewContext);
_camera.Position = new Vector3(0.0f, 5.0f, 0.0f);
Framework.GraphicsDevice.ViewContext.Camera = _camera;
@@ -54,7 +55,46 @@ namespace Game
base.OnUpdate(delta);
if (Framework.Keyboard.IsPressed(Blarg.GameFramework.Input.Key.Escape))
Framework.Application.Quit();
- _camera.OnUpdate(delta);
+
+ float pointerDeltaX = 0.0f;
+ float pointerDeltaY = 0.0f;
+ bool isPointerTouching = false;
+
+ if (Framework.Mouse != null && Framework.Mouse.IsDown(MouseButton.Left))
+ {
+ pointerDeltaX = Framework.Mouse.DeltaX;
+ pointerDeltaY = Framework.Mouse.DeltaY;
+ isPointerTouching = true;
+ }
+ else if (Framework.TouchScreen != null && Framework.TouchScreen.IsTouching)
+ {
+ pointerDeltaX = Framework.TouchScreen.PrimaryPointer.DeltaX;
+ pointerDeltaY = Framework.TouchScreen.PrimaryPointer.DeltaY;
+ isPointerTouching = true;
+ }
+
+
+ if (isPointerTouching)
+ {
+ _camera.Yaw += pointerDeltaX * 0.01f;
+ _camera.Pitch += pointerDeltaY * 0.01f;
+
+ _camera.Pitch = MathHelpers.RolloverClamp(_camera.Pitch, MathConstants.Radians0, MathConstants.Radians360);
+ _camera.Yaw = MathHelpers.RolloverClamp(_camera.Yaw, MathConstants.Radians0, MathConstants.Radians360);
+ }
+
+ var movement = Vector3.Zero;
+
+ if (Framework.Keyboard.IsDown(Key.Up))
+ movement.Z -= delta * 6.0f;
+ if (Framework.Keyboard.IsDown(Key.Down))
+ movement.Z += delta * 6.0f;
+ if (Framework.Keyboard.IsDown(Key.Left))
+ movement.X -= delta * 6.0f;
+ if (Framework.Keyboard.IsDown(Key.Right))
+ movement.X += delta * 6.0f;
+
+ _camera.Position += Quaternion.Transform(_camera.Rotation, movement);
}
}
}