Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Basically I wrote a world editor for a game I'm working on. Looking ahead, I was brainstorming ways to save the created world including the tile-sets (this game will rely on a tile engine).

I was hoping to save the image data of each tile-set in the same file containing the tile positions, etc. and load the image data into a Texture with XNA.

Is it possible? Something like this is what I'm going for.

Texture2D tileset = Content.LoadFromString<Texture2D>("png tileset data");
share|improve this question
    
In XNA3.0 you could do Texture2D.FromStream, but now you have tu build texture using content pipeline and then load it –  Kikaimaru Sep 3 '12 at 10:50
4  
You can still use Texture2D.FromStream in XNA 4.0 msdn.microsoft.com/en-us/library/… –  dadoo Games Sep 3 '12 at 16:47

2 Answers 2

up vote 5 down vote accepted

As mentioned in the comments you can load a Texture from stream. The only issue with this is the content processor premultiplies the alpha which is necessary unless you use BlendState.NonPremultiplied as the BlendState argument when creating your SpriteBatch.

Below is a snippet of code that I use to premultiplied the alpha for textures loaded via a stream. It pushes the work onto the GPU and is a lot faster than iterating though the color array and multiplying it that way.

        Texture2D file;
        RenderTarget2D result;

        using (var titleStream = TitleContainer.OpenStream(loc)) {
            file = Texture2D.FromStream(graphicsDevice, titleStream);
        }

        //Setup a render target to hold our final texture which will have premulitplied alpha values
        result = new RenderTarget2D(graphicsDevice, file.Width, file.Height);

        graphicsDevice.SetRenderTarget(result);
        graphicsDevice.Clear(Color.Black);

        //Multiply each color by the source alpha, and write in just the color values into the final texture
        var blendColor = new BlendState {
            ColorWriteChannels = ColorWriteChannels.Red | ColorWriteChannels.Green | ColorWriteChannels.Blue,
            AlphaDestinationBlend = Blend.Zero,
            ColorDestinationBlend = Blend.Zero,
            AlphaSourceBlend = Blend.SourceAlpha,
            ColorSourceBlend = Blend.SourceAlpha
        };

        var spriteBatch = new SpriteBatch(graphicsDevice);
        spriteBatch.Begin(SpriteSortMode.Immediate, blendColor);
        spriteBatch.Draw(file, file.Bounds, Color.White);
        spriteBatch.End();

        //Now copy over the alpha values from the PNG source texture to the final one, without multiplying them
        var blendAlpha = new BlendState {
            ColorWriteChannels = ColorWriteChannels.Alpha,
            AlphaDestinationBlend = Blend.Zero,
            ColorDestinationBlend = Blend.Zero,
            AlphaSourceBlend = Blend.One,
            ColorSourceBlend = Blend.One
        };

        spriteBatch.Begin(SpriteSortMode.Immediate, blendAlpha);
        spriteBatch.Draw(file, file.Bounds, Color.White);
        spriteBatch.End();

        //Release the GPU back to drawing to the screen
        graphicsDevice.SetRenderTarget(null);

        return result as Texture2D;
share|improve this answer
    
So this is a function? or just a snippet of code. I'm confused because the last line returns the result. Thanks for the response by the way! –  Austin Brunkhorst Sep 3 '12 at 21:48
    
Its a snippet of the relevant bits out of a larger function. Left the 'return result as Texture2D;' to indicate the value you want ti be using. –  ClassicThunder Sep 4 '12 at 0:43

Building on the example by ClassicThunder. The class below is a more complete example for someone who is new to XNA/MonorGame. Basically, drop it into your project and you can load textures from disk into a List or Dictionary.

You'll probably want to utilize the .NET zip library to compress/decompress your assets manually and reduce clutter. If you're on .NET 4.0+ you have access to rather robust zip classes. Slap some encryption on this, and you've gotten a halfway decent texture loader.

public class TextureLoader
{
    public static List<Texture2D> LoadTextureList(string directory, GraphicsDevice graphicsDevice)
    {
        List<Texture2D> blendedTextures = new List<Texture2D>();
        //load any valid files in directory
        foreach (var fileName in Directory.GetFiles(directory, "*.jpg|*.png|*.gif"))
        {
            var blendedTexture = LoadFromFileStream(fileName, graphicsDevice);
            if (blendedTexture != null)
                blendedTextures.Add(blendedTexture);
        }
        return blendedTextures;
    }

    public static Dictionary<string, Texture2D> LoadTextureDictionary(string directory, GraphicsDevice graphicsDevice)
    {
        Dictionary<string, Texture2D> blendedTextures = 
                            new Dictionary<string, Texture2D>();
        //load any valid files in directory
        foreach (var fileName in Directory.GetFiles(directory, "*.jpg|*.png|*.gif"))
        {
            var blendedTexture = LoadFromFileStream(fileName, graphicsDevice);
            if (blendedTexture != null)
                blendedTextures.Add(fileName, blendedTexture);
        }
        return blendedTextures;
    }

    public static Texture2D LoadFromFileStream(string fileName , GraphicsDevice graphicsDevice)
    {
        Texture2D file;
        RenderTarget2D result;

        using(var fileStream = new FileStream(fileName, FileMode.Open))
        {
            file = Texture2D.FromStream(graphicsDevice, fileStream);
        }         

        //Setup a render target to hold our final texture which will have premulitplied alpha values
        result = new RenderTarget2D(graphicsDevice, file.Width, file.Height);
        graphicsDevice.SetRenderTarget(result);
        graphicsDevice.Clear(Color.Black);

        //Multiply each color by the source alpha, and write in just the color values into the final texture
        var blendColor = new BlendState
        {
            ColorWriteChannels = ColorWriteChannels.Red | ColorWriteChannels.Green | ColorWriteChannels.Blue,
            AlphaDestinationBlend = Blend.Zero,
            ColorDestinationBlend = Blend.Zero,
            AlphaSourceBlend = Blend.SourceAlpha,
            ColorSourceBlend = Blend.SourceAlpha
        };

        var spriteBatch = new SpriteBatch(graphicsDevice);
        spriteBatch.Begin(SpriteSortMode.Immediate, blendColor);
        spriteBatch.Draw(file, file.Bounds, Color.White);
        spriteBatch.End();

        //Now copy over the alpha values from the PNG source texture to the final one, without multiplying them
        var blendAlpha = new BlendState
        {
            ColorWriteChannels = ColorWriteChannels.Alpha,
            AlphaDestinationBlend = Blend.Zero,
            ColorDestinationBlend = Blend.Zero,
            AlphaSourceBlend = Blend.One,
            ColorSourceBlend = Blend.One
        };

        spriteBatch.Begin(SpriteSortMode.Immediate, blendAlpha);
        spriteBatch.Draw(file, file.Bounds, Color.White);
        spriteBatch.End();

        //Release the GPU back to drawing to the screen
        graphicsDevice.SetRenderTarget(null);

        return result as Texture2D;        
    }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.