Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
October 21, 2014
arrowPress Releases
October 21, 2014
PR Newswire
View All
View All     Submit Event





If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 
Converting an XNA4 Game to FNA
by Michael Hicks on 06/23/14 11:16:00 am   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

Converting an XNA4 Game to FNA

This tutorial will walk you through converting an XNA4 project to the open source FNA library. By the end of this tutorial you will have your XNA project running on Windows, Mac and Linux.

What is FNA?

FNA was originally called MonoGame-SDL2, a branch of MonoGame that uses SDL2 under the hood. This branch is managed by Ethan Lee, who used it to port games such as FEZ, Dust: An Elysian Tail, Capsized, Gateways, Escape Goat and more.

Eventually the branch contained several major rewrites that made it difficult to merge back into the mainline version of MonoGame, thus FNA was born. FNA focuses solely on accurate XNA4 behavior for desktop platforms (Windows, Mac, Linux).

In the past, something I’ve struggled with understanding is the open source nature of MonoGame. From what I’ve seen, a lot of people seem to fork from the mainline, and then patch it up to work for their game. There’s nothing wrong with this, but as someone who doesn’t want to spend a lot of time on underlying tech, I’ve been looking for something that “just works” with my XNA4 code. FNA has been that solution for me!

This tutorial will walk you through the process of porting your XNA4 game over to FNA.

Tips and Disclaimers

  • I recommend having your XNA4 game 100% completed before porting.
     
  • Like MonoGame, FNA is open source and constantly being updated, so pull and update your library often!
     
  • To help you get an idea, the project I ported primarily relies on the 2D side of XNA. The most advanced thing I do in my game relies on custom blend states for SpriteBatch, and some basic HLSL shaders. I can report that all of these things worked great.
     
  • FNA is not a solution for targeting non-desktop platforms such as Xbox or PlayStation. However, the MonoGame team has specific branches targeting platforms like PS4 that might interest you!

Getting Setup

1. Download the latest version of FNA here. If you don’t have Git installed, you can press “Download Zip” on the right side of the screen.

Make sure SDL2#, TheoraPlay# and MonoKickstart are also downloaded and placed in their respective folders under ThirdParty (get these manually here).

Note: We are about to prebuild the FNA library for use in our new project, but you can also add the .csproj files from FNA into your new project so you can edit the library and look at the changes a lot quicker than rebuilding the files everytime.

2. Open the FNA solution and press F5 to build the library (preferably in Release mode). This will spit out two files in the bin folder called "FNA.dll" and "FNA.dll.config". Essentially, these files contain the code needed to replace the XNA libraries in your project! If you get an error message saying the libraries cannot be launched, that means they were built successfully (probably the only time an error message is a good thing)!  

3. Now we need to download the native libraries used by FNA. Ethan has provided some of them here. The other ones you need are SDL2, SDL2_Image, OpenAL Soft, and SDL2_Mixer. You'll want to download the 32bit runtime binaries.

For now we'll be using the Win32 libs provided from Ethan's site. If you're targeting Mac and Linux, those libs are also in the file we downloaded, but we won't use those until later on in the tutorial.

4. Make a copy of your project to use for the FNA version. Copy the .dlls from steps two and three next to your .csproj file. In Visual Studio, right click your project name and go to "Add-> Existing Item..." and add all of these .dlls to the root of your project.

It's easiest to just add all of the libs and move to the next step, but you really only need to add the libs your project requires at runtime. For example, if you don't use Song/Video, you'll only need SDL2 and OpenAL Soft. SDL2_mixer/libvorbisfile are used for Song, TheoraPlay is used for Video, and libogg/libvorbis are used for both Song and Video.

5. In Visual Studio, select all of the.dlls we just added. Under Properties, change Copy to Output Directory to "Copy if Newer". If you don't know what this does, whenever you build your game this will move the .dlls to the bin folder so the .exe can find them!

Replacing XNA

1. In Visual Studio, look under References and remove any reference that contains the words "Microsoft.Xna".

2. Right click References and click "Add Reference". Now go to the browse tab and add “MonoGame.Framework.dll”, “SDL2-CS.dll” and “TheoraPlay-CS.dll”.  The other .dlls we downloaded do not need to be referenced from here.

