Example #1
0
        public void UpdatePiece(JunctionPiece Piece, VoxelHandle Location)
        {
            DetachFromNeighbors();

            this.Piece    = Piece;
            this.Location = Location;

            LocalTransform = Matrix.CreateTranslation(Location.WorldPosition + new Vector3(Piece.Offset.X, 0, Piece.Offset.Y) + new Vector3(0.5f, 0.2f, 0.5f));

            var piece = RailLibrary.GetRailPiece(Piece.RailPiece);

            Frame = piece.Tile;
            ResetPrimitive();

            // Hack to make the listener update it's damn bounding box
            var deathTrigger = EnumerateChildren().OfType <GenericVoxelListener>().FirstOrDefault();

            if (deathTrigger != null)
            {
                deathTrigger.LocalTransform = Matrix.Identity;
            }

            AttachToNeighbors();
            PropogateTransforms();
        }
Example #2
0
        public List <Tuple <Vector3, Vector3> > GetTransformedConnections()
        {
            var piece     = RailLibrary.GetRailPiece(Piece.RailPiece);
            var transform = Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)Piece.Orientation) * GlobalTransform;

            return(piece.EnumerateConnections().Select(l => Tuple.Create(Vector3.Transform(l.Item1, transform), Vector3.Transform(l.Item2, transform))).ToList());
        }
Example #3
0
        public override void CreateCosmeticChildren(ComponentManager manager)
        {
            base.CreateCosmeticChildren(manager);

            var piece = RailLibrary.GetRailPiece(Piece.RailPiece);

            Sheet = new SpriteSheet(ContentPaths.rail_tiles, 32, 32);

            AddChild(new GenericVoxelListener(manager, Matrix.Identity, new Vector3(0.8f, 1.5f, 0.8f), Vector3.Zero, (_event) =>
            {
                if (!Active)
                {
                    return;
                }

                if (_event.Type == VoxelChangeEventType.VoxelTypeChanged && _event.NewVoxelType == 0)
                {
                    Die();
                    var designation = World.PlayerFaction.Designations.EnumerateEntityDesignations(DesignationType.Craft).FirstOrDefault(d => Object.ReferenceEquals(d.Body, this));
                    if (designation != null)
                    {
                        World.PlayerFaction.Designations.RemoveEntityDesignation(this, DesignationType.Craft);
                        var craftDesignation = designation.Tag as CraftDesignation;
                        if (craftDesignation.WorkPile != null)
                        {
                            craftDesignation.WorkPile.Die();
                        }
                    }
                }
            })).SetFlag(Flag.ShouldSerialize, false);

            UpdatePiece(Piece, Location);
        }
Example #4
0
        public static IEnumerable <uint> EnumerateForwardNetworkConnections(RailEntity Leaving, RailEntity Entering)
        {
            if (Leaving == null)
            {
                foreach (var neighbor in Entering.NeighborRails)
                {
                    yield return(neighbor.NeighborID);
                }
                yield break;
            }

            var connectionPoint = FindConnectionPoint(Leaving, Entering);

            if (connectionPoint != null)
            {
                var transformToEntitySpace = Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)Entering.GetPiece().Orientation) * Entering.GlobalTransform;
                var backConnection         = FindConnectionPoint(Entering, Leaving);

                var connection = FindConnectionFromTransformedEntrancePoint(RailLibrary.GetRailPiece(Entering.GetPiece().RailPiece), transformToEntitySpace,
                                                                            backConnection.Raised ? (connectionPoint.Position - Vector3.UnitY) : connectionPoint.Position);

                if (connection != null)
                {
                    foreach (var exit in connection.Exits)
                    {
                        var transformedExit = Vector3.Transform(exit, transformToEntitySpace);
                        foreach (var neighbor in Entering.NeighborRails)
                        {
                            if (neighbor.Raised)
                            {
                                transformedExit += Vector3.UnitY;
                            }

                            if ((neighbor.Position - transformedExit).LengthSquared() < 0.01f)
                            {
                                yield return(neighbor.NeighborID);
                            }
                        }
                    }
                }
            }
        }
