diff --git a/TrueCraft.API/Vector3.cs b/TrueCraft.API/Vector3.cs index 26970ef..8b878a3 100644 --- a/TrueCraft.API/Vector3.cs +++ b/TrueCraft.API/Vector3.cs @@ -79,6 +79,14 @@ namespace TrueCraft.API return new Vector3(Math.Floor(X), Math.Floor(Y), Math.Floor(Z)); } + /// + /// Rounds the decimal component of each part of this Vector3. + /// + public Vector3 Round() + { + return new Vector3(Math.Round(X), Math.Round(Y), Math.Round(Z)); + } + /// /// Clamps the vector to within the specified value. /// diff --git a/TrueCraft.Client/Content/icons.png b/TrueCraft.Client/Content/icons.png new file mode 100644 index 0000000..590a89e Binary files /dev/null and b/TrueCraft.Client/Content/icons.png differ diff --git a/TrueCraft.Client/Modules/HUDModule.cs b/TrueCraft.Client/Modules/HUDModule.cs new file mode 100644 index 0000000..1a9a574 --- /dev/null +++ b/TrueCraft.Client/Modules/HUDModule.cs @@ -0,0 +1,38 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace TrueCraft.Client.Modules +{ + public class HUDModule : IGraphicalModule + { + private TrueCraftGame Game { get; set; } + private SpriteBatch SpriteBatch { get; set; } + private Texture2D GUI { get; set; } + private Texture2D Icons { get; set; } + + public HUDModule(TrueCraftGame game) + { + Game = game; + SpriteBatch = new SpriteBatch(game.GraphicsDevice); + GUI = game.TextureMapper.GetTexture("gui/gui.png"); + Icons = game.TextureMapper.GetTexture("gui/icons.png"); + } + + public void Update(GameTime gameTime) + { + } + + static readonly Color CrosshairColor = new Color(255, 255, 255, 70); + + public void Draw(GameTime gameTime) + { + SpriteBatch.Begin(samplerState: SamplerState.PointClamp); + SpriteBatch.Draw(Icons, new Vector2( + Game.GraphicsDevice.Viewport.Width / 2 - (8 * Game.ScaleFactor * 2), + Game.GraphicsDevice.Viewport.Height / 2 - (8 * Game.ScaleFactor * 2)), + new Rectangle(0, 0, 16, 16), CrosshairColor, + 0, Vector2.Zero, Game.ScaleFactor * 2, SpriteEffects.None, 1); + SpriteBatch.End(); + } + } +} diff --git a/TrueCraft.Client/Modules/HighlightModule.cs b/TrueCraft.Client/Modules/HighlightModule.cs index d38523e..fd750e7 100644 --- a/TrueCraft.Client/Modules/HighlightModule.cs +++ b/TrueCraft.Client/Modules/HighlightModule.cs @@ -3,6 +3,9 @@ using Microsoft.Xna.Framework.Graphics; using TrueCraft.API; using TrueCraft.Client.Rendering; using Microsoft.Xna.Framework; +using XVector3 = Microsoft.Xna.Framework.Vector3; +using TVector3 = TrueCraft.API.Vector3; +using TRay = TrueCraft.API.Ray; namespace TrueCraft.Client.Modules { @@ -10,51 +13,37 @@ namespace TrueCraft.Client.Modules { public TrueCraftGame Game { get; set; } - private Texture2D HighlightTexture { get; set; } private Coordinates3D HighlightedBlock { get; set; } - private Mesh HighlightMesh { get; set; } private BasicEffect HighlightEffect { get; set; } + private static readonly VertexPositionColor[] CubeVerticies; + private static readonly short[] CubeIndicies; + + static HighlightModule() + { + var color = Color.Black; + CubeVerticies = new[] + { + new VertexPositionColor(new XVector3(0, 0, 1), color), + new VertexPositionColor(new XVector3(1, 0, 1), color), + new VertexPositionColor(new XVector3(1, 1, 1), color), + new VertexPositionColor(new XVector3(0, 1, 1), color), + new VertexPositionColor(new XVector3(0, 0, 0), color), + new VertexPositionColor(new XVector3(1, 0, 0), color), + new VertexPositionColor(new XVector3(1, 1, 0), color), + new VertexPositionColor(new XVector3(0, 1, 0), color) + }; + CubeIndicies = new short[] + { + 0, 1, 1, 2, 2, 3, 3, 0, + 0, 4, 4, 7, 7, 6, 6, 2, + 1, 5, 5, 4, 3, 7, 6, 5 + }; + } public HighlightModule(TrueCraftGame game) { Game = game; - - const int size = 64; - HighlightedBlock = -Coordinates3D.One; - HighlightTexture = new Texture2D(Game.GraphicsDevice, size, size); - - var colors = new Color[size * size]; - for (int i = 0; i < colors.Length; i++) - colors[i] = Color.Transparent; - for (int x = 0; x < size; x++) - colors[x] = Color.Black; // Top - for (int x = 0; x < size; x++) - colors[x + (size - 1) * size] = Color.Black; // Bottom - for (int y = 0; y < size; y++) - colors[y * size] = Color.Black; // Left - for (int y = 0; y < size; y++) - colors[y * size + (size - 1)] = Color.Black; // Right - - HighlightTexture.SetData(colors); - var texcoords = new[] - { - Vector2.UnitX + Vector2.UnitY, - Vector2.UnitY, - Vector2.Zero, - Vector2.UnitX - }; - int[] indicies; - var verticies = BlockRenderer.CreateUniformCube(Microsoft.Xna.Framework.Vector3.Zero, - texcoords, VisibleFaces.All, 0, out indicies, Color.White); - HighlightMesh = new Mesh(Game, verticies, indicies); - HighlightEffect = new BasicEffect(Game.GraphicsDevice); - HighlightEffect.EnableDefaultLighting(); - HighlightEffect.DirectionalLight0.SpecularColor = Color.Black.ToVector3(); - HighlightEffect.DirectionalLight1.SpecularColor = Color.Black.ToVector3(); - HighlightEffect.DirectionalLight2.SpecularColor = Color.Black.ToVector3(); - HighlightEffect.TextureEnabled = true; - HighlightEffect.Texture = HighlightTexture; HighlightEffect.VertexColorEnabled = true; } @@ -66,18 +55,19 @@ namespace TrueCraft.Client.Modules Matrix.CreateRotationY(MathHelper.ToRadians(Game.Client.Yaw))); var cast = VoxelCast.Cast(Game.Client.World, - new TrueCraft.API.Ray(Game.Camera.Position, - new TrueCraft.API.Vector3(direction.X, direction.Y, direction.Z)), - Game.BlockRepository, TrueCraftGame.Reach); + new TRay(Game.Camera.Position, new TVector3(direction.X, direction.Y, direction.Z)), + Game.BlockRepository, (int)TrueCraftGame.Reach); if (cast == null) HighlightedBlock = -Coordinates3D.One; else { HighlightedBlock = cast.Item1; - HighlightEffect.World = Matrix.CreateScale(1.02f) * - Matrix.CreateTranslation(new Microsoft.Xna.Framework.Vector3( - cast.Item1.X, cast.Item1.Y, cast.Item1.Z)); + HighlightEffect.World = + Matrix.CreateTranslation(new XVector3(-0.5f)) * + Matrix.CreateScale(1.01f) * + Matrix.CreateTranslation(new XVector3(0.5f)) * + Matrix.CreateTranslation(new XVector3(cast.Item1.X, cast.Item1.Y, cast.Item1.Z)); } } @@ -87,8 +77,13 @@ namespace TrueCraft.Client.Modules if (HighlightedBlock != -Coordinates3D.One) { - Game.GraphicsDevice.DepthStencilState = DepthStencilState.None; - HighlightMesh.Draw(HighlightEffect); + foreach (var pass in HighlightEffect.CurrentTechnique.Passes) + { + pass.Apply(); + HighlightEffect.GraphicsDevice.DrawUserIndexedPrimitives( + PrimitiveType.LineList, CubeVerticies, 0, + CubeVerticies.Length, CubeIndicies, 0, CubeIndicies.Length / 2); + } } } } diff --git a/TrueCraft.Client/Modules/PlayerControlModule.cs b/TrueCraft.Client/Modules/PlayerControlModule.cs index af9aea1..c844f3d 100644 --- a/TrueCraft.Client/Modules/PlayerControlModule.cs +++ b/TrueCraft.Client/Modules/PlayerControlModule.cs @@ -11,10 +11,12 @@ namespace TrueCraft.Client.Modules { private TrueCraftGame Game { get; set; } private Vector3 Delta { get; set; } + private bool Capture { get; set; } public PlayerControlModule(TrueCraftGame game) { Game = game; + Capture = true; } public bool KeyDown(GameTime gameTime, KeyboardKeyEventArgs e) @@ -55,6 +57,14 @@ namespace TrueCraft.Client.Modules Delta += Vector3.Backward; return true; + case Keys.I: + Game.Client.Position = Game.Client.Position.Floor(); + return true; + + case Keys.Tab: + Capture = !Capture; + return true; + case Keys.Space: if (Math.Floor(Game.Client.Position.Y) == Game.Client.Position.Y) Game.Client.Velocity += TrueCraft.API.Vector3.Up * 0.3; @@ -96,6 +106,8 @@ namespace TrueCraft.Client.Modules public void MouseMove(GameTime gameTime, MouseMoveEventArgs e) { + if (!Capture) + return; var centerX = Game.GraphicsDevice.Viewport.Width / 2; var centerY = Game.GraphicsDevice.Viewport.Height / 2; Mouse.SetPosition(centerX, centerY); diff --git a/TrueCraft.Client/MultiplayerClient.cs b/TrueCraft.Client/MultiplayerClient.cs index 0d6ce0b..eb74f92 100644 --- a/TrueCraft.Client/MultiplayerClient.cs +++ b/TrueCraft.Client/MultiplayerClient.cs @@ -256,7 +256,8 @@ namespace TrueCraft.Client { get { - return new BoundingBox(Position, Position + Size); + var pos = Position - new Vector3(Width / 2, 0, Depth / 2); + return new BoundingBox(pos, pos + Size); } } diff --git a/TrueCraft.Client/Rendering/BlockRenderer.cs b/TrueCraft.Client/Rendering/BlockRenderer.cs index 8a27cda..f8b6ca5 100644 --- a/TrueCraft.Client/Rendering/BlockRenderer.cs +++ b/TrueCraft.Client/Rendering/BlockRenderer.cs @@ -147,50 +147,50 @@ namespace TrueCraft.Client.Rendering CubeMesh[0] = new[] // Positive Z face { - new Vector3(0.5f, -0.5f, 0.5f), - new Vector3(-0.5f, -0.5f, 0.5f), - new Vector3(-0.5f, 0.5f, 0.5f), - new Vector3(0.5f, 0.5f, 0.5f) + new Vector3(1, 0, 1), + new Vector3(0, 0, 1), + new Vector3(0, 1, 1), + new Vector3(1, 1, 1) }; CubeMesh[1] = new[] // Negative Z face { - new Vector3(-0.5f, -0.5f, -0.5f), - new Vector3(0.5f, -0.5f, -0.5f), - new Vector3(0.5f, 0.5f, -0.5f), - new Vector3(-0.5f, 0.5f, -0.5f) + new Vector3(0, 0, 0), + new Vector3(1, 0, 0), + new Vector3(1, 1, 0), + new Vector3(0, 1, 0) }; CubeMesh[2] = new[] // Positive X face { - new Vector3(0.5f, -0.5f, -0.5f), - new Vector3(0.5f, -0.5f, 0.5f), - new Vector3(0.5f, 0.5f, 0.5f), - new Vector3(0.5f, 0.5f, -0.5f) + new Vector3(1, 0, 0), + new Vector3(1, 0, 1), + new Vector3(1, 1, 1), + new Vector3(1, 1, 0) }; CubeMesh[3] = new[] // Negative X face { - new Vector3(-0.5f, -0.5f, 0.5f), - new Vector3(-0.5f, -0.5f, -0.5f), - new Vector3(-0.5f, 0.5f, -0.5f), - new Vector3(-0.5f, 0.5f, 0.5f) + new Vector3(0, 0, 1), + new Vector3(0, 0, 0), + new Vector3(0, 1, 0), + new Vector3(0, 1, 1) }; CubeMesh[4] = new[] // Positive Y face { - new Vector3(0.5f, 0.5f, 0.5f), - new Vector3(-0.5f, 0.5f, 0.5f), - new Vector3(-0.5f, 0.5f, -0.5f), - new Vector3(0.5f, 0.5f, -0.5f) + new Vector3(1, 1, 1), + new Vector3(0, 1, 1), + new Vector3(0, 1, 0), + new Vector3(1, 1, 0) }; CubeMesh[5] = new[] // Negative Y face { - new Vector3(0.5f, -0.5f, -0.5f), - new Vector3(-0.5f, -0.5f, -0.5f), - new Vector3(-0.5f, -0.5f, 0.5f), - new Vector3(0.5f, -0.5f, 0.5f) + new Vector3(1, 0, 0), + new Vector3(0, 0, 0), + new Vector3(0, 0, 1), + new Vector3(1, 0, 1) }; } } diff --git a/TrueCraft.Client/Rendering/Blocks/SnowRenderer.cs b/TrueCraft.Client/Rendering/Blocks/SnowRenderer.cs index 6a16e2a..a8eff25 100644 --- a/TrueCraft.Client/Rendering/Blocks/SnowRenderer.cs +++ b/TrueCraft.Client/Rendering/Blocks/SnowRenderer.cs @@ -27,17 +27,13 @@ namespace TrueCraft.Client.Rendering.Blocks public override VertexPositionNormalColorTexture[] Render(BlockDescriptor descriptor, Vector3 offset, VisibleFaces faces, Tuple textureMap, int indiciesOffset, out int[] indicies) { - var overhead = new Vector3(0.5f, 0.5f, 0.5f); - var cube = CreateUniformCube(overhead, Texture, faces, indiciesOffset, out indicies, Color.White); + var cube = CreateUniformCube(Vector3.Zero, Texture, faces, indiciesOffset, out indicies, Color.White); var heightMultiplier = new Vector3(1, ((descriptor.Metadata + 1) / 16f), 1); for (int i = 0; i < cube.Length; i++) { if (cube[i].Position.Y > 0) - { cube[i].Position *= heightMultiplier; - } cube[i].Position += offset; - cube[i].Position -= overhead; } return cube; } diff --git a/TrueCraft.Client/Rendering/Blocks/WheatRenderer.cs b/TrueCraft.Client/Rendering/Blocks/WheatRenderer.cs index debaf0c..2f75b09 100644 --- a/TrueCraft.Client/Rendering/Blocks/WheatRenderer.cs +++ b/TrueCraft.Client/Rendering/Blocks/WheatRenderer.cs @@ -46,10 +46,11 @@ namespace TrueCraft.Client.Rendering indicies = new int[4 * 2 * 6]; var verticies = new VertexPositionNormalColorTexture[4 * 2 * 6]; int[] _indicies; + var center = new Vector3(-0.5f, -0.5f, -0.5f); for (int _side = 0; _side < 4; _side++) // Y faces are the last two in the CubeFace enum, so we can just iterate to 4 { var side = (CubeFace)_side; - var quad = CreateQuad(side, Vector3.Zero, texture, 0, indiciesOffset, out _indicies, Color.White); + var quad = CreateQuad(side, center, texture, 0, indiciesOffset, out _indicies, Color.White); if (side == CubeFace.NegativeX || side == CubeFace.PositiveX) { for (int i = 0; i < quad.Length; i++) @@ -73,7 +74,7 @@ namespace TrueCraft.Client.Rendering for (int _side = 0; _side < 4; _side++) { var side = (CubeFace)_side; - var quad = CreateQuad(side, Vector3.Zero, texture, 0, indiciesOffset, out _indicies, Color.White); + var quad = CreateQuad(side, center, texture, 0, indiciesOffset, out _indicies, Color.White); if (side == CubeFace.NegativeX || side == CubeFace.PositiveX) { for (int i = 0; i < quad.Length; i++) @@ -98,6 +99,7 @@ namespace TrueCraft.Client.Rendering for (int i = 0; i < verticies.Length; i++) { verticies[i].Position.Y -= 1 / 16f; + verticies[i].Position -= center; } return verticies; } diff --git a/TrueCraft.Client/Rendering/FlatQuadRenderer.cs b/TrueCraft.Client/Rendering/FlatQuadRenderer.cs index d53106e..94da96d 100644 --- a/TrueCraft.Client/Rendering/FlatQuadRenderer.cs +++ b/TrueCraft.Client/Rendering/FlatQuadRenderer.cs @@ -80,34 +80,34 @@ namespace TrueCraft.Client.Rendering QuadMesh[0] = new[] { - new Vector3(0.5f, -0.5f, 0.5f), - new Vector3(-0.5f, -0.5f, -0.5f), - new Vector3(-0.5f, 0.5f, -0.5f), - new Vector3(0.5f, 0.5f, 0.5f) + new Vector3(1, 0, 1), + new Vector3(0, 0, 0), + new Vector3(0, 1, 0), + new Vector3(1, 1, 1) }; QuadMesh[1] = new[] { - new Vector3(-0.5f, -0.5f, -0.5f), - new Vector3(0.5f, -0.5f, 0.5f), - new Vector3(0.5f, 0.5f, 0.5f), - new Vector3(-0.5f, 0.5f, -0.5f) + new Vector3(0, 0, 0), + new Vector3(1, 0, 1), + new Vector3(1, 1, 1), + new Vector3(0, 1, 0) }; QuadMesh[2] = new[] { - new Vector3(-0.5f, -0.5f, 0.5f), - new Vector3(0.5f, -0.5f, -0.5f), - new Vector3(0.5f, 0.5f, -0.5f), - new Vector3(-0.5f, 0.5f, 0.5f) + new Vector3(0, 0, 1), + new Vector3(1, 0, 0), + new Vector3(1, 1, 0), + new Vector3(0, 1, 1) }; QuadMesh[3] = new[] { - new Vector3(0.5f, -0.5f, -0.5f), - new Vector3(-0.5f, -0.5f, 0.5f), - new Vector3(-0.5f, 0.5f, 0.5f), - new Vector3(0.5f, 0.5f, -0.5f) + new Vector3(1, 0, 0), + new Vector3(0, 0, 1), + new Vector3(0, 1, 1), + new Vector3(1, 1, 0) }; } } diff --git a/TrueCraft.Client/Rendering/TextureMapper.cs b/TrueCraft.Client/Rendering/TextureMapper.cs index 0e0486c..a6557d1 100644 --- a/TrueCraft.Client/Rendering/TextureMapper.cs +++ b/TrueCraft.Client/Rendering/TextureMapper.cs @@ -31,6 +31,8 @@ namespace TrueCraft.Client.Rendering Defaults.Add("items.png", new PngReader().Read(File.OpenRead("Content/items.png"), graphicsDevice)); Defaults.Add("terrain.png", new PngReader().Read(File.OpenRead("Content/terrain.png"), graphicsDevice)); + Defaults.Add("gui/gui.png", new PngReader().Read(File.OpenRead("Content/gui.png"), graphicsDevice)); + Defaults.Add("gui/icons.png", new PngReader().Read(File.OpenRead("Content/icons.png"), graphicsDevice)); } /// diff --git a/TrueCraft.Client/TrueCraft.Client.csproj b/TrueCraft.Client/TrueCraft.Client.csproj index 47c8691..3655bf5 100644 --- a/TrueCraft.Client/TrueCraft.Client.csproj +++ b/TrueCraft.Client/TrueCraft.Client.csproj @@ -132,6 +132,7 @@ + @@ -230,8 +231,11 @@ PreserveNewest + + PreserveNewest + - + \ No newline at end of file diff --git a/TrueCraft.Client/TrueCraftGame.cs b/TrueCraft.Client/TrueCraftGame.cs index 2e0adbe..4fcb959 100644 --- a/TrueCraft.Client/TrueCraftGame.cs +++ b/TrueCraft.Client/TrueCraftGame.cs @@ -28,6 +28,7 @@ namespace TrueCraft.Client public ConcurrentBag PendingMainThreadActions { get; set; } public double Bobbing { get; set; } public ChunkModule ChunkModule { get; set; } + public float ScaleFactor { get; set; } private List Modules { get; set; } private SpriteBatch SpriteBatch { get; set; } @@ -43,7 +44,7 @@ namespace TrueCraft.Client private GameTime GameTime { get; set; } private DebugInfoModule DebugInfoModule { get; set; } - public static readonly int Reach = 5; + public static readonly double Reach = 3; public IBlockRepository BlockRepository { @@ -63,6 +64,7 @@ namespace TrueCraft.Client Graphics.PreferredBackBufferWidth = UserSettings.Local.WindowResolution.Width; Graphics.PreferredBackBufferHeight = UserSettings.Local.WindowResolution.Height; Graphics.ApplyChanges(); + Window.ClientSizeChanged += Window_ClientSizeChanged; Client = client; EndPoint = endPoint; LastPhysicsUpdate = DateTime.MinValue; @@ -80,6 +82,16 @@ namespace TrueCraft.Client Components.Add(mouseComponent); } + void Window_ClientSizeChanged(object sender, EventArgs e) + { + if (GraphicsDevice.Viewport.Width < 640 || GraphicsDevice.Viewport.Height < 480) + ScaleFactor = 0.5f; + else if (GraphicsDevice.Viewport.Width < 978 || GraphicsDevice.Viewport.Height < 720) + ScaleFactor = 1.0f; + else + ScaleFactor = 1.5f; + } + protected override void Initialize() { Modules = new List(); @@ -92,6 +104,7 @@ namespace TrueCraft.Client Modules.Add(ChunkModule); Modules.Add(new HighlightModule(this)); Modules.Add(new PlayerControlModule(this)); + Modules.Add(new HUDModule(this)); Modules.Add(DebugInfoModule); Client.PropertyChanged += HandleClientPropertyChanged; @@ -111,6 +124,8 @@ namespace TrueCraft.Client Window.ClientSizeChanged += (sender, e) => CreateRenderTarget(); CreateRenderTarget(); SpriteBatch = new SpriteBatch(GraphicsDevice); + + Window_ClientSizeChanged(null, null); } private void CreateRenderTarget() @@ -235,9 +250,10 @@ namespace TrueCraft.Client var bobbing = Bobbing * 1.5; var xbob = Math.Cos(bobbing + Math.PI / 2) * bobbingMultiplier; var ybob = Math.Sin(Math.PI / 2 - (2 * bobbing)) * bobbingMultiplier; + Camera.Position = new TrueCraft.API.Vector3( Client.Position.X + xbob - (Client.Size.Width / 2), - Client.Position.Y + (Client.Size.Height - 0.5) + ybob, + Client.Position.Y + Client.Size.Height + ybob, Client.Position.Z - (Client.Size.Depth / 2)); Camera.Pitch = Client.Pitch; diff --git a/TrueCraft.Client/VoxelCast.cs b/TrueCraft.Client/VoxelCast.cs index 0ac6efb..9fdb467 100644 --- a/TrueCraft.Client/VoxelCast.cs +++ b/TrueCraft.Client/VoxelCast.cs @@ -15,122 +15,42 @@ namespace TrueCraft.Client // Thanks to http://gamedev.stackexchange.com/questions/47362/cast-ray-to-select-block-in-voxel-game public static Tuple Cast(ReadOnlyWorld world, - Ray ray, IBlockRepository repository, double max) + Ray ray, IBlockRepository repository, int max) { - var origin = ray.Position.Floor(); - var direction = ray.Direction; - var step = new Vector3(SigNum(ray.Direction.X), SigNum(ray.Direction.Y), SigNum(ray.Direction.Z)); - var tMax = new Vector3( - IntBound(origin.X, direction.X), - IntBound(origin.Y, direction.Y), - IntBound(origin.Z, direction.Z)); - var tDelta = new Vector3( - step.X / direction.X, - step.Y / direction.Y, - step.Z / direction.Z); - BlockFace face = BlockFace.PositiveY; + // TODO: There are more efficient ways of doing this, fwiw - if (ray.Direction == Vector3.Zero) + double min = max * 2; + var pick = -Coordinates3D.One; + for (int x = -max; x <= max; x++) + { + for (int y = -max; y <= max; y++) + { + for (int z = -max; z <= max; z++) + { + var coords = (Coordinates3D)(new Vector3(x, y, z) + ray.Position).Round(); + if (!world.IsValidPosition(coords)) + continue; + var id = world.GetBlockID(coords); + if (id != 0) + { + var provider = repository.GetBlockProvider(id); + var box = provider.BoundingBox; + if (box != null) + { + var distance = ray.Intersects(box.Value.OffsetBy(coords)); + if (distance != null && distance.Value < min) + { + min = distance.Value; + pick = coords; + } + } + } + } + } + } + if (pick == -Coordinates3D.One) return null; - - max /= Math.Sqrt(ray.Direction.X * ray.Direction.X - + ray.Direction.Y * ray.Direction.Y - + ray.Direction.Z * ray.Direction.Z); - - while (world.IsValidPosition((Coordinates3D)origin)) - { - var provider = repository.GetBlockProvider(world.GetBlockID((Coordinates3D)origin)); - var _box = provider.BoundingBox; - if (_box != null) - { - var box = _box.Value.OffsetBy((Coordinates3D)origin); - if (ray.Intersects(box) != null) - return new Tuple((Coordinates3D)origin, face); - } - - if (tMax.X < tMax.Y) - { - if (tMax.X < tMax.Z) - { - if (tMax.X > max) - return null; - // Update which cube we are now in. - origin.X += step.X; - // Adjust tMaxX to the next X-oriented boundary crossing. - tMax.X += tDelta.X; - // Record the normal vector of the cube face we entered. - if (step.X < 0) - face = BlockFace.PositiveX; - else - face = BlockFace.NegativeX; - } - else - { - if (tMax.Z > max) - return null; - origin.Z += step.Z; - tMax.Z += tDelta.Z; - if (step.Z < 0) - face = BlockFace.PositiveZ; - else - face = BlockFace.NegativeZ; - } - } - else - { - if (tMax.Y < tMax.Z) - { - if (tMax.Y > max) - return null; - origin.Y += step.Y; - tMax.Y += tDelta.Y; - if (step.Y < 0) - face = BlockFace.PositiveY; - else - face = BlockFace.NegativeY; - } - else - { - // Identical to the second case, repeated for simplicity in - // the conditionals. - if (tMax.Z > max) - break; - origin.Z += step.Z; - tMax.Z += tDelta.Z; - if (step.Z < 0) - face = BlockFace.PositiveZ; - else - face = BlockFace.NegativeZ; - } - } - } - - return null; - } - - private static double IntBound(double s, double ds) - { - // Find the smallest positive t such that s+t*ds is an integer. - if (ds < 0) - { - return IntBound(-s, -ds); - } - else - { - s = Mod(s, 1); - // problem is now s+t*ds = 1 - return (1 - s) / ds; - } - } - - private static int SigNum(double x) - { - return x > 0 ? 1 : x < 0 ? -1 : 0; - } - - private static double Mod(double value, double modulus) - { - return (value % modulus + modulus) % modulus; + return new Tuple(pick, BlockFace.PositiveY); } } }