3. At this point, you should be able to run your game with FNA! My game did not immediately run because I was using the namespace Microsoft.Xna.Framework.GamerServices, which isn't in FNA since it's mainly for Xbox 360 development. There might be a few minor things like this you have to edit, but it shouldn't be anything too bad!

Note: If your project relies on Microsoft.Xna.Framework.GamerServices or Microsoft.Xna.Framework.Net, there's a separate assembly called MonoGame.Net.dll that's been introduced to help standardize the netcode for the library. If you're interested, there's more reading here.

Note Two: In FNA, songs are Ogg Vorbis, Videos are Ogg Theora. Keep the XNB files, throw out any WMA/WMV files if applicable.

4. If you're using custom shaders (.fx files), your game will crash when loading them (we're about to fix that). If you're not using custom shaders, there's a good chance you're done porting for Windows at this point! Yay!!

Using Custom Shaders

Like MonoGame, FNA uses a new file type called MGFX for shaders. Here's the reasoning for it from the MonoGame documentation:

"For MonoGame we have the burden of supporting stock and custom effects for desktop GLSL, mobile GLSL, DirectX HLSL, and custom formats like that of the PlayStation Mobile. There currently is no effect system or shader language that supports all the platforms we require, forcing us to build a new custom effect system."

If you don't understand the difference between HLSL and GLSL, the TL;DR version is OpenGL/GLSL is supported on many platforms, whereas DirectX/HLSL is mainly used on Microsoft platforms. Since FNA supports Windows, Mac and Linux it uses OpenGL underneath.

Thankfully for us, there's a tool called 2MGFX by Tom Spilman that will convert our .fx files over to this dandy new format! But before we convert our files, we'll need to make some edits to our shaders:

1. Inside each of your .fx files, you will need to change how you compile your pixel shader and vertex shader: it will need to compile for shader model 4. To help keep your shader working in both XNA4 and FNA, you can do something like this:

//Old code:

technique BloomCombine

{

                pass Pass1

                {

                                PixelShader = compile ps_2_0 PixelShaderFunction();

                }

}

//New code:

technique BloomCombine

{

                pass Pass1

                {

                                #if SM4

                                                PixelShader = compile ps_4_0_level_9_1 PixelShaderFunction();

                                #elif SM3

                                                PixelShader = compile ps_3_0 PixelShaderFunction();

                                #else

                                                PixelShader = compile ps_2_0 PixelShaderFunction();

                                #endif

                }

}

 

The "compile ps_4_0_level_9_1" line is the important part, you'll need to add that to any pixel shader you have. For vertex shaders use "compile vs_4_0_level_9_1". Once you do this, your shaders should be ready for conversion.

2. Open up the FNA repository you downloaded earlier and look in the Tools folder for 2MGFX. Once you find it, open the solution!

3. Open Program.cs. Everywhere you see "return 0" or "return 1" add this line of code right before that call: System.Threading.Thread.Sleep(5000); 2MGFX is a console application, and as soon as you run it, it will close.  Since it displays helpful error messages to us, calling Thread.Sleep will keep the window open a bit so we can read any messages before it closes.

4. Run 2MGFX in Release and then go to the bin\Release folder where 2MGFX.exe is located. Now copy all of the .fx files you want to convert to this location, right next to the .exe.

5. Go to the start menu and open Run. In the Open line, run this:

C:\Path To Your Release Folder\2MGFX.exe ShaderName.fx ShaderName.fxg /Profile:OpenGL

You will need to fill this out to work on your machine. The first parameter is the path to 2MGFX.exe, the second parameter is the name of the .fx file you want to convert and the third parameter is the new MGFX file that will be spit out. Since FNA uses OpenGL, the flag at the end tells 2MGFX we're targeting that profile; other flags you could use here are "DirectX_11" or "PlayStation4".

Repeat this step for all of your shaders.

6. Return to Visual Studio and remove your old .fx files, replacing them with the new .fxg files we just created. Once added, select all of the shaders and change the Build Action property to "None" since we're not going to run these through the normal content pipeline!

After this, you should have no problem loading in and using your effects - your game should now be running in Windows! *fireworks go off*

Note: Ethan is currently planning on removing the dependency on MGFX in future versions of FNA. He intends to make it where the original XNB shader files can be used without recompilation. I will try to update the tutorial when this happens.

Building Your Game for Mac

Remember the native libs we downloaded earlier for Mac and Linux? It's time to use those!

1. Inside the FNA folder you downloaded, go to ThirdParty\MonoKickstart. Dig through this until you find the folder named "precompiled", this folder contains some precompiled .dll files from Mono (an open source implementation of .NET) so we won't have to require a system install of Mono for Mac and Linux versions of our project. These files will be needed for all non-Win32 targets (Mac and Linux)! Also located here are some additional folders that we need to drop the downloaded libs into. The file you downloaded should already have the libs separated into their respective folders, you just need to copy them over. The Linux libs go into the "lib" and "lib64" folders, and the Mac libs go into the "osx" folder.

2. Rename "Kick", "kick.bin.x86", "kick.bin.osx" and "kick.bin.x86_64" to the name of your .exe instead of the word "kick". For example, if your exe name is MyGame.exe it would look like "MyGame.bin.osx" and so on.

3. Open up the file now called "MyGame". Inside this file, everytime you see the word "kick" replace it with the name of your game's .exe, similar to what we just did in the last step.

4. Now we'll need to put together the "app shell" to distribute to Mac players. The shell is just a folder organized a certain way, so we can easily put this together on Windows. To make this super easy, you can download an example shell here. (Thanks to Nick Gravelyn, developer of Shipwreck for providing this!)

5. Open the example shell and go to Contents\MacOS. You can think of this folder as the working directory for your game. Copy and paste your game's exe, Content folder and managed .dll files to this location. 

6. From the precompiled folder, copy all of the .dlls and the files called "MyGame" and "MyGame.bin.osx" into the Contents\MacOS folder. You will also need to copy the files in the precompiled\osx folder into the Contents\MacOS\osx folder, and all of the files in the precompiled\mono folder into the Contents\MacOS\mono folder.

7. Replace and rename all remaining information that belongs to Shipwreck with your own game's info. To create an icon for your game, you can use this website to generate the file.

8. We now need to package the .app folder so we can distribute it on Mac. Something worth noting is that the .app folder is technically a folder, but OS X treats this as a file! We'll need to treat the app bundle as if it's a file and have the folders organized correctly - if you followed the example shell format, you shouldn't have anything to worry about. Use the program called "Disk Utility" found in OS X to package the .app folder (File -> New -> Disk Image From Folder).

For both OS X and Linux, the bin files in addition to the renamed "Kick" file must be marked as executable! If you just zip up the .app folder from Windows it's possible that you can lose these permissions. You should now be ready to test your project on OS X, and if it works properly, distribute it on OS X!

Building Your Game for Linux

1. You will need to be running in Linux to complete this step.

2. We'll need to make an installer for Linux, Ethan has provided a program to do this here.

3. Replace all of the examplegame information with your own game's info.

4. Run ./build.sh YourGameName  and a Linux installer will be spit out! Be sure to test your project on Linux before celebrating!

The End

I hope this was useful for people that would like to continue using XNA code in the future. I ran into a few hiccups getting my game working 100% accurately, but I probably got up and running on Windows in under eight hours. I'm personally pretty impressed with that!

Big thanks to Ethan Lee and Nick Gravelyn for helping me get set up, most of this info came from them.

                - Michael Hicks (@michaelartsxm)


Related Jobs

Treyarch / Activision
Treyarch / Activision — Santa Monica, California, United States
[10.21.14]

Senior UI Artist (temporary) Treyarch
Treyarch / Activision
Treyarch / Activision — Santa Monica, California, United States
[10.21.14]

Lead UI Artist
Infinity Ward / Activision
Infinity Ward / Activision — Woodland Hills, California, United States
[10.21.14]

Senior AI Engineer - Infinity Ward
Treyarch / Activision
Treyarch / Activision — Santa Monica, California, United States
[10.21.14]

Senior Software Engineer - Treyarch






Comments


Kujel Selsuru
profile image
This is useful information, thakns for posting :)

Emma Maassen
profile image
This was very useful even though I wasn't switching from XNA4 but from MonoGame trunk. Thanks! :)

Michael Hicks
profile image
You're welcome! Glad it was useful!

Mark Mennell
profile image
Great article - thanks! I am stuck at Step 3 - 4 in Getting Setup, you say "...you'll only need SDL2 and OpenAL Soft..", I downloaded Ethan's libs and the ones from the SDL2 sites however I do not have anything to do with OpenAL. It seems I do need it as my XNA4 game compiles now using FNA instead of XNA but when I try run it I get:

Unable to load DLL 'soft_oal.dll': The specified module could not be found.

In the ctor of my Game class. I even when ahead and installed OpenAL and OpenTK and did a system wide search for soft_oal.dll but could not find...

Where did you get it from and where can I get it? Or is it because things have moved on and you did not need it? Thanks!

Mark Mennell
profile image
Hey Guys got the Windows port to use FNA working - it "just works"!

However now stuck with MacOS.

Running Mac OS X 10.6.8 on a MacBook

After following the instructions running MyGame.app does not start and the following is logged to Console:

com.apple.launchd.peruser.501[109] ([0x0-0x4b04b].com.mycompany[4557]) posix_spawn("/Users/macbook/Desktop/MacBeta/MyGame.app/Contents/MacOS/MyGame", ...): No such file or directory

Running ./MyGame from Terminal in MacOS folder gives:

-bash: ./MyGame: /bin/bash^M: bad interpreter: No such file or directory

I think that script just chooses the binary to run? So I tired just running it myself with ./MyGame.bin.osx and that gives:

dyld: Library not loaded: /usr/local/lib/libmono-2.0.1.dylib
Referenced from: /Users/macbook/Desktop/MacBeta/MyGame.app/Contents/MacOS/./MyGame.bin.osx
Reason: image not found
Trace/BPT trap

Looks like it is looking in the wrong place for mono? If the MyGame script were working would this fix that issue?

Mark Mennell
profile image
OK script problem was just some dodgy characters inserted by Windows so edited in vi and reduced it to (since this script will only be running Mac:

#!/bin/bash
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:./osx/
./MyGame.bin.osx $@

Now runs! Then crashes - could not find SDL-CS, must have forgot that dll...

Mark Mennell
profile image
OK got SDL-CS dll in there, now getting: SDL2.dll not found, where to I get that?

There is no SDL2.dll for osx on the SDL2 site only SDL2-2.0.3.dmg which I put along with the other native libs in the osx folder...

[ERROR] FATAL UNHANDLED EXCEPTION: System.DllNotFoundException: SDL2.dll
at (wrapper managed-to-native) SDL2.SDL:SDL_GetPlatform ()
at Microsoft.Xna.Framework.SDL2_GamePlatform..ctor (Microsoft.Xna.Framework.Game game) [0x00000] in :0
at Microsoft.Xna.Framework.GamePlatform.Create (Microsoft.Xna.Framework.Game game) [0x00000] in :0
at Microsoft.Xna.Framework.Game..ctor () [0x00000] in :0
at SquareHeroes.XnaGame..ctor () [0x00000] in :0
at SquareHeroes.Program.Main (System.String[] args) [0x00000] in :0

Mark Mennell
profile image
As you can see I am a Mac noob :) Figured out what a .dmg is and got SDL2 file from there.. Making OpenAL now...

Michael Hicks
profile image
Ok great! Sorry for late reply... Internet has been down haha

Mark Mennell
profile image
Sorry so I am back to teh SDL2.dll not found issue - how come it is not picking up libSDL2-2.0.0.dylib in the osx folder?

Incidentally exact same problem on Linux.

Mark Mennell
profile image
Problem solved, needed SDL2-CS.dll.config alongside the exe

Mark Mennell
profile image
Hmmm no I shouldn't have to be compiling things...

The scripts sets DYLD_LIBRARY_PATH to the osx folder which has all the .dylib files.


none
 
Comment: