Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading a PNG with alpha and rendering not working correctly on Windows GL #1946

Closed
battlebottle opened this issue Aug 20, 2013 · 22 comments
Closed

Comments

@battlebottle
Copy link

This issue affect MonoGame on Windows GL but may affect other platforms too. It affects MonoGame 3.0, and also 3.2.

Basically loading a texture with this code (F#):

use file = System.IO.File.OpenRead("testTexture.png")
this.texture <- Texture2D.FromStream(this.GraphicsDevice, file)

and rendering with this code:

this.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
this.spriteBatch.Draw(this.texture, Vector2.Zero, Color.White)
this.spriteBatch.End()

will reproduce the error. This code works fine and renders fine when using the XNA4 libraries, but has weird alpha blending artefacts when using MonoGame.

Here's some renderings to illustrate the issue. First the correct renderings using the XNA libraries
Image

Now the bad renderings using MonoGame:

Image

I've tried to figure out the nature of the issue, but havne;t gotten very far besides realising that it's not a simple case of BlendState.NonPremultiplied being ignored or something similar. For examples, on analysis I've noticed the green colour channel blends differently than the red and blue colour channels among other odd things. I've creates a large image that illustrates the issue I've noticed in what is hopefully a useful way:

http://i.imgur.com/CEUQqm0.png

Here's the project files for reproducing the bad rendering (F# project):
http://www.qfpost.com/file/d?g=EhZh52Zjc

I also made a post about this issue on stack overflow which may be worth monitoring:
http://stackoverflow.com/questions/18320633/loading-texture-form-png-in-monogame-transaprency-issue

@dellis1972
Copy link
Contributor

Thanks for one of the most comprehensive bug reports we have ever had :)
It looks like a very weird problem. Does the same thing happen when using
an .xnb file? It would be nice to narrow this down to a specific area. I
suspect the error is in the FromStream method where is processes the pixel
data to the texture. I know we had all sorts of issues with that in the
past with Colour channels being reversed.

On 20 August 2013 20:39, battlebottle notifications@github.com wrote:

This issue affect MonoGame on Windows GL but may affect other platforms
too. It affects MonoGame 3.0, and also 3.2.

Basically loading a texture with this code (F#):

use file = System.IO.File.OpenRead("testTexture.png")
this.texture <- Texture2D.FromStream(this.GraphicsDevice, file)

and rendering with this code:

this.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
this.spriteBatch.Draw(this.texture, Vector2.Zero, Color.White)
this.spriteBatch.End()

will reproduce the error. This code works fine and renders fine when using
the XNA4 libraries, but has weird alpha blending artefacts when using
MonoGame.

Here's some renderings to illustrate the issue. First the correct
renderings using the XNA libraries
[image: Image]https://github-camo.global.ssl.fastly.net/fb7f6900f42dcc18411ad888f69fdf8f9428ceb0/687474703a2f2f692e696d6775722e636f6d2f3252747168756b2e706e67

Now the bad renderings using MonoGame:

[image: Image]https://github-camo.global.ssl.fastly.net/38cd617ba477449a91ac6934cd14401837291d60/687474703a2f2f692e696d6775722e636f6d2f446e79323667492e706e67

I've tried to figure out the nature of the issue, but havne;t gotten very
far besides realising that it's not a simple case of
BlendState.NonPremultiplied being ignored or something similar. For
examples, on analysis I've noticed the green colour channel blends
differently than the red and blue colour channels among other odd things.
I've creates a large image that illustrates the issue I've noticed in what
is hopefully a useful way:

http://i.imgur.com/CEUQqm0.png

I've attached the project files for reproducing the bad rendering (F#
project).

I also made a post about this issue on stack overflow which may be worth
monitoring:

http://stackoverflow.com/questions/18320633/loading-texture-form-png-in-monogame-transaprency-issue


Reply to this email directly or view it on GitHubhttps://github.com//issues/1946
.

@dellis1972
Copy link
Contributor

I wonder if this is messing things up

https://github.com/mono/MonoGame/blame/develop/MonoGame.Framework/Graphics/ImageEx.cs

On 20 August 2013 22:23, Dean Ellis dellis1972@googlemail.com wrote:

Thanks for one of the most comprehensive bug reports we have ever had :)
It looks like a very weird problem. Does the same thing happen when using
an .xnb file? It would be nice to narrow this down to a specific area. I
suspect the error is in the FromStream method where is processes the pixel
data to the texture. I know we had all sorts of issues with that in the
past with Colour channels being reversed.

On 20 August 2013 20:39, battlebottle notifications@github.com wrote:

This issue affect MonoGame on Windows GL but may affect other platforms
too. It affects MonoGame 3.0, and also 3.2.

Basically loading a texture with this code (F#):

use file = System.IO.File.OpenRead("testTexture.png")
this.texture <- Texture2D.FromStream(this.GraphicsDevice, file)

and rendering with this code:

this.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
this.spriteBatch.Draw(this.texture, Vector2.Zero, Color.White)
this.spriteBatch.End()

will reproduce the error. This code works fine and renders fine when
using the XNA4 libraries, but has weird alpha blending artefacts when using
MonoGame.

Here's some renderings to illustrate the issue. First the correct
renderings using the XNA libraries
[image: Image]https://github-camo.global.ssl.fastly.net/fb7f6900f42dcc18411ad888f69fdf8f9428ceb0/687474703a2f2f692e696d6775722e636f6d2f3252747168756b2e706e67

Now the bad renderings using MonoGame:

[image: Image]https://github-camo.global.ssl.fastly.net/38cd617ba477449a91ac6934cd14401837291d60/687474703a2f2f692e696d6775722e636f6d2f446e79323667492e706e67

I've tried to figure out the nature of the issue, but havne;t gotten very
far besides realising that it's not a simple case of
BlendState.NonPremultiplied being ignored or something similar. For
examples, on analysis I've noticed the green colour channel blends
differently than the red and blue colour channels among other odd things.
I've creates a large image that illustrates the issue I've noticed in what
is hopefully a useful way:

http://i.imgur.com/CEUQqm0.png

I've attached the project files for reproducing the bad rendering (F#
project).

I also made a post about this issue on stack overflow which may be worth
monitoring:

http://stackoverflow.com/questions/18320633/loading-texture-form-png-in-monogame-transaprency-issue


Reply to this email directly or view it on GitHubhttps://github.com//issues/1946
.

@battlebottle
Copy link
Author

Hey Dellis,

Thanks for the response. You got it in one! The problem seems to be definitely related to ImageEx.cs and the RGBToBGR(Image bmp) method. When I remove the RGBToBGR call from Text2D.FromStream() it loads the texture from the PNG with Red and Blue channels reversed... but the alpha renders correctly! I'm messing about with it now to see can I figure out what's happening, but this is certainly the source of the misbehaviour.

@battlebottle
Copy link
Author

Success! I believe I have it all working now.

    internal static void RGBToBGR(this Image bmp)
    {
        System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes();
        System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(rgbtobgr);

        ia.SetColorMatrix(cm);
        using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
        {
            g.DrawImage(bmp, new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, System.Drawing.GraphicsUnit.Pixel, ia);
        }
    }

Should be changed to:

    internal static void RGBToBGR(this Image bmp)
    {
        using (Bitmap bmpCopy = (Bitmap)bmp.Clone())
        {
            System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes();
            System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(rgbtobgr);

            ia.SetColorMatrix(cm);
            using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
            {
                g.Clear(Color.Transparent);
                g.DrawImage(bmpCopy, new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, System.Drawing.GraphicsUnit.Pixel, ia);
            }
        }
    }

in https://github.com/mono/MonoGame/blame/develop/MonoGame.Framework/Graphics/ImageEx.cs

What's happening is when the RGBToBGR conversion performed, it draws the converted version of the image on top of the image object it's converting from. This is what's causing the strange effects. As far as I can tell the only thing to do is to clear the image object before drawing over it again, which of course means the bitmap you're converting from must be copied so you can read from the copied version while writing over the original version that was just cleared. That's probably more explanation than was required..

Can I trust someone to submit this fix?

Thanks for the help. Spent all day scratching my head over this one :).

@dellis1972
Copy link
Contributor

I'll make sure this gets in, thanks for finding the solution :)

On 20 August 2013 23:11, battlebottle notifications@github.com wrote:

Success! I believe I have it all working now.

internal static void RGBToBGR(this Image bmp)
{
    System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes();
    System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(rgbtobgr);

    ia.SetColorMatrix(cm);
    using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
    {
        g.DrawImage(bmp, new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, System.Drawing.GraphicsUnit.Pixel, ia);
    }
}

Should be changed to:

internal static void RGBToBGR(this Image bmp)
{
    using (Bitmap bmpCopy = (Bitmap)bmp.Clone())
    {
        System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes();
        System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(rgbtobgr);

        ia.SetColorMatrix(cm);
        using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
        {
            g.Clear(Color.Transparent);
            g.DrawImage(bmpCopy, new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, System.Drawing.GraphicsUnit.Pixel, ia);
        }
    }
}

in
https://github.com/mono/MonoGame/blame/develop/MonoGame.Framework/Graphics/ImageEx.cs

What's happening is when the RGBToBGR conversion performed, it draws the
converted version of the image on top of the image object it's
converting from. This is what's causing the strange effects. As far as I
can tell the only thing to do is to clear the image object before drawing
over it again, which of course means the bitmap you're converting from must
be copied so you can read from the copied version while writing over the
original version that was just cleared. That's probably more explanation
than was required..

Can I trust someone to submit this fix?

Thanks for the help. Spent all day scratching my head over this one :).


Reply to this email directly or view it on GitHubhttps://github.com//issues/1946#issuecomment-22981911
.

@battlebottle
Copy link
Author

Glad to have been of some help. MonoGame rocks :)

@Sumez
Copy link

Sumez commented Jan 3, 2014

Has this somehow been fixed elsewhere, or is it forgotten? Cause I'm not seeing the code, as mentioned in here, in the MonoGame repository yet.

@Draih
Copy link

Draih commented Mar 27, 2015

This issue is still not fixed in Monogame 3.3. I'm attempting to render a transparent .PNG file which is primarily red, and in the running file, the image comes out purple. Checking the repository, the change to fix this issue never made it in.

@fjeandinot
Copy link

Hi ! This issue is still not fixed in Monogame 3.4.

As you can see, this is the result with WindowsGL (classic png + BlendState.NonPremultiplied)
(the center of the picture is a sample for comparaison)
bad

And the result expected
good

The "grood" result can be obtained with WindowsDX + a premultiplied png and BlendState.AlphaBlend so I guess it is a GL specific issue...

@tomspilman
Copy link
Member

@fjeandinot - Can you test with the latest development build of 3.5? We though that #2424 resolved this.

@fjeandinot
Copy link

Hi tom !

Still the same result. Sorry.

@tomspilman
Copy link
Member

@fjeandinot - Are your textures being processed by the content pipeline or being loaded from PNGs? Can you share a simple test project that exhibits the error?

@fjeandinot
Copy link

The picture is loaded from a png processed by inkscape.
I used to process the texture with the MonoGame Pipeline but the xnb files where too large and the dxt compression deteriorate my sprites.

Here's my tesing code :

`
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace View
{
public class Viewer : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D texture;
Viewport viewport;

    public Viewer ()
    {
        graphics = new GraphicsDeviceManager (this);
        Content.RootDirectory = "Content";              
    }

    protected override void Initialize ()
    {
        const int width = 1024;
        const int height = 1024;

        Window.Position = new Point ((GraphicsDevice.DisplayMode.Width / 2) - (width / 2),
            (GraphicsDevice.DisplayMode.Height / 2) - (height / 2));
        graphics.PreferredBackBufferWidth = width;
        graphics.PreferredBackBufferHeight = height;
        graphics.ApplyChanges ();

        viewport = new Viewport (0, 0, width, height);

        base.Initialize ();
    }

    protected override void LoadContent ()
    {
        texture = Content.Load<Texture2D> ("spritesheet.png");
        spriteBatch = new SpriteBatch (GraphicsDevice);
    }

    protected override void Update (GameTime gameTime)
    {
        if (texture == null) {
            this.Exit ();
        }
        base.Update (gameTime);
    }

    protected override void Draw (GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear (Color.White);
        graphics.GraphicsDevice.Viewport = viewport;
        spriteBatch.Begin (SpriteSortMode.Deferred, BlendState.NonPremultiplied);
        spriteBatch.Draw (texture, Vector2.Zero, Color.White);
        spriteBatch.End ();
        base.Draw (gameTime);
    }
}

}

`

Do you want a zipped version of the project with the png ?

@fjeandinot
Copy link

Link to my Viewer

dellis1972 added a commit to dellis1972/MonoGame that referenced this issue Feb 1, 2016
tomspilman added a commit that referenced this issue Feb 2, 2016
Fixed #1946 Turns out the Image needs to be cleared first otherwise the colors bleed.
@fjeandinot
Copy link

If the developpement build is recreated under the next 24 hour, I'll be glad to test every flavor of monogame with the premultiplied and the non premultiplied png with each option. As the viewer produce a direct result, it could be a cool non-regression test.

@tomspilman
Copy link
Member

If the developpement build is recreated under the next 24 hour

The new build is already up... we update the website on every merge to the develop branch. So if you grab the current version it will have the fix in #4487.

it could be a cool non-regression test.

Seems like we could make a simpler test. If the issue is just one of Texture2D.FromStream() not loading textures correctly... we can test it by just examining the pixels of the loaded texture. No rendering required.

I see we have no unit test for Texture2D.FromStream()... so this would be a good start to rectifying that.

@tomspilman
Copy link
Member

@fjeandinot - FYI... @Tzenchor is adding some unit tests for Texture2D.FromStream() in #4493. You might want to wait for his PR if you planned to work on your own.

@fjeandinot
Copy link

Hi ! I'have tested the DesktopGL ans the Windows

Here's the result for the non premultiplied alpha png :

  • DesktopGL + BlendState.AlphaBlend => white screen
  • DesktopGL + BlendState.NonPremultiplied => white screen
  • Windows + BlendState.AlphaBlend => perfect !!!
  • Windows + BlendState.NonPremultiplied => gray borders

Here's the result for the premultiplied alpha png :

  • DesktopGL + BlendState.AlphaBlend => white screen
  • DesktopGL + BlendState.NonPremultiplied => white screen
  • Windows + BlendState.AlphaBlend => perfect !!!
  • Windows + BlendState.NonPremultiplied => gray borders

Something's probably broken with the GL version, but isn't it strange that the windows version act that way ?

I think I'm missing a point about the differents version of monogame...

@tomspilman
Copy link
Member

I think I'm missing a point about the differents version of monogame

DesktopGL uses OpenGL to render. Windows uses DirectX. So very different code and graphics layers to the same hardware.

hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
hach-que pushed a commit to RedpointArchive/MonoGame that referenced this issue Feb 7, 2016
@fjeandinot
Copy link

Hi ! Since you have fixed this problem, the GL version seems to display "nothing" from a png regadless of the BlendState or the png alpha mode.

@fjeandinot
Copy link

Hi,

I keep updating my version of monogame by downloading the daily build but the GL version keep not showing raw png...

@KonajuGames
Copy link
Contributor

I keep updating my version of monogame by downloading the daily build but the GL version keep not showing raw png.

I replicated the problem and created a fix in #4609.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants