132 lines
3.8 KiB
C#

using System;
using System.Drawing;
using OpenTK;
using OpenTK.Input;
namespace ClassicalSharp {
public abstract class Camera {
protected Game game;
public abstract Matrix4 GetProjection();
public abstract Matrix4 GetView();
public abstract bool IsThirdPerson { get; }
public virtual void Tick( double elapsed ) {
}
public virtual bool MouseZoom( MouseWheelEventArgs e ) {
return false;
}
public abstract void RegrabMouse();
public virtual void GetPickedBlock( PickedPos pos ) {
}
}
public abstract class PerspectiveCamera : Camera {
protected LocalPlayer player;
public PerspectiveCamera( Game game ) {
this.game = game;
player = game.LocalPlayer;
}
public override Matrix4 GetProjection() {
float fovy = (float)Utils.DegreesToRadians( 70 );
float aspectRatio = (float)game.Width / game.Height;
float zNear = game.Graphics.MinZNear;
return Matrix4.CreatePerspectiveFieldOfView( fovy, aspectRatio, zNear, game.ViewDistance );
}
public override void GetPickedBlock( PickedPos pos ) {
Vector3 dir = Utils.GetDirVector( player.YawRadians, player.PitchRadians );
Vector3 eyePos = player.EyePosition;
float reach = game.LocalPlayer.ReachDistance;
Picking.GetPickedBlockPos( game, eyePos, dir, reach, pos );
}
internal Point previous, delta;
void CentreMousePosition() {
if( !game.Focused ) return;
Point current = game.DesktopCursorPos;
delta = new Point( current.X - previous.X, current.Y - previous.Y );
Rectangle bounds = game.Bounds;
int cenX = bounds.Left + bounds.Width / 2;
int cenY = bounds.Top + bounds.Height / 2;
game.DesktopCursorPos = new Point( cenX, cenY );
// Fixes issues with large DPI displays on Windows >= 8.0.
previous = game.DesktopCursorPos;
}
public override void RegrabMouse() {
Rectangle bounds = game.Bounds;
int cenX = bounds.Left + bounds.Width / 2;
int cenY = bounds.Top + bounds.Height / 2;
game.DesktopCursorPos = new Point( cenX, cenY );
previous = new Point( cenX, cenY );
delta = Point.Empty;
}
static readonly float sensiFactor = (float)Utils.RadiansToDegrees( 0.0002f );
private void UpdateMouseRotation() {
float sensitivity = sensiFactor * game.MouseSensitivity;
float yaw = player.nextYaw + delta.X * sensitivity;
float pitch = player.nextPitch + delta.Y * sensitivity;
LocationUpdate update = LocationUpdate.MakeOri( yaw, pitch );
// Need to make sure we don't cross the vertical axes, because that gets weird.
if( update.Pitch >= 90 && update.Pitch <= 270 )
update.Pitch = player.nextPitch < 180 ? 89.9f : 270.1f;
game.LocalPlayer.SetLocation( update, true );
}
public override void Tick( double elapsed ) {
if( game.ScreenLockedInput ) return;
CentreMousePosition();
UpdateMouseRotation();
}
}
public class ThirdPersonCamera : PerspectiveCamera {
public ThirdPersonCamera( Game window ) : base( window ) {
}
float distance = 3;
public override bool MouseZoom( MouseWheelEventArgs e ) {
distance -= e.DeltaPrecise;
if( distance < 2 ) distance = 2;
return true;
}
public override Matrix4 GetView() {
Vector3 eyePos = player.EyePosition;
Vector3 cameraPos = eyePos - Utils.GetDirVector( player.YawRadians, player.PitchRadians ) * distance;
return Matrix4.LookAt( cameraPos, eyePos, Vector3.UnitY );
}
public override bool IsThirdPerson {
get { return true; }
}
}
public class FirstPersonCamera : PerspectiveCamera {
public FirstPersonCamera( Game window ) : base( window ) {
}
public override Matrix4 GetView() {
Vector3 eyePos = player.EyePosition;
Vector3 cameraDir = Utils.GetDirVector( player.YawRadians, player.PitchRadians );
return Matrix4.LookAt( eyePos, eyePos + cameraDir, Vector3.UnitY );
}
public override bool IsThirdPerson {
get { return false; }
}
}
}