New To XNA / Programically Drawing A Texture2D

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Tyler Wiebe
    New Member
    • Mar 2011
    • 66

    New To XNA / Programically Drawing A Texture2D

    Okay, I have a few questions about auto drawing a Texture2D, to be used in an 2D Windows Game I'm making for the fun of it.

    But first, a few things,

    1: The code is in my own custom .dll file that I'm making for this.

    2: I've taught myself everything I know about C#, so any comment about my coding style isn't important to me, but is appreciated anyway.

    3: And finally, a lot of code:
    Code:
        public class ProgressBar
        {
            #region Overrides
    
            [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
            public override bool Equals(object obj) { return base.Equals(obj); }
            [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
            public override int GetHashCode() { return base.GetHashCode(); }
            [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
            public override string ToString() { return base.ToString(); }
    
            #endregion
    
            #region Texture Graphics Device & SpriteBatch
    
            private Microsoft.Xna.Framework.Graphics.GraphicsDevice PGraphicsDevice;
            public Microsoft.Xna.Framework.Graphics.GraphicsDevice GraphicsDevice
            {
                get { return this.PGraphicsDevice; }
                set { this.PGraphicsDevice = value; }
            }
    
            private Microsoft.Xna.Framework.Graphics.SpriteBatch PSpriteBatch;
            public Microsoft.Xna.Framework.Graphics.SpriteBatch SpriteBatch
            {
                get { return this.PSpriteBatch; }
                set { this.PSpriteBatch = value; }
            }
    
            #endregion
    
            public ProgressBar(Microsoft.Xna.Framework.Graphics.GraphicsDevice GraphicsDevice, Microsoft.Xna.Framework.Graphics.SpriteBatch SpriteBatch)
            {
                this.PGraphicsDevice = GraphicsDevice;
                this.PSpriteBatch = SpriteBatch;
    
                this.PBackColor = new Microsoft.Xna.Framework.Color(210, 210, 210, 255);
                this.HighlightColor = new Microsoft.Xna.Framework.Color(255, 255, 255, 170);
                this.ForeColor = new Microsoft.Xna.Framework.Color(0, 255, 0, 255);
            }
    
            #region Texture Drawing
    
            /// <summary>
            /// Draws the texture at the specified location.
            /// </summary>
            public void Draw()
            {
                SpriteBatch.Begin();
                SpriteBatch.Draw(this.GetTexture, this.Location, Microsoft.Xna.Framework.Color.White);
                SpriteBatch.End();
            }
    
            private Microsoft.Xna.Framework.Graphics.Texture2D GetTexture
            {
                get
                {
                    System.Drawing.Bitmap Texture2DBitmap = new System.Drawing.Bitmap(this.Width, this.Height);
                    int BufferSize = Texture2DBitmap.Height * Texture2DBitmap.Width * 4;
    
                    System.Drawing.Graphics GraphicsImage = System.Drawing.Graphics.FromImage(Texture2DBitmap);
    
                    GraphicsImage.FillPath(new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(this.BackColor.A, this.BackColor.R, this.BackColor.G, this.BackColor.B)), this.BackgroundPath);
                    GraphicsImage.FillPath(new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(this.ForeColor.A, this.ForeColor.R, this.ForeColor.G, this.ForeColor.B)), this.PercentagePath);
                    if (this.Highlight) GraphicsImage.FillPath(new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(this.HighlightColor.A, this.HighlightColor.R, this.HighlightColor.G, this.HighlightColor.B)), this.HighlightPath);
                    if (this.Border) GraphicsImage.DrawPath(new System.Drawing.Pen(System.Drawing.Color.FromArgb(this.BorderColor.A,this.BorderColor.R,this.BorderColor.G,this.BorderColor.B), 1), this.BackgroundPath);
    
                    GraphicsImage.Dispose();
    
                    System.IO.MemoryStream MemoryStream = new System.IO.MemoryStream(BufferSize);
                    Texture2DBitmap.Save(MemoryStream, System.Drawing.Imaging.ImageFormat.Png);
    
                    return Microsoft.Xna.Framework.Graphics.Texture2D.FromStream(GraphicsDevice, MemoryStream);
                }
            }
    
            private System.Drawing.Drawing2D.GraphicsPath BackgroundPath
            {
                get
                {
                    System.Drawing.Drawing2D.GraphicsPath Path = new System.Drawing.Drawing2D.GraphicsPath();
                    if (this.Style == Styles.Sqaured)
                    {
                        if (this.Border)
                        {
                            Path.AddLine(0, 0, this.WidthM1, 0);
                            Path.AddLine(this.WidthM1, 0, this.WidthM1, this.HeightM1);
                            Path.AddLine(this.WidthM1, this.HeightM1, 0, this.HeightM1);
                            Path.AddLine(0, this.HeightM1, 0, 0);
                        }
                        else
                        {
                            Path.AddLine(0, 0, this.Width, 0);
                            Path.AddLine(this.Width, 0, this.Width, this.Height);
                            Path.AddLine(this.Width, this.Height, 0, this.Height);
                            Path.AddLine(0, this.Height, 0, 0);
                        }
                    }
                    else if (this.Style == Styles.Rounded)
                    {
                        if (this.Border)
                        {
                            Path.AddArc(0, 0, this.HeightM1, this.HeightM1, 90, 180);
                            Path.AddLine(this.HeightD2, 0, this.WidthM1 - this.HeightD2, 0);
                            Path.AddArc(this.WidthM1 - this.HeightM1, 0, this.HeightM1, this.HeightM1, -90, 180);
                            Path.AddLine(this.WidthM1 - this.HeightD2, this.HeightM1, this.HeightD2, this.HeightM1);
                        }
                        else
                        {
                            Path.AddArc(-1, 0, this.Height, this.Height, 90, 180);
                            Path.AddLine(this.HeightD2, 0, this.Width - this.HeightD2, 0);
                            Path.AddArc(this.Width - this.Height, 0, this.Height, this.Height, -90, 180);
                            Path.AddLine(this.Width - this.HeightD2, this.Height, this.HeightD2, this.Height);
                        }
                    }
                    return Path;
                }
            }
            private System.Drawing.Drawing2D.GraphicsPath PercentagePath
            {
                get
                {
                    System.Drawing.Drawing2D.GraphicsPath Path = new System.Drawing.Drawing2D.GraphicsPath();
    
                    if (Style == Styles.Sqaured)
                    {
                        Path.AddLine(0, 0, this.Width * this.PercentageD100, 0);
                        Path.AddLine(this.Width * this.PercentageD100, 0, this.Width * this.PercentageD100, this.Height);
                        Path.AddLine(this.Width * this.PercentageD100, this.Height, 0, this.Height);
                        Path.AddLine(0, this.Height, 0, 0);
                    }
                    else if (Style == Styles.Rounded)
                    {
                        Path.AddLine(0, 0, this.Width * this.PercentageD100, 0);
                        Path.AddLine(this.Width * this.PercentageD100, 0, this.Width * this.PercentageD100, this.Height);
                        Path.AddLine(this.Width * this.PercentageD100, this.Height, 0, this.Height);
                        Path.AddLine(0, this.Height, 0, 0);
                    }
    
                    return Path;
                }
            }
            private System.Drawing.Drawing2D.GraphicsPath HighlightPath
            {
                get
                {
                    System.Drawing.Drawing2D.GraphicsPath Path = new System.Drawing.Drawing2D.GraphicsPath();
    
                    if (this.Style == Styles.Sqaured)
                    {
                        Path.AddLine(0, 0, this.Width, 0);
                        Path.AddLine(this.Width, 0, this.Width, this.HeightD2);
                        Path.AddLine(this.Width, this.HeightD2, 0, this.HeightD2);
                        Path.AddLine(0, this.HeightD2, 0, 0);
                    }
                    else if (this.Style == Styles.Rounded)
                    {
                        Path.AddArc(-1, 0, this.Height, this.Height, 180, 90);
                        Path.AddLine(this.HeightD2, 0, this.Width - this.HeightD2, 0);
                        Path.AddArc(this.Width - this.Height, 0, this.Height, this.Height, -90, 90);
                        Path.AddLine(this.Width, this.HeightD2, 0, this.HeightD2);
                    }
    
                    return Path;
                }
            }
            
            #endregion
    
            #region Texture Location
    
            private Microsoft.Xna.Framework.Vector2 PLocation;
            /// <summary>
            /// Gets or sets the location of the texture.
            /// </summary>
            public Microsoft.Xna.Framework.Vector2 Location
            {
                get { return this.PLocation; }
                set { this.PLocation = value; }
            }
    
            /// <summary>
            /// Gets or sets the center point of the texture.
            /// </summary>
            public Microsoft.Xna.Framework.Vector2 Center
            {
                get { return new Microsoft.Xna.Framework.Vector2(this.PLocation.X + (this.Width / 2), this.PLocation.Y + (this.Height / 2)); }
                set { this.Location = new Microsoft.Xna.Framework.Vector2(value.X - (this.Width / 2), value.Y - (this.Height / 2)); }
            }
    
            #endregion
    
            #region Texture Size
    
            private Size PSize;
            /// <summary>
            /// Gets or sets the size of the texture.
            /// </summary>
            public Size Size
            {
                get
                {
                    if (this.PSize != null && this.PSize.Width > 0 && this.PSize.Height > 0) return this.PSize;
                    else return new Size(200, 20);
                }
                set
                {
                    if (value.Width > 0 && value.Height > 0) this.PSize = value;
                }
            }
    
            /// <summary>
            /// Gets or sets the width of the texture.
            /// </summary>
            public int Width
            {
                get { return this.Size.Width; }
                set { this.PSize.Width = value; }
            }
            private int WidthM1 { get { return this.Width - 1; } }
    
            /// <summary>
            /// Gets or sets the height of the texture.
            /// </summary>
            public int Height
            {
                get { return this.Size.Height; }
                set { this.PSize.Height = value; }
            }
            private int HeightM1 { get { return this.Height - 1; } }
            private int HeightD2 { get { return this.Height / 2; } }
    
            #endregion
    
            #region Texture Styles
    
            /// <summary>
            /// A list of different styles that the texture can look like.
            /// </summary>
            public enum Styles : int
            {
                /// <summary>
                /// The texture will be displayed as a square the exact size specified.
                /// </summary>
                Sqaured = 0,
    
                /// <summary>
                /// The texture will be displayed as a square with rounded ends.
                /// </summary>
                Rounded = 1,
            }
            
            private Styles PStyle;
            /// <summary>
            /// Gets or sets the style of the texture.
            /// </summary>
            public Styles Style
            {
                get { return this.PStyle; }
                set { this.PStyle = value; }
            }
    
            #endregion
    
            #region Texture Colors
    
            private Microsoft.Xna.Framework.Color PBackColor;
            /// <summary>
            /// Gets or sets the back color of the texture.
            /// </summary>
            public Microsoft.Xna.Framework.Color BackColor
            {
                get { return this.PBackColor; }
                set { this.PBackColor = value; }
            }
    
            private Microsoft.Xna.Framework.Color PForeColor;
            /// <summary>
            /// Gets or sets the fore color of the texture.
            /// </summary>
            public Microsoft.Xna.Framework.Color ForeColor
            {
                get { return this.PForeColor; }
                set { this.PForeColor = value; }
            }
    
            private bool PHighlight;
            /// <summary>
            /// Gets or sets if a highlight should be displayed on the top half of the texture.
            /// </summary>
            public bool Highlight
            {
                get { return this.PHighlight; }
                set { this.PHighlight = value; }
            }
    
            private Microsoft.Xna.Framework.Color PHighlightColor;
            /// <summary>
            /// Gets or sets the highlight color of the texture
            /// </summary>
            public Microsoft.Xna.Framework.Color HighlightColor
            {
                get { return this.PHighlightColor; }
                set { this.PHighlightColor = value; }
            }
    
            private bool PBorder;
            /// <summary>
            /// Gets or sets if a border should be displayed around the texture.
            /// </summary>
            public bool Border
            {
                get { return this.PBorder; }
                set
                {
                    this.PBorder = value;
                    if (this.Border)
                    {
                        if (this.Size.Width < 3) this.PSize.Width = 3;
                        if (this.Size.Height < 3) this.PSize.Height = 3;
                    }
                }
            }
    
            private Microsoft.Xna.Framework.Color PBorderColor;
            /// <summary>
            /// Gets or sets the border color of the texture
            /// </summary>
            public Microsoft.Xna.Framework.Color BorderColor
            {
                get { return this.PBorderColor; }
                set { this.PBorderColor = value; }
            }
    
            #endregion
    
            #region Texture Percentage
    
            private float PPercentageD100;
            private float PercentageD100 { get { return this.PPercentageD100; } }
            /// <summary>
            /// Gets or sets the percentage value of the texture.
            /// </summary>
            public float Percentage
            {
                get { return this.PPercentageD100 * 100; }
                set
                {
                    if (value >= 0 && value <= 100) this.PPercentageD100 = value / 100;
                    else if (value < 0) this.PPercentageD100 = 0;
                    else if (value > 100) this.PPercentageD100 = 1;
                }
            }
    
            #endregion
        }

    The following is a custom class that was used in the previous code:
    Code:
        public class Size
        {
            #region Overrides
    
            [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
            public override bool Equals(object obj) { return base.Equals(obj); }
            [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
            public override int GetHashCode() { return base.GetHashCode(); }
            [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
            public override string ToString() { return base.ToString(); }
    
            #endregion
    
            private int PWidth;
            public int Width
            { 
                get { return this.PWidth; }
                set { this.PWidth = value; }
            }
    
            private int PHeight;
            public int Height
            {
                get { return this.PHeight; }
                set { this.PHeight = value; }
            }
    
            public Size(int Width, int Height)
            {
                this.Width = Width;
                this.Height = Height;
            }
        }

    HOW TO USE THE ABOVE CODE:
    Code:
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            private Microsoft.Xna.Framework.GraphicsDeviceManager GraphicsDeviceManager;
            private Microsoft.Xna.Framework.Graphics.SpriteBatch SpriteBatch;
    
            private ProgressBar ProgressBar1;
    
            public Game1()
            {
                this.GraphicsDeviceManager = new Microsoft.Xna.Framework.GraphicsDeviceManager(this);
                Content.RootDirectory = "Content";
            }
    
            protected override void Initialize()
            {
                base.Initialize();
                this.SpriteBatch = new Microsoft.Xna.Framework.Graphics.SpriteBatch(this.GraphicsDevice);
    
                this.ProgressBar1 = new ProgressBar(this.GraphicsDevice, SpriteBatch);
                this.ProgressBar1.Size = new Size(30, 30);
                //this.ProgressBar1.Location = new Microsoft.Xna.Framework.Vector2(20, 10);
                this.ProgressBar1.Center = new Microsoft.Xna.Framework.Vector2(275, 15);
                this.ProgressBar1.Style = ProgressBar.Styles.Rounded;
                this.ProgressBar1.BackColor = new Microsoft.Xna.Framework.Color(210, 210, 210, 255);
                this.ProgressBar1.ForeColor = new Microsoft.Xna.Framework.Color(0, 255, 0, 255);
    
                this.ProgressBar1.Highlight = true;
                this.ProgressBar1.HighlightColor = new Microsoft.Xna.Framework.Color(255, 255, 255, 170);
    
                this.ProgressBar1.Border = true;
                this.ProgressBar1.BorderColor = new Microsoft.Xna.Framework.Color(255, 0, 0, 100);
            }
    
            protected override void LoadContent()
            {
                
            }
    
            protected override void UnloadContent()
            {
    
            }
    
            protected override void Update(Microsoft.Xna.Framework.GameTime GameTime)
            {
                if (Microsoft.Xna.Framework.Input.Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Left)) this.ProgressBar1.Percentage -= 1;
                if (Microsoft.Xna.Framework.Input.Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Right)) this.ProgressBar1.Percentage += 1;
                base.Update(GameTime);
            }
    
            protected override void Draw(Microsoft.Xna.Framework.GameTime GameTime)
            {
                GraphicsDevice.Clear(new Microsoft.Xna.Framework.Color(0, 0, 255, 0));
    
                this.ProgressBar1.Draw();
    
                base.Draw(GameTime);
            }
        }

    And finally, the questions:

    1: How do I get rid of the use of the System.Drawing and System.Drawing. Drawing2D namespaces and replace them with something in the XNA framework?

    2: For the rounded style, how would I make the progress bar look proper when the percentage gets increased? Is there a way to erase the outside of a GraphicsPath? Drawing on the outside won't help, it actually needs to be erased. (From what I'm aware of atleast.)

    3: Is there a way to make it so I don't have to change the BackgroundPath depending on whether or not there is supposed to be a border?

    4: The reason the GetTexture is private is because I can't seem to make it get stored, so every time the draw function is called, it gets redrawn, but I'd like to be able to store the texture, and change it when the percentage value changes, so that way it doesn't have to keep redrawing.

    5: How would I go about making the Background Path into a BoundingBox to detect collisions?

    6: If you think I should be doing something completely different, please let me know.

    And that is all.
    Any help is appreciated.
    Last edited by Tyler Wiebe; Nov 6 '11, 09:13 PM. Reason: Forgot to ask a question.
  • GaryTexmo
    Recognized Expert Top Contributor
    • Jul 2009
    • 1501

    #2
    Trying to understand what you're doing here...

    Are you replacing a progress control that was done in GDI with an XNA one and dropping it on a windows form, or are you trying to recode this progress bar control so that can use it in an XNA game?

    I'm thinking it's the latter and if so, the question is how do you replace the GraphicsPath code with something that exists solely in the XNA framework? I assume you want to do this so your code will run on the XBox360... as if you were deploying on a PC you could continue to use this :)

    If this is all the case... I'm looking at the GraphicsPath and it looks like it's used to define a series of lines, then you can use the FillPath method on a Graphics object to get your texture in the shape of your GraphicsPath. Effectively, it looks like you're masking your texture to the shape you want.

    I don't think there's anything built into the XNA code that does this. The closest I can think of is an overload on the SpriteBatch.Dra w method which takes a rectangle as the source rectangle to draw. This will clip your source image and would let you cover your non-rounded corner case. I did a quick google and couldn't find anything that does this... which doesn't mean it doesn't exist, just that I can't find it ;)

    From my perspective, I think you're going to have to do this yourself. That said, it's an algorithm that should be fairly possible. I can think of a few ways to do it, though I'm not sure how fast they will be. I'll describe them here...

    Method 1: Polygon containment
    Create your own object to define a path, then add points to it... this will effectively define a polygon. Then when you fill the image, you can check to see if a pixel in the source image is inside your polygon or not. To see if a point is inside a polygon or not, check to see if the line defined by the point and a point outside the polygon (top-left of the image, for example) intersects an odd number of times with that polygon. If so, the point is inside the polygon.

    Method 2: Dynamic Image Generation and Masking
    You could also dynamically create a masking Texture2D object with what you want. and then use that to mask your images directly.

    Method 3: Pre-generated Masks with Scaling
    The final option I can think of is kind of an extension of the above. You can always create your masks as bitmap objects, then use scaling on them to size them appropriately, then mask your progress bar with them. If you did the whole image for the progress bar (with rounded corners) you run the risk of squishing it at smaller portions, so you might also just want to build a composite of endpoint cap masks with a middle section that's just a scaled rectangle.

    Anyway, I apologize for the large amount of rambling I've done there... hopefully it gives you some ideas of where you want to go, and hopefully I've read your question correctly and given you something you can use :)

    Comment

    • Tyler Wiebe
      New Member
      • Mar 2011
      • 66

      #3
      Thanks for your reply, and you're right about it being for an XNA game, and it is for a the PC, but I was hoping to make it for the Xbox 360 eventually, but if this is the case, I guess it'll stay a PC game.

      But about your response of how to cut off the sides of the rounded progress bar, I'm sorry, but I'm sadly not understanding what you mean.
      And do you have any opinion on question number three? It's no big deal, but it's rather annoying needing to change the pattern depending whether or not there is supposed to be a border.

      And that's it for now, thanks again for your reply.

      Comment

      • GaryTexmo
        Recognized Expert Top Contributor
        • Jul 2009
        • 1501

        #4
        You only have to stay PC if you want to keep the reliance on this... and yea, you can change it to be however you like. This is one method of making a progress bar, but there are others.

        Regarding your question 3, I'm not sure what you mean. I don't know enough about what your paths are actually doing to say, I'm sorry. As I understand it, you're masking your image in different ways so you'd have to change the path, wouldn't you?

        Finally, regarding my method 3 (your question on cutting off the sides of a rounded progress bar), it's a bit complicated but the general idea would be to use PNG files for the caps of your progress bar and another PNG file for the center part that you scaled to the correct width and put in the center.

        So then your draw would look something like...

        Code:
        spriteBatch.Draw(leftCapGraphic, new Vector2(this.X, this.Y));
        spriteBatch.Draw(midGraphic, new Vector2(this.X + leftCapGraphic.Width, this.Y), ..., new Vector2(this.Width - leftCapGraphic.Width - rightCapGraphic.Width, 1), ...); // Where that second Vector2 is the scale
        spritebatch.Draw(rightCapGraphic, new Vector2(this.X + leftCapGraphic.Width + (this.Width - leftCapGraphic.Width - rightCapGraphic.Width), this.Y));
        This works if the colour of your progress bar is the same all along the horizontal and can be reduced to a single pixel in width. Then you can just scale it to fit the middle portion that you require. You will run into some troubles when your current progress bar is less than the width of both caps, but clever scaling and cropping will take care of that.

        Comment

        • Tyler Wiebe
          New Member
          • Mar 2011
          • 66

          #5
          I just got back to my computer and thought a bit about what you said before, and I got an idea of how I could achieve my goal, it's different then your suggestion that I now see, but if you're suggestion is right, it should have the same result, but sadly, I'm not understanding it, so I'm just use my idea. And if you wouldn't mind, tell me what you think of it.

          First, I made it so it would store the BackgroundPath so it wouldn't need to recreate it every time the draw method was called, which from what I'm aware of, will save some time on the rendering.

          Secondly, the BackgroundPath is the only path now, and is called DesignPath.

          Code:
                  private System.Drawing.Drawing2D.GraphicsPath PDesignPath;
                  public System.Drawing.Drawing2D.GraphicsPath DesignPath { get { return this.PDesignPath; } }
                  private void CreateDesignPath()
                  {
                      this.PDesignPath = new System.Drawing.Drawing2D.GraphicsPath();
                      if (this.Style == Styles.Sqaured)
                      {
                          if (this.Border)
                          {
                              this.PDesignPath.AddLine(0, 0, this.WidthM1, 0);
                              this.PDesignPath.AddLine(this.WidthM1, 0, this.WidthM1, this.HeightM1);
                              this.PDesignPath.AddLine(this.WidthM1, this.HeightM1, 0, this.HeightM1);
                              this.PDesignPath.AddLine(0, this.HeightM1, 0, 0);
                          }
                          else
                          {
                              this.PDesignPath.AddLine(0, 0, this.Width, 0);
                              this.PDesignPath.AddLine(this.Width, 0, this.Width, this.Height);
                              this.PDesignPath.AddLine(this.Width, this.Height, 0, this.Height);
                              this.PDesignPath.AddLine(0, this.Height, 0, 0);
                          }
                      }
                      else if (this.Style == Styles.Rounded)
                      {
                          if (this.Border)
                          {
                              this.PDesignPath.AddArc(0, 0, this.HeightM1, this.HeightM1, 90, 180);
                              this.PDesignPath.AddLine(this.HeightD2, 0, this.WidthM1 - this.HeightD2, 0);
                              this.PDesignPath.AddArc(this.WidthM1 - this.HeightM1, 0, this.HeightM1, this.HeightM1, -90, 180);
                              this.PDesignPath.AddLine(this.WidthM1 - this.HeightD2, this.HeightM1, this.HeightD2, this.HeightM1);
                          }
                          else
                          {
                              this.PDesignPath.AddArc(-1, 0, this.Height, this.Height, 90, 180);
                              this.PDesignPath.AddLine(this.HeightD2, 0, this.Width - this.HeightD2, 0);
                              this.PDesignPath.AddArc(this.Width - this.Height, 0, this.Height, this.Height, -90, 180);
                              this.PDesignPath.AddLine(this.Width - this.HeightD2, this.Height, this.HeightD2, this.Height);
                          }
                      }
                  }
          I placed a call to the CreateDesignPat h function into anything that will change the shape of the progress bar(Border, Size, Style), which in turn is what makes it get called far less often.

          The reason there is only one GraphicsPath now is because I modified the GetTexture function into this:

          Code:
                  private Microsoft.Xna.Framework.Graphics.Texture2D GetTexture()
                  {
                      System.Drawing.Bitmap MainBitmap = new System.Drawing.Bitmap(this.Width, this.Height);
                      System.Drawing.Graphics MainBitmapGraphics = System.Drawing.Graphics.FromImage(MainBitmap);
          
                      MainBitmapGraphics.FillPath(new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(this.BackColor.A, this.BackColor.R, this.BackColor.G, this.BackColor.B)), this.DesignPath);
          
                      if ((int)(this.Width * this.PercentageD100) > 0)
                      {
                          System.Drawing.Bitmap PercentageBitmap = new System.Drawing.Bitmap((int)(this.Width * this.PercentageD100), this.Height);
                          System.Drawing.Graphics PercentageBitmapGraphics = System.Drawing.Graphics.FromImage(PercentageBitmap);
                          PercentageBitmapGraphics.FillPath(new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(this.ForeColor.A, this.ForeColor.R, this.ForeColor.G, this.ForeColor.B)), this.DesignPath);
                          MainBitmapGraphics.DrawImage(PercentageBitmap, 0, 0);
          
                          PercentageBitmapGraphics.Dispose();
                      }
                      if (this.Highlight)
                      {
                          System.Drawing.Bitmap HighlightBitmap = new System.Drawing.Bitmap(this.Width, this.HeightD2);
                          System.Drawing.Graphics HighlightBitmapGraphics = System.Drawing.Graphics.FromImage(HighlightBitmap);
                          HighlightBitmapGraphics.FillPath(new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(this.HighlightColor.A, this.HighlightColor.R, this.HighlightColor.G, this.HighlightColor.B)), this.DesignPath);
                          MainBitmapGraphics.DrawImage(HighlightBitmap, 0, 0);
          
                          HighlightBitmapGraphics.Dispose();
                      }
                      if (this.Border) MainBitmapGraphics.DrawPath(new System.Drawing.Pen(System.Drawing.Color.FromArgb(this.BorderColor.A,this.BorderColor.R,this.BorderColor.G,this.BorderColor.B), 1), this.DesignPath);
          
                      MainBitmapGraphics.Dispose();
          
                      System.IO.MemoryStream MemoryStream = new System.IO.MemoryStream(this.BufferSize);
                      MainBitmap.Save(MemoryStream, System.Drawing.Imaging.ImageFormat.Png);
                      return Microsoft.Xna.Framework.Graphics.Texture2D.FromStream(GraphicsDevice, MemoryStream);
                  }
          Now all that has to do is save a GraphicsPath to DesignPath for every change of appearance, and then it all it has to do is create three bitmaps using the DesignPath, cut them to the right size, put them into one bitmap, and change that one bitmap into a Texture2D every time the draw method is called.

          I hope you understood that, if not, I don't think I can explain it any better. But I do assume that because it doesn't have to do as much math as before, and is only done once(Unless the appearance gets changed), that it saves some rendering time. Am I correct about that? It worked fine before, but an increase of rendering speed never hurts, right?

          And thanks again for your help.

          Comment

          • GaryTexmo
            Recognized Expert Top Contributor
            • Jul 2009
            • 1501

            #6
            I think that's a great approach... with XNA, the less you do in a draw method the better. So caching your image and only updating it when something triggers a change is absolutely the way to go :)

            You're still reliant on paths here so you can't port easily to XBox360 (which is where my suggestions come in) but you know what? My advice to you would be to just carry on. Try to keep your new code going forward away from the winforms .NET library if you can, but for this? Just worry about the port if/when you decide to code for XBox360. You have the correct design approach here in that your code is completely modular and outputs something that XNA can understand. So if you ever need to move away from the winforms .NET stuff and into full XNA support your public interface won't change, just the guts of your class.

            Comment

            Working...