Пример #1
0
 public virtual void handleMouseMove(Point mouseLocation,
                                 PlayFrame frame,
                                 PitchScreenCoordConverter converter,
                                 VisualOverlay overlay)
 {
     //No op for normal tools.
 }
        public override void handleMouseDown(Point mouseLocation, 
                                         PlayFrame frame,
                                         PitchScreenCoordConverter converter,
                                         VisualOverlay overlay)
        {
            if (mSelectedPlayer == null)
              {
            PointF pitchCoords = converter.screenToPitchCoords(mouseLocation);

            // No player is yet selected so attempt to find the one closest
            // to the selected spot.
            mSelectedPlayer = frame.GetClosestPlayer(pitchCoords,
                                                 Settings.Default.PlayerDiameter * 2.0f);

            if (mSelectedPlayer == null)
            {
              LinearMovement prevCut = frame.GetClosestCutEnd(pitchCoords,
                                                          Settings.Default.PlayerDiameter * 2.0f);

              if (prevCut != null &&
              prevCut != frame.DiscFrameMovement.ReceivingCut)
              {
            mSelectedPlayer = prevCut.Player;
            overlay.DrawingNewCut = true;
            overlay.CutStart = prevCut;
              }
            }
            else
            {
              overlay.DrawingNewCut = true;
              overlay.CutStart = frame.PlayerMovement[mSelectedPlayer][0];
            }
              }
        }
 public override void handleMouseDown(Point mouseLocation,
                                  PlayFrame frame,
                                  PitchScreenCoordConverter converter,
                                  VisualOverlay overlay)
 {
     //Noop
 }
        public override void handleMouseUp(Point mouseLocation,
                                       PlayFrame frame,
                                       PitchScreenCoordConverter converter,
                                       VisualOverlay overlay)
        {
            frame.AddPlayer(new Player(Team.BLUE_TEAM,
                                 "",
                                 Settings.Default.DefaultPlayerSpeed,
                                 frame.GetNextFreePlayerId(Team.BLUE_TEAM)),
                      converter.screenToPitchCoords(mouseLocation));

              IsComplete = true;
              ModelChanged = true;
        }
 public override void handleMouseUp(Point mouseLocation, 
                                PlayFrame frame,
                                PitchScreenCoordConverter converter,
                                VisualOverlay overlay)
 {
     if (mSelectedPlayer != null)
       {
     frame.PlayerMovement[mSelectedPlayer].Add(
       new LinearMovement(converter.screenToPitchCoords(mouseLocation),
                          100,
                          mSelectedPlayer));
     IsComplete = true;
     ModelChanged = true;
       }
 }
        public override void handleMouseUp(Point mouseLocation, 
                                       PlayFrame frame,
                                       PitchScreenCoordConverter converter,
                                       VisualOverlay overlay)
        {
            PointF pitchCoords = converter.screenToPitchCoords(mouseLocation);

              Player closestPlayer = frame.GetClosestPlayer(pitchCoords,
                                                    Settings.Default.PlayerDiameter);

              if (closestPlayer != null)
              {
            frame.AddDisc(closestPlayer);

            IsComplete = true;
            ModelChanged = true;
              }
        }
        public override void handleMouseUp(Point mouseLocation, 
                                       PlayFrame frame,
                                       PitchScreenCoordConverter converter,
                                       VisualOverlay overlay)
        {
            PointF pitchCoords = converter.screenToPitchCoords(mouseLocation);

              if (mSelectedPlayer != null)
              {
            // This function doesn't necessarily create a trigger but regardless
            // we say that the tool is complete anyway.
            if (frame.MaybeCreateTrigger(pitchCoords,
                                     Settings.Default.PitchLength,
                                     mSelectedPlayer))
            {
              ModelChanged = true;
            }

            IsComplete = true;
              }
        }
        /// <summary>
        /// In order to move an item we catch the mouse down event to decide which
        /// thing has been selected. This function chooses either the selected
        /// cut, trigger or player.
        /// </summary>
        /// <param name="mouseLocation">Screen coordinates.</param>
        /// <param name="frame">Frame currently being designed.</param>
        /// <param name="converter">Used to convert from screen to pitch 
        /// coordinates.</param>
        public override void handleMouseDown(Point mouseLocation, 
                                         PlayFrame frame,
                                         PitchScreenCoordConverter converter,
                                         VisualOverlay overlay)
        {
            PointF pitchCoords = converter.screenToPitchCoords(mouseLocation);

              // Choose closest selected item.
              mSelectedPlayer = frame.GetClosestPlayer(pitchCoords,
                                               SELECTION_MAX_DISTANCE);
              mSelectedCut = frame.GetClosestCutEnd(pitchCoords,
                                              SELECTION_MAX_DISTANCE);
              mSelectedTrigger = frame.GetClosestTrigger(pitchCoords,
                                                 SELECTION_MAX_DISTANCE);
              mIsMovingDiscControlPoint = frame.IsNearControlPoint(pitchCoords,
                                                           SELECTION_MAX_DISTANCE);

              // Note that the ordering of priorities here MUST be the same as the
              // ordering on mouse up.
              if (mSelectedTrigger != null)
              {
            overlay.SelectedTrigger = mSelectedTrigger;
            overlay.TriggerPlayer = mSelectedTrigger.AffectedPlayer;
              }
              else if (mSelectedCut != null)
              {
            overlay.DrawingNewCut = false;
            overlay.CutStart = mSelectedCut;
              }
              else if (mSelectedPlayer != null)
              {
            overlay.SelectedPlayer = mSelectedPlayer;
              }
              else if (mIsMovingDiscControlPoint)
              {
            overlay.MovingDiscControlPoint = true;
              }
        }
        public override void handleMouseUp(Point mouseLocation,
                                       PlayFrame frame,
                                       PitchScreenCoordConverter converter,
                                       VisualOverlay overlay)
        {
            PointF pitchCoords = converter.screenToPitchCoords(mouseLocation);

              LinearMovement cut = frame.GetClosestDiscFlightPoint(pitchCoords,
                                                           Settings.Default.PlayerDiameter);

              if (cut == null)
              {
            // The user has clicked away from any cut. They may want the disc to
            // go to ground so check before setting it.
            DialogResult result = MessageBox.Show(
              "You have not selected a cut to throw to, would you like the " +
              " disc to go here anyway",
              "Throw disc to ground?",
              MessageBoxButtons.YesNo);

            if (result == DialogResult.Yes)
            {
              frame.DiscFrameMovement.AbsoluteFlightPath = pitchCoords;
              frame.DiscFrameMovement.HasMoved = true;

              IsComplete = true;
              ModelChanged = true;
            }
              }
              else
              {
            frame.DiscFrameMovement.ReceivingCut = cut;
            frame.DiscFrameMovement.HasMoved = true;
            IsComplete = true;
            ModelChanged = true;
              }
        }
        /// <summary>
        /// There are two components to the drawing. The first is the data model
        /// which is represented by a single PlayFrame.
        /// 
        /// The second is a visual overlay indicating what the user is current 
        /// doing.
        /// 
        /// This function takes the frame and 'applies' the overlay to it by
        /// creating a deep copy and then moving/adding items as required by
        /// the overlay. For this to work we need to be able to uniquely
        /// reference items in a playmodel by an id (as their refs change on a
        /// deep copy).
        /// </summary>
        /// <param name="frame"></param>
        /// <param name="overlay"></param>
        /// <param name="converter"></param>
        /// <returns></returns>
        private static PlayFrame AdjustFrameForOverlay(PlayFrame frame, 
                                                   VisualOverlay overlay, 
                                                   PitchScreenCoordConverter converter)
        {
            // Take a deep copy of the frame so that we can adjust it based on what
              // visual overlay is required.
              PlayFrame adjustableFrame = frame.Clone();

              PointF pitchCoords = converter.screenToPitchCoords(overlay.MouseLocation);

              // First move any players who need to be.
              if (overlay.SelectedPlayer != null)
              {
            Player movedPlayer = adjustableFrame.GetPlayerById(overlay.SelectedPlayer.UniqueId);
            if (movedPlayer != null)
            {
              adjustableFrame.PlayerMovement[movedPlayer][0].FinalPosition = pitchCoords;
            }
            else
            {
              adjustableFrame.AddPlayer(overlay.SelectedPlayer, pitchCoords);
            }
              }

              // Either a new cut is being drawn or a cut is being moved.
              if (overlay.CutStart != null)
              {
            if (overlay.DrawingNewCut)
            {
              Player cuttingPlayer = adjustableFrame.GetPlayerById(overlay.CutStart.Player.UniqueId);

              adjustableFrame.PlayerMovement[cuttingPlayer].Add(
                                           new LinearMovement(pitchCoords,
                                                              100,
                                                              cuttingPlayer));
            }
            else
            {
              LinearMovement movedCut = adjustableFrame.GetCutById(overlay.CutStart.UniqueId);

              adjustableFrame.ReplaceCut(movedCut, pitchCoords);
            }
              }

              // Check if the user is drawing the disc movement at the moment.
              if (overlay.DrawingDiscMovement)
              {
            adjustableFrame.DiscFrameMovement.AbsoluteFlightPath = pitchCoords;
            adjustableFrame.DiscFrameMovement.HasMoved = true;
              }

              if (overlay.MovingDiscControlPoint)
              {
            adjustableFrame.DiscFrameMovement.ControlPoint = pitchCoords;
              }

              // If there is a trigger being moved then the selected trigger must have
              // it's position updated.
              if (overlay.SelectedTrigger != null)
              {
            CutRatio closestCutPoint = adjustableFrame.GetClosestCutPoint(pitchCoords,
              sPitchLength,
              overlay.SelectedTrigger.AffectedPlayer);

            if (closestCutPoint != null)
            {
              Trigger adjustedTrigger = adjustableFrame.GetTriggerById(overlay.SelectedTrigger.UniqueId);

              if (adjustedTrigger != null)
              {
            adjustedTrigger.CausingCutRatio = closestCutPoint;
              }
            }
              }
              else if (overlay.PlacingTrigger)
              {
            adjustableFrame.MaybeCreateTrigger(pitchCoords,
                                           sPitchLength,
                                           overlay.TriggerPlayer);
              }

              return adjustableFrame;
        }
        /// <summary>
        /// Place the disc onto the display. This must happen after the players
        /// are drawn so that they don't end up on top of the disc.
        /// </summary>
        /// <param name="display"></param>
        /// <param name="location"></param>
        /// <param name="converter"></param>
        private void DrawDisc(Graphics display, 
                          PointF location, 
                          PitchScreenCoordConverter converter)
        {
            PointF offsetCentre = new PointF(location.X,
                                       location.Y);
              offsetCentre.X -= ((float)Settings.Default.PlayerDiameter) / 4.0F;
              offsetCentre.Y -= ((float)Settings.Default.PlayerDiameter) / 4.0F;

              DrawSprite(display,
                 converter,
                 Playbook.Properties.Resources.disc,
                 offsetCentre,
                 Settings.Default.PlayerDiameter / 2.0f,
                 Settings.Default.PlayerDiameter / 2.0f);
        }
        /// <summary>
        /// Creates a font object with the correct size to be placed on a player.
        /// 
        /// Must be disposed of by the calling code.
        /// </summary>
        /// <param name="converter"></param>
        /// <returns></returns>
        internal static Font CreatePlayerIdFont(PitchScreenCoordConverter converter)
        {
            // The player width and length in screen coordinates cannot be 0
              // or the drawing will crash.
              int playerDiameterScreen = converter.pitchToScreenLength(Settings.Default.PlayerDiameter);
              if (playerDiameterScreen == 0) playerDiameterScreen = 1;

              int fontSize = playerDiameterScreen > 2 ? playerDiameterScreen - 2 : playerDiameterScreen;
              Font font = new Font("consolas",
                           fontSize,
                           FontStyle.Regular,
                           GraphicsUnit.Pixel);

              return font;
        }
        /// <summary>
        /// Draw a single player onto the given display object. The conversion 
        /// from pitch to screen coordinates is done internally.
        /// </summary>
        /// <param name="player"></param>
        /// <param name="position"></param>
        /// <param name="display"></param>
        /// <param name="converter"></param>
        /// <param name="isSelected">A selected player shows a slightly different 
        /// sprite to indicate the selection.</param>
        /// <param name="isOutline">Set to true to draw only the outline of the 
        /// player.</param>
        internal void DrawPlayer(Player player, 
                             PointF position, 
                             Graphics display, 
                             PitchScreenCoordConverter converter,
                             Boolean isOutline)
        {
            Image playerImage = isOutline ? player.PlayerTeam.OutlineSprite :
                                      player.PlayerTeam.Sprite;

              PointF offsetCentre = new PointF(position.X, position.Y);
              offsetCentre.X -= Settings.Default.PlayerDiameter / 2.0f;
              offsetCentre.Y -= Settings.Default.PlayerDiameter / 2.0f;
              DrawSprite(display,
                 converter,
                 playerImage,
                 offsetCentre,
                 Settings.Default.PlayerDiameter,
                 Settings.Default.PlayerDiameter);

              using (Font font = CreatePlayerIdFont(converter))
              {
            // Draw the player id as an overlay onto the sprite.
            DrawString(display,
                   converter,
                   player.VisibleID.ToString(CultureInfo.InvariantCulture),
                   offsetCentre,
                   font,
                   Brushes.White);
              }
        }
        /// <summary>
        /// Draw a single sprite on the pitch at the given coordinates. Does the 
        /// conversion of pitch -> screen internally.
        /// </summary>
        /// <param name="display">The display on which to draw.</param>
        /// <param name="converter">The converter utility used to turn pitch
        /// coordinates into screen coordinates</param>
        /// <param name="image">The image to draw</param>
        /// <param name="position">The pitch coordinates</param>
        /// <param name="width">Pitch width</param>
        /// <param name="length">Pitch height/length</param>
        public void DrawSprite(Graphics display,
                           PitchScreenCoordConverter converter, 
                           Image image, 
                           PointF position, 
                           float width, 
                           float length)
        {
            Rectangle imagePlacement = new Rectangle();
              Point screenCoords = converter.pitchToScreenCoords(position);
              PointF imageSize = new PointF(width, length);
              Point convertedImageSize = converter.pitchToScreenSize(imageSize);

              imagePlacement.Location = screenCoords;
              imagePlacement.Width = convertedImageSize.X;
              imagePlacement.Height = convertedImageSize.Y;

              display.DrawImage(image,
                        imagePlacement);
        }
        /// <summary>
        /// Draw a string onto the pitch at the given pitch coordinates. Does
        /// the conversion from pitch to screen internally.
        /// </summary>
        /// <param name="display"></param>
        /// <param name="converter"></param>
        /// <param name="text"></param>
        /// <param name="position"></param>
        /// <param name="font"></param>
        /// <param name="brush"></param>
        public void DrawString(Graphics display,
                           PitchScreenCoordConverter converter,
                           String text,
                           PointF position,
                           Font font,
                           Brush brush)
        {
            Point screenCoords = converter.pitchToScreenCoords(position);

              display.DrawString(text, font, brush, screenCoords);
        }
        /// <summary>
        /// We capture the mouse up event and use it to place whatever it was that
        /// was selected on the mouse down event. If nothing was selected this does
        /// nothing. 
        /// </summary>
        /// <param name="mouseLocation"></param>
        /// <param name="frame"></param>
        /// <param name="converter"></param>
        public override void handleMouseUp(Point mouseLocation,
                                       PlayFrame frame,
                                       PitchScreenCoordConverter converter,
                                       VisualOverlay overlay)
        {
            PointF pitchCoords = converter.screenToPitchCoords(mouseLocation);

              if (mSelectedTrigger != null)
              {
            // If we are moving a trigger then only move it if the position it is
            // being placed is valid.
            if (frame.MaybeCreateTrigger(pitchCoords,
                                     SELECTION_MAX_DISTANCE,
                                     mSelectedTrigger.AffectedPlayer))
            {
              frame.RemoveTrigger(mSelectedTrigger);
              ModelChanged = true;
            }
              }
              else if (mSelectedPlayer != null)
              {
            frame.PlayerMovement[mSelectedPlayer][0].FinalPosition = pitchCoords;
            ModelChanged = true;
              }
              else if (mSelectedCut != null)
              {
            mSelectedCut.FinalPosition = pitchCoords;
            ModelChanged = true;
              }
              else if (mIsMovingDiscControlPoint)
              {
            frame.DiscFrameMovement.ControlPoint = pitchCoords;
            ModelChanged = true;
              }

              // Regardless of whether anything moved the move tool is complete on
              // mouse up.
              mSelectedCut = null;
              mSelectedPlayer = null;
              mSelectedTrigger = null;
              IsComplete = true;
        }
        /// <summary>
        /// Render the frame into a small visible area with squares for players 
        /// and without drawing the cuts or disc flight.
        /// </summary>
        /// <param name="frame"></param>
        /// <param name="display"></param>
        /// <param name="converter"></param>
        /// <param name="displayRectangle"></param>
        public void DrawSmallFrame(PlayFrame frame,
                               Graphics display,
                               PitchScreenCoordConverter converter)
        {
            display.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
              display.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

              // Draw the pitch itself.
              DrawPitch(display, converter);

              foreach (Player player in frame.PlayerMovement.Keys)
              {
            DrawSmallPlayer(display,
                        player,
                        frame.PlayerMovement[player][0].FinalPosition,
                        converter);
              }
        }
        protected override void OnResize(EventArgs e)
        {
            using (Graphics display = this.CreateGraphics())
              {
            Converter = new PitchScreenCoordConverter(display);
              }

              base.OnResize(e);
        }
        /// <summary>
        /// Draw the disc flight.
        /// 
        /// Currently simply a straight line from A to B. Could enhance this so
        /// that it draws a cardinal spline instead at some point. The UI to draw
        /// that is the more difficult area.
        /// </summary>
        /// <param name="display"></param>
        /// <param name="startLocation"></param>
        /// <param name="controlPoint"></param>
        /// <param name="endLocation"></param>
        /// <param name="converter"></param>
        private void DrawDiscFlight(Graphics display,
                                PointF startLocation,
                                PointF controlPoint,
                                PointF endLocation,
                                PitchScreenCoordConverter converter)
        {
            Point screenCoordsStart = converter.pitchToScreenCoords(startLocation);
              Point screenCoordsEnd = converter.pitchToScreenCoords(endLocation);
              Point screenControlPoint = converter.pitchToScreenCoords(controlPoint);

              QuadraticBezierCurve curve = new QuadraticBezierCurve(screenCoordsStart,
                                                            screenControlPoint,
                                                            screenCoordsEnd);

              display.DrawBeziers(mDiscFlightPen, curve.ToCubic());

              display.DrawRectangle(mDiscFlightPen,
                            screenControlPoint.X - 1,
                            screenControlPoint.Y - 1,
                            2, 2);
        }
        /// <summary>
        /// Draw a trigger onto the screen. The location is tied to the trigger 
        /// object.
        /// 
        /// The description of what the trigger will look like is contained wholly 
        /// within this function.
        /// </summary>
        /// <param name="display"></param>
        /// <param name="trigger"></param>
        /// <param name="converter"></param>
        private void DrawTrigger(Graphics display, 
                             Trigger trigger, 
                             PitchScreenCoordConverter converter)
        {
            PointF locationToDraw = trigger.CausingCutRatio.GetAbsolutePosition();

              DrawPlayer(trigger.AffectedPlayer,
                 trigger.CausingCutRatio.GetAbsolutePosition(),
                 display,
                 converter,
                 true);
        }
 public abstract void Render(Graphics display, 
                         FrameRenderer renderer,
                         PitchScreenCoordConverter converter);
        public override void Render(Graphics display,
                                FrameRenderer renderer,
                                PitchScreenCoordConverter converter)
        {
            base.Render(display, renderer, converter);

              using (Font font = FrameRenderer.CreatePlayerIdFont(converter))
              {
            renderer.DrawString(display,
                            converter,
                            ItemProperties["id"],
                            DrawLocation,
                            font,
                            Brushes.White);
              }
        }
        public override void Render(Graphics display, 
                                FrameRenderer renderer, 
                                PitchScreenCoordConverter converter)
        {
            // Adjust the item location so that the location is at the centre of
              // the image.
              DrawLocation = new PointF(ItemLocation.X - mWidth / 2.0f,
                                ItemLocation.Y - mHeight / 2.0f);

              renderer.DrawSprite(display, converter, mSprite, DrawLocation, mWidth, mHeight);
        }