Example #5
0
        private void AddScaffoldGeometry(Matrix transform, Vector4 sideBounds, Vector2[] sideUvs, float HeightOffset, bool FlipTexture)
        {
            var uvDelta = sideUvs[1].X - sideUvs[0].X;

            foreach (var railSpline in RailLibrary.GetRailPiece(Piece.RailPiece).RailSplines)
            {
                var uvStep = 1.0f / (railSpline.Count - 1);

                for (var i = 1; i < railSpline.Count; ++i)
                {
                    var baseIndex = Primitive.VertexCount;

                    Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(railSpline[i - 1].X, HeightOffset + 1.0f, railSpline[i - 1].Y), transform), Color.White, Color.White,
                                                           FlipTexture ? new Vector2(sideUvs[0].X + uvDelta - uvDelta * (uvStep * (i - 1)), sideUvs[0].Y) :
                                                           new Vector2(sideUvs[0].X + uvDelta * (uvStep * (i - 1)), sideUvs[0].Y),
                                                           sideBounds));

                    Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(railSpline[i].X, HeightOffset + 1.0f, railSpline[i].Y), transform), Color.White, Color.White,
                                                           FlipTexture ? new Vector2(sideUvs[0].X + uvDelta - uvDelta * (uvStep * i), sideUvs[0].Y) :
                                                           new Vector2(sideUvs[0].X + uvDelta * (uvStep * i), sideUvs[0].Y),
                                                           sideBounds));

                    Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(railSpline[i].X, HeightOffset, railSpline[i].Y), transform), Color.White, Color.White,
                                                           FlipTexture ? new Vector2(sideUvs[0].X + uvDelta - uvDelta * (uvStep * i), sideUvs[2].Y) :
                                                           new Vector2(sideUvs[0].X + uvDelta * (uvStep * i), sideUvs[2].Y),
                                                           sideBounds));

                    Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(railSpline[i - 1].X, HeightOffset, railSpline[i - 1].Y), transform), Color.White, Color.White,
                                                           FlipTexture ? new Vector2(sideUvs[0].X + uvDelta - uvDelta * (uvStep * (i - 1)), sideUvs[2].Y) :
                                                           new Vector2(sideUvs[0].X + uvDelta * (uvStep * (i - 1)), sideUvs[2].Y),
                                                           sideBounds));

                    Primitive.AddOffsetIndicies(new short[] { 0, 1, 3, 1, 2, 3 }, baseIndex);
                }
            }
        }
Example #6
0
        public override void Update(DwarfGame game, DwarfTime time)
        {
            if (Player.IsCameraRotationModeActive())
            {
                Player.VoxSelector.Enabled = false;
                Player.World.SetMouse(null);
                Player.BodySelector.Enabled = false;
                return;
            }

            Player.VoxSelector.Enabled       = true;
            Player.BodySelector.Enabled      = false;
            Player.VoxSelector.DrawBox       = false;
            Player.VoxSelector.DrawVoxel     = true;
            Player.VoxSelector.SelectionType = VoxelSelectionType.SelectEmpty;

            if (Player.World.IsMouseOverGui)
            {
                Player.World.SetMouse(Player.World.MousePointer);
            }
            else
            {
                Player.World.SetMouse(new Gui.MousePointer("mouse", 1, 4));
            }

            // Don't attempt any camera control if the user is trying to type intoa focus item.
            if (Player.World.Gui.FocusItem != null && !Player.World.Gui.FocusItem.IsAnyParentTransparent() && !Player.World.Gui.FocusItem.IsAnyParentHidden())
            {
                return;
            }
            KeyboardState state    = Keyboard.GetState();
            bool          leftKey  = state.IsKeyDown(ControlSettings.Mappings.RotateObjectLeft);
            bool          rightKey = state.IsKeyDown(ControlSettings.Mappings.RotateObjectRight);

            if (LeftPressed && !leftKey)
            {
                if (PathVoxels.Count > 1)
                {
                    var matched         = false;
                    var firstDelta      = CompassOrientationHelper.GetVoxelDelta(PathVoxels[0], PathVoxels[1]);
                    var firstConnection = new CompassConnection(OverrideStartingOrientation ? StartingOppositeOrientation : CompassOrientationHelper.Opposite(firstDelta), firstDelta);

                    var orientationDelta = 1;

                    for (; orientationDelta < 8 && !matched; ++orientationDelta)
                    {
                        firstConnection.A = CompassOrientationHelper.Rotate(firstConnection.A, 1);
                        foreach (var piece in RailLibrary.EnumeratePieces().Where(p => p.CompassConnections.Count != 0))
                        {
                            for (int j = 0; j < 4 && !matched; ++j)
                            {
                                foreach (var compassConnection in piece.CompassConnections)
                                {
                                    if (compassConnection.RotateToPiece((PieceOrientation)j) == firstConnection)
                                    {
                                        matched = true;
                                    }
                                }
                            }
                            if (matched)
                            {
                                break;
                            }
                        }
                    }

                    if (matched)
                    {
                        StartingOppositeOrientation = firstConnection.A;
                    }

                    OverrideStartingOrientation = true;
                }
            }
            if (RightPressed && !rightKey)
            {
                if (PathVoxels.Count > 1)
                {
                    var matched        = false;
                    var lastDelta      = CompassOrientationHelper.GetVoxelDelta(PathVoxels[PathVoxels.Count - 1], PathVoxels[PathVoxels.Count - 2]);
                    var lastConnection = new CompassConnection(lastDelta, OverrideEndingOrientation ? EndingOppositeOrientation : CompassOrientationHelper.Opposite(lastDelta));

                    var orientationDelta = 1;

                    for (; orientationDelta < 8 && !matched; ++orientationDelta)
                    {
                        lastConnection.B = CompassOrientationHelper.Rotate(lastConnection.B, 1);
                        foreach (var piece in RailLibrary.EnumeratePieces().Where(p => p.CompassConnections.Count != 0))
                        {
                            for (int j = 0; j < 4 && !matched; ++j)
                            {
                                foreach (var compassConnection in piece.CompassConnections)
                                {
                                    if (compassConnection.RotateToPiece((PieceOrientation)j) == lastConnection)
                                    {
                                        matched = true;
                                    }
                                }
                            }
                            if (matched)
                            {
                                break;
                            }
                        }
                    }

                    if (matched)
                    {
                        EndingOppositeOrientation = lastConnection.B;
                    }

                    OverrideEndingOrientation = true;
                }
            }
            LeftPressed  = leftKey;
            RightPressed = rightKey;

            var tint = Color.White;

            if (!Dragging)
            {
            }
            else
            {
                var voxelUnderMouse = Player.VoxSelector.VoxelUnderMouse;
                if (voxelUnderMouse == DragStartVoxel)
                {
                    // Create single straight preview piece
                }
                else
                {
                    var destinationPoint = voxelUnderMouse.Coordinate;

                    // Prevent path finding from attempting slopes - not supported yet.
                    destinationPoint = new GlobalVoxelCoordinate(destinationPoint.X, DragStartVoxel.Coordinate.Y, destinationPoint.Z);
                    var currentVoxel = DragStartVoxel.Coordinate;

                    PathVoxels.Clear();
                    PathVoxels.Add(currentVoxel);

                    while (true)
                    {
                        var   closestDirection = 0;
                        float closestDistance  = float.PositiveInfinity;
                        for (var i = 0; i < 8; ++i)
                        {
                            var offsetPos = currentVoxel + CompassOrientationHelper.GetOffset((CompassOrientation)i);
                            var distance  = (destinationPoint.ToVector3() - offsetPos.ToVector3()).LengthSquared();
                            if (distance < closestDistance)
                            {
                                closestDistance  = distance;
                                closestDirection = i;
                            }
                        }

                        var nextCoordinate = currentVoxel + CompassOrientationHelper.GetOffset((CompassOrientation)closestDirection);
                        PathVoxels.Add(nextCoordinate);
                        if (PathVoxels.Count >= 100)
                        {
                            break;
                        }

                        if (nextCoordinate == destinationPoint)
                        {
                            break;
                        }
                        currentVoxel = nextCoordinate;
                    }

                    // Iterate PathVoxels, determining deltas and using them to decide which piece to create.
                    var pathCompassConnections = new List <CompassConnection>();

                    if (PathVoxels.Count > 1)
                    {
                        var firstDelta = CompassOrientationHelper.GetVoxelDelta(PathVoxels[0], PathVoxels[1]);
                        pathCompassConnections.Add(new CompassConnection(OverrideStartingOrientation ? StartingOppositeOrientation : CompassOrientationHelper.Opposite(firstDelta), firstDelta));

                        for (var i = 1; i < PathVoxels.Count - 1; ++i)
                        {
                            pathCompassConnections.Add(new CompassConnection(
                                                           CompassOrientationHelper.GetVoxelDelta(PathVoxels[i], PathVoxels[i - 1]),
                                                           CompassOrientationHelper.GetVoxelDelta(PathVoxels[i], PathVoxels[i + 1])));
                        }

                        var lastDelta = CompassOrientationHelper.GetVoxelDelta(PathVoxels[PathVoxels.Count - 1], PathVoxels[PathVoxels.Count - 2]);
                        pathCompassConnections.Add(new CompassConnection(lastDelta, OverrideEndingOrientation ? EndingOppositeOrientation : CompassOrientationHelper.Opposite(lastDelta)));
                    }

                    var bodyCounter = 0;
                    var previousPieceAddedTrailingDiagonals = false;

                    for (var i = 0; i < pathCompassConnections.Count; ++i)
                    {
                        var pieceAdded = false;

                        foreach (var piece in RailLibrary.EnumeratePieces().Where(p => p.CompassConnections.Count != 0))
                        {
                            var matchedOrientation = PieceOrientation.North;
                            CompassConnection matchedConnection = new CompassConnection();
                            bool matched = false;
                            for (int j = 0; j < 4 && !matched; ++j)
                            {
                                foreach (var compassConnection in piece.CompassConnections)
                                {
                                    var rotated = compassConnection.RotateToPiece((PieceOrientation)j);
                                    if (rotated == pathCompassConnections[i])
                                    {
                                        matched            = true;
                                        matchedOrientation = (PieceOrientation)j;
                                        matchedConnection  = pathCompassConnections[i];
                                        break;
                                    }
                                }
                            }

                            if (matched)
                            {
                                var newPiece = new JunctionPiece
                                {
                                    Offset      = new Point(PathVoxels[i].X - DragStartVoxel.Coordinate.X, PathVoxels[i].Z - DragStartVoxel.Coordinate.Z),
                                    RailPiece   = piece.Name,
                                    Orientation = matchedOrientation
                                };

                                if (PreviewBodies.Count <= bodyCounter)
                                {
                                    PreviewBodies.Add(RailHelper.CreatePreviewBody(Player.World.ComponentManager, DragStartVoxel, newPiece));
                                }
                                else
                                {
                                    PreviewBodies[bodyCounter].UpdatePiece(newPiece, DragStartVoxel);
                                }

                                bodyCounter += 1;
                                pieceAdded   = true;

                                if (!previousPieceAddedTrailingDiagonals &&
                                    (matchedConnection.A == CompassOrientation.Northeast || matchedConnection.A == CompassOrientation.Southeast || matchedConnection.A == CompassOrientation.Southwest ||
                                     matchedConnection.A == CompassOrientation.Northwest))
                                {
                                    bodyCounter = AddDiagonal(bodyCounter, matchedConnection.A, newPiece, 7, 5);
                                    bodyCounter = AddDiagonal(bodyCounter, matchedConnection.A, newPiece, 1, 1);
                                }

                                if (matchedConnection.B == CompassOrientation.Northeast || matchedConnection.B == CompassOrientation.Southeast || matchedConnection.B == CompassOrientation.Southwest ||
                                    matchedConnection.B == CompassOrientation.Northwest)
                                {
                                    previousPieceAddedTrailingDiagonals = true;

                                    bodyCounter = AddDiagonal(bodyCounter, matchedConnection.B, newPiece, 7, 5);
                                    bodyCounter = AddDiagonal(bodyCounter, matchedConnection.B, newPiece, 1, 1);
                                }
                                else
                                {
                                    previousPieceAddedTrailingDiagonals = false;
                                }

                                break;
                            }
                        }

                        if (!pieceAdded)
                        {
                            break;
                        }
                    }

                    // Clean up any excess preview entities.
                    var lineSize = bodyCounter;

                    while (bodyCounter < PreviewBodies.Count)
                    {
                        PreviewBodies[bodyCounter].GetRoot().Delete();
                        bodyCounter += 1;
                    }

                    PreviewBodies = PreviewBodies.Take(lineSize).ToList();
                }
            }

            CanPlace = RailHelper.CanPlace(Player, PreviewBodies);
            if (CanPlace)
            {
                tint = GameSettings.Default.Colors.GetColor("Positive", Color.Green);
            }
            else
            {
                tint = GameSettings.Default.Colors.GetColor("Negative", Color.Red);
            }

            foreach (var body in PreviewBodies)
            {
                body.SetVertexColorRecursive(tint);
            }
        }
