diff --git a/ClassicalSharp/Entities/Player.Rendering.cs b/ClassicalSharp/Entities/Player.Rendering.cs
index b7569f0ef..1ec04dd81 100644
--- a/ClassicalSharp/Entities/Player.Rendering.cs
+++ b/ClassicalSharp/Entities/Player.Rendering.cs
@@ -45,11 +45,16 @@ namespace ClassicalSharp {
Vector3 pos = Position;
pos.Y += Model.NameYOffset;
+ float u1 = nameTex.U1, u2 = nameTex.U2;
+ if( game.Camera is ForwardThirdPersonCamera ) {
+ u1 = nameTex.U2; u2 = nameTex.U1;
+ }
+
FastColour col = FastColour.White;
- api.texVerts[0] = new VertexPos3fTex2fCol4b( Utils.RotateY( x1, y1, 0, cosA, sinA ) + pos, nameTex.U1, nameTex.V1, col );
- api.texVerts[1] = new VertexPos3fTex2fCol4b( Utils.RotateY( x2, y1, 0, cosA, sinA ) + pos, nameTex.U2, nameTex.V1, col );
- api.texVerts[2] = new VertexPos3fTex2fCol4b( Utils.RotateY( x2, y2, 0, cosA, sinA ) + pos, nameTex.U2, nameTex.V2, col );
- api.texVerts[3] = new VertexPos3fTex2fCol4b( Utils.RotateY( x1, y2, 0, cosA, sinA ) + pos, nameTex.U1, nameTex.V2, col );
+ api.texVerts[0] = new VertexPos3fTex2fCol4b( Utils.RotateY( x1, y1, 0, cosA, sinA ) + pos, u1, nameTex.V1, col );
+ api.texVerts[1] = new VertexPos3fTex2fCol4b( Utils.RotateY( x2, y1, 0, cosA, sinA ) + pos, u2, nameTex.V1, col );
+ api.texVerts[2] = new VertexPos3fTex2fCol4b( Utils.RotateY( x2, y2, 0, cosA, sinA ) + pos, u2, nameTex.V2, col );
+ api.texVerts[3] = new VertexPos3fTex2fCol4b( Utils.RotateY( x1, y2, 0, cosA, sinA ) + pos, u1, nameTex.V2, col );
api.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b );
api.DrawDynamicIndexedVb( DrawMode.Triangles, api.texVb, api.texVerts, 4, 6 );
diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs
index 3b8572bc4..188803b2d 100644
--- a/ClassicalSharp/Game/Game.cs
+++ b/ClassicalSharp/Game/Game.cs
@@ -27,7 +27,7 @@ namespace ClassicalSharp {
public CpeListInfo[] CpePlayersList = new CpeListInfo[256];
public LocalPlayer LocalPlayer;
public Camera Camera;
- Camera firstPersonCam, thirdPersonCam;
+ Camera firstPersonCam, thirdPersonCam, forwardThirdPersonCam;
public BlockInfo BlockInfo;
public double accumulator;
public TerrainAtlas2D TerrainAtlas;
@@ -153,6 +153,7 @@ namespace ClassicalSharp {
firstPersonCam = new FirstPersonCamera( this );
thirdPersonCam = new ThirdPersonCamera( this );
+ forwardThirdPersonCam = new ForwardThirdPersonCamera( this );
Camera = firstPersonCam;
CommandManager = new CommandManager();
CommandManager.Init( this );
@@ -332,7 +333,9 @@ namespace ClassicalSharp {
public void SetCamera( bool thirdPerson ) {
PerspectiveCamera oldCam = (PerspectiveCamera)Camera;
- Camera = ( thirdPerson && CanUseThirdPersonCamera ) ? thirdPersonCam : firstPersonCam;
+ Camera = (thirdPerson && CanUseThirdPersonCamera) ?
+ (Camera is FirstPersonCamera ? thirdPersonCam : forwardThirdPersonCam ) :
+ firstPersonCam;
PerspectiveCamera newCam = (PerspectiveCamera)Camera;
newCam.delta = oldCam.delta;
newCam.previous = oldCam.previous;
diff --git a/ClassicalSharp/Game/InputHandler.cs b/ClassicalSharp/Game/InputHandler.cs
index 614de5f6d..b0757a961 100644
--- a/ClassicalSharp/Game/InputHandler.cs
+++ b/ClassicalSharp/Game/InputHandler.cs
@@ -194,7 +194,7 @@ namespace ClassicalSharp {
WindowState.Normal : WindowState.Fullscreen;
}
} else if( key == game.Keys[KeyMapping.ThirdPersonCamera] ) {
- bool useThirdPerson = game.Camera is FirstPersonCamera;
+ bool useThirdPerson = !(game.Camera is ForwardThirdPersonCamera);
game.SetCamera( useThirdPerson );
} else if( key == game.Keys[KeyMapping.ViewDistance] ) {
if( game.IsKeyDown( Key.ShiftLeft ) || game.IsKeyDown( Key.ShiftRight ) ) {
diff --git a/ClassicalSharp/Physics/Picking.cs b/ClassicalSharp/Physics/Picking.cs
index bb3a6562c..12dd950a8 100644
--- a/ClassicalSharp/Physics/Picking.cs
+++ b/ClassicalSharp/Physics/Picking.cs
@@ -90,7 +90,7 @@ namespace ClassicalSharp {
float t0, t1;
if( Intersection.RayIntersectsBox( origin, dir, min, max, out t0, out t1 ) ) {
Vector3 intersect = origin + dir * t0;
- pickedPos.SetAsValid( min, max, intersect );
+ pickedPos.SetAsValid( min, max, block, intersect );
return;
}
}
@@ -122,12 +122,14 @@ namespace ClassicalSharp {
public Vector3I TranslatedPos;
public bool Valid = true;
public CpeBlockFace BlockFace;
+ public byte BlockType;
- public void SetAsValid( Vector3 min, Vector3 max, Vector3 intersect ) {
+ public void SetAsValid( Vector3 min, Vector3 max, byte block, Vector3 intersect ) {
Min = min;
Max = max;
BlockPos = Vector3I.Truncate( Min );
Valid = true;
+ BlockType = block;
Vector3I normal = Vector3I.Zero;
float dist = float.PositiveInfinity;
@@ -144,6 +146,7 @@ namespace ClassicalSharp {
Valid = false;
BlockPos = TranslatedPos = Vector3I.MinusOne;
BlockFace = (CpeBlockFace)255;
+ BlockType = 0;
}
void TestAxis( float dAxis, ref float dist, Vector3I nAxis, ref Vector3I normal,
diff --git a/ClassicalSharp/Rendering/MapEnvRenderer.cs b/ClassicalSharp/Rendering/MapEnvRenderer.cs
index 84e768f34..c5a13850f 100644
--- a/ClassicalSharp/Rendering/MapEnvRenderer.cs
+++ b/ClassicalSharp/Rendering/MapEnvRenderer.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
+using OpenTK;
namespace ClassicalSharp {
@@ -54,7 +55,8 @@ namespace ClassicalSharp {
graphics.BindVb( edgesVb );
// Do not draw water when we cannot see it.
// Fixes some 'depth bleeding through' issues with 16 bit depth buffers on large maps.
- if( game.LocalPlayer.EyePosition.Y >= 0 ) {
+ Vector3 eyePos = game.LocalPlayer.EyePosition;
+ if( game.Camera.GetCameraPos( eyePos ).Y >= 0 ) {
graphics.DrawIndexedVb_TrisT2fC4b( edgesVertices * 6 / 4, 0 );
} else {
graphics.DrawIndexedVb_TrisT2fC4b( edgesVerVertices * 6 / 4, edgesBaseVertices * 6 / 4 );
diff --git a/ClassicalSharp/Rendering/MapRenderer.cs b/ClassicalSharp/Rendering/MapRenderer.cs
index 46211c127..e9d6c5108 100644
--- a/ClassicalSharp/Rendering/MapRenderer.cs
+++ b/ClassicalSharp/Rendering/MapRenderer.cs
@@ -225,7 +225,8 @@ namespace ClassicalSharp {
int[] distances;
void UpdateSortOrder() {
Player p = game.LocalPlayer;
- Vector3I newChunkPos = Vector3I.Floor( p.EyePosition );
+ Vector3 cameraPos = game.Camera.GetCameraPos( p.EyePosition );
+ Vector3I newChunkPos = Vector3I.Floor( cameraPos );
newChunkPos.X = (newChunkPos.X & ~0x0F) + 8;
newChunkPos.Y = (newChunkPos.Y & ~0x0F) + 8;
newChunkPos.Z = (newChunkPos.Z & ~0x0F) + 8;
diff --git a/ClassicalSharp/Rendering/PickingRenderer.cs b/ClassicalSharp/Rendering/PickingRenderer.cs
index 938eadbb9..e0deacd5e 100644
--- a/ClassicalSharp/Rendering/PickingRenderer.cs
+++ b/ClassicalSharp/Rendering/PickingRenderer.cs
@@ -7,11 +7,13 @@ namespace ClassicalSharp.Renderers {
public class PickingRenderer {
IGraphicsApi graphics;
+ BlockInfo info;
int vb;
public PickingRenderer( Game window ) {
graphics = window.Graphics;
vb = graphics.CreateDynamicVb( VertexFormat.Pos3fCol4b, verticesCount );
+ info = window.BlockInfo;
}
FastColour col = FastColour.Black;
@@ -27,6 +29,10 @@ namespace ClassicalSharp.Renderers {
Vector3 p2 = pickedPos.Max + new Vector3( offset, offset, offset );
col.A = 150;
graphics.AlphaBlending = true;
+ if( info.IsSprite[pickedPos.BlockType] ) {
+ p1.X += 2.50f/16f; p1.Z += 2.50f/16f;
+ p2.X -= 2.50f/16f; p2.Z -= 2.50f/16f;
+ }
// bottom face
DrawYPlane( p1.Y, p1.X, p1.Z, p1.X + size, p2.Z );
diff --git a/ClassicalSharp/Rendering/StandardEnvRenderer.cs b/ClassicalSharp/Rendering/StandardEnvRenderer.cs
index 422cf6f5e..a169cb9c0 100644
--- a/ClassicalSharp/Rendering/StandardEnvRenderer.cs
+++ b/ClassicalSharp/Rendering/StandardEnvRenderer.cs
@@ -25,7 +25,8 @@ namespace ClassicalSharp.Renderers {
public override void Render( double deltaTime ) {
if( skyVb == -1 || cloudsVb == -1 ) return;
- Vector3 pos = game.LocalPlayer.EyePosition;
+ Vector3 eyePos = game.LocalPlayer.EyePosition;
+ Vector3 pos = game.Camera.GetCameraPos( eyePos );
if( pos.Y < map.CloudHeight + 8 ) {
graphics.BeginVbBatch( VertexFormat.Pos3fCol4b );
graphics.BindVb( skyVb );
diff --git a/ClassicalSharp/Utils/Camera.cs b/ClassicalSharp/Utils/Camera.cs
index 57001988c..7fd93efae 100644
--- a/ClassicalSharp/Utils/Camera.cs
+++ b/ClassicalSharp/Utils/Camera.cs
@@ -12,6 +12,12 @@ namespace ClassicalSharp {
public abstract Matrix4 GetView();
+ /// Calculates the location of the camera's position in the world
+ /// based on the entity's eye position.
+ public abstract Vector3 GetCameraPos( Vector3 eyePos );
+
+ /// Whether this camera is using a third person perspective.
+ /// This causes the local player to be renderered if true.
public abstract bool IsThirdPerson { get; }
public virtual void Tick( double elapsed ) {
@@ -23,6 +29,7 @@ namespace ClassicalSharp {
public abstract void RegrabMouse();
+ /// Calculates the picked block based on the camera's current position.
public virtual void GetPickedBlock( PickedPos pos ) {
}
}
@@ -112,6 +119,37 @@ namespace ClassicalSharp {
public override bool IsThirdPerson {
get { return true; }
}
+
+ public override Vector3 GetCameraPos( Vector3 eyePos ) {
+ return eyePos - Utils.GetDirVector( player.YawRadians, player.PitchRadians ) * distance;
+ }
+ }
+
+ public class ForwardThirdPersonCamera : PerspectiveCamera {
+
+ public ForwardThirdPersonCamera( 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 override Vector3 GetCameraPos( Vector3 eyePos ) {
+ return eyePos + Utils.GetDirVector( player.YawRadians, player.PitchRadians ) * distance;
+ }
}
public class FirstPersonCamera : PerspectiveCamera {
@@ -128,5 +166,9 @@ namespace ClassicalSharp {
public override bool IsThirdPerson {
get { return false; }
}
+
+ public override Vector3 GetCameraPos( Vector3 eyePos ) {
+ return eyePos;
+ }
}
}