bijington/orbit

Exception thrown when loading an image on Windows

bijington opened this issue · 3 comments

When invoking "new W2DImageLoadingService().FromStream(stream)" I see this exception:

System.Exception: 'No resource creator has been registered globally or for this thread.'

I found the following open issue:
IImageLoadingServcie cannot load image on Windows

The suggested workaround to connect a GlobalCreator after the GraphicsView is loaded partially solves this issue.

Exception will be thrown until the GraphicView "Loaded" handler workaround is invoked, so you would need to defer resource loading until after Loaded is triggered.

I used a Lazy to load the resources on the first Render call to the GameObject.

Originally posted by @aluitink in #4 (comment)

Hi @bijington, I have done a little workaround for the windows environment.

Here is the updated GameSceneView class that will handle the missing GlobalCreator initialization:

public partial class GameSceneView : GraphicsView
{
    public GameSceneView()
    {
        BackgroundColor = Colors.Transparent;
#if WINDOWS
        Loaded += GameSceneView_Loaded;
    }

    private void GameSceneView_Loaded(object sender, EventArgs e)
    {
        System.Reflection.Assembly assembly = typeof(Microsoft.Maui.Graphics.Win2D.W2DCanvas).Assembly;
        var type = assembly.GetType("Microsoft.Maui.Graphics.Win2D.W2DGraphicsService");
        var prop = type.GetProperty("GlobalCreator");

        var graphicsView = (GraphicsView)sender;
        var view = (Microsoft.Maui.Platform.PlatformTouchGraphicsView)graphicsView.Handler.PlatformView;
        var view2 = (Microsoft.Maui.Graphics.Win2D.W2DGraphicsView)view.Content;
        prop.SetValue(null, view2.Content);
        }
#else
    }
#endif

    private IGameScene scene;

    public IGameScene Scene
    {
        get => scene;
        internal set
        {
            scene = value;
            Drawable = value;
        }
    }
}

Also you can make the image loading Lazy like this:

public class Asteroid : GameObject
{
    private readonly IGameSceneManager gameSceneManager;
    Lazy<Microsoft.Maui.Graphics.IImage> image;
    float x;
    float y;
    Movement movement;

    public Asteroid(IGameSceneManager gameSceneManager)
    {
        image = new Lazy<Microsoft.Maui.Graphics.IImage>(()=> LoadImage("asteroid.png"));

        this.gameSceneManager = gameSceneManager;
    }
}

@paramsaggu thank you for this update. Does this change prevent the possible COM exceptions that is mentioned here? dotnet/Microsoft.Maui.Graphics#422 (comment) I am definitely keen to follow this issue. I do believe the actual PlatformImage option on Windows should be coming in the not so distant future (I am hoping for .NET 7.0) meaning we can avoid having to do this workaround.

I like the idea of Lazy loading! We are actually discussing how to improve the efficiency around loading images and sharing them over at #19 so this could really help that!

@bijington I have committed the changes in the fork of this repository. And recently I found that if you load images after GameView is Loaded, the GlobalCreator will automatically get initialized.
You can have a look at the changes here:
main...paramsaggu:orbit:windows-com-exception-fixed