Example #7
0
        public static Texture2D RenderPatternIcons(GraphicsDevice device, Microsoft.Xna.Framework.Content.ContentManager Content, Gui.JsonTileSheet Sheet)
        {
            Initialize();

            var shader = new Shader(Content.Load <Effect>(ContentPaths.Shaders.TexturedShaders), true);

            var sqrt  = (int)(Math.Ceiling(Math.Sqrt(Patterns.Count)));
            var width = MathFunctions.NearestPowerOf2(sqrt * Sheet.TileWidth);

            var fitHorizontal = width / Sheet.TileWidth;
            var rowCount      = (int)Math.Ceiling((float)Patterns.Count / (float)fitHorizontal);
            var height        = MathFunctions.NearestPowerOf2(rowCount * Sheet.TileHeight);

            RenderTarget2D toReturn  = new RenderTarget2D(device, width, height, false, SurfaceFormat.Color, DepthFormat.Depth16, 16, RenderTargetUsage.PreserveContents);
            var            tileSheet = new SpriteSheet(ContentPaths.rail_tiles, 32);

            device.SetRenderTarget(toReturn);
            device.Clear(Color.Transparent);
            shader.SetTexturedTechnique();
            shader.MainTexture             = AssetManager.GetContentTexture(ContentPaths.rail_tiles);
            shader.SelfIlluminationEnabled = true;
            shader.SelfIlluminationTexture = AssetManager.GetContentTexture(ContentPaths.Terrain.terrain_illumination);
            shader.EnableShadows           = false;
            shader.EnableLighting          = false;
            shader.ClippingEnabled         = false;
            shader.CameraPosition          = new Vector3(-0.5f, 0.5f, 0.5f);
            shader.VertexColorTint         = Color.White;
            shader.LightRamp                = Color.White;
            shader.SunlightGradient         = AssetManager.GetContentTexture(ContentPaths.Gradients.sungradient);
            shader.AmbientOcclusionGradient = AssetManager.GetContentTexture(ContentPaths.Gradients.ambientgradient);
            shader.TorchlightGradient       = AssetManager.GetContentTexture(ContentPaths.Gradients.torchgradient);

            Viewport oldview = device.Viewport;
            int      rows    = height / Sheet.TileWidth;
            int      cols    = width / Sheet.TileWidth;

            device.ScissorRectangle  = new Rectangle(0, 0, Sheet.TileWidth, Sheet.TileHeight);
            device.RasterizerState   = RasterizerState.CullNone;
            device.DepthStencilState = DepthStencilState.Default;
            Vector3 half = Vector3.One * 0.5f;

            half = new Vector3(half.X, half.Y, half.Z);

            foreach (EffectPass pass in shader.CurrentTechnique.Passes)
            {
                int ID = 0;

                foreach (var type in Patterns)
                {
                    int row = ID / cols;
                    int col = ID % cols;

                    var xboundsMin = 0;
                    var xboundsMax = 0;
                    var yboundsMin = 0;
                    var yboundsMax = 0;

                    var primitive = new RawPrimitive();
                    foreach (var piece in type.Pieces)
                    {
                        var rawPiece = RailLibrary.GetRailPiece(piece.RailPiece);
                        var bounds   = Vector4.Zero;
                        var uvs      = tileSheet.GenerateTileUVs(rawPiece.Tile, out bounds);
                        primitive.AddQuad(
                            Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)piece.Orientation)
                            * Matrix.CreateTranslation(new Vector3(piece.Offset.X, 0.0f, piece.Offset.Y)),
                            Color.White, Color.White, uvs, bounds);

                        xboundsMin = Math.Min(xboundsMin, piece.Offset.X);
                        xboundsMax = Math.Max(xboundsMax, piece.Offset.X);
                        yboundsMin = Math.Min(yboundsMin, piece.Offset.Y);
                        yboundsMax = Math.Max(yboundsMax, piece.Offset.Y);
                    }

                    float xSize = xboundsMax - xboundsMin + 1;
                    float ySize = yboundsMax - yboundsMin + 1;

                    var cameraPos = new Vector3(xboundsMin + (xSize / 2), 2.0f, yboundsMax + 1.0f);

                    device.Viewport = new Viewport(col * Sheet.TileWidth, row * Sheet.TileHeight, Sheet.TileWidth, Sheet.TileHeight);
                    shader.View     = Matrix.CreateLookAt(cameraPos,
                                                          new Vector3((xboundsMin + (xSize / 2)), 0.0f, yboundsMin),
                                                          Vector3.UnitY);
                    shader.Projection     = Matrix.CreatePerspectiveFieldOfView(1.0f, 1.0f, 0.1f, 10);
                    shader.World          = Matrix.Identity;
                    shader.CameraPosition = cameraPos;
                    pass.Apply();
                    primitive.Render(device);

                    ++ID;
                }
            }
            device.Viewport = oldview;
            device.SetRenderTarget(null);
            return((Texture2D)toReturn);
        }
Example #8
0
        private void AttachToNeighbors()
        {
            System.Diagnostics.Debug.Assert(NeighborRails.Count == 0);

            var myPiece = RailLibrary.GetRailPiece(Piece.RailPiece);

            var myEndPoints = GetTransformedConnections().SelectMany(l => new Vector3[] { l.Item1, l.Item2 });

            foreach (var entity in Manager.World.EnumerateIntersectingObjects(this.BoundingBox.Expand(0.5f), CollisionType.Static))
            {
                if (Object.ReferenceEquals(entity, this))
                {
                    continue;
                }
                var neighborRail = entity as RailEntity;
                if (neighborRail == null)
                {
                    continue;
                }
                var neighborEndPoints = neighborRail.GetTransformedConnections().SelectMany(l => new Vector3[] { l.Item1, l.Item2 });
                foreach (var point in myEndPoints)
                {
                    foreach (var nPoint in neighborEndPoints)
                    {
                        if ((nPoint - point).LengthSquared() < 0.01f)
                        {
                            AttachNeighbor(neighborRail.GlobalID, point, false);
                            neighborRail.AttachNeighbor(this.GlobalID, point, false);
                            goto __CONTINUE;
                        }
                    }

                    if (myPiece.AutoSlope)
                    {
                        var raisedPoint = point + new Vector3(0.0f, 1.0f, 0.0f);
                        foreach (var nPoint in neighborEndPoints)
                        {
                            if ((nPoint - raisedPoint).LengthSquared() < 0.01f)
                            {
                                AttachNeighbor(neighborRail.GlobalID, raisedPoint, true);
                                neighborRail.AttachNeighbor(this.GlobalID, raisedPoint, false);
                                goto __CONTINUE;
                            }
                        }
                    }

                    var neighborPiece = RailLibrary.GetRailPiece(neighborRail.Piece.RailPiece);
                    if (neighborPiece.AutoSlope)
                    {
                        var loweredPoint = point - new Vector3(0.0f, 1.0f, 0.0f);
                        foreach (var nPoint in neighborEndPoints)
                        {
                            if ((nPoint - loweredPoint).LengthSquared() < 0.01f)
                            {
                                AttachNeighbor(neighborRail.GlobalID, point, false);
                                neighborRail.AttachNeighbor(this.GlobalID, point, true);
                                goto __CONTINUE;
                            }
                        }
                    }
                }
                __CONTINUE :;
            }
        }
Example #9
0
        override public void Render(DwarfTime gameTime, ChunkManager chunks, Camera camera, SpriteBatch spriteBatch, GraphicsDevice graphicsDevice, Shader effect, bool renderingForWater)
        {
            base.Render(gameTime, chunks, camera, spriteBatch, graphicsDevice, effect, renderingForWater);

            if (Debugger.Switches.DrawRailNetwork)
            {
                //Drawer3D.DrawBox(GetContainingVoxel().GetBoundingBox(), Color.White, 0.01f, true);
                Drawer3D.DrawLine(GetContainingVoxel().GetBoundingBox().Center(), GlobalTransform.Translation, Color.White, 0.01f);
                var transform = Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)Piece.Orientation) * GlobalTransform;
                var piece     = Rail.RailLibrary.GetRailPiece(Piece.RailPiece);

                foreach (var spline in piece.SplinePoints)
                {
                    for (var i = 1; i < spline.Count; ++i)
                    {
                        Drawer3D.DrawLine(Vector3.Transform(spline[i - 1], transform),
                                          Vector3.Transform(spline[i], transform), Color.Purple, 0.1f);
                    }
                }

                foreach (var connection in piece.EnumerateConnections())
                {
                    Drawer3D.DrawLine(Vector3.Transform(connection.Item1, transform) + new Vector3(0.0f, 0.2f, 0.0f),
                                      Vector3.Transform(connection.Item2, transform) + new Vector3(0.0f, 0.2f, 0.0f),
                                      Color.Brown, 0.1f);
                }


                foreach (var neighborConnection in NeighborRails)
                {
                    var neighbor = Manager.FindComponent(neighborConnection.NeighborID);
                    if (neighbor == null)
                    {
                        Drawer3D.DrawLine(Position, Position + Vector3.UnitY, Color.CornflowerBlue, 0.1f);
                    }
                    else
                    {
                        Drawer3D.DrawLine(Position + new Vector3(0.0f, 0.5f, 0.0f), (neighbor as Body).Position + new Vector3(0.0f, 0.5f, 0.0f), Color.Teal, 0.1f);
                    }
                }

                foreach (var compassConnection in piece.CompassConnections)
                {
                    var localConnection = compassConnection.RotateToPiece(Piece.Orientation);
                    Drawer3D.DrawLine(Position + new Vector3(0.0f, 0.7f, 0.0f), Position + Vector3.Transform(new Vector3(0.0f, 0.7f, 0.5f), Matrix.CreateRotationY(((float)Math.PI / 4) * (float)localConnection.A)), Color.DarkBlue, 0.1f);
                    Drawer3D.DrawLine(Position + new Vector3(0.0f, 0.7f, 0.0f), Position + Vector3.Transform(new Vector3(0.0f, 0.7f, 0.5f), Matrix.CreateRotationY(((float)Math.PI / 4) * (float)localConnection.B)), Color.DarkBlue, 0.1f);
                }
            }

            if (!IsVisible)
            {
                return;
            }

            if (Primitive == null)
            {
                var bounds   = Vector4.Zero;
                var uvs      = Sheet.GenerateTileUVs(Frame, out bounds);
                var rawPiece = RailLibrary.GetRailPiece(Piece.RailPiece);

                var transform = Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)Piece.Orientation);

                var realShape = 0;
                if (rawPiece.AutoSlope)
                {
                    var transformedConnections = GetTransformedConnections();
                    var matchingNeighbor1      = NeighborRails.FirstOrDefault(n => (n.Position - transformedConnections[0].Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f);
                    var matchingNeighbor2      = NeighborRails.FirstOrDefault(n => (n.Position - transformedConnections[1].Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f);

                    if (matchingNeighbor1 != null && matchingNeighbor2 != null)
                    {
                        realShape = 3;
                    }
                    else if (matchingNeighbor1 != null)
                    {
                        realShape = 1;
                    }
                    else if (matchingNeighbor2 != null)
                    {
                        realShape = 2;
                    }
                }

                Primitive = new RawPrimitive();
                Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(-0.5f, VertexHeightOffsets[realShape, 0], 0.5f), transform), Color.White, Color.White, uvs[0], bounds));
                Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(0.5f, VertexHeightOffsets[realShape, 1], 0.5f), transform), Color.White, Color.White, uvs[1], bounds));
                Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(0.5f, VertexHeightOffsets[realShape, 2], -0.5f), transform), Color.White, Color.White, uvs[2], bounds));
                Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(-0.5f, VertexHeightOffsets[realShape, 3], -0.5f), transform), Color.White, Color.White, uvs[3], bounds));
                Primitive.AddIndicies(new short[] { 0, 1, 3, 1, 2, 3 });

                var       sideBounds = Vector4.Zero;
                Vector2[] sideUvs    = null;

                sideUvs = Sheet.GenerateTileUVs(new Point(3, 4), out sideBounds);

                AddScaffoldGeometry(transform, sideBounds, sideUvs, -1.0f, false);

                if (realShape == 3)
                {
                    AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, false);
                }
                else if (realShape == 1)
                {
                    sideUvs = Sheet.GenerateTileUVs(new Point(0, 4), out sideBounds);
                    AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, true);
                }
                else if (realShape == 2)
                {
                    sideUvs = Sheet.GenerateTileUVs(new Point(0, 4), out sideBounds);
                    AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, false);
                }

                // Todo: Make these static and avoid recalculating them constantly.
                var bumperBackBounds  = Vector4.Zero;
                var bumperBackUvs     = Sheet.GenerateTileUVs(new Point(0, 5), out bumperBackBounds);
                var bumperFrontBounds = Vector4.Zero;
                var bumperFrontUvs    = Sheet.GenerateTileUVs(new Point(1, 5), out bumperFrontBounds);
                var bumperSideBounds  = Vector4.Zero;
                var bumperSideUvs     = Sheet.GenerateTileUVs(new Point(2, 5), out bumperSideBounds);

                foreach (var connection in GetTransformedConnections())
                {
                    var matchingNeighbor = NeighborRails.FirstOrDefault(n => (n.Position - connection.Item1).LengthSquared() < 0.001f);
                    if (matchingNeighbor == null && rawPiece.AutoSlope)
                    {
                        matchingNeighbor = NeighborRails.FirstOrDefault(n => (n.Position - connection.Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f);
                    }

                    if (matchingNeighbor == null)
                    {
                        var bumperOffset = connection.Item1 - GlobalTransform.Translation;
                        var bumperGap    = Vector3.Normalize(bumperOffset) * 0.1f;
                        var bumperAngle  = AngleBetweenVectors(new Vector2(bumperOffset.X, bumperOffset.Z), new Vector2(0, 0.5f));

                        var xDiag = bumperOffset.X <-0.001f || bumperOffset.X> 0.001f;
                        var zDiag = bumperOffset.Z <-0.001f || bumperOffset.Z> 0.001f;

                        if (xDiag && zDiag)
                        {
                            var y = bumperOffset.Y;
                            bumperOffset  *= sqrt2;
                            bumperOffset.Y = y;

                            var endBounds = Vector4.Zero;
                            var endUvs    = Sheet.GenerateTileUVs(new Point(6, 2), out endBounds);
                            Primitive.AddQuad(
                                Matrix.CreateRotationY((float)Math.PI * 1.25f)
                                * Matrix.CreateRotationY(bumperAngle)
                                // This offset would not be correct if diagonals could slope.
                                * Matrix.CreateTranslation(new Vector3(Sign(bumperOffset.X), 0.0f, Sign(bumperOffset.Z))),
                                Color.White, Color.White, endUvs, endBounds);
                        }

                        Primitive.AddQuad(
                            Matrix.CreateRotationX(-(float)Math.PI * 0.5f)
                            * Matrix.CreateTranslation(0.0f, 0.3f, -0.2f)
                            * Matrix.CreateRotationY(bumperAngle)
                            * Matrix.CreateTranslation(bumperOffset + bumperGap),
                            Color.White, Color.White, bumperBackUvs, bumperBackBounds);

                        Primitive.AddQuad(
                            Matrix.CreateRotationX(-(float)Math.PI * 0.5f)
                            * Matrix.CreateTranslation(0.0f, 0.3f, -0.2f)
                            * Matrix.CreateRotationY(bumperAngle)
                            * Matrix.CreateTranslation(bumperOffset),
                            Color.White, Color.White, bumperFrontUvs, bumperFrontBounds);

                        if (VoxelHelpers.FindFirstVoxelBelow(GetContainingVoxel()).RampType == RampType.None)
                        {
                            Primitive.AddQuad(
                                Matrix.CreateRotationX(-(float)Math.PI * 0.5f)
                                * Matrix.CreateRotationY(-(float)Math.PI * 0.5f)
                                * Matrix.CreateTranslation(0.3f, 0.3f, 0.18f)
                                * Matrix.CreateRotationY(bumperAngle)
                                * Matrix.CreateTranslation(bumperOffset),
                                Color.White, Color.White, bumperSideUvs, bumperSideBounds);

                            Primitive.AddQuad(
                                Matrix.CreateRotationX(-(float)Math.PI * 0.5f)
                                * Matrix.CreateRotationY(-(float)Math.PI * 0.5f)
                                * Matrix.CreateTranslation(-0.3f, 0.3f, 0.18f)
                                * Matrix.CreateRotationY(bumperAngle)
                                * Matrix.CreateTranslation(bumperOffset),
                                Color.White, Color.White, bumperSideUvs, bumperSideBounds);
                        }
                    }
                }
            }

            // Everything that draws should set it's tint, making this pointless.

            var under = new VoxelHandle(chunks.ChunkData,
                                        GlobalVoxelCoordinate.FromVector3(Position));

            if (under.IsValid)
            {
                Color color = new Color(under.Sunlight ? 255 : 0, 255, 0);
                LightRamp = color;
            }
            else
            {
                LightRamp = new Color(200, 255, 0);
            }

            Color origTint = effect.VertexColorTint;

            if (!Active)
            {
                DoStipple(effect);
            }
            effect.VertexColorTint = VertexColor;
            effect.LightRamp       = LightRamp;
            effect.World           = GlobalTransform;

            effect.MainTexture = Sheet.GetTexture();


            effect.EnableWind = false;

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                Primitive.Render(graphicsDevice);
            }

            effect.VertexColorTint = origTint;
            if (!Active)
            {
                EndDraw(effect);
            }
        }