2
\$\begingroup\$

I need to change texture size from for example 800x600 to 80x60. I have two ideas of how to do that, but i have problems with both approaches. 1) changre render target then draw and save resized. the problem is blinking screen while this method is working.

public static Texture2D Resize(Texture2D image, Rectangle source)
        {
            var graphics = image.GraphicsDevice;

            var ret = new RenderTarget2D(graphics, source.Width, source.Height);
            var sb = new SpriteBatch(graphics);

            graphics.SetRenderTarget(ret); // draw to image
            graphics.Clear(new Color(0, 0, 0, 0));

            sb.Begin();
            sb.Draw(image, source, Color.White);
            sb.End();

            graphics.SetRenderTarget(null); // set back to main window

            return (Texture2D)ret;
        }

2) use Texture.SaveAsPng(); this aproach is extremly stupid but it works

public static Texture2D Resize(Texture2D banner,Rectangle rectangle)
        {

                using (var file = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (var IsolatedStream = new IsolatedStorageFileStream("banner.te2", FileMode.Create, file))
                    {
                        IsolatedStream.Position = 0;
                        banner.SaveAsPng(IsolatedStream, rectangle.Width, rectangle.Height);
                        IsolatedStream.Close();
                    }
                }

                if (IsolatedStorageFile.GetUserStoreForApplication().FileExists("banner.te2"))
                {
                    using (var file = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        var IsolatedStream = new IsolatedStorageFileStream("banner.te2", FileMode.Open, file);
                        IsolatedStream.Position = 0;
                        banner = Texture2D.FromStream(Consts.GraphicsDevice, IsolatedStream);
                        IsolatedStream.Close();
                    }
                }
                return banner;

        }       

I'm looking for a clean fast solution, any suggestions? Resizing in Draw() method is not solution for me.

\$\endgroup\$
6
  • \$\begingroup\$ Oh great. It's that horridly wrong copy-pasted resizing code from XNA 3.1 being passed around. It was bad then, and doesn't even work in XNA 4. \$\endgroup\$ Sep 4, 2013 at 14:52
  • \$\begingroup\$ Do you mean resize or crop? \$\endgroup\$ Sep 4, 2013 at 14:58
  • \$\begingroup\$ Resize, i need to do icon from full texture. \$\endgroup\$
    – Feusp
    Sep 5, 2013 at 6:28
  • \$\begingroup\$ Your RenderTarget2D method appears to be doing a crop. \$\endgroup\$ Sep 5, 2013 at 10:06
  • \$\begingroup\$ Actually not, sb.Draw(image, source, Color.White); second parameter is rectangle, if there were Vector2 it would be crop. \$\endgroup\$
    – Feusp
    Sep 5, 2013 at 14:35

1 Answer 1

2
\$\begingroup\$

Setting the render target, by default, will clear the render target that you set. (In this case, null specifies the backbuffer as the render target - it gets cleared too).

You can change this by setting RenderTargetUsage.PreserveContents on the appropriate backbuffer. To do this, you need to respond to the PreparingDeviceSettings event at startup and set GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage.

If you are on any platform other than Windows (so, on Windows Phone or Xbox 360), then this is not recommended because it's very, very slow - which is why it is not the default.

Rather than changing modes, you should simply do all your render target operations at the start of your frame, before you draw your scene to the backbuffer. In your Update method is acceptable.

Note that "return (Texture2D)ret" doesn't turn your render target into a regular Texture2D. It's still a RenderTarget2D object and you must respond correctly to IsContentLost (or redraw it every frame, or copy it into a Texture2D with GetData and SetData).


A better solution than all of this, however, is probably to simply copy the original Texture2D into another Texture2D using GetData and SetData (performing whatever transform you want to apply on the CPU - if it is a simple crop operation, then this will be very fast).

\$\endgroup\$
2
  • \$\begingroup\$ Target platform is windows phone, so am i right i have only one good solution of this problem by using SetData and writing my own resize algorithm of the texture? \$\endgroup\$
    – Feusp
    Sep 5, 2013 at 6:37
  • \$\begingroup\$ No no - you can still do it on the GPU if you like. You should just be sure to do one of those three things I mentioned (refresh the render target each frame, refresh it on content lost, or copy it back to the CPU). \$\endgroup\$ Sep 5, 2013 at 10:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .