Loading raw png in wp8 does not work on high-end phones

Hi,

I must be annoying to come up with this topic again, but I still have issues loading raw png files in wp8/wp8.1 environment. If anyone can solve this, he/she will be my guest for some beers, no less! :smiley:
So… I bought a new Lumia 930 some days ago, and the solution that works in Lumia 520 and the emulators does not seem to work on this new device.
For me it seems that it cannot reach the texture, or simply cannot load the data from it and the app just hangs up for all eternity…

I made some screenshots for the codeplex site directly from my Lumia 520, so here you can see that this should be the expected result on every windows phone:

This is what I am using and this solution WORKS on my Lumia 520 and all of the emulators (this is obviously not my solution, I just googled it and found this at several dev sites):

private void AddTextures(string[] folderPath, bool useStaticCache)
    {
        using (var are = new System.Threading.AutoResetEvent(false))
        {
            System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                foreach (string path in folderPath)
                {
                    foreach (string fileName in Directory.GetFiles(path))
                    {
                        using (FileStream fs = new FileStream(fileName, System.IO.FileMode.Open))
                        {
                            _GameEngineManager.LoadTexture(
                                fileName,
                                TextureFromStreamForWP8(_GameEngineManager.GraphicsDevice, fs),
                                useStaticCache);
                        }
                    }
                }

                _TexturesLoaded = true;
            });
            are.WaitOne(2000);
        }
    }

public Texture2D TextureFromStreamForWP8(GraphicsDevice graphicsDevice, Stream stream)
    {
        Texture2D result = null;

        //using (var are = new System.Threading.AutoResetEvent(false))
        //{
        //System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
        //{
        var image = new BitmapImage();
        image.SetSource(stream);
        var bitmap = new WriteableBitmap(image);
        var pixels = SetColorsFromPixelData(bitmap.Pixels);
        Texture2D texture2D = new Texture2D(graphicsDevice, bitmap.PixelWidth,
                                    bitmap.PixelHeight);
        texture2D.SetData(pixels);
        result = texture2D;

        //are.Set();
        //});

        //are.WaitOne();
        //}

        return result;
    }

    private Color[] SetColorsFromPixelData(int[] pixelData)
    {
        var Colors = new Color[pixelData.Length];
        for (var i = 0; i < pixelData.Length; i++)
        {
            var packedColor = pixelData[i];
            Color unpackedColor = new Color();
            unpackedColor.B = (byte)(packedColor);
            unpackedColor.G = (byte)(packedColor >> 8);
            unpackedColor.R = (byte)(packedColor >> 16);
            unpackedColor.A = (byte)(packedColor >> 24);
            Colors[i] = unpackedColor;
        }
        return Colors;
    }

My friend is trying to help me as he was also unable to run my game on his 1520 Lumia. What he found is that this “System.Windows.Deployment.Current.Dispatcher.BeginInvoke” does not run on wp8.1. It compiles and the app is still copied to your phone, but this code will just not run.
What he tried is to use CoreWindow to get the current thread and run this loading logic, but it needs some code changes that I will try to implement within the next few days. This is the class that needs to be used:

It has a limitation in WP version as it is only supported in 8.1, but not in 8.0, so I will need to find a way to use the proper logic in both versions so my game will run in both environments.

I will post the solution as I am more than sure that lot of others are interested in that. :slight_smile:

Ok, so here is a working solution! The important thing is that when you store the loaded texture, the storing part must be in the same dispatcher call where the loading happens. I am calling this methods in the first draw call as there may be problems with the dispatcher (especially if you use CoreApplicationView).

private void LoadTextureFromStream(string[] folderPath, bool useStaticCache)
    {
        Texture2D tex;
        foreach (string path in folderPath) //I am loading pngs from different folders
        {
            if (Directory.Exists(path)) //Some safety check :)
            {
                foreach (string fileName in Directory.GetFiles(path))
                {
                    var dop = Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        using (FileStream fs = new FileStream(fileName, System.IO.FileMode.Open))
                        {
                            var image = new BitmapImage();
                            image.SetSource(fs);
                            var bitmap = new WriteableBitmap(image);
                            var pixels = SetColorsFromPixelData(bitmap.Pixels);
                            tex = new Texture2D(_GameEngineManager.GraphicsDevice, bitmap.PixelWidth,
                                                        bitmap.PixelHeight);
                            tex.SetData(pixels);

                            _GameEngineManager.LoadTexture(
                                        fileName,
                                        tex,
                                        useStaticCache); //This is my game engine's image cache. This call must be here in the same dispatcher call, else you may store NULLs!
                        }
                    });
                }
            }
        }
    }

    private Color[] SetColorsFromPixelData(int[] pixelData)
    {
        var Colors = new Color[pixelData.Length];
        for (var i = 0; i < pixelData.Length; i++)
        {
            var packedColor = pixelData[i];
            Color unpackedColor = new Color();
            unpackedColor.B = (byte)(packedColor);
            unpackedColor.G = (byte)(packedColor >> 8);
            unpackedColor.R = (byte)(packedColor >> 16);
            unpackedColor.A = (byte)(packedColor >> 24);
            Colors[i] = unpackedColor;
        }
        return Colors;
    }