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

[WIP] Embedding Game in WPF and WinForms #1474

Draft
wants to merge 26 commits into
base: master
Choose a base branch
from

Conversation

juyanith
Copy link

@juyanith juyanith commented Jul 24, 2022

Updates Window so that it will accept a parent HWND and create a child in which to render.

Description

This is a Windows (OS) specific update. By passing in the parent window, using SDL CreateWindowFrom(), and some calls to native windows code I was able to host a Game inside WPF and WinForms. I used the Particles Sample project to create example implementations: ParticlesSample.Wpf and ParticlesSample.WinForms.

The WPF example makes use of GameEngineHost while the WinForms example doesn't need it. Both make use of SDL.Window which has been modifed to create child windows when passed a parent HWND. There is also an update to GameBase that prevents the PreferredBackBufferWidth and PreferredBackBufferHeight from overriding the Context RequestedWidth and RequestedHeight.

I'm not sure how you would go about doing something similar in Avalonia Given but how similar it is to WPF it may not be too difficult, although I suspect an equivalent class to GameEngineHost would need to be created.

Related Issue

#870
#1315

Motivation and Context

I would like to use Stride as a visualization tool inside an existing WPF application.

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My change requires a change to the documentation.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@CLAassistant
Copy link

CLAassistant commented Jul 24, 2022

CLA assistant check
All committers have signed the CLA.

@tebjan
Copy link
Member

tebjan commented Jul 25, 2022

Nice one, I wonder whether we can introduce the parent window idea to the platform-independent GameWindow class. So that it works for SDL, Winforms, and whatever windowing backend will be used. Or do you think the abstraction would create too much work?

@ericwj
Copy link
Collaborator

ericwj commented Jul 25, 2022

Would be absolutely awesome if the sample would consist of three projects, for WPF, WinUI3 and WinForms. For WinUI3 I would just try and start with a MAUI app and see if appropriate use of #if can actually yield a solution listed for WinUI3, but its probably fine to start with WinUI3 and leave the crossplat for later.

See Retrieve a window handle (HWND) - Windows apps | Microsoft Docs

@juyanith
Copy link
Author

juyanith commented Jul 28, 2022

I added a WinForms sample. It works, but user input is not quite working. Specifically, the right side arrows don't respond to mouse clicks. It's also sluggish, but I figured it was worthwhile to show something partially working.

@tebjan
Copy link
Member

tebjan commented Jul 28, 2022

For Windforms there is another context, that also uses the winforms message loop. That might fix the issues. https://github.com/stride3d/stride/blob/master/sources/engine/Stride.Games/GameContextWinforms.cs

@ericwj
Copy link
Collaborator

ericwj commented Jul 28, 2022

Its not sluggish on my machine. Maybe thats much better if you build in Release.

For Windforms there is another context

Interesting though that right now this WinForms project is the only one not affected by the freezing while dragging.

@juyanith
Copy link
Author

juyanith commented Jul 28, 2022

Interesting though that right now this WinForms project is the only one not affected by the freezing while dragging.

I experimented with this and running the WPF game loop in a task and it accomplished the same thing. It even shows the same behavior on failing to register clicks the right arrows. However, what is interesting is that after you resize the window that problem goes away. I tried forcing a refresh after starting the game loop but it didn't help. It is a clue though and may help figure out what is happening on the WinForms side as well.

@SoggyBottomBoy
Copy link

Would this also address support for winui3?

@ericwj
Copy link
Collaborator

ericwj commented Jul 29, 2022

Maybe change the title to include WinForms, Win32 (if that is what Particles.Windows is) and WinUI3 once its in?

@juyanith
Copy link
Author

juyanith commented Jul 29, 2022

I at least figured a workaround for the game not responding to mouse clicks until resized. Basically, the game did not have the correct values set for width and height of the render area.

I'm still trying to work my way through the generic classes (e.g. GameWindow) to see if there is a way to encapsulate this in a platform independent way. I'm not having a great deal of luck however. That may be a task better suited to someone more familiar with Stride.

@SoggyBottomBoy I may try to add something for winui3. I'm not sure how much will have to be added since the WPF example makes use of the already existing GameEngineHost.

@ericwj I probably should adjust the title. I don't believe Particles.Windows was modified in this PR.

@juyanith juyanith changed the title Game Embedding in WPF [WIP] Embedding Game in WPF and WinForms Jul 29, 2022
@ericwj
Copy link
Collaborator

ericwj commented Jul 29, 2022

No indeed. The point would be to have people find this searching for Win32. But on second thought its only a temporary advantage; people won't normally find the PR once its merged. Particles should eventually be listed in the docs with these terms instead.

@ericwj
Copy link
Collaborator

ericwj commented Jul 29, 2022

I'm not sure how much will have to be added since the WPF example makes use of the already existing GameEngineHost.

Forget about WPF. Both WinUI3 and WPF have XAML but technically WPF is special. I think you should look at the Windows project to figure out how it'd work with WinUI3.

var wndClass = new NativeMethods.WndClassEx();
wndClass.cbSize = (uint)Marshal.SizeOf(wndClass);
wndClass.hInstance = NativeMethods.GetModuleHandle(null);
wndClass.lpfnWndProc = NativeMethods.DefaultWindowProc;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this causes the problems with resizing and dragging. It shouldn't be needed to run the rendering in a task, either.

Take a look at this window procedure and then add to that a handler for WM_PAINT which doesn't use BeginPaint, EndPaint, but calls into the rendering instead. You can see how it is done in C++ in the DirectX samples here.

The way to get WndProc to be called for a specific window instance is by forwarding like it is done here. Notice the [UnmanagedCallersOnly] and the use in there of CREATESTRUCTW to carry a GCHandle which targets the Window itself.

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

Successfully merging this pull request may close these issues.

5 participants