Skip to content

Instantly share code, notes, and snippets.

@westonsoftware
Last active April 11, 2024 16:13
Show Gist options
  • Save westonsoftware/a3fa982397fe1817ece4a27d3cbc5a89 to your computer and use it in GitHub Desktop.
Save westonsoftware/a3fa982397fe1817ece4a27d3cbc5a89 to your computer and use it in GitHub Desktop.
Stride 3D rendered into Avalonia
using System;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Rendering;
using Stride.Graphics;
using System.IO;
namespace InfinityGame
{
public class StartScript : SyncScript
{
private Random random = new Random();
public override void Start()
{
var model = Content.Load<Model>("Sphere");
var size = 100;
var count = 1000;
for (int i = 0; i < count; i++)
{
var modelComponent = new ModelComponent(model);
var randomPosition = new Vector3(random.Next(-size, size), random.Next(0, size), random.Next(-size, size));
var entity = new Entity(randomPosition, "NEW");
Entity.Scene.Entities.Add(entity);
entity.Add(modelComponent);
}
Game.Window.Position = new Int2(0, 0);
}
public override void Update()
{
var sprite = Entity.Get<SpriteComponent>();
var texture = sprite.CurrentSprite.Texture;
using (var image = texture.GetDataAsImage(Game.GraphicsContext.CommandList))
{
using (var stream = new MemoryStream())
{
image.Save(stream, ImageFileType.Bmp);
GlobalEvents.FrameReadyEventKey.Broadcast(stream.ToArray());
}
}
}
}
}
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using InfinityGame;
using Stride.Engine.Events;
using System;
using System.IO;
using System.Windows.Threading;
namespace AvaloniaApplication1.Views
{
public class UserControl1 : UserControl
{
private readonly DispatcherTimer timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100) };
public UserControl1()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
var strideImage = this.Find<Image>("StrideView");
var frameReady = new EventReceiver<byte[]>(GlobalEvents.FrameReadyEventKey);
timer.Tick += (s,e) =>
{
if (frameReady.TryReceive(out byte[] bmp))
{
using var stream = new MemoryStream(bmp);
var bitmap = new Avalonia.Media.Imaging.Bitmap(stream);
strideImage.Source = bitmap;
}
};
timer.Start();
}
}
}
@tebjan
Copy link

tebjan commented Mar 7, 2024

If anyone is looking for the GlobalEvents.FrameReadyEventKey you simply add it to your global events file: https://doc.stride3d.net/4.2/en/manual/scripts/events.html

For example:

public static class GlobalEvents
{
    public static EventKey<byte[]> FrameReadyEventKey = new EventKey<byte[]>("Global", "Frame Ready");
}

Also, note that downloading a texture from the GPU is a slow and blocking operation. Stride has a better TextureReadback class that at least doesn't block. However, the correct solution would be to create AvaloniaUI with a GPU context, if possible, and share a texture via a shared handle. This would be possible with Angle: AvaloniaUI/Avalonia#5432

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment