Skip to content

Instantly share code, notes, and snippets.

@flibitijibibo
Last active April 30, 2022 15:21
Show Gist options
  • Star 24 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save flibitijibibo/cf282bfccc1eaeb47550 to your computer and use it in GitHub Desktop.
Save flibitijibibo/cf282bfccc1eaeb47550 to your computer and use it in GitHub Desktop.
Example to hook up an SDL2 window to a Panel for use in a System.Windows.Forms window
#region License
/* FNA GameWindow for System.Windows.Forms Example
* Written by Ethan "flibitijibibo" Lee
* http://www.flibitijibibo.com/
*
* Released under public domain.
* No warranty implied; use at your own risk.
*/
#endregion
#region Using Statements
using System;
using System.Threading;
using System.Runtime.InteropServices;
/* Bad awful Win32 Stuff */
using System.Drawing;
using System.Windows.Forms;
using Point = System.Drawing.Point;
/* Good nice FNA Stuff */
using SDL2;
using Microsoft.Xna.Framework;
using Color = Microsoft.Xna.Framework.Color;
#endregion
public class FNAWindowExample : Form
{
#region FNA Game
class ExampleGame : Game
{
public Color ClearColor;
GraphicsDeviceManager graphics;
public ExampleGame() : base()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 640;
graphics.PreferredBackBufferHeight = 480;
ClearColor = new Color(255, 255, 255, 255);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(ClearColor);
}
}
#endregion
#region Private FNA Window/Control Variables
// These are the variables you care about.
private static ExampleGame game;
private Panel gamePanel;
private bool windowAttached = false;
#endregion
#region Private Variables
private Random random = new Random();
#endregion
#region WinAPI Entry Points
[DllImport("user32.dll")]
private static extern IntPtr SetWindowPos(
IntPtr handle,
IntPtr handleAfter,
int x,
int y,
int cx,
int cy,
uint flags
);
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr child, IntPtr newParent);
[DllImport("user32.dll")]
private static extern IntPtr ShowWindow(IntPtr handle, int command);
#endregion
#region Form Constructor
public FNAWindowExample()
{
// This is what we're going to attach the SDL2 window to
gamePanel = new Panel();
gamePanel.Size = new Size(640, 480);
gamePanel.Location = new Point(80, 10);
// Make the WinForms window
Size = new Size(800, 600);
FormClosing += new FormClosingEventHandler(WindowClosing);
Button button = new Button();
button.Text = "Whatever";
button.Location = new Point(
(Size.Width / 2) - (button.Size.Width / 2),
gamePanel.Location.Y + gamePanel.Size.Height + 10
);
button.Click += new EventHandler(ClickedButton);
Controls.Add(button);
Controls.Add(gamePanel);
}
#endregion
#region Button Event Method
private void ClickedButton(object sender, EventArgs e)
{
if (!windowAttached)
{
// Make the Game, give it time to start up
new Thread(GameThread).Start();
Thread.Sleep(1000);
// Get the Win32 HWND from the FNA window
SDL.SDL_SysWMinfo info = new SDL.SDL_SysWMinfo();
SDL.SDL_GetWindowWMInfo(game.Window.Handle, ref info);
IntPtr winHandle = info.info.win.window;
// Move the SDL2 window to 0, 0
game.Window.IsBorderlessEXT = true;
SetWindowPos(
winHandle,
Handle,
0,
0,
0,
0,
0x0401 // NOSIZE | SHOWWINDOW
);
// Attach the SDL2 window to the panel
SetParent(winHandle, gamePanel.Handle);
ShowWindow(winHandle, 1); // SHOWNORMAL
// We out.
windowAttached = true;
}
game.ClearColor = new Color(
(float) random.NextDouble(),
(float) random.NextDouble(),
(float) random.NextDouble(),
1.0f
);
}
#endregion
#region Window Close Method
private void WindowClosing(object sender, FormClosingEventArgs e)
{
game.Exit();
}
#endregion
#region Game Thread
// Run the Game in its own thread, to prevent GL ugliness
private static void GameThread()
{
using (game = new ExampleGame())
{
game.Run();
}
}
#endregion
#region Program Entry Point
[STAThread]
static void Main()
{
Application.Run(new FNAWindowExample());
}
#endregion
}
#region License
/* SDL2 Window for System.Windows.Forms Example
* Written by Ethan "flibitijibibo" Lee
* http://www.flibitijibibo.com/
*
* Released under public domain.
* No warranty implied; use at your own risk.
*/
#endregion
#region Using Statements
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using SDL2;
#endregion
public class SDL2WindowExample : Form
{
#region Private SDL2 Window/Control Variables
// These are the variables you care about.
private Panel gamePanel;
private IntPtr gameWindow; // For FNA, this is Game.Window.Handle
#endregion
#region Private GL Variables
// IGNORE MEEEEE
private Random random;
private IntPtr glContext;
private delegate void Viewport(int x, int y, int width, int height);
private delegate void ClearColor(float r, float g, float b, float a);
private delegate void Clear(uint flags);
private Viewport glViewport;
private ClearColor glClearColor;
private Clear glClear;
#endregion
#region WinAPI Entry Points
[DllImport("user32.dll")]
private static extern IntPtr SetWindowPos(
IntPtr handle,
IntPtr handleAfter,
int x,
int y,
int cx,
int cy,
uint flags
);
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr child, IntPtr newParent);
[DllImport("user32.dll")]
private static extern IntPtr ShowWindow(IntPtr handle, int command);
#endregion
#region Form Constructor
public SDL2WindowExample()
{
// This is what we're going to attach the SDL2 window to
gamePanel = new Panel();
gamePanel.Size = new Size(640, 480);
gamePanel.Location = new Point(80, 10);
// Make the WinForms window
Size = new Size(800, 600);
FormClosing += new FormClosingEventHandler(WindowClosing);
Button button = new Button();
button.Text = "Whatever";
button.Location = new Point(
(Size.Width / 2) - (button.Size.Width / 2),
gamePanel.Location.Y + gamePanel.Size.Height + 10
);
button.Click += new EventHandler(ClickedButton);
Controls.Add(button);
Controls.Add(gamePanel);
// IGNORE MEEEEE
random = new Random();
SDL.SDL_Init(SDL.SDL_INIT_VIDEO);
gameWindow = SDL.SDL_CreateWindow(
String.Empty,
0,
0,
gamePanel.Size.Width,
gamePanel.Size.Height,
SDL.SDL_WindowFlags.SDL_WINDOW_BORDERLESS | SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL
);
glContext = SDL.SDL_GL_CreateContext(gameWindow);
glViewport = (Viewport) Marshal.GetDelegateForFunctionPointer(
SDL.SDL_GL_GetProcAddress("glViewport"),
typeof(Viewport)
);
glClearColor = (ClearColor) Marshal.GetDelegateForFunctionPointer(
SDL.SDL_GL_GetProcAddress("glClearColor"),
typeof(ClearColor)
);
glClear = (Clear) Marshal.GetDelegateForFunctionPointer(
SDL.SDL_GL_GetProcAddress("glClear"),
typeof(Clear)
);
glViewport(0, 0, gamePanel.Size.Width, gamePanel.Size.Height);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(0x4000);
SDL.SDL_GL_SwapWindow(gameWindow);
// Get the Win32 HWND from the SDL2 window
SDL.SDL_SysWMinfo info = new SDL.SDL_SysWMinfo();
SDL.SDL_GetWindowWMInfo(gameWindow, ref info);
IntPtr winHandle = info.info.win.window;
// Move the SDL2 window to 0, 0
SetWindowPos(
winHandle,
Handle,
0,
0,
0,
0,
0x0401 // NOSIZE | SHOWWINDOW
);
// Attach the SDL2 window to the panel
SetParent(winHandle, gamePanel.Handle);
ShowWindow(winHandle, 1); // SHOWNORMAL
}
#endregion
#region Button Event Method
private void ClickedButton(object sender, EventArgs e)
{
glClearColor(
(float) random.NextDouble(),
(float) random.NextDouble(),
(float) random.NextDouble(),
1.0f
);
glClear(0x4000); // GL_COLOR_BUFFER_BIT
SDL.SDL_GL_SwapWindow(gameWindow);
}
#endregion
#region Window Close Method
private void WindowClosing(object sender, FormClosingEventArgs e)
{
glClear = null;
glClearColor = null;
glViewport = null;
SDL.SDL_GL_DeleteContext(glContext);
glContext = IntPtr.Zero;
SDL.SDL_DestroyWindow(gameWindow);
gameWindow = IntPtr.Zero;
SDL.SDL_Quit();
}
#endregion
#region Program Entry Point
[STAThread]
static void Main()
{
Application.Run(new SDL2WindowExample());
}
#endregion
}
@Goicox
Copy link

Goicox commented Feb 25, 2017

Where could I find more examples for using this library? Goicox

@Alan-FGR
Copy link

@Goicox FNA is a reimplementation of XNA, so you can use the docs and tutorials for it. SDL2-CS is just a thin wrapper, the API is pretty much the same as the C version, so you can use the same docs.

@DeafMan1983
Copy link

DeafMan1983 commented Sep 5, 2021

Hello everyone,

// REMOVE:
Because it doesn't work for WinAPI. Only X11 works as well if you add child window in SDL2 Only FreeBSD and Linux are successful with child windows, And macOS and Windows won't work because they don't have child window inside SDl2.
That is why - It is bad news for Windows 10 and macOS ( I am not sure if NS_Panel pops up from child of SDL2 like X11. But I don't see that. ??? )

// UPDATE:
It is simple button clicks with scene switchers:
https://gist.github.com/DeafMan1983/86934b03b701de37a39acb0163ce391a
Enjoy and understand how do you switch scenes of screen of game app!

Thanks regards!

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