Пример #24
0
 public abstract void handleMouseUp(Point mouseLocation,
                                PlayFrame frame,
                                PitchScreenCoordConverter converter,
                                VisualOverlay overlay);
        /// <summary>
        /// Render a small square for a player. This is used when we're rendering
        /// into a small space.
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="player"></param>
        /// <param name="location"></param>
        /// <param name="converter"></param>
        private void DrawSmallPlayer(Graphics graphics, 
                                 Player player, 
                                 PointF location, 
                                 PitchScreenCoordConverter converter)
        {
            Point screenCoords = converter.pitchToScreenCoords(location);
              Brush playerBrush = player.PlayerTeam.UniqueId ==
                          Team.RED_TEAM.UniqueId ? Brushes.Red : Brushes.Blue;

              graphics.FillRectangle(playerBrush,
                             screenCoords.X,
                             screenCoords.Y,
                             4, 4);
        }
        /// <summary>
        /// The pitch is drawn as a pair of rectangles rather than as a sprite.
        /// 
        /// All conversion between pitch coordinates and screen coordinates is done
        /// internally.
        /// </summary>
        /// <param name="display"></param>
        /// <param name="converter"></param>
        public void DrawPitch(Graphics display, 
                          PitchScreenCoordConverter converter)
        {
            Rectangle outerPitch = new Rectangle();
              Rectangle innerPitch = new Rectangle();
              using (Pen linePen = new Pen(mLineColor, mLineWidth))
              {
            Point bottomRight = converter.pitchToScreenCoords(
              new PointF(sPitchWidth, sPitchLength));
            Point innerBottomRight = converter.pitchToScreenCoords(
              new PointF(sPitchWidth, (sPitchLength - 2.0f * sEndzoneDepth)));
            Point leftBrick = converter.pitchToScreenCoords(
              new PointF(sPitchWidth / 2.0f,
                     sEndzoneDepth + sBrickDistance));
            Point rightBrick = converter.pitchToScreenCoords(
              new PointF(sPitchWidth / 2.0f,
                     sPitchLength - sEndzoneDepth - sBrickDistance));
            int brickDistanceScreen = converter.pitchToScreenLength(sBrickRadius);

            outerPitch.Location = converter.pitchToScreenCoords(new PointF(0.0f, 0.0f));
            outerPitch.Width = bottomRight.X;
            outerPitch.Height = bottomRight.Y;

            innerPitch.Location = converter.pitchToScreenCoords(new PointF(0.0f, sEndzoneDepth));
            innerPitch.Width = innerBottomRight.X;
            innerPitch.Height = innerBottomRight.Y;

            display.FillRectangle(mPitchBrush, outerPitch);
            display.DrawRectangle(linePen, outerPitch);
            display.DrawRectangle(linePen, innerPitch);
            DrawCross(display, linePen, leftBrick, brickDistanceScreen);
            DrawCross(display, linePen, rightBrick, brickDistanceScreen);
              }
        }
        /// <summary>
        /// Called whenever the underlying frame changes to redraw the frame.
        /// </summary>
        public void DrawFrame(PlayFrame frame, 
                          Graphics display, 
                          PitchScreenCoordConverter converter,
                          VisualOverlay overlay,
                          Rectangle displayRectangle)
        {
            BufferedGraphicsContext currentContext;
              BufferedGraphics myBuffer;
              currentContext = BufferedGraphicsManager.Current;
              myBuffer = currentContext.Allocate(display,
                                         displayRectangle);
              myBuffer.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
              myBuffer.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
              myBuffer.Graphics.Clear(mBackColor);

              // Draw the pitch itself.
              DrawPitch(myBuffer.Graphics, converter);

              // This moves items around based on what the user is doing.
              // e.g. If a user is dragging a cut at the moment it adds a new cut for
              // the given player.
              PlayFrame adjustableFrame = FrameRenderer.AdjustFrameForOverlay(frame,
                                                                      overlay,
                                                                      converter);

              foreach (Player player in adjustableFrame.PlayerMovement.Keys)
              {
            List<LinearMovement> playerMoves = adjustableFrame.PlayerMovement[player];

            if (playerMoves.Count > 0)
            {

              DrawPlayer(player,
                     playerMoves[0].FinalPosition,
                     myBuffer.Graphics,
                     converter,
                     false);

              if (playerMoves.Count > 1)
              {
            List<Point> cutLocations = new List<Point>();

            foreach (LinearMovement playerMove in playerMoves)
            {
              cutLocations.Add(converter.pitchToScreenCoords(playerMove.FinalPosition));
            }

            myBuffer.Graphics.DrawLines(mCutPen, cutLocations.ToArray<Point>());
              }
            }
              }

              foreach (Trigger trigger in adjustableFrame.Triggers)
              {
            DrawTrigger(myBuffer.Graphics, trigger, converter);
              }

              // Draw the disc after the players because the sprite sits on top of the
              // player sprite who is holding it.
              if (adjustableFrame.DiscFrameMovement.Thrower != null)
              {
            DrawDisc(myBuffer.Graphics,
                 adjustableFrame.DiscFrameMovement.StartPosition(),
                 converter);

            if (adjustableFrame.DiscFrameMovement.HasMoved)
            {
              DrawDiscFlight(myBuffer.Graphics,
                         adjustableFrame.DiscFrameMovement.StartPosition(),
                         adjustableFrame.DiscFrameMovement.ControlPoint,
                         adjustableFrame.DiscFrameMovement.EndPosition(),
                         converter);
            }
              }
              else if (overlay.PlacingDisc)
              {
            // The mouse location is stored in the overlay but we need to pass the
            // pitch coordinates to the drawing function.
            DrawDisc(myBuffer.Graphics,
                 converter.screenToPitchCoords(overlay.MouseLocation),
                 converter);
              }

              myBuffer.Render();
              myBuffer.Dispose();
        }
        /// <summary>
        /// Takes a model and outputs it as a set of images to the output directory. 
        /// Note that if the files already exist then they'll be removed
        /// </summary>
        /// <param name="outputDir">Location for temporary images.</param>
        private void ModelToImageFiles(String outputDir)
        {
            mCallback.Begin(0, mModel.CycleCount / 4);

              Color backColor = Color.FromArgb(40, 40, 40);
              using (FrameRenderer renderer = new FrameRenderer(backColor, Settings.Default.PitchColor, Settings.Default.LineColor))
              {
            using (Bitmap bitmap = new Bitmap((int)(Settings.Default.PitchLength * 10.0f),
                                          (int)(Settings.Default.PitchWidth * 10.0f)))
            {
              using (Graphics graphics = Graphics.FromImage(bitmap))
              {
            int imageIndex = 0;
            FramePlayData fpd;
            foreach (PlayFrame frame in mModel.GetAllFrames())
            {
              fpd = frame.GenerateViewingData();

              // I made a cop out decision to allow for slow speed playback by
              // creating 4 times as many cycles as needed. Here though we want
              // to keep the output format as small as possible so only 1 in every
              // 4 frames is displayed.
              //
              // Frankly, this is terrible and will definitely bite me later on.
              int ii = 0;
              foreach (List<ItemPlayData> cycleData in fpd.PlayData)
              {
                ii++;
                if (ii % 4 != 0 && cycleData != fpd.PlayData.Last()) continue; // Thusly do I cry.
                PitchScreenCoordConverter converter = new PitchScreenCoordConverter(graphics);

                graphics.Clear(backColor);
                renderer.DrawPitch(graphics, converter);

                foreach (ItemPlayData itemPlayData in cycleData)
                {
                  itemPlayData.Render(graphics, renderer, converter);
                }

                imageIndex++;
                BitmapExtensions.SaveJpg100(bitmap, outputDir + Path.DirectorySeparatorChar + "image" +
                  imageIndex.ToString("D6", CultureInfo.InvariantCulture) + ".jpg");

                mCallback.Increment(1);
              }
            }
              }
            }
              }
        }