Introduction
“SFML (Simple and Fast Multimedia Library) is a portable and easy-to-use API for multimedia programming. It is an object oriented alternative for the SDL. SFML provides 2D graphics that are hardware accelerated with OpenGL. SFML can also be used for OpenGL windowing. SFML also provides different modules made to ease programming games and multimedia applications.“ It is written in C++, it does already have a binding for .NET, which is not my concern, what I am caring about is that how I would be able to create the C# wrapper libraries for the whole packages of C++ DLLs automatically using xInterop NGen++. (By the way, this is going to be the official name of the C# .NET PInvoke Interop SDK for the native C++ DLL)
“The modules currently available are:
- The System module manages the clock and threads.
- The Window module manages windows and user interactions.
- The Graphics module makes it easy to display simple shapes and images.
- The Audio module provides an interface to handle sounds and music.
- The Network module handles sockets in a portable way. “
By using xInterop NGen++, I was able to build 5 individual C# .NET wrapper assemblies for all the 5 modules in less than 10 minutes. (I certainly spent a few hours testing them to make sure they work correctly with a couple of examples of using SFML, I did not have any knowledge of SFML, I went to its web site to learn all the samples, it was easy though since I just needed to change the syntax from C++ to C#.) Their assembly names and namespaces are automatically given based on the names of the original C++ native DLLs.
• NSpeech.Win32.Nsfml_system_2
• NSpeech.Win32.Nsfml_audio_2
• NSpeech.Win32.Nsfml_network_2
• NSpeech.Win32.Nsfml_window_2
• NSpeech.Win32.Nsfml_graphics_2
Since I have both x86/win32 32 bits and x64 64 bits DLLs, I was able to build C# .NET Assemblies targeting AnyCPU, which means I will be able to use the DLL under x86, x64 platform or x64 WoW.
By using those C# .NET assemblies, I was able to write the C# example code which looks almost similar to the original C++ sample code since they share the same class names, same methods name inside of each class. All I had to do is to change the syntax of declaring variables and calling methods.
I studied the C++ samples from SFML tutorials herefor a few minutes and I picked up one simple sample of creating shapes. The following is the original C++ code to create an outline of a circle shape, which I shamefully copied from SFML web site with credits to Laurent Gomila.
// The following code was copied from SFML web site, credit to Laurent Gomila sf::CircleShape shape(50); shape.setFillColor(sf::Color(150, 50, 250)); // set a 10-pixel wide orange outline shape.setOutlineThickness(-10); shape.setOutlineColor(sf::Color(250, 150, 100));
Now, let’s write some C# code to call the SFML C++ code via the C# wrapper libraries generated by xInterop NGen++, remember, the auto-generated C# source code only replies on Explicit P/Invoke, but really, it is so easy and simple to call the C++ class methods or access the C++ internal properties from C# by using the auto-generated C# wrapper classes.
Here is a C# example to create a outline of the shape of a circle.
CircleShape shape = new CircleShape(50); shape.setFillColor(new Color(150, 50, 250)); // set a 10-pixel wide orange outline shape.setOutlineThickness(-10); // set the outline color. shape.setOutlineColor(new Color(250, 150, 100)); // Draw the shape. Draw(shape); // Make sure that the shape object will not get GC-collected. GC.KeepAlive(shape);
And here is the draw method which accepts a parameter of the base class of any drawable class, namely Drawable class. This way, I will be able to draw any supported drawable objects in a window.
static void Draw(Drawable drawable) { // ContextSettings of Version 2.0 ContextSettings contextSettings = new ContextSettings { majorVersion = 2 }; // Create the render window. RenderWindow renderWindow = new RenderWindow(); renderWindow.create(new VideoMode(750, 120), new NString(title), 4, contextSettings); // Convert render window to RenderTarget. NGen++ currently does not support multiple inheritance // This is a workaround to create RenderTarget based on a renderWindow C++ pointer. It will be fixed // in the near future. RenderTarget target = new RenderTarget(renderWindow.CppPointer + (new Window()).Size, IntPtr.Zero, false); target.Disposable = false; while (renderWindow.isOpen()) { // Clear screen target.clear(Color.Black); // Draw the sprite. target.draw(drawable, RenderStates.Default); // Update the window renderWindow.display(); // Check any input. using (Event inputEvent = new Event(IntPtr.Zero, IntPtr.Zero, false, true)) { while (renderWindow.pollEvent(inputEvent)) { if (inputEvent.type == EventType.Closed) { // Close the window if it is closed event. renderWindow.close(); break; } } } } // Dispose the render window. Clean up the native C++ resource. renderWindow.Dispose(); }
Here is the captured image by running the preceding sample C# code. You can find the similar image created by the original C++ code from here.
This is the Part I. Stay tuned, I will present the Part II soon.