Issue with colours moving from DirectX

Hi all,

I’ve recently decided to move a community project of and old MMORPG over to Monogame but having issues creating textures. All the games textures are stored in a custom image library and I’m pulling the data out fine but the images are coming out blue.

Old function for creating a texture:

    int w = Width;// + (4 - Width % 4) % 4;
    int h = Height;// + (4 - Height % 4) % 4;
    GraphicsStream stream = null;
    Image = new Texture(DXManager.Device, w, h, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
    stream = Image.LockRectangle(0, LockFlags.Discard);
    Data = (byte*)stream.InternalDataPointer;
    byte[] decomp = DecompressImage(reader.ReadBytes(Length));
    stream.Write(decomp, 0, decomp.Length);
    stream.Dispose();
    Image.UnlockRectangle(0);

My new code in Monogame:

        Texture = new Texture2D(SceneManager.Instance.GraphicsDevice, Width, Height, false, SurfaceFormat.Color);
        Texture.SetData(DecompressImage(binaryReader.ReadBytes(Length)));

The decompress method is the same in both sources:

    private static byte[] DecompressImage(byte[] imageData)
    {
        using (var stream = new GZipStream(new MemoryStream(imageData), CompressionMode.Decompress))
        {
            const int size = 4096;
            var buffer = new byte[size];
            using (var memoryStream = new MemoryStream())
            {
                var count = 0;
                do
                {
                    count = stream.Read(buffer, 0, size);
                    if (count > 0)
                        memoryStream.Write(buffer, 0, count);
                }
                while (count > 0);
                return memoryStream.ToArray();
            }
        }
    }

I’m guessing it’s the SurfaceFormat is wrong I tried setting it too Rgba32 but then I receive an exception saying format is not supported.

Images:


The images are stored as Bitmaps, I thought FromStream was JPG/PNG only?
Thanks for the reply.

Looks like you just need to swap the red and blue channels.

As @Jjagg mentioned, the red and blue channels are swapped. This is a common situation. Internally, the DirectX version uses SharpDX.DXGI.Format.R8G8B8A8_UNorm for SurfaceFormat.Color. These format symbols are always confusing, and the DXGI naming appears to be specified in the reverse order to your original code, but suffice to say that the R and B channels are in opposite positions.

This is some code borrowed from our Texture2D.DirectX.cs file.

    private static void ConvertToRGBA(int pixelHeight, int pixelWidth, byte[] pixels)
    {
        int offset = 0;

        for (int row = 0; row < (uint)pixelHeight; row++)
        {
            for (int col = 0; col < (uint)pixelWidth; col++)
            {
                offset = (row * pixelWidth * 4) + (col * 4);

                byte B = pixels[offset];
                byte R = pixels[offset + 2];

                pixels[offset] = R;
                pixels[offset + 2] = B;
            }
        }
    }

It could be made slightly faster using unsafe code, but it does the job.

@PumpkinPudding, Texture2D.FromStream only works with common image file formats. This is using a custom data format.

2 Likes

Thanks working perfectly, wondered if it was because the channels were swapped but was unsure how to go about swapping them.

1 Like