diff --git a/Barotrauma/BarotraumaClient/ClientCode.projitems b/Barotrauma/BarotraumaClient/ClientCode.projitems
index 26cd574b9..dddac413d 100644
--- a/Barotrauma/BarotraumaClient/ClientCode.projitems
+++ b/Barotrauma/BarotraumaClient/ClientCode.projitems
@@ -221,6 +221,7 @@
+
diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj
index a96474014..a4375f0b3 100644
--- a/Barotrauma/BarotraumaClient/LinuxClient.csproj
+++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj
@@ -83,8 +83,9 @@
..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\GameAnalytics.Mono.dll
-
- ..\..\Libraries\NuGet\MonoGame.Framework.DesktopGL.3.7.1.189\lib\net45\MonoGame.Framework.dll
+
+ False
+ ..\..\Libraries\MonoGame.Framework\DesktopGL\MonoGame.Framework.dll
..\..\Libraries\NuGet\NLog.4.3.8\lib\net45\NLog.dll
@@ -354,9 +355,7 @@
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/UWP.md b/Libraries/MonoGame.Framework/Src/Documentation/UWP.md
new file mode 100644
index 000000000..6402ae880
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/UWP.md
@@ -0,0 +1,43 @@
+# Game class constructor
+Due to some UWP implementation details, MonoGame has to construct your `Game` derived class by itself, using a static initializer `MonoGame.Framework.XamlGame.Create(...)`.
+
+In this situation, you have two main possibilities to create a `Game` derived class:
+
+1. Let `XamlGame` initialize your `Game` derived class using the default constructor
+2. Let `XamlGame` initialize your `Game` derived class using a custom constructor.
+
+#### 1. XamlGame uses the default constructor
+
+With this logic, it isn't possible to inject dependencies through the constructor since the default constructor is called:
+ `var game = new T();`
+
+
+
+#### 2. XamlGame uses a custom constructor
+
+Why may you need this constructor?
+
+Consider `Game1` needs some dependencies such as an `ISettingsRepository` to get some values from each *platform* settings store. You would then implement an `AndroidSettingsRepository` and a `UwpSettingsRepository`, but you cannot construct those dependencies in `Game1` itself, **because they are platform dependent**, so you'll have to inject them into its constructor.
+
+For example, in a `MainActivity` on Android you would do:
+
+```csharp
+_game = new Game1(
+ new AndroidTextFileImporter(Assets),
+ new AndroidSettingsRepository(this));
+```
+
+With the UWP implementation using `XamlGame` static initializer, you could do this:
+
+```csharp
+_game = MonoGame.Framework.XamlGame.Create(
+ launchArguments,
+ Window.Current.CoreWindow,
+ swapChainPanel,
+ () => new Game1(
+ new UwpTextFileImporter(Assets),
+ new UwpSettingsRepository(this)));
+```
+
+In this way, you tell the static initializer **how** you'd like to construct `Game1`.
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/adding_ttf_fonts.md b/Libraries/MonoGame.Framework/Src/Documentation/adding_ttf_fonts.md
new file mode 100644
index 000000000..d78fb05f0
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/adding_ttf_fonts.md
@@ -0,0 +1,43 @@
+MonoGame supports more than one method of using fonts, the following is an explanation of how to use TrueType fonts.
+
+#### Using TrueType Fonts with MonoGame
+To be able to use a truetype font, MonoGame requires the truetype font file and a .spritefont file.
+Truetype fonts may be installed on the system, or added to the project manually using your IDE in the same directory as the .spritefont file.
+
+1. Create the .spritefont file.
+
+
+
+
+
+
+
+
+
+2- Open the newly created .spritefont file in your text editor of choice, find this line and change it to your selected .ttf font.
+If the font is installed on the system, just type the name of the font.
+```xml
+Arial
+```
+
+#### Usage Example
+Make a class variable of type Spritefont
+```csharp
+SpriteFont font;
+```
+Load the font in the LoadContent function
+```csharp
+font = myGame.Content.Load("Fonts/myFont")
+```
+Draw any text in the Draw function
+```csharp
+spriteBatch.Begin();
+// Finds the center of the string in coordinates inside the text rectangle
+Vector2 textMiddlePoint = font.MeasureString(text) / 2;
+// Places text in center of the screen
+Vector2 position = new Vector2(myGame.Window.ClientBounds.Width / 2, myGame.Window.ClientBounds.Height / 2);
+spriteBatch.DrawString(font, "MonoGame Font Test", position, Color.White, 0, textMiddlePoint, 1.0f, SpriteEffects.None, 0.5f)
+spriteBatch.End();
+```
+
+If you want to know more, please refer to the [API Documentation]()
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/android.md b/Libraries/MonoGame.Framework/Src/Documentation/android.md
new file mode 100644
index 000000000..503f20835
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/android.md
@@ -0,0 +1,60 @@
+#
+
+## Target Frameworks
+Specifying the target Android versions can be confusing. MonoGame is built to target Android 4.2 (API Level 17), but can run on lower Android versions. If you build MonoGame from source, you will need the SDK Platform for API Level 17 installed in the Android SDK Manager.
+
+Since MonoGame targets Android 4.2, the Target Framework in your Android project must be set to 4.2 or higher. To allow your game to run on lower Android versions, set the Minimum Android version to the desired version in the project properties.
+
+### Visual Studio
+There are three settings in the Application tab of the project properties to set the target Android versions.
+
+`Compile using Android version` must be set to a minimum of `Android 4.2`. If you are using APIs available only in later Android versions, this must be set to the Android version that API became available or higher.
+
+`Minimum Android to target` is set to the lowest Android version that you wish to support.
+
+`Target Android version` is usually set to `Use Compile using SDK version`. This means to use the same value that we set the app to be built with. There is usually no reason to set this to any other value.
+
+This is an example of a project set to build with the 4.4 SDK and target 4.0 as a minimum Android version.
+
+
+
+
+
+### Xamarin Studio
+
+Xamarin Studio has the same settings in the project options dialog. They are just in different places.
+
+`Target framework` on the `General` page is the equivalent of Visual Studio's `Compile using Android version`.
+
+
+
+
+
+On the `Android Application` page, you will find `Minimum Android version` (Visual Studio's `Minimum Android to target`) and `Target Android version` (same as Visual Studio).
+
+
+
+
+
+
+## Android Manifest Requirements
+
+### OpenGL ES 2.0 Support
+
+MonoGame uses OpenGL ES 2.0. Google requires the following to be added to AndroidManifest.xml in order for the Market to hide the game from devices that do not have support for OpenGL ES 2.0.
+
+
+```
+
+
+```
+
+### Texture Compression
+
+The Market can also filter games by the types of texture compression they support. Add a ```
+ ``` node for each type of texture compression used in your game. See the [Android documentation](http://developer.android.com/guide/topics/manifest/supports-gl-texture-element.html) for further details on this node.
+
+## References
+
+[Such Android API Levels, Much Confuse. Wow.](http://redth.codes/such-android-api-levels-much-confuse-wow/) is a blog post by Redth going into more detail about setting the Android versions in a Xamarin project.
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/config.xml b/Libraries/MonoGame.Framework/Src/Documentation/config.xml
new file mode 100644
index 000000000..957c9c0cc
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/config.xml
@@ -0,0 +1,117 @@
+
+
+
+
+ MonoGame Documentation
+
+
+ Output
+
+
+
+
+
+ images
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\MonoGame.Framework\bin\Windows\AnyCPU\Release\MonoGame.Framework.dll
+ ..\MonoGame.Framework.Content.Pipeline\bin\Windows\AnyCPU\Release\MonoGame.Framework.Content.Pipeline.dll
+
+
+
+
+ ..\MonoGame.Framework\bin\Linux\AnyCPU\Release\MonoGame.Framework.dll
+ ..\MonoGame.Framework.Content.Pipeline\bin\Linux\AnyCPU\Release\MonoGame.Framework.Content.Pipeline.dll
+
+
+
+
+
+
+
+ ..\MonoGame.Framework\bin\WindowsGL\AnyCPU\Release\MonoGame.Framework.dll
+
+
+
+
+ ..\MonoGame.Framework\bin\Web\AnyCPU\Release\MonoGame.Framework.dll
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/content_intro.md b/Libraries/MonoGame.Framework/Src/Documentation/content_intro.md
new file mode 100644
index 000000000..dce6e3377
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/content_intro.md
@@ -0,0 +1,12 @@
+A big part of your game is your content. This includes standard files like textures, sound effects, music, videos, and custom effects as well as custom content like level and enemy files.
+
+MonoGame implements its own content pipeline for transforming your unoptimized assets into platform optimized content. This is critical in building a game which runs as fast as possible under tight resource constraints.
+
+This section will cover the following topics:
+
+ - What is Game Content
+ - [Using The Pipeline Tool](using_pipeline_tool.md)
+ - [Using TrueType Fonts](adding_ttf_fonts.md)
+ - [Custom Effects](custom_effects.md)
+ - Custom Content Types
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/custom_effects.md b/Libraries/MonoGame.Framework/Src/Documentation/custom_effects.md
new file mode 100644
index 000000000..fcbc3de91
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/custom_effects.md
@@ -0,0 +1,75 @@
+A core element of Microsoft XNA is the effect system which is used for all rendering.
+
+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.
+
+# MGFX
+MGFX is MonoGame's own "FX" runtime and tools which with the following core goals:
+
+* Support a similar technique, passes, shaders structure as Microsoft FX files.
+* Have a textual format for ease of editing.
+* Have a compiled and optimized binary format for runtime use.
+* Be cross-platform and support multiple shader languages and bytecodes.
+* Easy to extend for future platforms and features.
+
+# Stock Effects
+MonoGame has the following effects built-in and fully supported on current platforms:
+
+* SpriteEffect
+* BasicEffect
+* AlphaTestEffect
+* DualTextureEffect
+* EnvironmentMapEffect
+* SkinnedEffect
+
+Under the hood these effects use the same system and tools as one would for a custom Effect. The source and pre-compiled versions of these effects can be found in the ['MonoGame.Framework\Graphics\Effect\Resources'](https://github.com/MonoGame/MonoGame/tree/develop/MonoGame.Framework/Graphics/Effect/Resources) folder.
+
+If your game requires an extra little bit of performance you can easily hand edit the existing effects to remove unnecessary features or optimize for specific hardware and rebuild them with the MGFX tool.
+
+# Custom Effects
+To use a custom effect with MonoGame you must do one of the following (not both):
+* Run the effect file through the [MonoGame Effect content processor](mgcb.md) for loading via the `ContentManager` (Recommended).
+* Process your effect file with the [2MGFX tool](2mgfx.md) and load them yourself at runtime.
+
+
+### Effect Writing Tips
+These are some tips for writing or converting effects for use with MonoGame.
+
+* The supported shader models when targeting DX are the following:
+ * `vs_4_0_level_9_1` and `ps_4_0_level_9_1`
+ * `vs_4_0_level_9_3` and `ps_4_0_level_9_3`
+ * `vs_4_0` and `ps_4_0` (requires `HiDef` `GraphicsProfile` at runtime)
+ * `vs_4_1` and `ps_4_1` (requires `HiDef` `GraphicsProfile` at runtime)
+ * `vs_5_0` and `ps_5_0` (requires `HiDef` `GraphicsProfile` at runtime)
+* When targeting GL platforms we automatically translate FX files to GLSL using a library called [MojoShader](http://icculus.org/mojoshader/). The supported feature levels are the following:
+ * `vs_2_0` and `ps_2_0`
+ * `vs_3_0` and `ps_3_0`
+* You can use preprocessor checks to add conditional code or compilation depending on defined symbols. MonoGame defines the following symbols when compiling effects:
+ * `2MGFX`
+ * `HLSL` and `SM4` for DirectX
+ * `OpenGL` and `GLSL` for OpenGL
+
+ As an example, you can conditionally set shader models depending on the platform with the following code:
+ ```
+ #if OPENGL
+ #define VS_SHADERMODEL vs_3_0
+ #define PS_SHADERMODEL ps_3_0
+ #else
+ #define VS_SHADERMODEL vs_4_0_level_9_1
+ #define PS_SHADERMODEL ps_4_0_level_9_1
+ #endif
+
+ technique
+ {
+ pass
+ {
+ VertexShader = compile VS_SHADERMODEL MainVS();
+ PixelShader = compile PS_SHADERMODEL MainPS();
+ }
+ };
+ ```
+ Custom symbols can be defined from the [Pipeline Tool](pipeline.md) or via [2MGFX](2mgfx.md).
+* Make sure the pixel shaders inputs **exactly match** the vertex shader outputs so the parameters are passed in the correct registers. The parameters need to have the same size and order. Omitting parameters might not break compilation, but can cause unexpected results.
+* Note that on GL platforms default values on Effect parameters do not work. Either set the parameter from code or use a real constant like a #define.
+* The effect compiler is aggressive about removing unused parameters, be sure the parameters you are setting are actually used.
+* Preshaders are not supported.
+* If you think you've found a bug porting a shader [please let us know](https://github.com/MonoGame/MonoGame/issues).
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project.md b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project.md
new file mode 100644
index 000000000..a58e91ed4
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project.md
@@ -0,0 +1,3 @@
+This tutorial assumes that you have configured MonoGame correctly on your system, if you haven't, please read the [Setting Up MonoGame](setting_up_monogame.md).
+
+Depending on the software you plan on using please follow either [Visual Studio](getting_started/1_creating_a_new_project_vs.md), or [VS for Mac / MonoDevelop](getting_started/1_creating_a_new_project_md.md) guide.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project_md.md b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project_md.md
new file mode 100644
index 000000000..7ed195515
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project_md.md
@@ -0,0 +1,21 @@
+Start up MonoDevelop / Xamarin Studio and select **New...** in the upper left corner.
+
+
+
+Now you should see a "New Project" dialog pop up. From here select **MonoGame > App** category, then select **MonoGame Cross Platform Desktop Project** and click **Next**.
+
+
+
+On the following dialog, type in the name that you wish to give your project. Do note that you should not use space character for it. For this tutorial, it will be named **ExampleGame**. After you've entered the name, click on the **Browse** button next to location text field, and select where you wish to save your project. Finally click **Create** to create a new project.
+
+
+
+If everything went correctly, you should see an **ExampleGame** project open up like in the picture bellow. To run your game simply press the big **Play Button** in the upper left corner or press **F5**.
+
+
+
+You should now see your game window running.
+
+
+
+Currently it's just clearing the surface with blue color. For further information on creating your game, please look at the [Understanding the Code](getting_started/2_understanding_the_code.md).
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project_vs.md b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project_vs.md
new file mode 100644
index 000000000..f0519ee00
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/1_creating_a_new_project_vs.md
@@ -0,0 +1,17 @@
+Start up Visual Studio and select **New Project...** in the upper left corner.
+
+
+
+Now you should see a "New Project" dialog pop up, from here select **Templates > Visual C# > MonoGame** category, and then select **MonoGame Cross Platform Desktop Project**. Next type in the name that you wish to give your project, for this tutorial let's just use **ExampleGame** (do note that you should not use space character for it). After you've entered the name, click on the **Browse** button next to the location text field, and select where you wish to save your project. Finally click **OK** to create a new project.
+
+
+
+If everything went correctly, you should see an **ExampleGame** project open up like in the picture bellow. To run your game simply press the big **Play Button** in the toolbar or press **F5**.
+
+
+
+You should now see your game window running.
+
+
+
+Currently it's just clearing the surface with blue color. For further information on creating your game, please look at the [Understanding the Code](getting_started/2_understanding_the_code.md).
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/getting_started/2_understanding_the_code.md b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/2_understanding_the_code.md
new file mode 100644
index 000000000..a986e657e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/2_understanding_the_code.md
@@ -0,0 +1,103 @@
+
+This file will go over the code that is getting created when you start a blank project. For help on creating a project please look at [Creating a New Project](getting_started/1_creating_a_new_project.md)
+
+**Using Statements**
+
+```csharp
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Storage;
+using Microsoft.Xna.Framework.Input;
+```
+
+These using statements are required in order to use the code that MonoGame has to offer.
+
+The reason why they start with Microsoft.Xna.Framework is because MonoGame is an open source implementation of Microsoft Xna framework, and in order to maintain compatibility with the XNA code, it is using the same namespaces.
+
+**The Game1 Class**
+
+```csharp
+public class Game1 : Game
+```
+
+The main Game1 class is inheriting from the Game class, which provides all the core methods for your game (ie. Load/Unload Content, Update, Draw etc.). You usually have only one Game class per game so its name isn't that important.
+
+**Instanced Variables**
+
+```csharp
+GraphicsDeviceManager graphics;
+SpriteBatch spriteBatch;
+```
+
+The two default variables that the blank template starts with are GraphicsDeviceManager and SpriteBatch. Both of these variables are used for drawing stuff as you will see in a later tutorial.
+
+**Constructor**
+
+```csharp
+public Game1()
+{
+ graphics = new GraphicsDeviceManager(this);
+ Content.RootDirectory = "Content";
+}
+```
+The main game constructor is used to initialize the starting variables. In this case we are creating a new GraphicsDeviceManager from our game, and are setting the folder which the game will search for content.
+
+**Initialize Method**
+
+```csharp
+protected override void Initialize()
+{
+ // TODO: Add your initialization logic here
+
+ base.Initialize();
+}
+```
+
+This method is called after the constructor, but before the main game loop(Update/Draw). This is where you can query any required services and load any non-graphic related content.
+
+**LoadContent Method**
+
+```csharp
+protected override void LoadContent()
+{
+ // Create a new SpriteBatch, which can be used to draw textures.
+ spriteBatch = new SpriteBatch(GraphicsDevice);
+
+ // TODO: use this.Content to load your game content here
+}
+```
+
+This method is used to load your game content. It is called only once per game, after Initialize method, but before the main game loop methods.
+
+**Update Method**
+
+```csharp
+protected override void Update(GameTime gameTime)
+{
+ if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
+ Exit();
+
+ // TODO: Add your update logic here
+
+ base.Update(gameTime);
+}
+```
+
+This method is called multiple times per second, and is used to update your game state (checking for collisions, gathering input, playing audio, etc.).
+
+**Draw Method**
+
+```csharp
+protected override void Draw(GameTime gameTime)
+{
+ graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
+
+ // TODO: Add your drawing code here
+
+ base.Draw(gameTime);
+}
+```
+
+Similar to the Update method, it is also called multiple times per second.
+
+For the next part, look at [Adding Content](getting_started/3_adding_content.md) page.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/getting_started/3_adding_content.md b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/3_adding_content.md
new file mode 100644
index 000000000..55b525f7d
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/3_adding_content.md
@@ -0,0 +1,78 @@
+This file will go over adding content to your game. For help on creating a project please look at [Creating a New Project](getting_started/1_creating_a_new_project.md)
+
+First of all you are gonna need some content for your game. For this tutorial use the following image of a ball:
+
+
+
+Do **right-click > Save Image As** and save it somewhere with the name "ball.png".
+
+Now open up your game project and look at the left. You should see a solution explorer window. Expand the **Content** folder and open up **Content.mgcb** file by double clicking on it.
+
+
+
+You should now see a MonoGame Pipeline Tool window open up. In case it didn't get opened, you can right-click on **Content.mgcb**, select **open with** and then select **MonoGame Pipeline**.
+
+
+
+Your game content is managed from this external tool. You can add content to your game in one of the following ways:
+
+- **Add Existing Item** toolbar button
+- **Edit > Add > Existing Item...** menu button
+- **right-click > Add > Existing Item...** context menu
+
+In our case let's use the **Add Existing Item** toolbar button.
+
+
+
+You should now be prompted to select a file. Select the "ball.png" that you have downloaded a moment ago. After that you will be asked on what action you want to do for adding the file. Just leave the it to default and click **OK**.
+
+
+
+Now simply click **Save** toolbar button and close the tool.
+
+
+
+Now that we have added the content, it's time to load it. First declare a new variable so we can load the ball image into memory.
+
+```csharp
+public class Game1 : Game
+{
+ Texture2D textureBall;
+
+ GraphicsDeviceManager graphics;
+```
+
+Next find the Load Content method and use it to initialize the ball private variable:
+
+```csharp
+protected override void LoadContent()
+{
+ // Create a new SpriteBatch, which can be used to draw textures.
+ spriteBatch = new SpriteBatch(GraphicsDevice);
+
+ // TODO: use this.Content to load your game content here
+ textureBall = Content.Load("ball");
+}
+```
+
+And finally, find the Draw method, and let's draw the ball onto the screen:
+
+```csharp
+protected override void Draw(GameTime gameTime)
+{
+ graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
+
+ // TODO: Add your drawing code here
+ spriteBatch.Begin();
+ spriteBatch.Draw(textureBall, new Vector2(0, 0), Color.White);
+ spriteBatch.End();
+
+ base.Draw(gameTime);
+}
+```
+
+Now run the game and you should get the following:
+
+
+
+For the next part, look at [Adding Basic Code](getting_started/4_adding_basic_code.md) page.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/getting_started/4_adding_basic_code.md b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/4_adding_basic_code.md
new file mode 100644
index 000000000..41accabaf
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/4_adding_basic_code.md
@@ -0,0 +1,111 @@
+This file will go over adding basic logic to your game. Do note that this file continues where [Adding Content](getting_started/3_adding_content.md) tutorial left off.
+
+First of all we need to add few new variables, one for position, and one for speed.
+
+```csharp
+public class Game1 : Game
+{
+ Texture2D ballTexture;
+ Vector2 ballPosition;
+ float ballSpeed;
+```
+
+Next let's initialize them. Find the **Initialize** method and add the following lines.
+
+```csharp
+// TODO: Add your initialization logic here
+ballPosition = new Vector2(graphics.PreferredBackBufferWidth / 2,
+ graphics.PreferredBackBufferHeight / 2);
+ballSpeed = 100f;
+
+base.Initialize();
+```
+
+With this we are putting our ball starting position to the center of the screen. Last thing we need to do is modify the position that the ball is getting drawn to. Find **Draw** method and modify the Draw call to:
+
+```csharp
+spriteBatch.Draw(ballTexture, ballPosition, Color.White);
+```
+
+Now run the game.
+
+
+
+As you can see the ball doesn't seem quite centered yet. This is happening because MonoGame uses (0, 0) as the origin point for drawing by default. We can modify this by doing the following:
+
+```csharp
+spriteBatch.Draw(
+ ballTexture,
+ ballPosition,
+ null,
+ Color.White,
+ 0f,
+ new Vector2(ballTexture.Width / 2, ballTexture.Height / 2),
+ Vector2.One,
+ SpriteEffects.None,
+ 0f
+);
+```
+
+With this we are setting the origin to the center of the image. Now the image will get drawn to the center of the screen.
+
+
+
+Next let's setup some movement. Find the **Update** method and add:
+
+```csharp
+// TODO: Add your update logic here
+var kstate = Keyboard.GetState();
+
+if (kstate.IsKeyDown(Keys.Up))
+ ballPosition.Y -= ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
+
+if(kstate.IsKeyDown(Keys.Down))
+ ballPosition.Y += ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
+
+if (kstate.IsKeyDown(Keys.Left))
+ ballPosition.X -= ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
+
+if(kstate.IsKeyDown(Keys.Right))
+ ballPosition.X += ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
+
+base.Update(gameTime);
+```
+
+Let's discuss the code a bit.
+
+With this we are getting the current keyboard state and just putting it into a variable.
+
+```csharp
+var kstate = Keyboard.GetState();
+```
+
+Next is just a simple check to see if the Up arrow key is pressed.
+
+```csharp
+if (kstate.IsKeyDown(Keys.Up))
+```
+
+And last is a simple code for moving the ball by **ballSpeed**. The reason why **ballSpeed** is getting multiplied by **gameTime.ElapsedGameTime.TotalSeconds** is because Update is not usually fixed, that is the time between update calls is not the same, so in order to get smooth movement we multiple speed by the time since the last update method was called.
+
+```csharp
+ ballPosition.Y -= ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
+```
+
+The last 2 code parts repeat for Down, Left and Right arrow keys.
+
+Run the game and you should be able to move the ball with the arrow keys. You will probably notice that you can get out of the window, so let's make it so that the ball can't escape the window. We will do this by setting bounds onto the ballPosition after it has already been moved.
+
+```csharp
+if(kstate.IsKeyDown(Keys.Right))
+ ballPosition.X += ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
+
+ballPosition.X = Math.Min(Math.Max(ballTexture.Width / 2, ballPosition.X), graphics.PreferredBackBufferWidth - ballTexture.Width / 2);
+ballPosition.Y = Math.Min(Math.Max(ballTexture.Height / 2, ballPosition.Y), graphics.PreferredBackBufferHeight - ballTexture.Height / 2);
+
+base.Update(gameTime);
+```
+
+Now run the game and the ball won't be able to escape window bounds anymore.
+
+Happy Coding ^^
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/getting_started/getting_started.md b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/getting_started.md
new file mode 100644
index 000000000..65203616d
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/getting_started/getting_started.md
@@ -0,0 +1,8 @@
+This section walks you through the basics of MonoGame and help you create your first game.
+
+- [Creating a New Project](getting_started/1_creating_a_new_project.md)
+ - [Visual Studio](getting_started/1_creating_a_new_project_vs.md)
+ - [MonoDevelop / Xamarin Studio](getting_started/1_creating_a_new_project_md.md)
+- [Understanding the Code](getting_started/2_understanding_the_code.md)
+- [Adding Content](getting_started/3_adding_content.md)
+- [Adding Basic Code](getting_started/4_adding_basic_code.md)
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/help_and_support.md b/Libraries/MonoGame.Framework/Src/Documentation/help_and_support.md
new file mode 100644
index 000000000..a97c32b81
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/help_and_support.md
@@ -0,0 +1,9 @@
+This section will provide help and support for MonoGame.
+
+## Help
+
+If you wish to learn how to use MonoGame, please checkout our [Tutorials page](tutorials.md). If you want to find an answer to a more specific problem, you can ask it on our [Community page](http://community.monogame.net/).
+
+## Bugs and New Feature Requests
+
+If you find a bug or have a feature request, [please open a new issue](https://github.com/mono/monogame/issues). Before opening any issue, please search for existing issues and read the [Issue Guidelines](https://github.com/necolas/issue-guidelines).
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/add_as_link.png b/Libraries/MonoGame.Framework/Src/Documentation/images/add_as_link.png
new file mode 100644
index 000000000..41f3f75b2
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/add_as_link.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/adding_ttf_fonts_step_1.PNG b/Libraries/MonoGame.Framework/Src/Documentation/images/adding_ttf_fonts_step_1.PNG
new file mode 100644
index 000000000..b5fc82fd0
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/adding_ttf_fonts_step_1.PNG differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/adding_ttf_fonts_step_2.PNG b/Libraries/MonoGame.Framework/Src/Documentation/images/adding_ttf_fonts_step_2.PNG
new file mode 100644
index 000000000..da27b1e9a
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/adding_ttf_fonts_step_2.PNG differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/android_vs_target_frameworks.png b/Libraries/MonoGame.Framework/Src/Documentation/images/android_vs_target_frameworks.png
new file mode 100644
index 000000000..7318a484f
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/android_vs_target_frameworks.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/android_xs_minimum_framework.png b/Libraries/MonoGame.Framework/Src/Documentation/images/android_xs_minimum_framework.png
new file mode 100644
index 000000000..769b11339
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/android_xs_minimum_framework.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/android_xs_target_framework.png b/Libraries/MonoGame.Framework/Src/Documentation/images/android_xs_target_framework.png
new file mode 100644
index 000000000..11e20ed2b
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/android_xs_target_framework.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/copy_if_newer.png b/Libraries/MonoGame.Framework/Src/Documentation/images/copy_if_newer.png
new file mode 100644
index 000000000..aba59496d
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/copy_if_newer.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/existing_item.png b/Libraries/MonoGame.Framework/Src/Documentation/images/existing_item.png
new file mode 100644
index 000000000..9157f0b8f
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/existing_item.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_game_md.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_game_md.png
new file mode 100644
index 000000000..39f85507e
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_game_md.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_game_vs.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_game_vs.png
new file mode 100644
index 000000000..18ea8b6ab
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_game_vs.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_new_soulution_md.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_new_soulution_md.png
new file mode 100644
index 000000000..2b8a5b855
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_new_soulution_md.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_new_soulution_vs.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_new_soulution_vs.png
new file mode 100644
index 000000000..a5ffc8e32
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_new_soulution_vs.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_project_dialog_md.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_project_dialog_md.png
new file mode 100644
index 000000000..d360a7469
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_project_dialog_md.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_run_game_md.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_run_game_md.png
new file mode 100644
index 000000000..a8c023017
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_run_game_md.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_run_game_vs.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_run_game_vs.png
new file mode 100644
index 000000000..cc97ec672
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_run_game_vs.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_template_dialog_md.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_template_dialog_md.png
new file mode 100644
index 000000000..9d5786543
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_template_dialog_md.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_template_dialog_vs.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_template_dialog_vs.png
new file mode 100644
index 000000000..e52aa3b47
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/1_template_dialog_vs.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_add_content.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_add_content.png
new file mode 100644
index 000000000..84be90c3c
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_add_content.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_copy_content.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_copy_content.png
new file mode 100644
index 000000000..f328bd3ef
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_copy_content.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_game.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_game.png
new file mode 100644
index 000000000..e62602c8f
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_game.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_open_content.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_open_content.png
new file mode 100644
index 000000000..574c8c89c
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_open_content.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_pipeline_tool.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_pipeline_tool.png
new file mode 100644
index 000000000..3ab18d091
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_pipeline_tool.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_save_content.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_save_content.png
new file mode 100644
index 000000000..b71afe030
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/3_save_content.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/4_ball_center.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/4_ball_center.png
new file mode 100644
index 000000000..0e55a0110
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/4_ball_center.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/4_ball_not_center.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/4_ball_not_center.png
new file mode 100644
index 000000000..c35888c29
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/4_ball_not_center.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/ball.png b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/ball.png
new file mode 100644
index 000000000..f23ff6104
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/getting_started/ball.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline.png b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline.png
new file mode 100644
index 000000000..c3b6130b2
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_import.png b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_import.png
new file mode 100644
index 000000000..2d62d544a
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_import.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_items.png b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_items.png
new file mode 100644
index 000000000..fc05d60d0
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_items.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_newitem.png b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_newitem.png
new file mode 100644
index 000000000..631bcae18
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_newitem.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_project.png b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_project.png
new file mode 100644
index 000000000..f735bb872
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Documentation/images/pipeline_project.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/introduction.md b/Libraries/MonoGame.Framework/Src/Documentation/introduction.md
new file mode 100644
index 000000000..d79aa363f
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/introduction.md
@@ -0,0 +1,10 @@
+This section will give you an overview of MonoGame including, what it contains, development requirements, setup instructions, and additional links for help and support.
+
+This section will cover the following topics:
+
+ - [What is MonoGame](what_is_monogame.md)
+ - [System Requirements](system_requirements.md)
+ - [Setting Up MonoGame](setting_up_monogame.md)
+ - [Getting Started](getting_started/getting_started.md)
+ - [MonoGame FAQ](monogame_faq.md)
+ - [Help and Support](help_and_support.md)
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/links.md b/Libraries/MonoGame.Framework/Src/Documentation/links.md
new file mode 100644
index 000000000..0c5999249
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/links.md
@@ -0,0 +1,9 @@
+Links to several useful reference sites related to MonoGame.
+
+ - [Microsoft XNA Documentation](http://msdn.microsoft.com/en-us/library/bb203940.aspx)
+ - [OpenGL 4.3 Reference Card](http://www.khronos.org/files/opengl43-quick-reference-card.pdf)
+ - [OpenGL ES 2.0 Reference Card](http://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf)
+ - [WebGL Reference Card](http://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf)
+ - [Collada Specification](http://www.khronos.org/collada/)
+ - [Valve's Guide to Porting to Linux](https://developer.nvidia.com/sites/default/files/akamai/gamedev/docs/Porting%20Source%20to%20Linux.pdf)
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/localization.md b/Libraries/MonoGame.Framework/Src/Documentation/localization.md
new file mode 100644
index 000000000..b529ac514
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/localization.md
@@ -0,0 +1,150 @@
+Localization is an important part of any game. While it can be possible to design a
+game that is region independent, its quite hard. At some point you will need to
+produce localized text and graphics.
+
+MonoGame has a simple localization system built in. If you want to develop your own
+system you are still able to do so. But the default system should be good enough for
+most use cases.
+
+# Creating resx files.
+
+MonoGame runs on .net/Mono on most platforms. Localization is handled by those platforms
+via the use of resx files. There are walkthroughs on [MSDN](https://msdn.microsoft.com/en-us/library/aa992030(v=vs.100).aspx)
+which walk you through the process. A simplified version is presented here.
+
+Create a .resx file in the IDE e.g Foo.resx and add it to your game project. Note this needs to be added to the
+main app projects. The Foo.resx file should have an Action of EmbeddedResouce and a Generator value of ResXFileCodeGenerator.
+There is a snippet from the .csproj
+
+```xml
+
+ ResXFileCodeGenerator
+ Foo.Designer.cs
+
+```
+
+Add any string resources to that file. These are in the form of a Key/Value pair. You can use the built in editor
+or manually edit the .resx file by hand. Its an xml file so you can view the contents easily.
+
+```xml
+
+ Wall Style : {0}
+
+```
+
+What happens when the resx is processed by the generator and produces a Foo.Designer.cs file which is then
+included in your project. You can then access the "string" value by using code as follows
+
+```csharp
+ var s = MyProject.Foo.Wall_Style;
+```
+
+Note in the example we have a place holder ({0}) for additional text. You can still use te property of Foo.Wall_Style with
+things like string.Format.
+
+```csharp
+ int i = 1;
+ var s = string.Format (MyProject.Foo.Wall_Style, i);
+```
+
+All this means you dont need to hard the string directly. When accessing MyProject.Foo.Wall_Style the code will lookup the value from
+the embedded resx file.
+
+You can add support for a new language by adding a new resx file which uses the language/region code e.g Foo.de-DE.resx.
+This new file will contain the translations for that language/region. In the example we are targetting German.
+
+## Universal Windows Platform (UWP) considerations.
+
+Unfortunately UWP does not support resx files anymore. They have a new file called resw. The format is similar but
+incompatible. As a result you will need to duplicate the data into a set of resw files to get the to work on UWP. The
+process is like the standrd resx process.
+
+# Upgrading your SpriteFont files
+
+By default the SpriteFont processor uses a limited set of characters to generate the font. While this is fine for english
+languages it would probably not include special characters needed for other languages (French, Arabic, Korean etc).
+
+As a result MonoGame has a LocalizedFontProcessor which does something slightly different. The process looks at the resx
+files you provide it with and generates an optimized spritefont which only contains the characters your game uses.
+
+To make use of this functionality you ned to tell the spritefont which resx files to use. Open the .spritefont with a
+xml/text editor and add lines like this inside the Asset node
+
+```xml
+
+ ..\Foo.resx
+ ..\Foo.de-DE.resx
+
+```
+
+Note the paths are relative to the .spritefont directory. In the example above the resx files are in the directory
+above the .spritefont.
+
+You should end up with a .spritefont file like this
+
+```xml
+
+
+
+ Verdana
+ 14
+ 1
+
+
+
+
+
+
+
+
+ ..\Foo.resx
+ ..\Foo.de-DE.resx
+
+
+
+```
+
+Once that is done you then need to change the .mgcb file so that the SpriteFontProcessor is replaced with
+the LocalizedFontProcessor. This can be done by editing the .mgcb file or using the Pipeline tool. After
+that you can just compile your content as normal. If the processor has any trouble resolving or reading the
+resx files you will get an error.
+
+# Loading the Font
+
+Loading the font can be done in the normal way. The end result of the process is a .xnb file containing a normal
+SpriteFont.
+
+```csharp
+ var font = Content.Load("Foo");
+```
+
+# Other Localized assets
+
+Not all localized assets will be fonts. In certain situtions you might need to swap out an entire texture or spritesheet.
+For these cases a new method has been added to the ContentManager, LoadLocalized. The idea behind this method is that it will
+look for localized files BEFORE loading the default one.
+
+So for example say you have an asset, MyCharacter. You have a MyCharacter.xnb file which contains the data for that item. You
+can also has a MyCharacter.de-DE.xnb file which contains the German version of that asset. This asset could be a Texture, Audio
+or any other game asset. You can then use LoadLocalized to load the localized version of the asset.
+
+```csharp
+var myCharacter = Content.LoadLocalized("MyCharacter");
+```
+
+The decision on which localized asset to load is made by looking for a file with the following patterns
+
+```xml
+.
+.
+```
+
+These values are retrieved from
+
+```csharp
+ CultureInfo.CurrentCulture.Name // eg. "en-US"
+ CultureInfo.CurrentCulture.TwoLetterISOLanguageName // eg. "en"
+```
+
+which are part of the System.Globalization namespace. On a side note you can also use the `LoadLocalized` to load language
+specific SpriteFonts. They just need to be named in the same way as we have described above.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/mgcb.md b/Libraries/MonoGame.Framework/Src/Documentation/mgcb.md
new file mode 100644
index 000000000..27c5cfc8c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/mgcb.md
@@ -0,0 +1,194 @@
+The MonoGame Content Builder (MGCB.exe) is a command line tool for building XNB content on Windows, Mac, and Linux desktop systems.
+
+Typically it is executed by the [Pipeline GUI tool](pipeline.md) when editing content or indirectly from VisualStudio or MonoDevelop during the build process of a MonoGame project. Alternatively you can use it yourself from the command line for specialized build pipelines or for debugging content processing.
+
+## Command Line Options
+The options are processed "left to right". When an option is repeated the last option always wins.
+
+### Output Directory
+```
+/outputDir:
+```
+It specifies the directory where all content is written. If this option is omitted the output will be put into the current working directory.
+
+### Intermediate Directory
+```
+/intermediateDir:
+```
+It specifies the directory where all intermediate files are written. If this option is omitted the intermediate data will be put into the current working directory.
+
+### Rebuild Content
+```
+/rebuild
+```
+An optional parameter which forces a full rebuild of all content.
+
+### Clean Content
+```
+/clean
+```
+Delete all previously built content and intermediate files. Only the `/intermediateDir` and `/outputDir` need to be defined for clean to do its job.
+
+### Incremental Build
+```
+/incremental
+```
+Skip cleaning files not included in the current build. Useful for custom tools which only require a subset of the game content built.
+
+### Assembly Reference
+```
+/reference:
+```
+An optional parameter which adds an assembly reference which contains importers, processors, or writers needed during content building.
+
+### Target Platform
+```
+/platform:
+```
+Set the target platform for this build. It must be a member of the TargetPlatform enum:
+* Windows
+* iOS
+* Android
+* DesktopGL
+* MacOSX
+* WindowsStoreApp
+* NativeClient
+* PlayStation4
+* WindowsPhone8
+* RaspberryPi
+* PSVita
+* XboxOne
+* Switch
+
+If not set it will default to Windows.
+
+NOTE: PlayStation 4, Xbox One, PS Vita, and Switch support is only available to licensed console developers.
+
+### Target Graphics Profile
+```
+/profile:
+```
+Set the target graphics profile for this build. It must be a member of the GraphicsProfile enum:
+* HiDef
+* Reach
+
+If not set it will default to HiDef.
+
+### Target Build Configuration
+```
+/config:
+```
+The optional build configuration name from the build system. This is sometimes used as a hint in content processors.
+
+### Content Compression
+```
+/compress
+```
+Uses LZ4 compression to compress the contents of the XNB files. Content build times will increase with this option enabled. Compression is not recommended for platforms such as Android, Windows Phone 8 and Windows 8 as the app package is already compressed. This is not compatible with LZX compression used in XNA content.
+
+### Content Importer Name
+```
+/importer:
+```
+An optional parameter which defines the class name of the content importer for reading source content. If the option is omitted or used without a class name the default content importer for the source type is used.
+
+### Content Processor Name
+```
+/processor:
+```
+An optional parameter which defines the class name of the content processor for processing imported content. If the option is omitted used without a class name the default content processor for the imported content is used.
+
+Note that when you change the processor all previously defined `/processorParam` are cleared.
+
+### Content Processor Parameter
+```
+/processorParam:=
+```
+An optional parameter which defines a parameter name and value to set on a content processor.
+
+Note all defined processor parameters are cleared when the `/processor` is set.
+
+### Build Content File
+```
+/build:
+/build:;
+```
+Instructs the content builder to build the specified content file using the previously set switches and options. Optional destination path may be specified if you want to change the output filepath.
+
+### Response File
+```
+/@:
+```
+This defines a text response file (sometimes called a command file) that contains the same options and switches you would normally find on the command line.
+
+Each switch is specified on a new line. Comment lines are prefixed with #. You can specify multiple response files or mix normal command line switches with response files.
+
+An example response file could look like this:
+```
+# Directories
+/outputDir:bin/foo
+/intermediateDir:obj/foo
+
+/rebuild
+
+# Build a texture
+/importer:TextureImporter
+/processor:TextureProcessor
+/processorParam:ColorKeyEnabled=false
+/build:Textures\wood.png
+/build:Textures\metal.png
+/build:Textures\plastic.png
+```
+### Launch Debugger
+```
+/launchdebugger
+```
+Allows a debugger to attach to the MGCB executable before content is built.
+### Define Preprocessor Parameter
+```
+/define =
+```
+Sets or creates a preprocessor parameter with the given name and value.
+### Preprocessor Macros
+```
+$if =
+$endif
+```
+Preprocessor macros are intended to allow conditionals within a response file.
+
+The preprocess step is what expands a response file command into its composite commands for each line in the file. However, a line is only emitted if all conditionals which contain the line evaluate true.
+```
+
+MGCB.exe /define:BuildEffects=No /@:example.mgcb
+
+
+$if BuildEffects=Yes
+ /importer:EffectImporter
+ /processor:EffectProcessor
+ /build:Effects\custom.fx
+ # all other effects here....
+$endif
+```
+
+### Customizing your Build Process
+
+When building content from your project via `msbuild` there are a few ways to can hook into the build process. The `MonoGame.Content.Builder.targets` runs a target called
+`BuildContent` just before your project builds. If you want to do any processing before or after this process you can use the `BeforeTargets` and `AfterTargets` mechanism provided
+by `msbuild` to run your own targest.
+
+```
+
+
+
+
+
+
+```
+
+If you want to customise the arguements sent to the `MGCB.exe` as part of the build process you can use the `` property to define those.
+For example if you wanted to pass in the current project configuration you could define
+
+```
+-config:$(Configuration)
+```
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/monogame_faq.md b/Libraries/MonoGame.Framework/Src/Documentation/monogame_faq.md
new file mode 100644
index 000000000..7c9935c1b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/monogame_faq.md
@@ -0,0 +1,11 @@
+This page contains a list of frequently asked questions.
+
+### What software do I need to start?
+
+Depending on the platform you wish to develop for the following thing are needed:
+
+- Android: [Xamarin.Android](https://docs.microsoft.com/en-us/xamarin/android/)
+- iOS: [Xamarin.iOS](https://docs.microsoft.com/en-us/xamarin/ios/)
+
+The linked pages will guide you through the setup process.
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/pipeline.md b/Libraries/MonoGame.Framework/Src/Documentation/pipeline.md
new file mode 100644
index 000000000..b8daab685
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/pipeline.md
@@ -0,0 +1,23 @@
+The MonoGame Pipeline Tool (Pipeline.exe) is the front-end GUI editor for MonoGame content builder projects.
+
+
+
+
+
+The Pipeline Tool has the following features:
+
+ * Create, open, and save MGCB projects.
+ * Import existing XNA .contentproj.
+ * Tree view showing content of project.
+ * Property grid for editing content settings.
+ * Full undo/redo support.
+ * Build, rebuild, and clean the project.
+ * Rebuild selected items.
+ * Create new content like fonts and xml.
+ * Support for custom importers/processors/writers.
+ * Template format for adding new custom content types.
+
+The Pipeline Tool is included in the SDK installation.
+
+[Read detailed documentation](using_pipeline_tool.md)
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/platform_specific.md b/Libraries/MonoGame.Framework/Src/Documentation/platform_specific.md
new file mode 100644
index 000000000..4aa003cef
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/platform_specific.md
@@ -0,0 +1,5 @@
+While MonoGame aims to provide a platform-agnostic framework for developing games and apps, there are still some specific for each platform that need the developer needs to be aware of. This section lists those specifics broken down by platform.
+
+ - [Android](android.md)
+ - [tvOS](tvOS.md)
+ - [Windows Universal Platform (UWP)](UWP.md)
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame.md b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame.md
new file mode 100644
index 000000000..955117346
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame.md
@@ -0,0 +1,6 @@
+This section will help you setup MonoGame on Platform of your choice. Please select the platform you wish to develop from:
+
+ - [Windows](setting_up_monogame_windows.md)
+ - [Mac](setting_up_monogame_mac.md)
+ - [Linux](setting_up_monogame_linux.md)
+ - [Building from source](setting_up_monogame_source.md)
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_linux.md b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_linux.md
new file mode 100644
index 000000000..8f49b03ac
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_linux.md
@@ -0,0 +1,30 @@
+This section will help you setup MonoGame on Linux.
+
+### Running MonoGame Applications
+
+The following packages are needed for the MonoGame Applications to run on Linux:
+* libopenal-dev
+* mono-runtime
+
+For Ubuntu/Debian based Linux systems, you can run:
+```
+sudo apt-get install libopenal-dev mono-runtime
+```
+
+### Developing MonoGame Applications
+
+* Go to [MonoGame Downloads page](http://www.monogame.net/downloads/)
+* Download MonoGame for Linux
+* Open up terminal and type in:
+```
+cd Downloads
+chmod +x monogame-sdk.run
+sudo ./monogame-sdk.run
+```
+* During the installation process the installer will give you the following list of dependencies, please make sure they are installed:
+ * monodevelop ([http://www.monodevelop.com/download/](http://www.monodevelop.com/download/))
+ * libopenal-dev
+ * gtk-sharp3
+ * referenceassemblies-pcl (needed to use PCL template)
+ * ttf-mscorefonts-installer (recommended, but not needed)
+* That's it, MonoGame SDK is installed
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_mac.md b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_mac.md
new file mode 100644
index 000000000..620138b01
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_mac.md
@@ -0,0 +1,34 @@
+This section will help you setup MonoGame on Mac OSX.
+
+### Running MonoGame Applications
+
+
+### Developing MonoGame Applications
+
+Developing on the Mac requires a number of other frameworks and applications.
+To get started you can use the Linux or DesktopGL platforms which will run quite happily
+on MacOS providing you have mono installed.
+
+So to get setup you will first need to install mono.
+* Go to [Mono Downloads page](http://www.mono-project.com/download/)
+* Download the latest Mac OS installer.
+
+Note: If you are running El Capitan you will need to install the very latest mono otherwise things
+will not work correctly.
+
+You will also need Visual Studio for Mac
+* Go to the [Visual Studio for Mac website](https://visualstudio.microsoft.com/vs/mac/)
+* Download the installer.
+
+This will install Visual Studio for Mac (which is free).
+
+To setup MonoGame application development on mac OSX do the following:
+* Go to [MonoGame Downloads page](http://www.monogame.net/downloads/)
+* Click on the newest MonoGame release
+* Download MonoGame for Mac
+* Open the .pkg
+ * You will probably get an error about signing. If you do , right click and Open the .pkg file and you will be able to continue
+* That's it, MonoGame is installed.
+
+Make sure you install mono and Visual Studio for Mac first so that MonoGame can correctly setup the
+project templates and addins.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_source.md b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_source.md
new file mode 100644
index 000000000..ae1148aab
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_source.md
@@ -0,0 +1,40 @@
+This section will help you setup MonoGame by building it from source code.
+
+### Prerequisites
+
+Install the tools for the system you are building from:
+* Windows:
+ * [Git for Windows](https://git-scm.com/download/win)
+ * [Visual Studio](https://www.visualstudio.com/)
+ * [Xamarin.Android](https://www.xamarin.com/download) (Optional)
+ * [Windows Phone 8 SDK](https://www.microsoft.com/en-us/download/details.aspx?id=35471) (Optional)
+* Mac:
+ * [Git](https://git-scm.com/download/mac)
+ * [Xamarin Studio](https://store.xamarin.com/)
+ * Xamarin.Android and Xamarin.iOS can be installed with the Xamarin Studio installer (Optional)
+* Linux:
+ * [Git](https://git-scm.com/download/linux)
+ * [Monodevelop](http://www.monodevelop.com/download/linux/)
+
+### Getting the source code
+
+Start up a Terminal (Mac/Linux) or Git Bash (Windows) and clone the MonoGame repository:
+```
+git clone https://github.com/MonoGame/MonoGame.git
+cd MonoGame
+git submodule init
+git submodule update
+```
+
+### Building from source
+
+MonoGame uses [Protobuild](https://protobuild.org/) to generate project and solution files. Protobuild.exe will be in your MonoGame folder. To run Protobuild:
+
+- On Windows run Protobuild.exe either by double-clicking or by executing it from the command line.
+- On Mac/Linux open a terminal and run `mono Protobuild.exe` in the MonoGame folder.
+
+Once the project and solution files are generated you can build them with the IDE you installed.
+
+### Referencing the projects
+
+First get the MonoGame SDK from the [downloads page](http://www.monogame.net/downloads/) and install it to get the IDE templates. Start up the IDE you have installed and create a new project from one of the templates. Click Add > Existing Project... on your solution and select the MonoGame.Framework project that matches the template (i.e. MonoGame.Framework.Windows.csproj for a MonoGame Windows project template). The project files are located in MonoGame/MonoGame.Framework. Delete the existing MonoGame.Framework reference and add a reference to the added project by clicking Add Reference... > Projects and selecting the project. You can run your game now. If you make changes to the MonoGame.Framework project it will automatically rebuild when running your game.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_windows.md b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_windows.md
new file mode 100644
index 000000000..2aba7081f
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/setting_up_monogame_windows.md
@@ -0,0 +1,20 @@
+This section will help you setup MonoGame on Windows.
+
+### Developing MonoGame Applications
+
+You will need an IDE to develop MonoGame applications, the most common on Windows is Visual Studio.
+* Go to the [Visual Studio website](https://visualstudio.microsoft.com/)
+* Download a Visual Studio IDE, the Community edition is free for personal use.
+* Run the installer and complete the installation.
+
+Visual Studio is an IDE used to develop applications in, among other languages, C#. C# is the most common language used in MonoGame development.
+
+After installing Visual Studio, do the following:
+* Go to [MonoGame Downloads page](http://www.monogame.net/downloads/)
+* Click on the newest MonoGame release
+* Download MonoGame for Visual Studio
+* Run the installer
+ * You will probably get an error from Windows Defender due to the install file not being digitally signed. If you do, click "More info" and then "Run anyway" to continue the installation.
+* That's it, MonoGame is installed.
+
+You are now ready to develop MonoGame applications using Visual Studio. The next time you open Visual Studio you will find a list of MonoGame template projects ready to use.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/system_requirements.md b/Libraries/MonoGame.Framework/Src/Documentation/system_requirements.md
new file mode 100644
index 000000000..b33a85723
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/system_requirements.md
@@ -0,0 +1,16 @@
+This section will give you an overview of minimal system requirements for developing and running MonoGame Applications.
+
+### Development
+* Windows -
+* Linux - 1 GB Ram
+* Mac -
+
+### Running MonoGame Application on specific Platform
+* WindowsDX - DirectX 9.0c capable gpu
+* WindowsGL -
+* Linux - 512 MB Ram
+* Mac -
+* Android - Android 4.2 or higher
+* iOS -
+* Windows Phone - Windows Phone 10
+
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/tools.md b/Libraries/MonoGame.Framework/Src/Documentation/tools.md
new file mode 100644
index 000000000..d197822a0
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/tools.md
@@ -0,0 +1,4 @@
+This section explains the various command line tools that are part of MonoGame.
+
+ - [2MGFX](2mgfx.md) is used to compile stand alone effects.
+ - [MGCB](mgcb.md) is used to build content pipeline content.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/tutorials.md b/Libraries/MonoGame.Framework/Src/Documentation/tutorials.md
new file mode 100644
index 000000000..c6dc83a18
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/tutorials.md
@@ -0,0 +1,50 @@
+Links to various tutorials and articles to help you get started with MonoGame.
+
+### RB Whitaker's MonoGame Tutorials
+ - [1 - C# Crash Course](http://rbwhitaker.wikidot.com/c-sharp-tutorials)
+ - [2 - Getting started](http://rbwhitaker.wikidot.com/monogame-getting-started-tutorials)
+ - [3 - 2D tutorials](http://rbwhitaker.wikidot.com/monogame-2d-tutorials)
+ - [4 - 3D tutorials](http://rbwhitaker.wikidot.com/monogame-3d-tutorials)
+ - [Extra - XNA tutorials](http://rbwhitaker.wikidot.com/xna-tutorials)
+
+### Microsoft
+Tara Walker's "Building a Shooter Game" tutorial series.
+
+ - [Part 1: Overview, Installation, MonoGame 3.0 Project Creation](http://blogs.msdn.com/b/tarawalker/archive/2012/12/04/windows-8-game-development-using-c-xna-and-monogame-3-0-building-a-shooter-game-walkthrough-part-1-overview-installation-monogame-3-0-project-creation.aspx)
+ - [Part 2: Creating the Shooter/Player Asset of the Game](http://blogs.msdn.com/b/tarawalker/archive/2012/12/10/windows-8-game-development-using-c-xna-and-monogame-3-0-building-a-shooter-game-walkthrough-part-2-creating-the-shooter-player-asset-of-the-game.aspx)
+ - [Part 3: Updating Graphics using Content Pipeline with MonoGame](http://blogs.msdn.com/b/tarawalker/archive/2013/01/04/windows-8-game-development-using-c-xna-and-monogame-3-0-building-a-shooter-game-walkthrough-part-3-updating-graphics-using-content-pipeline-with-monogame.aspx)
+ - [Part 4: Adding and Processing Player (User) Input](http://blogs.msdn.com/b/tarawalker/archive/2013/02/23/windows-8-game-development-using-c-xna-and-monogame-3-0-building-a-shooter-game-walkthrough-part-4-adding-and-processing-player-user-input.aspx)
+ - [Part 5: Animating the Player/Ship and Creating a Parallaxing Background](http://blogs.msdn.com/b/tarawalker/archive/2013/04/12/windows-8-game-development-using-c-xna-and-monogame-3-0-building-a-shooter-game-walkthrough-part-5-animating-the-player-ship-and-creating-a-parallaxing-background.aspx)
+ - [Part 6: Creating Enemies and Detecting Collisions](http://blogs.msdn.com/b/tarawalker/archive/2013/08/26/windows-8-game-development-using-c-xna-and-monogame-3-0-building-a-shooter-game-walkthrough-part-6-creating-enemies-and-detecting-collisions.aspx)
+ - [Part 7: Creating Projectiles and Detecting Collisions](http://chrisongames.blogspot.com/2014/12/windows-8-game-development-using-c-xna.html)
+ - [Part 8: Creating Explosions using Sprite Animations](http://chrisongames.blogspot.com/2015/02/windows-8-game-development-using-c-xna.html)
+ - [Part 9: Adding Sound Effects and Game Music](http://chrisongames.blogspot.com/2015/12/windows-810-game-development-using-c.html)
+
+### Neil Danson's F# series
+ - [Part 1 - MacOS](http://neildanson.wordpress.com/2013/07/30/f-and-monogame/)
+ - [Part 2 - Android](http://neildanson.wordpress.com/2013/07/31/f-and-monogame-part-2-android/)
+ - [Part 3 - iOS](http://neildanson.wordpress.com/2013/07/31/f-and-monogame-part-3-ios/)
+ - [Part 4 - Content Pipeline](http://neildanson.wordpress.com/2013/08/13/f-and-monogame-part-4-content-pipeline/)
+
+### Others
+ - [How to create animations and sprite sheets for MonoGame](https://www.codeandweb.com/texturepacker/tutorials/how-to-create-sprite-sheets-and-animations-with-monogame)
+ - [Making a platformer in F# with MonoGame](http://bruinbrown.wordpress.com/2013/10/06/making-a-platformer-in-f-with-monogame/)
+ - [XNA 4.0 Shader Programming / HLSL](http://digitalerr0r.wordpress.com/tutorials/)
+ - [Using Spine with MonoGame - by Randolph Burt (Randeroo)](http://randolphburt.co.uk/2013/03/30/dragons-and-dancing-crabs/)
+ - [Mac porting series](http://benkane.wordpress.com/2012/01/20/the-great-porting-adventure-day-8/)
+ - [Porting a Windows Phone 7 Game to Android](http://warrenburch.blogspot.co.uk/2011/12/porting-windows-phone-7-game-to-android.html)
+ - [A series on embedding MonoGame/WinGL into WinForms](http://jaquadro.com/2013/03/bringing-your-xna-winforms-controls-to-monogame-opengl/)
+ - [French articles about MonoGame on Linux, Windows and Windows 8](http://www.demonixis.net/blog/category/tutoriels/tuto-xna/)
+ - [Dark Genesis Blog](http://darkgenesis.zenithmoon.com/tag/monogame/)
+ - [MonoGame "Hello World" on Mac OS X and Xamarin Studio](http://jaquadro.com/2013/09/monogame-hello-world-on-mac-os-x-and-xamarin-studio/)
+ - [Solving Resolution Independent Rendering And 2D Camera Using Monogame](http://blog.roboblob.com/2013/07/27/solving-resolution-independent-rendering-and-2d-camera-using-monogame/)
+ - [XNA is Dead; Long Live the New XNA, MonoGame](http://www.codemag.com/Article/1411081)
+ - [Make Santa Jump - Making an endless runner game in F# using MonoGame](http://timjones.tw/blog/archive/2014/12/28/make-santa-jump-game-in-fsharp-using-monogame)
+ - [Running MonoGame on Android Wear](http://crossplatform.io/running-monogame-on-android-wear/)
+
+## Video Tutorials
+
+ - [CodingMadeEasy RPG Tutorial](http://www.youtube.com/watch?feature=player_embedded&v=agt9-J9RPZ0)
+ - [Psuedo Games Tutorials](http://www.youtube.com/watch?feature=player_embedded&v=BwtQn02oy6A)
+ - [Desenvolvendo jogos multiplataforma em C# com MonoGame - Alexandre Chohfi (Portuguese)](http://channel9.msdn.com/Blogs/MSDN-Brasil-Cursos-de-Desenvolvimento/Desenvolvendo-jogos-multiplataforma-em-C-com-MonoGame)
+ - [Desenvolvimento de jogos para Windows 8 com XNA - Alexandre Chohfi (Portuguese)](https://www.youtube.com/watch?v=gM5pRnYV1tA)
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/tvOS.md b/Libraries/MonoGame.Framework/Src/Documentation/tvOS.md
new file mode 100644
index 000000000..19451422c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/tvOS.md
@@ -0,0 +1,53 @@
+## Menu Button Handling
+
+The Menu button will map to the "Back" button on the GamePad. However on tvOS,
+the Menu button requires some special processing. According to the Apple
+documentation the Menu Button
+
+"*Pauses/resumes gameplay.
+Returns to previous screen, exits to main game menu, and/or exits to Apple TV Home screen.*"
+
+By default MonoGame will exit to the Apple TV Home screen when the Menu button is pressed,
+this is not alawys the desired behviour. When in gameplay the Menu button really should
+Pause the game rather than Exiting to the Home screen.
+
+Because MonoGame has no idea of the game state, it is down to the developer to inform
+it when it can exit to the Home screen and when it should ignore the Menu event and allow
+the developer to the event.
+
+Some sample code.
+
+```csharp
+
+public class Game1 : Game, IPlaformBackButton
+{
+
+ private bool _isOnRootMenu = true;
+
+ public bool Handled()
+ {
+ return !_isOnRootMenu;
+ }
+
+ public Game1()
+ {
+ Services.AddService(this);
+ }
+
+ public override Update(GameTime gametime)
+ {
+ if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
+ {
+ // do something in game
+ }
+ }
+}
+```
+
+The key to this working is the `IPlatformBackButton` interface. By implementing
+and registering this interface MonoGame can callback into your application to ask if it
+should let you handle the Menu button or if it should pass it up to tvOS. So in this case if
+the app is on the "Main menu" the developer will set *IsOnRootMenu* to true and when the Menu
+button is pressed the game with Exit. However if IsOnRootMenu is false then the "Menu" button
+click will be routed to the GamePad Back button and the developer can check for the Back button
+press and act accordingly.
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/using_pipeline_tool.md b/Libraries/MonoGame.Framework/Src/Documentation/using_pipeline_tool.md
new file mode 100644
index 000000000..20da18278
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/using_pipeline_tool.md
@@ -0,0 +1,110 @@
+The [Pipeline Tool](pipeline.md) is used to organize and build content for use with MonoGame. It is installed as part of the MonoGame SDK Installer or can be built [directly from source](https://github.com/mono/MonoGame/tree/develop/Tools/Pipeline) if needed.
+
+## Create A Project
+
+To start a new project just select "New..." from the "File" menu. This will give you a new empty project to add content to.
+
+If you are starting from an existing XNA project, the Pipeline Tool supports importing your existing .contentproj. Again you can access this from the the "File" menu:
+
+
+
+
+
+This creates a new project, adding all your content and content settings from the XNA project. If you happened to be using custom processors you may need to edit the assembly references to link to the correct paths which we discuss next.
+
+## Project Settings
+
+You can edit the content project settings directly from the property grid editor after selecting the project node in the tree view:
+
+
+
+
+
+This is where you setup the folders for output, the platform to target, the assembly references for custom processors, etc.
+
+Note that currently the Pipeline tool is not setup to support multiple target platforms. This means you may need to manage mutliple content projects or manually change the target platform between builds. We are working on adding functionaliy to support multiple platforms and configurations within a single project.
+
+
+## Adding Content Items
+
+Once you have a project setup you can add content to it for building. You can do this from the "Edit" menu:
+
+
+
+
+
+Selecting "New Item..." will bring up the New Item dialog which displays a list of new items that can be created:
+
+
+
+
+
+When you select "Existing Item..." you get to select an existing item from disk to add to the content project.
+
+
+## Custom Content Processors
+
+Just like XNA, the MonoGame content pipeline supports custom content processors. To use them you need to rebuild them correctly to work against MonoGame.
+
+The first step is removing all `Microsoft.Xna.Framework.XXX` references and replacing them with references to `MonoGame.Framework` and `MonoGame.Framework.Content.Pipeline`. This is required as you will no longer be building against Microsoft XNA.
+
+Once you references are working you then need to change your assembly target platform. MonoGame does not support x86 (aka 32bit) assemblies in the content pipeline. This is mainly to allow of processing really big content as well as to simplify the number of configurations and native code dependancies. For this reason you should try to target "Any CPU" with your custom content assembly.
+
+After you have done these fixes you should be able to add these new processors to the content project "References".
+
+## Building Content
+
+The Pipeline Tool has 3 actions related to building content: Build, Rebuild and Clean. Build will build all content that needs to be built and put the xnb's in the output directory (bin by default). Content will be skipped if it hasn't changed since the last build. The time source content was last edited is saved in the intermediate directory (obj by default) to determine if content changed since the last build. Clean will empty the output and intermediate directories. Rebuild will first Clean and then Build.
+
+## Linking Content To Your Game
+
+Once you have built your content you have a few different ways to add the xnb's to your game project. They all have the same goal, to get the built xnb's in your project output folder so a ContentManager can easily find and load them.
+
+### MonoGameContentReference
+
+The simplest method is to setup your game project from one of the templates that come with the SDK. When you create a new project it will include a Content.mgcb file with its Build Action set to MonoGameContentReference. This build action is defined in the .targets file [here](https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework.Content.Pipeline/MonoGame.Content.Builder.targets). MonoGameContentReference is set up so that when the project is built, the mgcb will build any new/modified content and copy the resulting xnb's to the project output directory so they can be used in the project. Note that this way you don't even have to manually build the content with the Pipeline Tool. Just add your content to the .mgcb with the Pipeline Tool and the rest will happen when you build your project. The content files do not need to be added to your project.
+
+### Manual Copy
+
+If you don't want to use the automated process, you can build the content project with the Pipeline Tool and copy the xnb's to the output folder of your project manually.
+
+
+### Add As Content
+
+If you are using Visual Studio you can simply add the xnb files to your C# game project. Create a folder in the project called Content then right click on the folder and select Add -> Existing Item.
+
+
+
+
+
+You will now see a file dialog from which you can add your content files. Note that if you don't want Visual Studio to make a local copy of the files be sure to use "Add As Link".
+
+
+
+
+
+Once the files are added you need to select them all and change their build action to "Content" and "Copy if newer".
+
+
+
+
+
+
+### Add With Wildcard
+
+The more automatic option is to hand edit your game .csproj and have it include you content using wildcards. To do this just open the .csproj with any text editor then add the following after any other ``:
+
+```
+
+
+ PreserveNewest
+
+
+```
+
+Then any files you put in a Content folder within your game project will automatically be included in the build.
+
+
+## Reporting Bugs
+
+If you run into any problems with MGCB or the Pipeline Tool, please ask for help on the [community site](http://community.monogame.net/) or submit a [bug report on GitHub](https://github.com/MonoGame/MonoGame/issues).
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/welcome.md b/Libraries/MonoGame.Framework/Src/Documentation/welcome.md
new file mode 100644
index 000000000..d7edfa5cf
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/welcome.md
@@ -0,0 +1,16 @@
+Welcome to the MonoGame game library documentation hub.
+
+This area of the site contains the documentation on the API of MonoGame as well as how to use it to create great games.
+Note that this is a work in progress so there will be gaps in the documentation coverage.
+
+If you cannot find what you need here you can also look at the [Microsoft XNA documentation](https://msdn.microsoft.com/en-us/library/bb200104.aspx). MonoGame is API compatible
+with [XNA](https://msdn.microsoft.com/en-us/library/bb203940.aspx) even down to the namespaces. So usually what works for XNA will work for MonoGame too.
+
+Note that this documentation hub is built from the source code on every commit to the development branch. As such
+it applies to the development builds available on the [Downloads](http://www.monogame.net/downloads) page. This may include new features which may
+not be available in the current stable release
+
+### We Need Your Help!
+Truly great open source projects require high quality documentation. This is call for volunteers to help us make the MonoGame documentation truly great. If you can help write tutorials, guides, code snippets, reference docs, video walkthroughs or just any improvement to our current documentation we could use your help!
+
+Check out the [README on GitHub](https://github.com/mono/MonoGame/blob/develop/Documentation/README.md) or [talk with us on the community site](http://community.monogame.net/t/lets-improve-the-monogame-documentation/916) to learn how to help!
diff --git a/Libraries/MonoGame.Framework/Src/Documentation/what_is_monogame.md b/Libraries/MonoGame.Framework/Src/Documentation/what_is_monogame.md
new file mode 100644
index 000000000..02499564e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Documentation/what_is_monogame.md
@@ -0,0 +1,25 @@
+MonoGame is an Open Source implementation of the Microsoft XNA 4 Framework. Our goal is to allow people to make great games using a simple API.
+The currently supported platforms are as follows.
+
+ * Desktop PCs
+ * Windows 10 Store Apps (UWP)
+ * Windows Win32 (OpenGL & DirectX)
+ * Linux (OpenGL)
+ * Mac OS X (OpenGL)
+ * Mobile/Tablet Devices
+ * Android (OpenGL)
+ * iPhone/iPad (OpenGL)
+ * Windows Phone 10
+* Television
+ * tvOS
+
+MonoGame also supports a number of Game Consoles. The templates and source for these platforms
+are not publicly availalbe. However they are available to developers registered with the appropriate
+developer programs.
+
+ * Consoles (for registered developers)
+ * PlayStation 4 (Sony)
+ * PlayStation Vita (Sony)
+ * Xbox One (both UWP and XDK) (id@xbox)
+ * Nintendo Switch (Nintendo)
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Addin.sln b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Addin.sln
new file mode 100644
index 000000000..3e4e4086c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Addin.sln
@@ -0,0 +1,44 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.MonoGame.Core", "MonoDevelop.MonoGame.Core\MonoDevelop.MonoGame.Core.csproj", "{3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.MonoGame", "MonoDevelop.MonoGame\MonoDevelop.MonoGame.csproj", "{B2C75BDF-A022-41C6-9618-EDD8BEE76556}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.MonoGame.Android", "MonoDevelop.MonoGame.Android\MonoDevelop.MonoGame.Android.csproj", "{FB8E0F6F-522F-4C22-A2F2-1097EB549FE5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.MonoGame.iOS", "MonoDevelop.MonoGame.iOS\MonoDevelop.MonoGame.iOS.csproj", "{B2150BB5-02A0-4CD7-A61F-C17C09045D1D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.MonoGame.Mac", "MonoDevelop.MonoGame.Mac\MonoDevelop.MonoGame.Mac.csproj", "{08E68315-4124-4199-BBD9-E57282458A31}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {08E68315-4124-4199-BBD9-E57282458A31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08E68315-4124-4199-BBD9-E57282458A31}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08E68315-4124-4199-BBD9-E57282458A31}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08E68315-4124-4199-BBD9-E57282458A31}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B2150BB5-02A0-4CD7-A61F-C17C09045D1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B2150BB5-02A0-4CD7-A61F-C17C09045D1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B2150BB5-02A0-4CD7-A61F-C17C09045D1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B2150BB5-02A0-4CD7-A61F-C17C09045D1D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B2C75BDF-A022-41C6-9618-EDD8BEE76556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B2C75BDF-A022-41C6-9618-EDD8BEE76556}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B2C75BDF-A022-41C6-9618-EDD8BEE76556}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B2C75BDF-A022-41C6-9618-EDD8BEE76556}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FB8E0F6F-522F-4C22-A2F2-1097EB549FE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FB8E0F6F-522F-4C22-A2F2-1097EB549FE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FB8E0F6F-522F-4C22-A2F2-1097EB549FE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FB8E0F6F-522F-4C22-A2F2-1097EB549FE5}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = ..\MonoDevelop.MonoGame\MonoDevelop.MonoGame.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/MonoDevelop.MonoGame.Android.csproj b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/MonoDevelop.MonoGame.Android.csproj
new file mode 100644
index 000000000..b6209ad11
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/MonoDevelop.MonoGame.Android.csproj
@@ -0,0 +1,110 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {FB8E0F6F-522F-4C22-A2F2-1097EB549FE5}
+ Library
+ MonoDevelop.MonoGame.Android
+ MonoDevelop.MonoGame.Android
+ v4.5
+
+
+ true
+ full
+ false
+ ..\bin\Debug
+ DEBUG;
+ prompt
+ 4
+ false
+
+
+ full
+ true
+ ..\bin\Release
+ prompt
+ 4
+ false
+
+
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/MonoDevelop.Ide.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/MonoDevelop.Core.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns/MonoDevelop.MonoDroid/MonoDevelop.MonoDroid.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns/Xamarin.Ide/Xamarin.Components.Ide.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns/Xamarin.Ide/Xamarin.Ide.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop//AddIns/Xamarin.Ide.Insights/Xamarin.Ide.Insights.dll
+ False
+
+
+
+
+
+
+
+
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}
+ MonoDevelop.MonoGame.Core
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/MonoGameAndroidProject.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/MonoGameAndroidProject.cs
new file mode 100644
index 000000000..53ce0345c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/MonoGameAndroidProject.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace MonoDevelop.MonoGame.Android
+{
+ public class MonoGameAndroidProject : MonoDevelop.MonoDroid.MonoDroidProject
+ {
+ public MonoGameAndroidProject () : base()
+ {
+ }
+
+ public override MonoDevelop.Projects.SolutionItemConfiguration CreateConfiguration (string name)
+ {
+ return base.CreateConfiguration (name);
+ }
+
+ protected override void PopulateSupportFileList (MonoDevelop.Projects.FileCopySet list, MonoDevelop.Projects.ConfigurationSelector configuration)
+ {
+ base.PopulateSupportFileList (list, configuration);
+ }
+
+ [Obsolete]
+ public override string ProjectType {
+ get {
+ return "MonoGameAndroid";
+ }
+ }
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/Properties/AssemblyInfo.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..ddff13d24
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/Properties/AssemblyInfo.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle ("MonoDevelop.MonoGame.Android")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("MonoGame Team")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion ("1.0.*")]
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutAssets.txt b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutAssets.txt
new file mode 100644
index 000000000..ee3988629
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutAssets.txt
@@ -0,0 +1,19 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories) and given a Build Action of "AndroidAsset".
+
+These files will be deployed with you package and will be accessible using Android's
+AssetManager, like this:
+
+public class ReadAsset : Activity
+{
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ InputStream input = Assets.Open ("my_asset.txt");
+ }
+}
+
+Additionally, some Android functions will automatically load asset files:
+
+Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutContent.txt b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutContent.txt
new file mode 100644
index 000000000..10f52d460
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutContent.txt
@@ -0,0 +1,44 @@
+Images, layout descriptions, binary blobs and string dictionaries can be included
+in your application as resource files. Various Android APIs are designed to
+operate on the resource IDs instead of dealing with images, strings or binary blobs
+directly.
+
+For example, a sample Android app that contains a user interface layout (main.axml),
+an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
+would keep its resources in the "Resources" directory of the application:
+
+Resources/
+ drawable/
+ icon.png
+
+ layout/
+ main.axml
+
+ values/
+ strings.xml
+
+In order to get the build system to recognize Android resources, set the build action to
+"AndroidResource". The native Android APIs do not operate directly with filenames, but
+instead operate on resource IDs. When you compile an Android application that uses resources,
+the build system will package the resources for distribution and generate a class called "R"
+(this is an Android convention) that contains the tokens for each one of the resources
+included. For example, for the above Resources layout, this is what the R class would expose:
+
+public class R {
+ public class drawable {
+ public const int icon = 0x123;
+ }
+
+ public class layout {
+ public const int main = 0x456;
+ }
+
+ public class strings {
+ public const int first_string = 0xabc;
+ public const int second_string = 0xbcd;
+ }
+}
+
+You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
+to reference the layout/main.axml file, or R.strings.first_string to reference the first
+string in the dictionary file values/strings.xml.
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutResources.txt b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutResources.txt
new file mode 100644
index 000000000..10f52d460
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AboutResources.txt
@@ -0,0 +1,44 @@
+Images, layout descriptions, binary blobs and string dictionaries can be included
+in your application as resource files. Various Android APIs are designed to
+operate on the resource IDs instead of dealing with images, strings or binary blobs
+directly.
+
+For example, a sample Android app that contains a user interface layout (main.axml),
+an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
+would keep its resources in the "Resources" directory of the application:
+
+Resources/
+ drawable/
+ icon.png
+
+ layout/
+ main.axml
+
+ values/
+ strings.xml
+
+In order to get the build system to recognize Android resources, set the build action to
+"AndroidResource". The native Android APIs do not operate directly with filenames, but
+instead operate on resource IDs. When you compile an Android application that uses resources,
+the build system will package the resources for distribution and generate a class called "R"
+(this is an Android convention) that contains the tokens for each one of the resources
+included. For example, for the above Resources layout, this is what the R class would expose:
+
+public class R {
+ public class drawable {
+ public const int icon = 0x123;
+ }
+
+ public class layout {
+ public const int main = 0x456;
+ }
+
+ public class strings {
+ public const int first_string = 0xabc;
+ public const int second_string = 0xbcd;
+ }
+}
+
+You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
+to reference the layout/main.axml file, or R.strings.first_string to reference the first
+string in the dictionary file values/strings.xml.
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Activity1.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Activity1.cs
new file mode 100644
index 000000000..48f7e672f
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Activity1.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Android.App;
+using Android.Content;
+using Android.Runtime;
+using Android.Content.PM;
+using Android.Views;
+using Android.Widget;
+using Android.OS;
+
+using Microsoft.Xna.Framework;
+
+namespace ${Namespace}
+{
+ [Activity (Label = "${ProjectName}",
+ MainLauncher = true,
+ Icon = "@drawable/icon",
+ Theme = "@style/Theme.Splash",
+ AlwaysRetainTaskState=true,
+ LaunchMode=LaunchMode.SingleInstance,
+ ScreenOrientation = ScreenOrientation.FullUser,
+ ConfigurationChanges = ConfigChanges.Orientation |
+ ConfigChanges.KeyboardHidden |
+ ConfigChanges.Keyboard |
+ ConfigChanges.ScreenSize |
+ ConfigChanges.ScreenLayout)]
+ public class Activity1 : AndroidGameActivity
+ {
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ var g = new Game1 ();
+ SetContentView (g.Services.GetService());
+ g.Run ();
+ }
+
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AndroidManifest.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AndroidManifest.xml
new file mode 100644
index 000000000..4ebab7d2c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Resource.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Resource.cs
new file mode 100644
index 000000000..491e76fe0
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Resource.cs
@@ -0,0 +1,103 @@
+#pragma warning disable 1591
+// ------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Mono Runtime Version: 4.0.30319.17020
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+// ------------------------------------------------------------------------------
+
+[assembly: Android.Runtime.ResourceDesignerAttribute("OpenGLApplication1.Resource", IsApplication=true)]
+
+namespace ${Namespace}
+{
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+ public partial class Resource
+ {
+
+ static Resource()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ public static void UpdateIdValues()
+ {
+ }
+
+ public partial class Attribute
+ {
+
+ static Attribute()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Attribute()
+ {
+ }
+ }
+
+ public partial class Drawable
+ {
+
+ // aapt resource value: 0x7f020000
+ public const int Icon = 2130837504;
+
+ static Drawable()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Drawable()
+ {
+ }
+ }
+
+ public partial class Id
+ {
+
+ static Id()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Id()
+ {
+ }
+ }
+
+ public partial class Layout
+ {
+
+ static Layout()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Layout()
+ {
+ }
+ }
+
+ public partial class String
+ {
+
+ // aapt resource value: 0x7f040001
+ public const int ApplicationName = 2130968577;
+
+ static String()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private String()
+ {
+ }
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Splash.png b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Splash.png
new file mode 100644
index 000000000..2f8610744
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Splash.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Styles.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Styles.xml
new file mode 100644
index 000000000..510213401
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/Android/Styles.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/MonoGameAndroidProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/MonoGameAndroidProject.xpt.xml
new file mode 100644
index 000000000..47b2d9c5e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Android/templates/MonoGameAndroidProject.xpt.xml
@@ -0,0 +1,63 @@
+
+
+
+ <_Name>MonoGame for Android Application
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>Creates an MonoGame for Android Project
+
+
+
+
+
+
+
+
+ ${ProjectName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/IMonoGameProject.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/IMonoGameProject.cs
new file mode 100644
index 000000000..d94200420
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/IMonoGameProject.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace MonoDevelop.MonoGame.Core
+{
+ public interface IMonoGameProject
+ {
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/MonoDevelop.MonoGame.Core.csproj b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/MonoDevelop.MonoGame.Core.csproj
new file mode 100644
index 000000000..af2eb9d17
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/MonoDevelop.MonoGame.Core.csproj
@@ -0,0 +1,40 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}
+ Library
+ MonoDevelop.MonoGame.Core
+ MonoDevelop.MonoGame.Core
+ v4.5
+
+
+ true
+ full
+ false
+ ..\bin\Debug
+ DEBUG;
+ prompt
+ 4
+ false
+
+
+ full
+ true
+ ..\bin\Release
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/Properties/AssemblyInfo.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..4a6cbd50e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Core/Properties/AssemblyInfo.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle ("MonoDevelop.MonoGame.Core")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("MonoGame Team")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion ("1.0.*")]
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/MonoDevelop.MonoGame.Mac.csproj b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/MonoDevelop.MonoGame.Mac.csproj
new file mode 100644
index 000000000..888733b7c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/MonoDevelop.MonoGame.Mac.csproj
@@ -0,0 +1,88 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {08E68315-4124-4199-BBD9-E57282458A31}
+ Library
+ MonoDevelop.MonoGame.Mac
+ MonoDevelop.MonoGame.Mac
+ v4.5
+
+
+ true
+ full
+ false
+ ..\bin\Debug
+ DEBUG;
+ prompt
+ 4
+ false
+
+
+ full
+ true
+ ..\bin\Release
+ prompt
+ 4
+ false
+
+
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/MonoDevelop.Ide.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/MonoDevelop.Core.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.dll
+ False
+
+
+
+
+
+
+
+
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}
+ MonoDevelop.MonoGame.Core
+ False
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/Properties/AssemblyInfo.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..1caf43bb7
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/Properties/AssemblyInfo.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle ("MonoDevelop.MonoGame.Mac")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("MonoGame Team")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion ("1.0.*")]
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/MacInfo.plist b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/MacInfo.plist
new file mode 100644
index 000000000..6db7056e2
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/MacInfo.plist
@@ -0,0 +1,18 @@
+
+
+
+
+ CFBundleIdentifier
+ project.MonoGame.${Namespace}
+ CFBundleName
+ ${Namespace}
+ CFBundleVersion
+ 1
+ LSMinimumSystemVersion
+ 10.6
+ NSPrincipalClass
+ NSApplication
+ NSMainNibFile
+ MainMenu
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/MainMenu.xib b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/MainMenu.xib
new file mode 100644
index 000000000..ff2faa0e1
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/MainMenu.xib
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/Program.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/Program.cs
new file mode 100644
index 000000000..e049b8f80
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/Program.cs
@@ -0,0 +1,45 @@
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using MonoMac.AppKit;
+using MonoMac.Foundation;
+#endregion
+
+namespace ${Namespace}
+{
+ static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ static void Main(string[] args)
+ {
+ NSApplication.Init ();
+
+ using (var p = new NSAutoreleasePool ()) {
+ NSApplication.SharedApplication.Delegate = new AppDelegate();
+ NSApplication.Main(args);
+ }
+ }
+ }
+
+ class AppDelegate : NSApplicationDelegate
+ {
+ private static Game1 game;
+
+ public override void FinishedLaunching (NSObject notification)
+ {
+ game = new Game1();
+ game.Run();
+ }
+
+ public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
+ {
+ return true;
+ }
+ }
+
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/XamMac2Program.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/XamMac2Program.cs
new file mode 100644
index 000000000..2b695a7da
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/XamMac2Program.cs
@@ -0,0 +1,26 @@
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using AppKit;
+using Foundation;
+#endregion
+
+namespace ${Namespace}
+{
+ static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ static void Main(string[] args)
+ {
+ NSApplication.Init ();
+
+ using (var game = new Game1 ()) {
+ game.Run ();
+ }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/XamMacProgram.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/XamMacProgram.cs
new file mode 100644
index 000000000..34f0adc75
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/Mac/XamMacProgram.cs
@@ -0,0 +1,27 @@
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using MonoMac.AppKit;
+using MonoMac.Foundation;
+#endregion
+
+namespace ${Namespace}
+{
+ static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ static void Main(string[] args)
+ {
+ NSApplication.Init ();
+
+ using (var game = new Game1 ()) {
+ game.Run ();
+ }
+ }
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameMacProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameMacProject.xpt.xml
new file mode 100644
index 000000000..3f520ab81
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameMacProject.xpt.xml
@@ -0,0 +1,49 @@
+
+
+
+ <_Name>MonoGame Mac Application (MonoMac)
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Application for Mac OS. This application uses MonoMac as a result you will need to have mono installed on your users machine.
+
+
+
+
+
+
+
+
+ ${ProjectName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameOSXProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameOSXProject.xpt.xml
new file mode 100644
index 000000000..0ab9c08f0
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameOSXProject.xpt.xml
@@ -0,0 +1,50 @@
+
+
+
+ <_Name>MonoGame Mac Application (Xamarin.Mac)
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Application for Mac OS. This application uses Xamarin.Mac and is suitable for the Apple Store.
+
+
+
+
+
+
+
+
+ ${ProjectName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameXamMacProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameXamMacProject.xpt.xml
new file mode 100644
index 000000000..d49598230
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.Mac/templates/MonoGameXamMacProject.xpt.xml
@@ -0,0 +1,56 @@
+
+
+
+ <_Name>MonoGame Mac Application (Xamarin.Mac Classic)
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Application for Mac OS. This application uses Xamarin.Mac Classic API
+
+
+
+
+
+
+
+
+ ${ProjectName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/MonoDevelop.MonoGame.iOS.csproj b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/MonoDevelop.MonoGame.iOS.csproj
new file mode 100644
index 000000000..48de71b54
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/MonoDevelop.MonoGame.iOS.csproj
@@ -0,0 +1,85 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {B2150BB5-02A0-4CD7-A61F-C17C09045D1D}
+ Library
+ MonoDevelop.MonoGame.iOS
+ MonoDevelop.MonoGame.iOS
+ v4.5
+
+
+ true
+ full
+ false
+ ..\bin\Debug
+ DEBUG;
+ prompt
+ 4
+ false
+
+
+ full
+ true
+ ..\bin\Release
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}
+ MonoDevelop.MonoGame.Core
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/Properties/AssemblyInfo.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..53434db08
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/Properties/AssemblyInfo.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle ("MonoDevelop.MonoGame.iOS")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("MonoGame Team")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion ("1.0.*")]
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameMobileOnly-PCL.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameMobileOnly-PCL.xpt.xml
new file mode 100644
index 000000000..f713c7041
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameMobileOnly-PCL.xpt.xml
@@ -0,0 +1,96 @@
+
+
+
+ <_Name>Universal MonoGame Mobile Application (Shared Project)
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Application for the iPhone/iPad and Android which uses a Shared Project to share common code.
+
+
+
+
+
+
+
+
+ ${ProjectName}.Droid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameMobileOnly-SAP.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameMobileOnly-SAP.xpt.xml
new file mode 100644
index 000000000..44e463819
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameMobileOnly-SAP.xpt.xml
@@ -0,0 +1,92 @@
+
+
+
+ <_Name>Universal MonoGame Mobile Application (Shared Project)
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Application for the iPhone/iPad and Android which uses a Shared Project to share common code.
+
+
+
+
+
+
+
+
+ ${ProjectName}.Droid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameiOSProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameiOSProject.xpt.xml
new file mode 100644
index 000000000..94b8d0fe9
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGameiOSProject.xpt.xml
@@ -0,0 +1,46 @@
+
+
+
+ <_Name>MonoGame iPhone/iPad Application
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Application for the iPhone/iPad
+
+
+
+
+
+
+
+
+ ${ProjectName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGametvOSProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGametvOSProject.xpt.xml
new file mode 100644
index 000000000..50103cc2d
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/MonoGametvOSProject.xpt.xml
@@ -0,0 +1,44 @@
+
+
+
+ <_Name>MonoGame tvOS Application
+ monogame/app/games
+ monogame-project
+ C#
+ MonoDevelop.IPhone.TVOSProjectTemplateWizard
+ MinimumOSVersion=9.0
+ <_Description>Creates a MonoGame Application for tvOS
+
+
+
+
+
+
+ ${ProjectName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/Shared/Activity1.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/Shared/Activity1.cs
new file mode 100644
index 000000000..becdc7118
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/Shared/Activity1.cs
@@ -0,0 +1,39 @@
+using System;
+
+using Android.App;
+using Android.Content;
+using Android.Runtime;
+using Android.Content.PM;
+using Android.Views;
+using Android.Widget;
+using Android.OS;
+
+using Microsoft.Xna.Framework;
+
+namespace ${Namespace}
+{
+ [Activity (Label = "${ProjectName}",
+ MainLauncher = true,
+ Icon = "@drawable/icon",
+ Theme = "@style/Theme.Splash",
+ AlwaysRetainTaskState=true,
+ LaunchMode=LaunchMode.SingleInstance,
+ ConfigurationChanges = ConfigChanges.Orientation |
+ ConfigChanges.KeyboardHidden |
+ ConfigChanges.Keyboard)]
+ public class Activity1 : AndroidGameActivity
+ {
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ // Create our OpenGL view, and display it
+ Game1.Activity = this;
+ var g = new Game1();
+ SetContentView (g.Window);
+ g.Run();
+ }
+
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/Shared/Program.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/Shared/Program.cs
new file mode 100644
index 000000000..a37be0bc4
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/Shared/Program.cs
@@ -0,0 +1,82 @@
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Linq;
+#if MONOMAC
+using MonoMac.AppKit;
+using MonoMac.Foundation;
+#elif __IOS__ || __TVOS__
+using Foundation;
+using UIKit;
+#endif
+#endregion
+
+
+namespace ${Namespace}
+{
+ #if __IOS__ || __TVOS__
+ [Register("AppDelegate")]
+ class Program : UIApplicationDelegate
+ #else
+ static class Program
+ #endif
+ {
+ private static Game1 game;
+
+ internal static void RunGame()
+ {
+ game = new Game1();
+ game.Run();
+ }
+
+ ///
+ /// The main entry point for the application.
+ ///
+ #if !MONOMAC && !__IOS__ && !__TVOS__
+ [STAThread]
+ #endif
+ static void Main(string[] args)
+ {
+ #if MONOMAC
+ NSApplication.Init ();
+
+ using (var p = new NSAutoreleasePool ()) {
+ NSApplication.SharedApplication.Delegate = new AppDelegate();
+ NSApplication.Main(args);
+ }
+ #elif __IOS__ || __TVOS__
+ UIApplication.Main(args, null, "AppDelegate");
+ #else
+ RunGame();
+ #endif
+ }
+
+ #if __IOS__ || __TVOS__
+ public override void FinishedLaunching(UIApplication app)
+ {
+ RunGame();
+ }
+ #endif
+ }
+
+ #if MONOMAC
+ class AppDelegate : NSApplicationDelegate
+ {
+ public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
+ {
+ AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs a) => {
+ if (a.Name.StartsWith("MonoMac")) {
+ return typeof(MonoMac.AppKit.AppKitFramework).Assembly;
+ }
+ return null;
+ };
+ Program.RunGame();
+ }
+
+ public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
+ {
+ return true;
+ }
+ }
+ #endif
+}
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/Entitlements.plist.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/Entitlements.plist.xml
new file mode 100644
index 000000000..0cdf11f38
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/Entitlements.plist.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/Info_tvOS.plist.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/Info_tvOS.plist.xml
new file mode 100644
index 000000000..419e6eadd
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/Info_tvOS.plist.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ CFBundleDisplayName
+ ${AppName}
+ CFBundleName
+ ${AppName}
+ CFBundleIdentifier
+ ${AppIdentifier}
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ MinimumOSVersion
+ ${MinimumOSVersion}
+ UIDeviceFamily
+
+ 3
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Resources/Images.xcassets/AppIcons.appiconset
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSDefault.png b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSDefault.png
new file mode 100644
index 000000000..1f9b909f1
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSDefault.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSGameThumbnail.png b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSGameThumbnail.png
new file mode 100644
index 000000000..99814c32f
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSGameThumbnail.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSInfo.plist b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSInfo.plist
new file mode 100644
index 000000000..4811dd198
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame.iOS/templates/iOS/iOSInfo.plist
@@ -0,0 +1,23 @@
+
+
+
+
+ CFBundleDisplayName
+ ${Namespace}
+ CFBundleIconFiles
+
+ GameThumbnail.png
+
+ CFBundleIdentifier
+ project.MonoGame.${Namespace}
+ MinimumOSVersion
+ 7.0
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/ContentItemTemplate.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/ContentItemTemplate.cs
new file mode 100644
index 000000000..27564325e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/ContentItemTemplate.cs
@@ -0,0 +1,53 @@
+using System;
+using MonoDevelop.Ide.Templates;
+using System.Xml;
+using MonoDevelop.Core;
+using MonoDevelop.Projects;
+
+namespace MonoDevelop.MonoGame
+{
+ public class ContentItemTemplate : FileDescriptionTemplate
+ {
+ SingleFileDescriptionTemplate template;
+ FileCopyMode mode = FileCopyMode.None;
+
+ public override string Name {
+ get { return template.Name; }
+ }
+
+ public override void Load (XmlElement filenode, FilePath baseDirectory)
+ {
+ foreach (XmlNode node in filenode.ChildNodes) {
+ if (node is XmlElement) {
+ template = CreateTemplate ((XmlElement) node, baseDirectory) as SingleFileDescriptionTemplate;
+ if (template == null)
+ throw new InvalidOperationException ("Resource templates must contain single-file templates.");
+ var attr = node.Attributes ["CopyToOutputDirectory"];
+ if (attr != null) {
+ Enum.TryParse ( attr.Value, out mode);
+ }
+ return;
+ }
+ }
+ }
+
+ public override bool AddToProject(SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ {
+ ProjectFile file = template.AddFileToProject(policyParent, project, language, directory, name);
+ if (file != null)
+ {
+ file.BuildAction = BuildAction.Content;
+ file.CopyToOutputDirectory = mode;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ public override void Show ()
+ {
+ template.Show ();
+ }
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoDevelop.MonoGame.addin.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoDevelop.MonoGame.addin.xml
new file mode 100644
index 000000000..122f3c62e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoDevelop.MonoGame.addin.xml
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoDevelop.MonoGame.csproj b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoDevelop.MonoGame.csproj
new file mode 100644
index 000000000..dc254792e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoDevelop.MonoGame.csproj
@@ -0,0 +1,246 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {B2C75BDF-A022-41C6-9618-EDD8BEE76556}
+ Library
+ MonoDevelop.MonoGame
+ MonoDevelop.MonoGame
+ v4.5
+
+
+ true
+ full
+ false
+ ..\bin\Debug
+ DEBUG;
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
+
+ full
+ true
+ ..\bin\Release
+ prompt
+ 4
+ false
+
+
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/MonoDevelop.Core.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/MonoDevelop.Ide.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/ICSharpCode.NRefactory.dll
+ False
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/Mono.TextEditor.dll
+ False
+
+
+
+
+
+
+ /Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/bin/Mono.Addins.dll
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {3FE5AAE8-BE24-4FC3-AF86-2AA3C3CD8DB4}
+ MonoDevelop.MonoGame.Core
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ templates\Common\OpenTK.dll.config
+ PreserveNewest
+
+
+ templates\Common\Tao.Sdl.dll.config
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ templates\Common\MonoGame.Framework.dll.config
+ PreserveNewest
+
+
+ templates\libs\libopenal.1.dylib
+ PreserveNewest
+
+
+ templates\libs\x64\libopenal.so.1
+ PreserveNewest
+
+
+ templates\libs\x64\soft_oal.dll
+ PreserveNewest
+
+
+ templates\libs\x86\soft_oal.dll
+ PreserveNewest
+
+
+ templates\libs\x86\libopenal.so.1
+ PreserveNewest
+
+
+ templates\libs\x64\libSDL2-2.0.so.0
+ PreserveNewest
+
+
+ templates\libs\x64\SDL2.dll
+ PreserveNewest
+
+
+ templates\libs\x86\SDL2.dll
+ PreserveNewest
+
+
+ templates\libs\x86\libSDL2-2.0.so.0
+ PreserveNewest
+
+
+ templates\libs\libSDL2-2.0.0.dylib
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameBuildExtension.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameBuildExtension.cs
new file mode 100644
index 000000000..3f98a8a57
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameBuildExtension.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Linq;
+using MonoDevelop.Projects;
+using System.Diagnostics;
+using System.IO;
+using System.Collections.Generic;
+
+namespace MonoDevelop.MonoGame
+{
+ public class MonoGameBuildExtension : ProjectServiceExtension
+ {
+ ///
+ /// List of ProjectTypes which map to the Platform Enum in MonoGame
+ /// This is used to pass the correct /platform parameter for the auto
+ /// build of content.
+ ///
+ static Dictionary supportedProjectTypes = new Dictionary() {
+ {"MonoMac", "MacOSX"},
+ {"XamMac","DesktopGL"},
+ };
+
+ string platform;
+
+ protected override BuildResult Build (MonoDevelop.Core.IProgressMonitor monitor, SolutionEntityItem item, ConfigurationSelector configuration)
+ {
+ #if DEBUG
+ monitor.Log.WriteLine("MonoGame Extension Build Called");
+ #endif
+ try
+ {
+ var proj = item as Project;
+ if (proj == null)
+ {
+ #if DEBUG
+ monitor.Log.WriteLine("MonoGame Extension Null Project");
+ #endif
+ return base.Build (monitor, item, configuration);
+ }
+ #if DEBUG
+ foreach(var p in proj.GetProjectTypes()) {
+ monitor.Log.WriteLine("MonoGame Extension Project Type {0}", p);
+ }
+ #endif
+ if (!proj.GetProjectTypes().Any(x => supportedProjectTypes.ContainsKey(x)))
+ return base.Build (monitor, item, configuration);
+
+ var files = proj.Items.Where(x => x is ProjectFile).Cast();
+ foreach(var file in files.Where(f => f.BuildAction == "MonoGameContentReference")) {
+ monitor.Log.WriteLine ("Found MonoGame Content Builder Response File : {0}", file.FilePath);
+ platform = proj.GetProjectTypes().FirstOrDefault(x => supportedProjectTypes.ContainsKey(x));
+ if (!string.IsNullOrEmpty (platform)) {
+ try {
+ RunMonoGameContentBuilder(file.FilePath.ToString(), supportedProjectTypes[platform], monitor);
+ } catch (Exception ex) {
+ monitor.ReportWarning(ex.ToString());
+ }
+ }
+ }
+ return base.Build (monitor, item, configuration);
+ }
+ finally
+ {
+ #if DEBUG
+ monitor.Log.WriteLine("MonoGame Extension Build Ended");
+ #endif
+ }
+ }
+
+ protected override BuildResult Compile (MonoDevelop.Core.IProgressMonitor monitor, SolutionEntityItem item, BuildData buildData)
+ {
+ var proj = item as Project;
+ if (proj == null)
+ return base.Compile (monitor, item, buildData);
+ if (!proj.GetProjectTypes().Any(x => supportedProjectTypes.ContainsKey(x)))
+ return base.Compile (monitor, item, buildData);
+ var files = buildData.Items.Where(x => x is ProjectFile).Cast().ToArray();
+ foreach (var file in files.Where(f => f.BuildAction == "MonoGameContentReference")) {
+ var path = System.IO.Path.Combine (Path.GetDirectoryName (file.FilePath.ToString ()), "bin", supportedProjectTypes[platform]);
+ monitor.Log.WriteLine("Processing {0}", path);
+ if (!Directory.Exists (path))
+ continue;
+ foreach (var output in Directory.GetFiles (path, "*.*", SearchOption.AllDirectories)) {
+ var link = string.Format ("Content{0}", output.Replace (path, ""));
+ if (proj.Files.FirstOrDefault (x => Path.GetFileName (x.FilePath.ToString ()) == Path.GetFileName (output)) == null) {
+ monitor.Log.WriteLine ("Auto Including Content {0}", output);
+ proj.Files.Add (new ProjectFile (output, BuildAction.BundleResource) {
+ Link = new MonoDevelop.Core.FilePath (link),
+ Flags = ProjectItemFlags.DontPersist | ProjectItemFlags.Hidden,
+ Visible = false,
+ });
+ }
+ }
+ }
+ return base.Compile (monitor, item, buildData);
+ }
+
+ void RunMonoGameContentBuilder(string responseFile, string platform, MonoDevelop.Core.IProgressMonitor monitor) {
+ var process = new Process ();
+ var location = Path.Combine (Path.GetDirectoryName (typeof(MonoGameBuildExtension).Assembly.Location), "MGCB.exe");
+ if (!File.Exists (location)) {
+ switch (Environment.OSVersion.Platform) {
+ case PlatformID.Win32NT:
+ location = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86), @"MSBuild\MonoGame\v3.0\Tools", "MGCB.exe");
+ break;
+ case PlatformID.Unix:
+ if (Directory.Exists ("/Applications") &&
+ Directory.Exists ("/Users")) {
+ location = Path.Combine ("/Applications/Pipeline.app/Contents/MonoBundle", "MGCB.exe");
+ } else {
+ location = Path.Combine ("/bin", "mgcb");
+ }
+ break;
+ case PlatformID.MacOSX:
+ location = Path.Combine ("/Applications/Pipeline.app/Contents/MonoBundle", "MGCB.exe");
+ break;
+ }
+ }
+ if (!File.Exists (location)) {
+ monitor.Log.WriteLine ("MGCB.exe not found");
+ return;
+ }
+ process.StartInfo.WorkingDirectory = Path.GetDirectoryName (responseFile);
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
+ process.StartInfo.FileName = location;
+ process.StartInfo.Arguments = string.Format ("/@:\"{1}\" /platform:{0}", platform, responseFile);
+ } else if (Directory.Exists ("/Applications") &&
+ Directory.Exists ("/Users")) {
+ process.StartInfo.FileName = "mono";
+ process.StartInfo.Arguments = string.Format ("\"{0}\" /@:\"{2}\" /platform:{1}", location, platform, responseFile);
+ } else {
+ process.StartInfo.FileName = location;
+ process.StartInfo.Arguments = string.Format ("/@:\"{1}\" /platform:{0}", platform, responseFile);
+ }
+ process.StartInfo.CreateNoWindow = true;
+ process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.RedirectStandardOutput = true;
+ process.OutputDataReceived += (sender, args) => monitor.Log.WriteLine(args.Data);
+
+ monitor.Log.WriteLine ("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+
+ // Fire off the process.
+ process.Start();
+ process.BeginOutputReadLine();
+ process.WaitForExit();
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameConditions.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameConditions.cs
new file mode 100644
index 000000000..f7c280477
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameConditions.cs
@@ -0,0 +1,38 @@
+using System;
+using Mono.Addins;
+using System.IO;
+
+namespace MonoDevelop.MonoGame
+{
+ public class MonoGameIsWindowsCondition : ConditionType
+ {
+ public override bool Evaluate (NodeElement conditionNode)
+ {
+ return Environment.OSVersion.Platform == PlatformID.Win32NT;
+ }
+ }
+
+ public class MonoGameIsLinuxCondition : ConditionType
+ {
+ public override bool Evaluate (NodeElement conditionNode)
+ {
+ return Environment.OSVersion.Platform == PlatformID.Unix
+ && !Directory.Exists ("/Applications")
+ && !Directory.Exists ("/Users")
+ && !Directory.Exists ("/Library");
+ }
+ }
+
+ public class MonoGameIsMacCondition : ConditionType
+ {
+ public override bool Evaluate (NodeElement conditionNode)
+ {
+ return (Environment.OSVersion.Platform == PlatformID.Unix
+ && Directory.Exists("/Applications")
+ && Directory.Exists("/Users")
+ && Directory.Exists("/Library"))
+ || Environment.OSVersion.Platform == PlatformID.MacOSX;
+ }
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameContentEditorViewContent.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameContentEditorViewContent.cs
new file mode 100644
index 000000000..c40789197
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameContentEditorViewContent.cs
@@ -0,0 +1,114 @@
+using System;
+using MonoDevelop.Ide.Gui;
+using Gtk;
+using System.IO;
+
+namespace MonoDevelop.MonoGame
+{
+ #if BUILDINEDITOR
+ class MonoGameContentEditorViewContent : AbstractBaseViewContent, IViewContent
+ {
+ Alignment control;
+ Pipeline.MacOS.MainView view;
+
+ public event EventHandler ContentNameChanged;
+ public event EventHandler ContentChanged;
+ public event EventHandler DirtyChanged;
+ public event EventHandler BeforeSave;
+ public void Load (string fileName)
+ {
+ view.Load (fileName);
+ }
+ public void LoadNew (Stream content, string mimeType)
+ {
+ view.LoadNew (content, mimeType);
+ }
+ public void Save (string fileName)
+ {
+ view.Save (fileName);
+ }
+ public void Save ()
+ {
+ view.Save ();
+ }
+ public void DiscardChanges ()
+ {
+ view.Undo ();
+ }
+ public MonoDevelop.Projects.Project Project {
+ get ;
+ set;
+ }
+ public string PathRelativeToProject {
+ get {
+ return string.Empty;
+ }
+ }
+ public string ContentName {
+ get;
+ set;
+ }
+ public string UntitledName {
+ get;
+ set;
+ }
+ public string StockIconId {
+ get {
+ return "monogame-project";
+ }
+ }
+ public bool IsUntitled {
+ get {
+ return false;
+ }
+ }
+ public bool IsViewOnly {
+ get {
+ return true;
+ }
+ }
+ public bool IsFile {
+ get {
+ return true;
+ }
+ }
+ public bool IsDirty {
+ get { return view.IsDirty; }
+ set { view.IsDirty = value; }
+ }
+ public bool IsReadOnly {
+ get {
+ return false;
+ }
+ }
+
+ public override Gtk.Widget Control {
+ get {
+ return control;
+ }
+ }
+
+ public MonoGameContentEditorViewContent (MonoDevelop.Core.FilePath filename, MonoDevelop.Projects.Project project)
+ {
+ this.ContentName = Path.GetFileName (filename.ToString());
+ this.Project = project;
+ control = new Alignment (0, 0, 1, 1);
+ control.SetPadding (5, 5, 5, 5);
+
+ view = new Pipeline.MacOS.MainView (null);
+
+ if (filename != null) {
+ view.OpenProjectPath = filename.ToString();
+ }
+ Pipeline.MacOS.MainView.CreateControllers (view);
+ view.BuildUI ();
+
+ control.Add (view);
+
+ control.ShowAll ();
+ }
+
+ }
+ #endif
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameMSBuildImports.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameMSBuildImports.cs
new file mode 100644
index 000000000..fa33621e7
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameMSBuildImports.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Xml;
+using System.Xml.XPath;
+using System.Linq;
+using System.Collections.Generic;
+using MonoDevelop.Projects.MSBuild;
+using MonoDevelop.Projects;
+
+namespace MonoDevelop.MonoGame
+{
+ public class MonoGameMSBuildImports : DotNetProjectExtension
+ {
+ const string MonoGameContentBuildTargets = "$(MSBuildExtensionsPath)\\MonoGame\\v3.0\\MonoGame.Content.Builder.targets";
+ const string MonoGameCommonProps = "$(MSBuildExtensionsPath)\\MonoGame\\v3.0\\MonoGame.Common.props";
+ const string MonoGameExtensionsPath = @"$(MonoGameInstallDirectory)\MonoGame\v3.0\Assemblies\{0}\{1}";
+ const string MonoGameExtensionsAbsolutePath = @"/Library/Frameworks/MonoGame.framework/v3.0/Assemblies/{0}/{1}";
+
+ static bool UpgradeMonoGameProject (MonoDevelop.Core.ProgressMonitor monitor, DotNetProjectExtension extension, MSBuildProject project)
+ {
+ bool needsSave = false;
+ bool containsMGCB = project.ItemGroups.Any (x => x.Items.Any (i => System.IO.Path.GetExtension (i.Include) == ".mgcb"));
+ bool isMonoGame = project.PropertyGroups.Any (x => x.GetProperties().Any (p => p.Name == "MonoGamePlatform")) ||
+ project.ItemGroups.Any (x => x.Items.Any (i => i.Name == "Reference" && i.Include == "MonoGame.Framework")) ||
+ containsMGCB;
+ bool isDesktopGL = project.ItemGroups.Any (x => x.Items.Any (i => i.Include.EndsWith ("SDL2.dll")));
+ bool isApplication = project.PropertyGroups.Any (x => x.GetProperties().Any (p => p.Name == "OutputType" && p.Value == "Exe"))
+ | project.PropertyGroups.Any (x => x.GetProperties().Any (p => p.Name == "AndroidApplication" && string.Compare (p.Value, bool.TrueString, true)==0));
+ bool isShared = project.PropertyGroups.Any (x => x.GetProperties().Any (p => p.Name == "HasSharedItems" && p.Value == "true"));
+ bool absoluteReferenes = false;
+ var type = extension.Project.GetType ().Name;
+
+ monitor.Log.WriteLine ("Found {0}", type);
+ monitor.Log.WriteLine ("Found {0}", project.GetType ().Name);
+ var platform = isDesktopGL ? "DesktopGL" : "Windows";
+ var path = MonoGameExtensionsPath;
+ if (extension.Project.FlavorGuids.Contains ("{FEACFBD2-3405-455C-9665-78FE426C6842}")) {
+ platform = "iOS";
+ }
+ if (extension.Project.FlavorGuids.Contains ("{06FA79CB-D6CD-4721-BB4B-1BD202089C55}")) {
+ platform = "tvOS";
+ }
+ if (extension.Project.FlavorGuids.Contains ("{EFBA0AD7-5A72-4C68-AF49-83D382785DCF}")) {
+ platform = "Android";
+ }
+ if (extension.Project.FlavorGuids.Contains ("{948B3504-5B70-4649-8FE4-BDE1FB46EC69}")) {
+ platform = "MacOSX";
+ // MonoMac Classic does not use MSBuild so we need to absolute path.
+ path = MonoGameExtensionsAbsolutePath;
+ absoluteReferenes = true;
+ }
+ if (extension.Project.FlavorGuids.Contains ("{42C0BBD9-55CE-4FC1-8D90-A7348ABAFB23}")) {
+ platform = "DesktopGL";
+ // Xamarin.Mac Classic does not use MSBuild so we need to absolute path.
+ path = MonoGameExtensionsAbsolutePath;
+ absoluteReferenes = true;
+ }
+ if (extension.Project.FlavorGuids.Contains ("{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1}")) {
+ platform = "DesktopGL";
+ }
+ monitor.Log.WriteLine ("Platform = {0}", platform);
+ monitor.Log.WriteLine ("Path = {0}", path);
+ monitor.Log.WriteLine ("isMonoGame {0}", isMonoGame);
+ if (isMonoGame) {
+ var ritems = new List ();
+ foreach (var ig in project.ItemGroups) {
+ foreach (var i in ig.Items.Where (x => x.Name == "Reference" && x.Include == "MonoGame.Framework")) {
+ var metaData = i.Metadata;
+ if (!metaData.HasProperty("HintPath")) {
+ monitor.Log.WriteLine ("Fixing {0} to be MonoGameContentReference", i.Include);
+ metaData.SetValue ("HintPath", string.Format (path, platform, "MonoGame.Framework.dll"));
+ needsSave = true;
+ }
+ }
+ foreach (var i in ig.Items.Where (x => x.Name == "Reference" && x.Include == "Tao.Sdl")) {
+ var metaData = i.Metadata;
+ if (!metaData.HasProperty("HintPath")) {
+ monitor.Log.WriteLine ("Fixing {0} to be Tao.Sdl", i.Include);
+ metaData.SetValue ("HintPath", string.Format (path, platform, "Tao.Sdl.dll"));
+ needsSave = true;
+ }
+ }
+ foreach (var i in ig.Items.Where (x => x.Name == "Reference" && x.Include.StartsWith ("OpenTK") &&
+ (platform != "iOS" && platform != "Android"))) {
+ var metaData = i.Metadata;
+ if (!metaData.HasProperty ("HintPath")) {
+ monitor.Log.WriteLine("Fixing {0} to be OpenTK", i.Include);
+ metaData.SetValue ("HintPath", string.Format (path, platform, "OpenTK.dll"));
+ metaData.SetValue ("SpecificVersion", "true");
+ needsSave = true;
+ }
+ }
+ }
+ foreach (var a in ritems) {
+ project.RemoveItem (a);
+ }
+ var dotNetProject = extension.Project;
+ if (dotNetProject != null && absoluteReferenes) {
+ var items = new List ();
+ var newitems = new List ();
+ foreach (var reference in dotNetProject.References) {
+ if (reference.Reference == "MonoGame.Framework" && string.IsNullOrEmpty (reference.HintPath)) {
+ items.Add (reference);
+ newitems.Add (ProjectReference.CreateCustomReference (ReferenceType.Assembly, reference.Reference, string.Format(path, platform, "MonoGame.Framework.dll")));
+ }
+ if (reference.Reference.StartsWith ("OpenTK", StringComparison.OrdinalIgnoreCase) && string.IsNullOrEmpty (reference.HintPath)) {
+ items.Add (reference);
+ newitems.Add (ProjectReference.CreateCustomReference (ReferenceType.Assembly, reference.Reference, string.Format (path, platform, "OpenTK.dll")));
+ }
+ if (reference.Reference == "Tao.Sdl" && string.IsNullOrEmpty (reference.HintPath)) {
+ items.Add (reference);
+ newitems.Add (ProjectReference.CreateCustomReference (ReferenceType.Assembly, reference.Reference, string.Format (path, platform, "Tao.Sdl.dll")));
+ }
+ }
+ dotNetProject.References.RemoveRange (items);
+ dotNetProject.References.AddRange (newitems);
+ }
+ }
+ if (isMonoGame && containsMGCB && (isApplication || isShared)) {
+ if (!project.PropertyGroups.Any (x => x.GetProperties().Any (p => p.Name == "MonoGamePlatform")) && !isShared) {
+ monitor.Log.WriteLine ("Adding MonoGamePlatform {0}", platform == "tvOS" ? "iOS" : platform);
+ project.PropertyGroups.First ().SetValue ("MonoGamePlatform", platform == "tvOS" ? "iOS" : platform, true);
+ needsSave = true;
+ }
+ if (!project.Imports.Any (x => x.Project.StartsWith (MonoGameCommonProps, StringComparison.OrdinalIgnoreCase))&& !isShared) {
+ monitor.Log.WriteLine ("Adding MonoGame.Common.props Import");
+ project.AddNewImport(MonoGameCommonProps, string.Format ("Exists('{0}')", MonoGameCommonProps), project.PropertyGroups.First());
+ needsSave = true;
+ }
+ if (containsMGCB) {
+ var ritems = new List ();
+ foreach (var ig in project.ItemGroups) {
+ foreach (var i in ig.Items.Where (x => System.IO.Path.GetExtension (x.Include) == ".mgcb")) {
+ if (i.Name != "MonoGameContentReference" && i.Name == "None") {
+ monitor.Log.WriteLine ("Fixing {0} to be MonoGameContentReference", i.Include);
+ ig.AddNewItem ("MonoGameContentReference", i.Include);
+ ritems.Add (i);
+ needsSave = true;
+ }
+ }
+ }
+ foreach (var a in ritems) {
+ project.RemoveItem (a);
+ }
+ }
+ if (!project.Imports.Any (x => x.Project.StartsWith (MonoGameContentBuildTargets, StringComparison.OrdinalIgnoreCase)) && !isShared) {
+ monitor.Log.WriteLine ("Adding MonoGame Content Builder .targets");
+ project.AddNewImport (MonoGameContentBuildTargets);
+ needsSave = true;
+ }
+ }
+ return needsSave;
+ }
+
+ protected override void OnWriteProject(MonoDevelop.Core.ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ base.OnWriteProject(monitor, msproject);
+ var changed = UpgradeMonoGameProject (monitor, this, msproject);
+ if (changed)
+ {
+ msproject.Save(msproject.FileName);
+ this.Project.NeedsReload = true;
+ }
+ }
+
+ protected override void OnReadProject(MonoDevelop.Core.ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ base.OnReadProject (monitor, msproject);
+ var changed = (UpgradeMonoGameProject(monitor, this, msproject));
+ if (changed)
+ {
+ msproject.Save (msproject.FileName);
+ this.Project.NeedsReload = true;
+ }
+ }
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameProject.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameProject.cs
new file mode 100644
index 000000000..cbbe89152
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/MonoGameProject.cs
@@ -0,0 +1,97 @@
+using System;
+using MonoDevelop.Projects.MSBuild;
+using MonoDevelop.Core.Assemblies;
+using System.Xml;
+using MonoDevelop.Projects;
+
+namespace MonoDevelop.MonoGame
+{
+ public class MonoGameProject : DotNetAssemblyProject
+ {
+ public MonoGameProject ()
+ {
+ Init ();
+ }
+
+ public MonoGameProject (string languageName)
+ : base (languageName)
+ {
+ Init ();
+ }
+
+ public MonoGameProject (string languageName, ProjectCreateInformation info, XmlElement projectOptions)
+ : base (languageName, info, projectOptions)
+ {
+ Init ();
+ }
+
+ private void Init()
+ {
+ }
+
+ public override SolutionItemConfiguration CreateConfiguration (string name)
+ {
+ var conf = new MonoGameProjectConfiguration (name);
+ conf.CopyFrom (base.CreateConfiguration (name));
+ return conf;
+ }
+
+ public override bool SupportsFormat (FileFormat format)
+ {
+ return format.Id == "MSBuild12";
+ }
+
+ public override TargetFrameworkMoniker GetDefaultTargetFrameworkForFormat (FileFormat format)
+ {
+ return new TargetFrameworkMoniker("4.0");
+ }
+
+ public override bool SupportsFramework (MonoDevelop.Core.Assemblies.TargetFramework framework)
+ {
+ if (!framework.CanReferenceAssembliesTargetingFramework (MonoDevelop.Core.Assemblies.TargetFrameworkMoniker.NET_4_0))
+ return false;
+ else
+ return base.SupportsFramework (framework);
+ }
+ }
+
+ public class MonoGameProjectBinding : IProjectBinding
+ {
+ public Project CreateProject (ProjectCreateInformation info, XmlElement projectOptions)
+ {
+ string lang = projectOptions.GetAttribute ("language");
+ return new MonoGameProject (lang, info, projectOptions);
+ }
+
+ public Project CreateSingleFileProject (string sourceFile)
+ {
+ throw new InvalidOperationException ();
+ }
+
+ public bool CanCreateSingleFileProject (string sourceFile)
+ {
+ return false;
+ }
+
+ public string Name {
+ get { return "MonoGame"; }
+ }
+ }
+
+ public class MonoGameProjectConfiguration : DotNetProjectConfiguration
+ {
+ public MonoGameProjectConfiguration () : base ()
+ {
+ }
+
+ public MonoGameProjectConfiguration (string name) : base (name)
+ {
+ }
+
+ public override void CopyFrom (ItemConfiguration configuration)
+ {
+ base.CopyFrom (configuration);
+ }
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/PipelineDisplayBinding.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/PipelineDisplayBinding.cs
new file mode 100644
index 000000000..306cc606e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/PipelineDisplayBinding.cs
@@ -0,0 +1,104 @@
+using System;
+using MonoDevelop.Ide.Gui;
+using System.IO;
+using System.Diagnostics;
+using MonoDevelop.Ide.Gui.Content;
+using Gtk;
+
+namespace MonoDevelop.MonoGame
+{
+ #if BUILDINEDITOR
+ public class PipelineDisplayBinding: IViewDisplayBinding
+ {
+ #region IViewDisplayBinding implementation
+
+ public IViewContent CreateContent (MonoDevelop.Core.FilePath fileName, string mimeType, MonoDevelop.Projects.Project ownerProject)
+ {
+ return new MonoGameContentEditorViewContent (fileName, ownerProject);
+ }
+
+ public string Name {
+ get {
+ return "MonoGame Content Builder";
+ }
+ }
+
+ #endregion
+
+ #region IDisplayBinding implementation
+
+ public bool CanHandle (MonoDevelop.Core.FilePath fileName, string mimeType, MonoDevelop.Projects.Project ownerProject)
+ {
+ return mimeType == "text/x-mgcb";
+ }
+
+ public bool CanUseAsDefault {
+ get {
+ return true;
+ }
+ }
+
+ #endregion
+ }
+ #else
+ public class PipelineDisplayBinding : IExternalDisplayBinding {
+ #region IExternalDisplayBinding implementation
+ public MonoDevelop.Ide.Desktop.DesktopApplication GetApplication (MonoDevelop.Core.FilePath fileName, string mimeType, MonoDevelop.Projects.Project ownerProject)
+ {
+ return new PipelineDesktopApplication (fileName.FullPath,ownerProject);
+ }
+ #endregion
+ #region IDisplayBinding implementation
+ public bool CanHandle (MonoDevelop.Core.FilePath fileName, string mimeType, MonoDevelop.Projects.Project ownerProject)
+ {
+ return mimeType == "text/x-mgcb";
+ }
+ public bool CanUseAsDefault {
+ get {
+ return true;
+ }
+ }
+ #endregion
+
+ }
+
+ class PipelineDesktopApplication : MonoDevelop.Ide.Desktop.DesktopApplication
+ {
+ MonoDevelop.Projects.Project project;
+ string filename;
+
+ public PipelineDesktopApplication (string filename, MonoDevelop.Projects.Project ownerProject)
+ : base ("MonoGamePipelineTool", "MonoGame Pipeline Tool", true)
+ {
+ this.project = ownerProject;
+ this.filename = filename;
+ }
+
+ public override void Launch (params string[] files)
+ {
+ var process = new Process ();
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
+ process.StartInfo.FileName = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86), @"MSBuild\MonoGame\v3.0\Tools", "Pipeline.exe");
+ process.StartInfo.Arguments = string.Format ("\"{0}\"", filename);
+ } else {
+ if (Directory.Exists ("/Applications/Pipeline.app")) {
+ process.StartInfo.FileName = "open";
+ process.StartInfo.EnvironmentVariables.Add("MONOGAME_PIPELINE_PROJECT", Path.GetFullPath (filename));
+ process.StartInfo.Arguments = string.Format ("-b com.monogame.pipeline --args \"{0}\"", Path.GetFullPath (filename));
+ } else {
+ // figure out linix
+ process.StartInfo.FileName = "monogame-pipeline-tool";
+ process.StartInfo.Arguments = string.Format ("\"{0}\"", filename);
+ }
+ }
+ process.StartInfo.CreateNoWindow = true;
+ process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ process.StartInfo.UseShellExecute = false;
+
+ // Fire off the process.
+ process.Start();
+ }
+ }
+ #endif
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/Properties/AssemblyInfo.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..39c2b593b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/Properties/AssemblyInfo.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle ("MonoDevelop.MonoGame")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("MonoGame Team")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion ("1.0.*")]
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/exclude.addins b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/exclude.addins
new file mode 100644
index 000000000..c0041baac
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/exclude.addins
@@ -0,0 +1,23 @@
+
+ Assimp64.dll
+ nvtt.dll
+ freetype6.dll
+ pvrtc.dll
+ templates/libs/x86/SDL2.dll
+ templates/libs/x64/SDL2.dll
+ templates/libs/x86/soft_oal.dll
+ templates/libs/x64/soft_oal.dll
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/icons/monogame-project-32.png b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/icons/monogame-project-32.png
new file mode 100644
index 000000000..1c64b51e8
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/icons/monogame-project-32.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/AssemblyInfo.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/AssemblyInfo.cs
new file mode 100644
index 000000000..28bcd70af
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+#if __ANDROID__
+using Android.App;
+#endif
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("${ProjectName}")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("${AuthorCompany}")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("${AuthorCopyright}")]
+[assembly: AssemblyTrademark("${AuthorTrademark}")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.0")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Content.mgcb b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Content.mgcb
new file mode 100644
index 000000000..70c5afb44
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Content.mgcb
@@ -0,0 +1,12 @@
+#----------------------------- Global Properties ----------------------------#
+
+/outputDir:bin/$(Platform)
+/intermediateDir:obj/$(Platform)
+/config:
+/profile:Reach
+/compress:False
+
+#-------------------------------- References --------------------------------#
+
+
+#---------------------------------- Content ---------------------------------#
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Game1.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Game1.cs
new file mode 100644
index 000000000..67e26cbe9
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Game1.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+
+namespace ${Namespace}
+{
+ ///
+ /// This is the main type for your game.
+ ///
+ public class Game1 : Game
+ {
+ GraphicsDeviceManager graphics;
+ SpriteBatch spriteBatch;
+
+ public Game1()
+ {
+ graphics = new GraphicsDeviceManager(this);
+ Content.RootDirectory = "Content";
+ }
+
+ ///
+ /// Allows the game to perform any initialization it needs to before starting to run.
+ /// This is where it can query for any required services and load any non-graphic
+ /// related content. Calling base.Initialize will enumerate through any components
+ /// and initialize them as well.
+ ///
+ protected override void Initialize()
+ {
+ // TODO: Add your initialization logic here
+
+ base.Initialize();
+ }
+
+ ///
+ /// LoadContent will be called once per game and is the place to load
+ /// all of your content.
+ ///
+ protected override void LoadContent()
+ {
+ // Create a new SpriteBatch, which can be used to draw textures.
+ spriteBatch = new SpriteBatch(GraphicsDevice);
+
+ //TODO: use this.Content to load your game content here
+ }
+
+ ///
+ /// Allows the game to run logic such as updating the world,
+ /// checking for collisions, gathering input, and playing audio.
+ ///
+ /// Provides a snapshot of timing values.
+ protected override void Update(GameTime gameTime)
+ {
+ // For Mobile devices, this logic will close the Game when the Back button is pressed
+ // Exit() is obsolete on iOS
+ #if !__IOS__ && !__TVOS__
+ if (GamePad.GetState (PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
+ Exit ();
+ #endif
+
+ // TODO: Add your update logic here
+
+ base.Update(gameTime);
+ }
+
+ ///
+ /// This is called when the game should draw itself.
+ ///
+ /// Provides a snapshot of timing values.
+ protected override void Draw(GameTime gameTime)
+ {
+ graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
+
+ //TODO: Add your drawing code here
+
+ base.Draw(gameTime);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon-hd.png b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon-hd.png
new file mode 100644
index 000000000..631d6532d
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon-hd.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon-md.png b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon-md.png
new file mode 100644
index 000000000..ce7f8c4a2
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon-md.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon.ico b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon.ico
new file mode 100644
index 000000000..7d9dec187
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Icon.ico differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Importer1.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Importer1.cs
new file mode 100644
index 000000000..52c3c29cf
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Importer1.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+
+using TImport = System.String;
+
+namespace ${Namespace}
+{
+ [ContentImporter(".txt", DisplayName = "Importer1", DefaultProcessor = "Processor1")]
+ public class Importer1 : ContentImporter
+ {
+ public override TImport Import(string filename, ContentImporterContext context)
+ {
+ return default(TImport);
+ }
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Processor1.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Processor1.cs
new file mode 100644
index 000000000..22906a686
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Processor1.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+
+using TInput = System.String;
+using TOutput = System.String;
+
+namespace ${Namespace}
+{
+ [ContentProcessor(DisplayName = "Processor1")]
+ class Processor1 : ContentProcessor
+ {
+ public override TOutput Process(TInput input, ContentProcessorContext context)
+ {
+ return default(TOutput);
+ }
+ }
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Program.cs b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Program.cs
new file mode 100644
index 000000000..483f2fa8c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/Program.cs
@@ -0,0 +1,84 @@
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Linq;
+#if MONOMAC
+using MonoMac.AppKit;
+using MonoMac.Foundation;
+#elif __IOS__ || __TVOS__
+using Foundation;
+using UIKit;
+#endif
+#endregion
+
+namespace ${Namespace}
+{
+ #if __IOS__ || __TVOS__
+ [Register("AppDelegate")]
+ class Program : UIApplicationDelegate
+ #else
+ static class Program
+ #endif
+ {
+ private static Game1 game;
+
+ internal static void RunGame()
+ {
+ game = new Game1();
+ game.Run();
+ #if !__IOS__ && !__TVOS__
+ game.Dispose ();
+ #endif
+ }
+
+ ///
+ /// The main entry point for the application.
+ ///
+ #if !MONOMAC && !__IOS__ && !__TVOS__
+ [STAThread]
+ #endif
+ static void Main(string[] args)
+ {
+ #if MONOMAC
+ NSApplication.Init ();
+
+ using (var p = new NSAutoreleasePool ()) {
+ NSApplication.SharedApplication.Delegate = new AppDelegate();
+ NSApplication.Main(args);
+ }
+ #elif __IOS__ || __TVOS__
+ UIApplication.Main(args, null, "AppDelegate");
+ #else
+ RunGame();
+ #endif
+ }
+
+ #if __IOS__ || __TVOS__
+ public override void FinishedLaunching(UIApplication app)
+ {
+ RunGame();
+ }
+ #endif
+ }
+
+ #if MONOMAC
+ class AppDelegate : NSApplicationDelegate
+ {
+ public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
+ {
+ AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs a) => {
+ if (a.Name.StartsWith("MonoMac")) {
+ return typeof(MonoMac.AppKit.AppKitFramework).Assembly;
+ }
+ return null;
+ };
+ Program.RunGame();
+ }
+
+ public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
+ {
+ return true;
+ }
+ }
+ #endif
+}
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/app.manifest b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/app.manifest
new file mode 100644
index 000000000..724f8c407
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/Common/app.manifest
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true/pm
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentBuilderTemplate.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentBuilderTemplate.xpt.xml
new file mode 100644
index 000000000..2acb64686
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentBuilderTemplate.xpt.xml
@@ -0,0 +1,14 @@
+
+
+
+ <_Name>MonoGame Content Builder File
+ monogame-project
+ <_Category>MonoGame
+ C#
+ <_Description>Creates a basic MonoGame Content Builder control file.
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentImporter.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentImporter.xpt.xml
new file mode 100644
index 000000000..a831b6cef
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentImporter.xpt.xml
@@ -0,0 +1,16 @@
+
+
+
+ <_Name>MonoGame Content Importer
+ monogame-project
+ <_Category>MonoGame
+ C#
+ <_Description>Creates a basic MonoGame Content Importer which can be used to extend the Pipeline tool.
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentProcessor.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentProcessor.xpt.xml
new file mode 100644
index 000000000..ebced5805
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameContentProcessor.xpt.xml
@@ -0,0 +1,15 @@
+
+
+
+ <_Name>MonoGame Content Processor
+ monogame-project
+ <_Category>MonoGame
+ C#
+ <_Description>Creates a basic MonoGame Content Processor which can be used to extend the Pipeline tool.
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGamePCLProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGamePCLProject.xpt.xml
new file mode 100644
index 000000000..a8a47ea0b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGamePCLProject.xpt.xml
@@ -0,0 +1,30 @@
+
+
+
+ <_Name>MonoGame Portable Library
+ monogame/library/crossplat
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Portable Library (PCL). This can be used to share most of your games code.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGamePipelineProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGamePipelineProject.xpt.xml
new file mode 100644
index 000000000..6e329adc7
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGamePipelineProject.xpt.xml
@@ -0,0 +1,28 @@
+
+
+
+ <_Name>MonoGame Pipeline Library
+ monogame/library/pipeline
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Pipeline Extenson so you can extend the Content Pipeline.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameProject.xpt.xml
new file mode 100644
index 000000000..e30915ea6
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameProject.xpt.xml
@@ -0,0 +1,80 @@
+
+
+
+ <_Name>MonoGame Cross Platform Desktop Project
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>A MonoGame game project for Windows, Mac and Linux using OpenGL.
+
+
+
+
+
+
+
+
+ ${ProjectName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameSharedProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameSharedProject.xpt.xml
new file mode 100644
index 000000000..876d6df61
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameSharedProject.xpt.xml
@@ -0,0 +1,26 @@
+
+
+
+ <_Name>MonoGame Shared Project
+ monogame/library/crossplat
+ monogame-project
+ C#
+ <_Description>Creates a MonoGame Shared Project to share common code. This can be used to share most of your shared code, but you can also include platform specific code using #defines.
+Note this is a Shared Project only, it will need to be referenced from another MonoGame project to work.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameWindowsProject.xpt.xml b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameWindowsProject.xpt.xml
new file mode 100644
index 000000000..d046d4f7c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/MonoDevelop.MonoGame/templates/MonoGameWindowsProject.xpt.xml
@@ -0,0 +1,42 @@
+
+
+
+ <_Name>MonoGame Application (DirectX)
+ monogame/app/games
+ monogame-project
+ C#
+ <_Description>Creates a new C# MonoGame Windows Application. This application will use the DirectX backend.
+
+
+
+
+
+
+
+
+ ${ProjectName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/default.build b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/default.build
new file mode 100644
index 000000000..75af7fb16
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoDevelop/default.build
@@ -0,0 +1,64 @@
+
+
+ Default Addins Automated Build script
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/MonoGame.IDE.Extensions.sln b/Libraries/MonoGame.Framework/Src/IDE/MonoGame.IDE.Extensions.sln
new file mode 100644
index 000000000..9f906d551
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/MonoGame.IDE.Extensions.sln
@@ -0,0 +1,23 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.IDE.VisualStudioForMac", "VisualStudioForMac\MonoGame.IDE.VisualStudioForMac.csproj", "{95728082-6120-4837-BB99-257181AF0506}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Templates", "..\ProjectTemplates\DotNetTemplate\MonoGame.Templates.csproj", "{01CCC19F-CEF9-4A47-9931-3F5AEF008BB1}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {95728082-6120-4837-BB99-257181AF0506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {95728082-6120-4837-BB99-257181AF0506}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {95728082-6120-4837-BB99-257181AF0506}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {95728082-6120-4837-BB99-257181AF0506}.Release|Any CPU.Build.0 = Release|Any CPU
+ {01CCC19F-CEF9-4A47-9931-3F5AEF008BB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01CCC19F-CEF9-4A47-9931-3F5AEF008BB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {01CCC19F-CEF9-4A47-9931-3F5AEF008BB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {01CCC19F-CEF9-4A47-9931-3F5AEF008BB1}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/MonoGame.IDE.VisualStudioForMac.csproj b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/MonoGame.IDE.VisualStudioForMac.csproj
new file mode 100644
index 000000000..116fc207b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/MonoGame.IDE.VisualStudioForMac.csproj
@@ -0,0 +1,156 @@
+
+
+ net461
+ $(AssemblySearchPaths);{GAC}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ monogame-project-32.png
+
+
+ monogame-android.png
+
+
+ monogame-desktopgl.png
+
+
+ monogame-ios.png
+
+
+ monogame-preview.png
+
+
+ monogame-shared.png
+
+
+ monogame-windows.png
+
+
+ project-monogame-32.png
+
+
+ project-monogame-32@2x.png
+
+
+ project-monogame-32@~dark.png
+
+
+ project-monogame-32~dark%402x.png
+
+
+ project-monogame-32~dark~sel.png
+
+
+ project-monogame-32~dark~sel%402x.png
+
+
+ project-monogame-32~sel.png
+
+
+ project-monogame-32~sel%402x.png
+
+
+ project-monogame-template.png
+
+
+ project-monogame-template%402x.png
+
+
+ project-monogame-template~dark.png
+
+
+ project-monogame-template~dark%402x.png
+
+
+ monogame-16.png
+
+
+ monogame-16@2x.png
+
+
+ monogame-16~dark.png
+
+
+ monogame-16~dark@2x.png
+
+
+ monogame-16~dark~sel.png
+
+
+ monogame-16~dark~sel@2x.png
+
+
+ monogame-16~sel.png
+
+
+ monogame-16~sel@2x.png
+
+
+
+
+ Templates\MonoGame.Templates.CSharp.nupkg
+
+
+
+
+ $(BUILD_NUMBER)
+ 3.7.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/PipelineDisplayBinding.cs b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/PipelineDisplayBinding.cs
new file mode 100644
index 000000000..eb9e5f2b5
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/PipelineDisplayBinding.cs
@@ -0,0 +1,64 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using MonoDevelop.Ide.Gui;
+
+namespace MonoGame.IDE.VisualStudioForMac {
+ public class PipelineDisplayBinding : IExternalDisplayBinding {
+ #region IExternalDisplayBinding implementation
+ public MonoDevelop.Ide.Desktop.DesktopApplication GetApplication (MonoDevelop.Core.FilePath fileName, string mimeType, MonoDevelop.Projects.Project ownerProject)
+ {
+ return new PipelineDesktopApplication (fileName.FullPath, ownerProject);
+ }
+ #endregion
+ #region IDisplayBinding implementation
+ public bool CanHandle (MonoDevelop.Core.FilePath fileName, string mimeType, MonoDevelop.Projects.Project ownerProject)
+ {
+ return mimeType == "text/x-mgcb";
+ }
+ public bool CanUseAsDefault {
+ get {
+ return true;
+ }
+ }
+ #endregion
+
+ }
+
+ class PipelineDesktopApplication : MonoDevelop.Ide.Desktop.DesktopApplication {
+ MonoDevelop.Projects.Project project;
+ string filename;
+
+ public PipelineDesktopApplication (string filename, MonoDevelop.Projects.Project ownerProject)
+ : base ("MonoGamePipelineTool", "MonoGame Pipeline Tool", true)
+ {
+ this.project = ownerProject;
+ this.filename = filename;
+ }
+
+ public override void Launch (params string [] files)
+ {
+ var process = new Process ();
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
+ process.StartInfo.FileName = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86), @"MSBuild\MonoGame\v3.0\Tools", "Pipeline.exe");
+ process.StartInfo.Arguments = string.Format ("\"{0}\"", filename);
+ } else {
+ if (Directory.Exists ("/Applications/Pipeline.app")) {
+ process.StartInfo.FileName = "open";
+ process.StartInfo.EnvironmentVariables.Add ("MONOGAME_PIPELINE_PROJECT", Path.GetFullPath (filename));
+ process.StartInfo.Arguments = string.Format ("-b com.monogame.pipeline --args \"{0}\"", Path.GetFullPath (filename));
+ } else {
+ // figure out linix
+ process.StartInfo.FileName = "monogame-pipeline-tool";
+ process.StartInfo.Arguments = string.Format ("\"{0}\"", filename);
+ }
+ }
+ process.StartInfo.CreateNoWindow = true;
+ process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ process.StartInfo.UseShellExecute = false;
+
+ // Fire off the process.
+ process.Start ();
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/Properties/AddinInfo.cs b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/Properties/AddinInfo.cs
new file mode 100644
index 000000000..be571ee71
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/Properties/AddinInfo.cs
@@ -0,0 +1,8 @@
+using System;
+using Mono.Addins;
+using Mono.Addins.Description;
+[assembly: Addin("MonoGame_IDE_VisualStudioForMac",Namespace = "MonoDevelop",Version = "0.0.0.0")]
+[assembly: AddinName("MonoGame Extension")]
+[assembly: AddinCategory("Game Development")]
+[assembly: AddinDescription("VisualStudio for Mac extension for MonoGame")]
+[assembly: AddinAuthor("@MonoGameTeam")]
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/Properties/Manifest.addin.xml b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/Properties/Manifest.addin.xml
new file mode 100644
index 000000000..a148df5d0
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/Properties/Manifest.addin.xml
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/default.build b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/default.build
new file mode 100644
index 000000000..c8ccd81d9
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/default.build
@@ -0,0 +1,41 @@
+
+
+ Default Addins Automated Build script
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16.png
new file mode 100644
index 000000000..dd7d9808f
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16@2x.png
new file mode 100644
index 000000000..318ddbbf5
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark.png
new file mode 100644
index 000000000..93d1deda3
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark@2x.png
new file mode 100644
index 000000000..9d1d4cc31
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark~sel.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark~sel.png
new file mode 100644
index 000000000..2a44eada1
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark~sel.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark~sel@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark~sel@2x.png
new file mode 100644
index 000000000..4c47b2a80
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~dark~sel@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~sel.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~sel.png
new file mode 100644
index 000000000..2a44eada1
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~sel.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~sel@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~sel@2x.png
new file mode 100644
index 000000000..4c47b2a80
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-16~sel@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-android.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-android.png
new file mode 100644
index 000000000..5e8b77d7e
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-android.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-desktopgl.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-desktopgl.png
new file mode 100644
index 000000000..70764ded0
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-desktopgl.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-ios.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-ios.png
new file mode 100644
index 000000000..e528d5963
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-ios.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-preview.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-preview.png
new file mode 100644
index 000000000..ee91ba6e5
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-preview.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-project-32.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-project-32.png
new file mode 100644
index 000000000..1c64b51e8
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-project-32.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-shared.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-shared.png
new file mode 100644
index 000000000..b23091738
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-shared.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-windows.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-windows.png
new file mode 100644
index 000000000..29b083ac4
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/monogame-windows.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32.png
new file mode 100644
index 000000000..1ab38b2c9
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32@2x.png
new file mode 100644
index 000000000..0f09567e9
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark.png
new file mode 100644
index 000000000..62417c6cd
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark@2x.png
new file mode 100644
index 000000000..27f82c43d
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark~sel.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark~sel.png
new file mode 100644
index 000000000..794c57427
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark~sel.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark~sel@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark~sel@2x.png
new file mode 100644
index 000000000..13d9d8098
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~dark~sel@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~sel.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~sel.png
new file mode 100644
index 000000000..794c57427
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~sel.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~sel@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~sel@2x.png
new file mode 100644
index 000000000..13d9d8098
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-32~sel@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template.png
new file mode 100644
index 000000000..7850126cf
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template@2x.png
new file mode 100644
index 000000000..ec753d61d
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template~dark.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template~dark.png
new file mode 100644
index 000000000..31d481db8
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template~dark.png differ
diff --git a/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template~dark@2x.png b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template~dark@2x.png
new file mode 100644
index 000000000..af09fc185
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/IDE/VisualStudioForMac/project-monogame-template~dark@2x.png differ
diff --git a/Libraries/MonoGame.Framework/Src/ISSUE_TEMPLATE.md b/Libraries/MonoGame.Framework/Src/ISSUE_TEMPLATE.md
new file mode 100644
index 000000000..dd46643a6
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/ISSUE_TEMPLATE.md
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+#### What version of MonoGame does the bug occur on:
+- MonoGame 3.7
+
+#### What operating system are you using:
+- Windows
+
+#### What MonoGame platform are you using:
+
+- DesktopGL
diff --git a/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/mgcb.1 b/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/mgcb.1
new file mode 100644
index 000000000..bd3819d6f
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/mgcb.1
@@ -0,0 +1,182 @@
+.TH MGCB 1 "October 2017" "MonoGame 3.7"
+
+.SH NAME
+mgcb \- builds optimized game content for MonoGame projects
+
+.SH SYNOPSIS
+.B mgcb
+[\fR\fIOPTIONS\fR]
+.\".IR file ...
+
+.SH DESCRIPTION
+.B mgcb
+is a command line tool for building XNB content on Windows, Mac, and Linux desktop systems.
+
+Typically it is executed by the Pipeline GUI tool when editing content or indirectly from Visual Studio or MonoDevelop during the build process of a MonoGame project. Alternatively you can use it yourself from the command line for specialized build pipelines or for debugging content processing.
+
+.TP
+.BR \fIFILENAME\fR
+Automatically selects either --build or --@ option, depending on the file extension. See below for more detail on what these options are.
+
+.TP
+.BR \-@ ", " \-\-@ =\fIRESPONSEFILE\fR
+Read a text response file with additional command line options and switches.
+
+.TP
+.BR \-b ", " \-\-build =\fISOURCEFILE\fR;\fIDESTINATIONFILE\fR
+Build the content source file using the previously set switches and options. Optional destination path may be specified if you want to change the output filepath.
+
+.TP
+.BR \-c ", " \-\-clean
+Delete all previously built content and intermediate files.
+
+.TP
+.BR \-\-compress
+Compress the XNB files for smaller file sizes.
+
+.TP
+.BR \-\-config =\fISTRING\fR
+The optional build config string from the build system.
+
+.TP
+.BR \-\-copy =\fISOURCEFILE\fR
+Copy the content source file verbatim to the output directory.
+
+.TP
+.BR \-h ", " \-\-help
+Displays help menu.
+
+.TP
+.BR \-i ", " \-\-importer =\fICLASSNAME\fR
+Defines the class name of the content importer for reading source content.
+
+.TP
+.BR \-I ", " \-\-incremental
+Skip cleaning files not included in the current build.
+
+.TP
+.BR \-n ", " \-\-intermediateDir =\fIPATH\fR
+The directory where all intermediate files are written. See below for path macros.
+
+.TP
+.BR \-d ", " \-\-launchdebugger
+Wait for debugger to attach before building content.
+
+.TP
+.BR \-o ", " \-\-outputDir =\fIPATH\fR
+The directory where all content is written. See below for path macros.
+
+.TP
+.BR \-t ", " \-\-platform =\fITARGETPLATFORM\fR
+Set the target platform for this build. Defaults to Windows desktop DirectX.
+
+The following is the list of available target platforms:
+.RS
+.TP 20
+.BR Windows
+Windows DirectX desktop platform.
+.TP 20
+.BR Xbox360
+Xbox 360 platform.
+.TP 20
+.BR iOS
+iOS platform.
+.TP 20
+.BR Android
+Android platform.
+.TP 20
+.BR DesktopGL
+OpenGL desktop platform.
+.TP 20
+.BR MacOSX
+MacOSX platform
+.TP 20
+.BR WindowsStoreApp
+UWP platform.
+.TP 20
+.BR NativeClient
+Web native client platform.
+.TP 20
+.BR PlayStationMobile
+PlayStation mobile platform.
+.TP 20
+.BR WindowsPhone8
+Windows Phone 8 platform.
+.TP 20
+.BR RaspberryPi
+Raspberry Pi platform.
+.TP 20
+.BR PlayStation4
+PlayStation 4 platform.
+.TP 20
+.BR PSVita
+PlayStation Vita platform.
+.TP 20
+.BR XboxOne
+Xbox One platform.
+.TP 20
+.BR Switch
+Nintendo Switch platform.
+.RE
+
+.TP
+.BR \-p ", " \-\-processor =\fICLASSNAME\fR
+Defines the class name of the content processor for processing imported content.
+
+.TP
+.BR \-P ", " \-\-processorParam =\fINAME:VALUE\fR
+Defines a parameter name and value to set on a content processor.
+
+.TP
+.BR \-g ", " \-\-profile =\fIGRAPHICSPROFILE\fR
+Set the target graphics profile for this build. Defaults to HiDef.
+
+The following is the list of available graphics profiles:
+.RS
+.TP 8
+.BR Reach
+Use a limited set of graphic features and capabilities, allowing the game to support the widest variety of devices.
+.TP 8
+.BR HiDef
+Use the largest available set of graphic features and capabilities to target devices, that have more enhanced graphic capabilities.
+.RE
+
+.TP
+.BR \-q ", " \-\-quiet
+Only output content build errors.
+
+.TP
+.BR \-r ", " \-\-rebuild
+Forces a full rebuild of all content.
+
+.TP
+.BR \-f ", " \-\-reference =\fIASSEMBLY\fR
+Adds an assembly reference for resolving content importers, processors, and writers.
+
+.TP
+.BR \-w ", " \-\-workingDir =\fIDIRECTORYPATH\fR
+The working directory where all source content is located.
+
+.TP
+All command can be also called using / instead of \-\- or \-, this is to ensure compatibility between executing the command from Windows and Unix.
+
+.SH PATH MACROS
+The following is a list of custom path macros:
+
+.TP
+.BR $(Platform)
+Gets replaced by the target platform.
+
+.TP
+.BR $(Configuration)\ /\ $(Config)
+Gets replaced by the current config string.
+
+.TP
+.BR $(Profile)
+Gets replaced by the current graphics profile.
+
+.SH SEE ALSO
+.TP
+More documentation is available at:
+
+
diff --git a/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/mgcbcomplete b/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/mgcbcomplete
new file mode 100644
index 000000000..9bd811fb6
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/mgcbcomplete
@@ -0,0 +1,85 @@
+# MGCB autocomplete for bash
+
+function _mgcbcomplete()
+{
+ local cur prev
+ _get_comp_words_by_ref -n = cur prev
+
+ case "$cur" in
+ "--platform="* | "-t="* | "/platform="* | "/t="*)
+ COMPREPLY=($(compgen -W "Windows Xbox360 iOS Android DesktopGL \
+ MacOSX WindowsStoreApp NativeClient \
+ PlayStationMobile WindowsPhone8 RaspberryPi \
+ PlayStation4 PSVita XboxOne Switch" -- ${cur#*=}))
+ compopt +o nospace
+ return 0;
+ ;;
+ "--profile="* | "-p="* | "/profile="* | "/p="*)
+ COMPREPLY=($(compgen -W "Reach HiDef" -- ${cur#*=}))
+ compopt +o nospace
+ return 0;
+ ;;
+ "--build="* | "--outputDir="* | "--intermediateDir="* | \
+ "--workingDir="* | "--copy="* | "--reference"* | "--@="* | \
+ "-b="* | "-o="* | "-n="* | "-w="* | "-f="* | "-@="* | \
+ "/build="* | "/outputDir="* | "/intermediateDir="* | \
+ "/workingDir="* | "/copy="* | "/reference"* | \
+ "/b="* | "/o="* | "/n="* | "/w="* | "/f="* | "/@="*)
+ COMPREPLY=()
+ return 0
+ ;;
+ "--config=" | "/config=")
+ return 0;
+ ;;
+ "--processor=" | "--importer=" | "--processorParam=" | \
+ "/processor=" | "/importer=" | "/processorParam=")
+ # TODO
+ return 0;
+ ;;
+ "-b" | "-o" | "-n" | "-w" | "-f" | "-@" | \
+ "-q" | "-t" | "-p" | "-P" | "-i" | \
+ "/b" | "/o" | "/n" | "/w" | "/f" | "/@" | \
+ "/q" | "/t" | "/p" | "/P" | "/i")
+ COMPREPLY=("$cur=")
+ return 0;
+ ;;
+ "-c" | "-h" | "-I" | "-d" | "-q" | "-r" | \
+ "/c" | "/h" | "/I" | "/d" | "/q" | "/r")
+ COMPREPLY=("$cur")
+ compopt +o nospace
+ return 0;
+ ;;
+ esac
+
+ if [[ "$cur" == "--"* ]]
+ then
+ COMPREPLY=($(compgen -W "--@= --build= --clean --compress --config= --copy= \
+ --help --importer= --incremental --intermediateDir= \
+ --launchdebugger --outputDir= --platform= --processor= \
+ --processorParam= --profile= --quiet --rebuild \
+ --reference= --workingDir=" -- $cur))
+ if [[ ${COMPREPLY[0]} != *"=" ]]
+ then
+ compopt +o nospace
+ fi
+
+ return 0;
+ fi
+
+ if [[ "$cur" == "/"* ]]
+ then
+ COMPREPLY=($(compgen -W "/@= /build= /clean /compress /config= /copy= \
+ /help /importer= /incremental /intermediateDir= \
+ /launchdebugger /outputDir= /platform= /processor= \
+ /processorParam= /profile= /quiet /rebuild \
+ /reference= /workingDir=" -- $cur))
+ if [[ ${COMPREPLY[0]} != *"=" ]]
+ then
+ compopt +o nospace
+ fi
+
+ return 0;
+ fi
+}
+
+complete -o nospace -o default -F _mgcbcomplete mgcb
diff --git a/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/monogame.svg b/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/monogame.svg
new file mode 100644
index 000000000..2eeb089c1
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/monogame.svg
@@ -0,0 +1,63 @@
+
+
+
+
+
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/x-mgcb.xml b/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/x-mgcb.xml
new file mode 100644
index 000000000..b710c2f53
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/Linux/Main/x-mgcb.xml
@@ -0,0 +1,9 @@
+
+
+
+ MonoGame Pipeline Project
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/Installers/Linux/RUN/postinstall.sh b/Libraries/MonoGame.Framework/Src/Installers/Linux/RUN/postinstall.sh
new file mode 100644
index 000000000..71342ff64
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/Linux/RUN/postinstall.sh
@@ -0,0 +1,143 @@
+#!/bin/bash
+
+# Functions
+echodep()
+{
+ line=" - $1"
+
+ while [ ${#line} -lt 50 ]
+ do
+ line="$line."
+ done
+
+ echo -ne "$line"
+
+ if eval "$2"
+ then
+ echo -e "\e[32m[Found]\e[0m"
+ else
+ echo -e "\e[31m[Not Found]\e[0m"
+ fi
+}
+
+# Check installation priviledge
+if [ "$(id -u)" != "0" ]; then
+ echo "Please make sure you are running this installer with sudo or as root." 1>&2
+ exit 1
+fi
+
+DIR=$(pwd)
+IDIR="/usr/lib/mono/xbuild/MonoGame/v3.0"
+
+# Show dependency list
+echo "Dependencies:"
+echodep "mono-runtime" "type 'mono' > /dev/null 2>&1"
+echo ""
+read -p "Continue (Y, n): " choice2
+case "$choice2" in
+ n|N ) exit ;;
+ *) ;;
+esac
+
+# Check previous versions
+if type "mgcb" > /dev/null 2>&1
+then
+ echo "Previous version detected, trying to uninstall..."
+
+ # Try and uninstall previus versions
+ if [ -f /opt/monogame/uninstall.sh ]
+ then
+ sudo bash /opt/monogame/uninstall.sh
+ elif [ -f /opt/MonoGameSDK/uninstall.sh ]
+ then
+ sudo bash /opt/MonoGameSDK/uninstall.sh
+ else
+ echo "Could not uninstall, please uninstall any previous version of MonoGame SDK manually." 1>&2
+ exit 1
+ fi
+fi
+
+# MonoGame SDK installation
+echo "Installing MonoGame SDK..."
+
+rm -rf "$IDIR"
+mkdir -p "$IDIR"
+cp -rf "$DIR/MonoGameSDK/." "$IDIR" -R
+rm -rf "/opt/MonoGameSDK"
+ln -s "$IDIR" "/opt/MonoGameSDK"
+
+# Fix Permissions
+chmod +x "$IDIR/Tools/ffmpeg"
+chmod +x "$IDIR/Tools/ffprobe"
+
+# Monogame Pipeline terminal commands
+echo "Creating launcher items..."
+
+cat > /usr/bin/monogame-pipeline-tool <<'endmsg'
+#!/bin/bash
+mono /usr/lib/mono/xbuild/MonoGame/v3.0/Tools/Pipeline.exe "$@"
+endmsg
+chmod +x /usr/bin/monogame-pipeline-tool
+
+cat > /usr/bin/mgcb <<'endmsg'
+#!/bin/bash
+mono /usr/lib/mono/xbuild/MonoGame/v3.0/Tools/MGCB.exe "$@"
+endmsg
+chmod +x /usr/bin/mgcb
+cp "$DIR/Main/mgcbcomplete" "/etc/bash_completion.d/mgcb"
+
+# MonoGame icon
+mkdir -p /usr/share/icons/hicolor/scalable/mimetypes
+cp $DIR/Main/monogame.svg /usr/share/icons/hicolor/scalable/mimetypes/monogame.svg
+gtk-update-icon-cache /usr/share/icons/hicolor/ -f &> /dev/null
+
+# Application launcher
+cat > /usr/share/applications/MonogamePipeline.desktop <<'endmsg'
+[Desktop Entry]
+Version=1.0
+Encoding=UTF-8
+Name=MonoGame Pipeline Tool
+GenericName=MonoGame Pipeline Tool
+Comment=Creates platform specific content files.
+Exec=monogame-pipeline-tool %F
+TryExec=monogame-pipeline-tool
+Icon=monogame
+StartupNotify=true
+Terminal=false
+Type=Application
+MimeType=text/x-mgcb;
+Categories=Development;
+StartupWMClass=Pipeline
+endmsg
+
+# Man pages
+echo "Installing man pages..."
+IFS=':' read -r -a ARRAY <<< "$(manpath)"
+for MANPATH in "${ARRAY[@]}"
+do
+ if [ -d "$MANPATH/man1" ]
+ then
+ cp -f "$DIR/Main/mgcb.1" "$MANPATH/man1/mgcb.1"
+ gzip -f "$MANPATH/man1/mgcb.1"
+ break
+ fi
+done
+
+# Mimetype
+echo "Adding mimetype..."
+touch mgcb.xml
+xdg-mime uninstall mgcb.xml
+xdg-mime install $DIR/Main/x-mgcb.xml > /dev/null
+xdg-mime default "MonogamePipeline.desktop" text/mgcb
+
+# Uninstall script
+chmod +x $IDIR/uninstall.sh
+ln -s $IDIR/uninstall.sh /usr/bin/monogame-uninstall
+
+echo "Installation complete"
+echo ""
+echo " - To uninstall MonoGame SDK you can run 'monogame-uninstall' from terminal."
+echo " - To install templates for MonoDevelop, go Tools > Extensions > Gallery > Game Development > MonoGame Extensions, and install it."
+echo " - To install templates for Rider simply run 'dotnet new --install MonoGame.Templates.CSharp'"
+echo ""
+echo ""
diff --git a/Libraries/MonoGame.Framework/Src/Installers/Linux/RUN/uninstall.sh b/Libraries/MonoGame.Framework/Src/Installers/Linux/RUN/uninstall.sh
new file mode 100644
index 000000000..ecfbcd9bc
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/Linux/RUN/uninstall.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# Check removale priviledge
+if [ "$(id -u)" != "0" ]; then
+ echo "Please make sure you are running this uninstaller with sudo or as root." 1>&2
+ exit 1
+fi
+
+# Remove terminal commands for mgcb and pipeline tool
+rm -f /usr/bin/monogame-pipeline-tool
+rm -f /usr/bin/monogame-uninstall
+rm -f /usr/bin/mgcb
+rm -f /etc/bash_completion.d/mgcb
+
+# Remove application icon
+rm -rf /usr/share/icons/gnome/scalable/mimetypes/monogame.svg
+
+# Remove pipeline tool application launcher
+rm -rf /usr/share/applications/Monogame\ Pipeline.desktop
+
+# Remove mgcb mimetype
+touch /opt/MonoGameSDK/x-mgcb.xml
+xdg-mime uninstall /opt/MonoGameSDK/x-mgcb.xml
+
+# Remove MonoGame SDK
+rm -rf /usr/lib/mono/xbuild/MonoGame
+rm -rf /opt/MonoGameSDK
+
+# Remove man pages
+IFS=':' read -r -a ARRAY <<< "$(manpath)"
+for MANPATH in "${ARRAY[@]}"
+do
+ rm -rf "$MANPATH/man1/mgcb.1.gz"
+done
diff --git a/Libraries/MonoGame.Framework/Src/Installers/MacOS/Resources/App.icns b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Resources/App.icns
new file mode 100644
index 000000000..d5a254841
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Resources/App.icns differ
diff --git a/Libraries/MonoGame.Framework/Src/Installers/MacOS/Resources/background.png b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Resources/background.png
new file mode 100644
index 000000000..8d4e28a01
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Resources/background.png differ
diff --git a/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Addin/postinstall b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Addin/postinstall
new file mode 100644
index 000000000..381d3dd8f
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Addin/postinstall
@@ -0,0 +1,19 @@
+#!/bin/bash
+if [ -d "/Applications/Xamarin Studio.app" ]
+then
+ CONSOLE_USER=$(stat -f '%Su' /dev/console)
+ sudo -u $CONSOLE_USER /Applications/Xamarin\ Studio.app/Contents/MacOS/mdtool setup install /tmp/MonoDevelop.MonoGame_*.mpack -y
+fi
+if [ -d "/Applications/Visual Studio.app" ]
+then
+ CONSOLE_USER=$(stat -f '%Su' /dev/console)
+ sudo -u $CONSOLE_USER /Applications/Visual\ Studio.app/Contents/MacOS/vstool setup install /tmp/MonoDevelop.MonoGame_IDE_VisualStudioForMac_*.mpack -y
+fi
+if [ -f "/tmp/MonoDevelop.MonoGame_*.mpack" ]
+then
+ sudo rm /tmp/MonoDevelop.MonoGame_*.mpack
+fi
+if [ -f "/tmp/MonoDevelop.MonoGame_IDE_VisualStudioForMac_*.mpack" ]
+then
+ sudo rm /tmp/MonoDevelop.MonoGame_IDE_VisualStudioForMac_*.mpack
+fi
diff --git a/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Framework/postinstall.in b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Framework/postinstall.in
new file mode 100644
index 000000000..e1f88a0bd
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Framework/postinstall.in
@@ -0,0 +1,2 @@
+#!/bin/bash
+
diff --git a/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Pipeline/postinstall b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Pipeline/postinstall
new file mode 100644
index 000000000..33ba7f1ef
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/MacOS/Scripts/Pipeline/postinstall
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+#fix permissions
+chmod +x /Applications/Pipeline.app/Contents/MacOS/Pipeline
+chmod +x /Applications/Pipeline.app/Contents/MonoBundle/ffmpeg
+chmod +x /Applications/Pipeline.app/Contents/MonoBundle/ffprobe
+chmod +x /Applications/Pipeline.app/Contents/MonoBundle/mono
+/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -v -f /Applications/Pipeline.app
+
+#mgcb terminal command
+if [ ! -d /usr/local/bin ]
+then
+ if [ ! -d /usr/local ]
+ then
+ mkdir /usr/local
+ fi
+ chgrp -R admin /usr/local
+ chmod -R 755 /usr/local
+ mkdir /usr/local/bin
+fi
+if [ -f /usr/local/bin/mgcb ]
+then
+ rm /usr/local//bin/mgcb
+fi
+echo "#!/bin/bash
+mono /Applications/Pipeline.app/Contents/MonoBundle/MGCB.exe \"\$@\"" >> /usr/local/bin/mgcb
+chmod u+x /usr/local/bin/mgcb
+#write an uninstaller
+if [ -f /usr/local/bin/monogame-uninstall ]
+then
+ rm /usr/local/bin/monogame-uninstall
+fi
+echo "#!/bin/bash
+
+sudo rm -Rf '/Applicatons/Pipeline.app/'
+sudo pkgutil --forget com.monogame.pipeline
+if [ -d '/Applications/Xamarin Studio.app' ]
+then
+ /Applications/Xamarin\ Studio.app/Contents/MacOS/mdtool setup uninstall MonoDevelop.MonoGame -y
+fi
+if [ ! -d '/Library/Frameworks/Mono.framework/Versions/4.6.2' ]
+ ln -s /Library/Frameworks/Mono.framework/Versions/Current /Library/Frameworks/Mono.framework/Versions/4.6.2
+fi
+sudo rm /usr/local/bin/mgcb
+sudo rm /usr/local/bin/monogame-uninstall
+" >> /usr/local/bin/monogame-uninstall
+chmod +x /usr/local/bin/monogame-uninstall
diff --git a/Libraries/MonoGame.Framework/Src/Installers/MacOS/distribution.xml b/Libraries/MonoGame.Framework/Src/Installers/MacOS/distribution.xml
new file mode 100644
index 000000000..b67ccce00
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/MacOS/distribution.xml
@@ -0,0 +1,30 @@
+
+
+ MonoGame 0.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pipeline.MacOS.pkg
+
+
+
+ MonoGame.XamarinStudio.Addin.pkg
+
+
+
+ MonoGame.framework.pkg
+
diff --git a/Libraries/MonoGame.Framework/Src/Installers/Windows/MonoGame.nsi b/Libraries/MonoGame.Framework/Src/Installers/Windows/MonoGame.nsi
new file mode 100644
index 000000000..55d010943
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/Windows/MonoGame.nsi
@@ -0,0 +1,396 @@
+SetCompressor /SOLID /FINAL lzma
+
+!include "header.nsh"
+!define APPNAME "MonoGame"
+
+;Include Modern UI
+
+!include "Sections.nsh"
+!include "MUI2.nsh"
+!include "InstallOptions.nsh"
+
+!define MUI_ICON "${FrameworkPath}\monogame.ico"
+
+!define MUI_UNICON "${FrameworkPath}\monogame.ico"
+
+Name '${APPNAME} SDK ${INSTALLERVERSION}'
+OutFile 'MonoGameSetup.exe'
+InstallDir '$PROGRAMFILES\${APPNAME}\v${VERSION}'
+!define MSBuildInstallDir '$PROGRAMFILES32\MSBuild\${APPNAME}\v${VERSION}'
+VIProductVersion "${INSTALLERVERSION}"
+VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "${APPNAME} SDK"
+VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "The MonoGame Team"
+VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${INSTALLERVERSION}"
+VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductVersion" "${INSTALLERVERSION}"
+VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "${APPNAME} SDK Installer"
+VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "Copyright © The MonoGame Team"
+
+; Request application privileges for Windows Vista
+RequestExecutionLevel admin
+
+;Interface Configuration
+
+!define MUI_HEADERIMAGE
+!define MUI_HEADERIMAGE_BITMAP "${FrameworkPath}\monogame.bmp"
+!define MUI_ABORTWARNING
+
+!define MUI_WELCOMEFINISHPAGE_BITMAP "${FrameworkPath}\panel.bmp"
+;Languages
+
+!insertmacro MUI_PAGE_WELCOME
+
+!insertmacro MUI_PAGE_LICENSE "..\..\License.txt"
+
+!insertmacro MUI_PAGE_COMPONENTS
+!insertmacro MUI_PAGE_INSTFILES
+
+!insertmacro MUI_PAGE_FINISH
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+
+
+!macro VS_ASSOCIATE_EDITOR TOOLNAME VSVERSION EXT TOOLPATH
+ WriteRegStr HKCU 'Software\Microsoft\VisualStudio\${VSVERSION}\Default Editors\${EXT}' 'Custom' '${TOOLNAME}'
+ WriteRegDWORD HKCU 'Software\Microsoft\VisualStudio\${VSVERSION}\Default Editors\${EXT}' 'Type' 0x00000002
+ WriteRegStr HKCU 'Software\Microsoft\VisualStudio\${VSVERSION}\Default Editors\${EXT}\${TOOLNAME}' '' '${TOOLPATH}'
+ WriteRegStr HKCU 'Software\Microsoft\VisualStudio\${VSVERSION}\Default Editors\${EXT}\${TOOLNAME}' 'Arguments' ''
+!macroend
+
+!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND
+ WriteRegStr HKCR ".${EXT}" "" "${FILECLASS}"
+ WriteRegStr HKCR "${FILECLASS}" "" `${DESCRIPTION}`
+ WriteRegStr HKCR "${FILECLASS}\DefaultIcon" "" `${ICON}`
+ WriteRegStr HKCR "${FILECLASS}\shell" "" "open"
+ WriteRegStr HKCR "${FILECLASS}\shell\open" "" `${COMMANDTEXT}`
+ WriteRegStr HKCR "${FILECLASS}\shell\open\command" "" `${COMMAND}`
+!macroend
+
+;--------------------------------
+;Languages
+
+!insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+
+; The stuff to install
+Section "MonoGame Core Components" CoreComponents ;No components page, name is not important
+ SectionIn RO
+
+ ; Install the VS support files.
+ SetOutPath ${MSBuildInstallDir}
+ File '..\..\MonoGame.Framework.Content.Pipeline\MonoGame.Content.Builder.targets'
+ File '..\..\MonoGame.Framework.Content.Pipeline\MonoGame.Common.props'
+ File '..\..\Tools\Pipeline\bin\Windows\AnyCPU\Release\MonoGame.Build.Tasks.dll'
+
+ ; Install the MonoGame tools to a single shared folder.
+ SetOutPath ${MSBuildInstallDir}\Tools
+ File /r '..\..\Tools\2MGFX\bin\Windows\AnyCPU\Release\*.exe'
+ File /r '..\..\Tools\2MGFX\bin\Windows\AnyCPU\Release\*.dll'
+ File /r '..\..\Tools\MGCB\bin\Windows\AnyCPU\Release\*.exe'
+ File /r '..\..\Tools\MGCB\bin\Windows\AnyCPU\Release\*.dll'
+ File /r '..\..\Tools\Pipeline\bin\Windows\AnyCPU\Release\*.exe'
+ File /r '..\..\Tools\Pipeline\bin\Windows\AnyCPU\Release\*.dll'
+ File /r '..\..\Tools\Pipeline\bin\Windows\AnyCPU\Release\*.xml'
+ File /r '..\..\Tools\Pipeline\bin\Windows\AnyCPU\Release\Templates'
+
+ ; Associate .mgcb files open in the Pipeline tool.
+ !insertmacro VS_ASSOCIATE_EDITOR 'MonoGame Pipeline' '10.0' 'mgcb' '${MSBuildInstallDir}\Tools\Pipeline.exe'
+ !insertmacro VS_ASSOCIATE_EDITOR 'MonoGame Pipeline' '11.0' 'mgcb' '${MSBuildInstallDir}\Tools\Pipeline.exe'
+ !insertmacro VS_ASSOCIATE_EDITOR 'MonoGame Pipeline' '12.0' 'mgcb' '${MSBuildInstallDir}\Tools\Pipeline.exe'
+ !insertmacro VS_ASSOCIATE_EDITOR 'MonoGame Pipeline' '14.0' 'mgcb' '${MSBuildInstallDir}\Tools\Pipeline.exe'
+ !insertmacro VS_ASSOCIATE_EDITOR 'MonoGame Pipeline' '15.0' 'mgcb' '${MSBuildInstallDir}\Tools\Pipeline.exe'
+ !insertmacro APP_ASSOCIATE 'mgcb' 'MonoGame.ContentBuilderFile' 'A MonoGame content builder project.' '${MSBuildInstallDir}\Tools\Pipeline.exe,0' 'Open with Pipeline' '${MSBuildInstallDir}\Tools\Pipeline.exe "%1"'
+
+ ; Install the assemblies for all the platforms we can
+ ; target from a Windows desktop system.
+
+ ; Install Android Assemblies
+ SetOutPath '$INSTDIR\Assemblies\Android'
+ File '..\..\MonoGame.Framework\bin\Android\AnyCPU\Release\*.dll'
+ File '..\..\MonoGame.Framework\bin\Android\AnyCPU\Release\*.xml'
+
+ ; Install DesktopGL Assemblies
+ SetOutPath '$INSTDIR\Assemblies\DesktopGL'
+ File /nonfatal '..\..\MonoGame.Framework\bin\WindowsGL\AnyCPU\Release\*.dll'
+ File /nonfatal ' ..\..\MonoGame.Framework\bin\WindowsGL\AnyCPU\Release\*.xml'
+ File '..\..\ThirdParty\Dependencies\SDL\MacOS\Universal\libSDL2-2.0.0.dylib'
+ File '..\..\ThirdParty\Dependencies\openal-soft\MacOS\Universal\libopenal.1.dylib'
+ File '..\..\ThirdParty\Dependencies\MonoGame.Framework.dll.config'
+
+ ; Install x86 DesktopGL Dependencies
+ SetOutPath '$INSTDIR\Assemblies\DesktopGL\x86'
+ File '..\..\ThirdParty\Dependencies\SDL\Windows\x86\SDL2.dll'
+ File '..\..\ThirdParty\Dependencies\openal-soft\Windows\x86\soft_oal.dll'
+ File '..\..\ThirdParty\Dependencies\SDL\Linux\x86\libSDL2-2.0.so.0'
+ File '..\..\ThirdParty\Dependencies\openal-soft\Linux\x86\libopenal.so.1'
+
+ ; Install x64 DesktopGL Dependencies
+ SetOutPath '$INSTDIR\Assemblies\DesktopGL\x64'
+ File '..\..\ThirdParty\Dependencies\SDL\Windows\x64\SDL2.dll'
+ File '..\..\ThirdParty\Dependencies\openal-soft\Windows\x64\soft_oal.dll'
+ File '..\..\ThirdParty\Dependencies\SDL\Linux\x64\libSDL2-2.0.so.0'
+ File '..\..\ThirdParty\Dependencies\openal-soft\Linux\x64\libopenal.so.1'
+
+ ; Install Windows Desktop DirectX Assemblies
+ SetOutPath '$INSTDIR\Assemblies\Windows'
+ File '..\..\MonoGame.Framework\bin\Windows\AnyCPU\Release\*.dll'
+ File '..\..\MonoGame.Framework\bin\Windows\AnyCPU\Release\*.xml'
+
+ ; Install Windows 10 UAP Assemblies
+ SetOutPath '$INSTDIR\Assemblies\WindowsUniversal'
+ File '..\..\MonoGame.Framework\bin\WindowsUniversal\AnyCPU\Release\*.dll'
+ File '..\..\MonoGame.Framework\bin\WindowsUniversal\AnyCPU\Release\*.xml'
+
+ ; Install iOS Assemblies
+ IfFileExists `$PROGRAMFILES\MSBuild\Xamarin\iOS\*.*` InstalliOSAssemblies SkipiOSAssemblies
+ InstalliOSAssemblies:
+ SetOutPath '$INSTDIR\Assemblies\iOS'
+ File '..\..\MonoGame.Framework\bin\iOS\iPhoneSimulator\Release\*.dll'
+ File '..\..\MonoGame.Framework\bin\iOS\iPhoneSimulator\Release\*.xml'
+ SetOutPath '$INSTDIR\Assemblies\tvOS'
+ File '..\..\MonoGame.Framework\bin\tvOS\iPhoneSimulator\Release\*.dll'
+ File '..\..\MonoGame.Framework\bin\tvOS\iPhoneSimulator\Release\*.xml'
+ SkipiOSAssemblies:
+
+ WriteRegStr HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Desktop OpenGL' '' '$INSTDIR\Assemblies\DesktopGL'
+ WriteRegStr HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows' '' '$INSTDIR\Assemblies\Windows'
+ WriteRegStr HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows 10 Universal' '' '$INSTDIR\Assemblies\WindowsUniversal'
+ WriteRegStr HKLM 'SOFTWARE\Microsoft\MonoAndroid\v2.3\AssemblyFoldersEx\${APPNAME} for Android' '' '$INSTDIR\Assemblies\Android'
+ WriteRegStr HKLM 'SOFTWARE\Microsoft\MonoTouch\v1.0\AssemblyFoldersEx\${APPNAME} for iOS' '' '$INSTDIR\Assemblies\iOS'
+
+ IfFileExists $WINDIR\SYSWOW64\*.* Is64bit Is32bit
+ Is32bit:
+ GOTO End32Bitvs64BitCheck
+ Is64bit:
+ WriteRegStr HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Desktop OpenGL' '' '$INSTDIR\Assemblies\DesktopGL'
+ WriteRegStr HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows' '' '$INSTDIR\Assemblies\Windows'
+ WriteRegStr HKLM 'SOFTWARE\Wow6432Node\Microsoft\MonoTouch\v1.0\AssemblyFoldersEx\${APPNAME} for iOS' '' '$INSTDIR\Assemblies\iOS'
+ WriteRegStr HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows 10 Universal' '' '$INSTDIR\Assemblies\WindowsUniversal'
+
+ End32Bitvs64BitCheck:
+ ; Add remote programs
+ WriteRegStr HKLM 'Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}' 'DisplayName' '${APPNAME} SDK'
+ WriteRegStr HKLM 'Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}' 'DisplayVersion' '${INSTALLERVERSION}'
+ WriteRegStr HKLM 'Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}' 'DisplayIcon' '$INSTDIR\monogame.ico'
+ WriteRegStr HKLM 'Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}' 'InstallLocation' '$INSTDIR\'
+ WriteRegStr HKLM 'Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}' 'Publisher' 'The MonoGame Team'
+ WriteRegStr HKLM 'Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}' 'UninstallString' '$INSTDIR\uninstall.exe'
+
+
+ SetOutPath '$INSTDIR'
+ File '..\monogame.ico'
+
+ ; Uninstaller
+ WriteUninstaller "uninstall.exe"
+
+
+SectionEnd
+
+Section "Visual Studio 2010 Templates" VS2010
+
+ IfFileExists `$DOCUMENTS\Visual Studio 2010\Templates\ProjectTemplates\*.*` InstallTemplates CannotInstallTemplates
+ InstallTemplates:
+ SetOutPath "$DOCUMENTS\Visual Studio 2010\Templates\ProjectTemplates\Visual C#\MonoGame"
+ File /r '..\..\ProjectTemplates\VisualStudio2010\*.zip'
+ GOTO EndTemplates
+ CannotInstallTemplates:
+ DetailPrint "Visual Studio 2010 not found"
+ EndTemplates:
+
+SectionEnd
+
+Section "Visual Studio 2013 Templates" VS2013
+
+ IfFileExists `$DOCUMENTS\Visual Studio 2013\Templates\ProjectTemplates\*.*` InstallTemplates CannotInstallTemplates
+ InstallTemplates:
+ SetOutPath "$DOCUMENTS\Visual Studio 2013\Templates\ProjectTemplates\Visual C#\MonoGame"
+ File /r '..\..\ProjectTemplates\VisualStudio2013\*.zip'
+ File /r '..\..\ProjectTemplates\VisualStudio2010\*.zip'
+ GOTO EndTemplates
+ CannotInstallTemplates:
+ DetailPrint "Visual Studio 2013 not found"
+ EndTemplates:
+
+SectionEnd
+
+Section "Visual Studio 2015 Templates" VS2015
+
+ IfFileExists `$DOCUMENTS\Visual Studio 2015\Templates\ProjectTemplates\*.*` InstallTemplates CannotInstallTemplates
+ InstallTemplates:
+ SetOutPath "$DOCUMENTS\Visual Studio 2015\Templates\ProjectTemplates\Visual C#\MonoGame"
+ File /r '..\..\ProjectTemplates\VisualStudio2010\*.zip'
+ File /r '..\..\ProjectTemplates\VisualStudio2015\*.zip'
+ GOTO EndTemplates
+ CannotInstallTemplates:
+ DetailPrint "Visual Studio 2015 not found"
+ EndTemplates:
+
+SectionEnd
+
+Section "Visual Studio 2017 Templates" VS2017
+
+ IfFileExists `$DOCUMENTS\Visual Studio 2017\Templates\ProjectTemplates\*.*` InstallTemplates CannotInstallTemplates
+ InstallTemplates:
+ SetOutPath "$DOCUMENTS\Visual Studio 2017\Templates\ProjectTemplates\Visual C#\MonoGame"
+ File /r '..\..\ProjectTemplates\VisualStudio2010\*.zip'
+ File /r '..\..\ProjectTemplates\VisualStudio2013\MonoGameShared.zip'
+ File /r '..\..\ProjectTemplates\VisualStudio2015\WindowsUniversal10.VB.zip'
+ File /r '..\..\ProjectTemplates\VisualStudio2017\*.zip'
+ GOTO EndTemplates
+ CannotInstallTemplates:
+ DetailPrint "Visual Studio 2017 not found"
+ EndTemplates:
+
+SectionEnd
+
+; Optional section (can be disabled by the user)
+Section "Start Menu Shortcuts" Menu
+ CreateDirectory $SMPROGRAMS\${APPNAME}
+ SetOutPath "$INSTDIR"
+ CreateShortCut "$SMPROGRAMS\${APPNAME}\Uninstall MonoGame.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
+ SetOutPath "${MSBuildInstallDir}\Tools"
+ CreateShortCut "$SMPROGRAMS\${APPNAME}\MonoGame Pipeline.lnk" "${MSBuildInstallDir}\Tools\Pipeline.exe" "" "${MSBuildInstallDir}\Tools\Pipeline.exe" 0
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Website.url" "InternetShortcut" "URL" "http://www.monogame.net"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Website.url" "InternetShortcut" "IconFile" "$INSTDIR\monogame.ico"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Website.url" "InternetShortcut" "IconIndex" "0"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Documentation.url" "InternetShortcut" "URL" "http://www.monogame.net/documentation"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Documentation.url" "InternetShortcut" "IconFile" "$INSTDIR\monogame.ico"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Documentation.url" "InternetShortcut" "IconIndex" "0"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Support.url" "InternetShortcut" "URL" "http://community.monogame.net/"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Support.url" "InternetShortcut" "IconFile" "$INSTDIR\monogame.ico"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Support.url" "InternetShortcut" "IconIndex" "0"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Bug Reports.url" "InternetShortcut" "URL" "https://github.com/mono/MonoGame/issues"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Bug Reports.url" "InternetShortcut" "IconFile" "$INSTDIR\monogame.ico"
+ WriteINIStr "$SMPROGRAMS\${APPNAME}\MonoGame Bug Reports.url" "InternetShortcut" "IconIndex" "0"
+
+SectionEnd
+
+LangString CoreComponentsDesc ${LANG_ENGLISH} "Install the Runtimes and the MSBuild extensions for MonoGame"
+LangString MonoDevelopDesc ${LANG_ENGLISH} "Install the project templates for MonoDevelop"
+LangString VS2010Desc ${LANG_ENGLISH} "Install the project templates for Visual Studio 2010"
+LangString VS2012Desc ${LANG_ENGLISH} "Install the project templates for Visual Studio 2012"
+LangString VS2013Desc ${LANG_ENGLISH} "Install the project templates for Visual Studio 2013"
+LangString VS2015Desc ${LANG_ENGLISH} "Install the project templates for Visual Studio 2015"
+LangString VS2017Desc ${LANG_ENGLISH} "Install the project templates for Visual Studio 2017"
+LangString MenuDesc ${LANG_ENGLISH} "Add a link to the MonoGame website to your start menu"
+
+!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+ !insertmacro MUI_DESCRIPTION_TEXT ${CoreComponents} $(CoreComponentsDesc)
+ !insertmacro MUI_DESCRIPTION_TEXT ${MonoDevelop} $(MonoDevelopDesc)
+ !insertmacro MUI_DESCRIPTION_TEXT ${VS2010} $(VS2010Desc)
+ !insertmacro MUI_DESCRIPTION_TEXT ${VS2012} $(VS2012Desc)
+ !insertmacro MUI_DESCRIPTION_TEXT ${VS2013} $(VS2013Desc)
+ !insertmacro MUI_DESCRIPTION_TEXT ${VS2015} $(VS2015Desc)
+ !insertmacro MUI_DESCRIPTION_TEXT ${VS2017} $(VS2017Desc)
+ !insertmacro MUI_DESCRIPTION_TEXT ${Menu} $(MenuDesc)
+!insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+Function checkVS2010
+IfFileExists `$DOCUMENTS\Visual Studio 2010\Templates\ProjectTemplates\*.*` end disable
+ disable:
+ SectionSetFlags ${VS2010} $0
+ end:
+FunctionEnd
+
+Function checkVS2012
+IfFileExists `$DOCUMENTS\Visual Studio 2012\Templates\ProjectTemplates\*.*` end disable
+ disable:
+ SectionSetFlags ${VS2012} $0
+ end:
+FunctionEnd
+
+Function checkVS2013
+IfFileExists `$DOCUMENTS\Visual Studio 2013\Templates\ProjectTemplates\*.*` end disable
+ disable:
+ SectionSetFlags ${VS2013} $0
+ end:
+FunctionEnd
+
+Function checkVS2015
+IfFileExists `$DOCUMENTS\Visual Studio 2015\Templates\ProjectTemplates\*.*` end disable
+ disable:
+ SectionSetFlags ${VS2015} $0
+ end:
+FunctionEnd
+
+Function checkVS2017
+IfFileExists `$DOCUMENTS\Visual Studio 2017\Templates\ProjectTemplates\*.*` end disable
+ disable:
+ SectionSetFlags ${VS2017} $0
+ end:
+FunctionEnd
+
+Function .onInit
+ IntOp $0 $0 | ${SF_RO}
+ Call checkVS2010
+ Call checkVS2012
+ Call checkVS2013
+ Call checkVS2015
+ Call checkVS2017
+ IntOp $0 ${SF_SELECTED} | ${SF_RO}
+ SectionSetFlags ${core_id} $0
+FunctionEnd
+
+;--------------------------------
+;Uninstaller Section
+
+Section "Uninstall"
+
+ DeleteRegKey HKLM 'Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Desktop OpenGL'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME}'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.5.50709\AssemblyFoldersEx\${APPNAME} for Windows Store'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.5.50709\AssemblyFoldersEx\${APPNAME} for Windows Phone 8.1'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows Phone ARM'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows Phone x86'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\.NETFramework\v4.5.50709\AssemblyFoldersEx\${APPNAME} for Windows 10 UAP'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\MonoAndroid\v2.3\AssemblyFoldersEx\${APPNAME} for Android'
+ DeleteRegKey HKLM 'SOFTWARE\Microsoft\MonoTouch\v1.0\AssemblyFoldersEx\${APPNAME} for iOS'
+
+ DeleteRegKey HKCU 'Software\Microsoft\VisualStudio\10.0\Default Editors\mgcb'
+ DeleteRegKey HKCU 'Software\Microsoft\VisualStudio\11.0\Default Editors\mgcb'
+ DeleteRegKey HKCU 'Software\Microsoft\VisualStudio\12.0\Default Editors\mgcb'
+
+ DeleteRegKey HKCR '.mgcb'
+ DeleteRegKey HKCR 'MonoGame.ContentBuilderFile'
+
+ IfFileExists $WINDIR\SYSWOW64\*.* Is64bit Is32bit
+ Is32bit:
+ GOTO End32Bitvs64BitCheck
+ Is64bit:
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Desktop OpenGL'
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows'
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.5.50709\AssemblyFoldersEx\${APPNAME} for Windows Store'
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.5.50709\AssemblyFoldersEx\${APPNAME} for Windows Phone 8.1'
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows Phone ARM'
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows Phone x86'
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\${APPNAME} for Windows 10 UAP'
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\MonoAndroid\v2.3\AssemblyFoldersEx\${APPNAME} for Android'
+ DeleteRegKey HKLM 'SOFTWARE\Wow6432Node\Microsoft\MonoTouch\v1.0\AssemblyFoldersEx\${APPNAME} for iOS'
+
+
+ End32Bitvs64BitCheck:
+
+ ReadRegStr $0 HKLM 'SOFTWARE\Wow6432Node\Xamarin\MonoDevelop' "Path"
+ ${If} $0 == "" ; check on 32 bit machines just in case
+ ReadRegStr $0 HKLM 'SOFTWARE\Xamarin\MonoDevelop' "Path"
+ ${EndIf}
+
+ ${If} $0 == ""
+ ${Else}
+ RMDir /r "$0\AddIns\MonoDevelop.MonoGame"
+ ${EndIf}
+
+ RMDir /r "$DOCUMENTS\Visual Studio 2010\Templates\ProjectTemplates\Visual C#\MonoGame"
+ RMDir /r "$DOCUMENTS\Visual Studio 2013\Templates\ProjectTemplates\Visual C#\MonoGame"
+ RMDir /r "$DOCUMENTS\Visual Studio 2015\Templates\ProjectTemplates\Visual C#\MonoGame"
+ RMDir /r "$DOCUMENTS\Visual Studio 2017\Templates\ProjectTemplates\Visual C#\MonoGame"
+ RMDir /r "${MSBuildInstallDir}"
+ RMDir /r "$SMPROGRAMS\${APPNAME}"
+
+ Delete "$INSTDIR\Uninstall.exe"
+ RMDir /r "$INSTDIR"
+
+SectionEnd
+
diff --git a/Libraries/MonoGame.Framework/Src/Installers/default.build b/Libraries/MonoGame.Framework/Src/Installers/default.build
new file mode 100644
index 000000000..937791e0c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/Installers/default.build
@@ -0,0 +1,216 @@
+
+
+ Default Installer Automated Build script
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+!define FrameworkPath "${project::get-base-directory()}"
+!define VERSION "3.0"
+!define INSTALLERVERSION "${buildNumber}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if [ -d '/Library/Frameworks/MonoGame.framework/v3.0' ]
+then
+ rm /Library/Frameworks/MonoGame.framework/v3.0
+fi
+if [ -d '/Library/Frameworks/MonoGame.framework/Current' ]
+then
+ rm /Library/Frameworks/MonoGame.framework/Current
+fi
+ln -sf /Library/Frameworks/MonoGame.framework/v${buildNumber} /Library/Frameworks/MonoGame.framework/v3.0
+ln -sf /Library/Frameworks/MonoGame.framework/v${buildNumber} /Library/Frameworks/MonoGame.framework/Current
+#fix permissions
+chmod +x /Library/Frameworks/MonoGame.framework/Current/Tools/ffmpeg
+chmod +x /Library/Frameworks/MonoGame.framework/Current/Tools/ffprobe
+mkdir -p /Library/Frameworks/Mono.framework/External/xbuild
+if [ -d '/Library/Frameworks/Mono.framework/External/xbuild' ]
+then
+ ln -sf /Library/Frameworks/MonoGame.framework /Library/Frameworks/Mono.framework/External/xbuild/MonoGame
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libraries/MonoGame.Framework/Src/Installers/monogame.bmp b/Libraries/MonoGame.Framework/Src/Installers/monogame.bmp
new file mode 100644
index 000000000..01e834d79
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Installers/monogame.bmp differ
diff --git a/Libraries/MonoGame.Framework/Src/Installers/monogame.ico b/Libraries/MonoGame.Framework/Src/Installers/monogame.ico
new file mode 100644
index 000000000..7d9dec187
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Installers/monogame.ico differ
diff --git a/Libraries/MonoGame.Framework/Src/Installers/panel.bmp b/Libraries/MonoGame.Framework/Src/Installers/panel.bmp
new file mode 100644
index 000000000..3aaba45c2
Binary files /dev/null and b/Libraries/MonoGame.Framework/Src/Installers/panel.bmp differ
diff --git a/Libraries/MonoGame.Framework/Src/LICENSE.txt b/Libraries/MonoGame.Framework/Src/LICENSE.txt
new file mode 100644
index 000000000..7a22869e7
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/LICENSE.txt
@@ -0,0 +1,86 @@
+Microsoft Public License (Ms-PL)
+MonoGame - Copyright © 2009-2018 The MonoGame Team
+
+All rights reserved.
+
+This license governs use of the accompanying software. If you use the software,
+you accept this license. If you do not accept the license, do not use the
+software.
+
+1. Definitions
+
+The terms "reproduce," "reproduction," "derivative works," and "distribution"
+have the same meaning here as under U.S. copyright law.
+
+A "contribution" is the original software, or any additions or changes to the
+software.
+
+A "contributor" is any person that distributes its contribution under this
+license.
+
+"Licensed patents" are a contributor's patent claims that read directly on its
+contribution.
+
+2. Grant of Rights
+
+(A) Copyright Grant- Subject to the terms of this license, including the
+license conditions and limitations in section 3, each contributor grants you a
+non-exclusive, worldwide, royalty-free copyright license to reproduce its
+contribution, prepare derivative works of its contribution, and distribute its
+contribution or any derivative works that you create.
+
+(B) Patent Grant- Subject to the terms of this license, including the license
+conditions and limitations in section 3, each contributor grants you a
+non-exclusive, worldwide, royalty-free license under its licensed patents to
+make, have made, use, sell, offer for sale, import, and/or otherwise dispose of
+its contribution in the software or derivative works of the contribution in the
+software.
+
+3. Conditions and Limitations
+
+(A) No Trademark License- This license does not grant you rights to use any
+contributors' name, logo, or trademarks.
+
+(B) If you bring a patent claim against any contributor over patents that you
+claim are infringed by the software, your patent license from such contributor
+to the software ends automatically.
+
+(C) If you distribute any portion of the software, you must retain all
+copyright, patent, trademark, and attribution notices that are present in the
+software.
+
+(D) If you distribute any portion of the software in source code form, you may
+do so only under this license by including a complete copy of this license with
+your distribution. If you distribute any portion of the software in compiled or
+object code form, you may only do so under a license that complies with this
+license.
+
+(E) The software is licensed "as-is." You bear the risk of using it. The
+contributors give no express warranties, guarantees or conditions. You may have
+additional consumer rights under your local laws which this license cannot
+change. To the extent permitted under your local laws, the contributors exclude
+the implied warranties of merchantability, fitness for a particular purpose and
+non-infringement.
+
+-------------------------------------------------------------------------------
+
+The MIT License (MIT)
+Portions Copyright © The Mono.Xna Team
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioContent.cs
new file mode 100644
index 000000000..7d361c409
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioContent.cs
@@ -0,0 +1,202 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Audio
+{
+ ///
+ /// Encapsulates and provides operations, such as format conversions, on the
+ /// source audio. This type is produced by the audio importers and used by audio
+ /// processors to produce compiled audio assets.
+ ///
+ /// Note that AudioContent can load and process audio files that are not supported by the importers.
+ public class AudioContent : ContentItem, IDisposable
+ {
+ private bool _disposed;
+ private readonly string _fileName;
+ private readonly AudioFileType _fileType;
+ private ReadOnlyCollection _data;
+ private TimeSpan _duration;
+ private AudioFormat _format;
+ private int _loopStart;
+ private int _loopLength;
+
+ ///
+ /// The name of the original source audio file.
+ ///
+ [ContentSerializer(AllowNull = false)]
+ public string FileName { get { return _fileName; } }
+
+ ///
+ /// The type of the original source audio file.
+ ///
+ public AudioFileType FileType { get { return _fileType; } }
+
+ ///
+ /// The current raw audio data without header information.
+ ///
+ ///
+ /// This changes from the source data to the output data after conversion.
+ /// For MP3 and WMA files this throws an exception to match XNA behavior.
+ ///
+ public ReadOnlyCollection Data
+ {
+ get
+ {
+ if (_disposed || _data == null)
+ throw new InvalidContentException("Could not read the audio data from file \"" + Path.GetFileName(_fileName) + "\".");
+ return _data;
+ }
+ }
+
+ ///
+ /// The duration of the audio data.
+ ///
+ public TimeSpan Duration
+ {
+ get
+ {
+ return _duration;
+ }
+ }
+
+ ///
+ /// The current format of the audio data.
+ ///
+ /// This changes from the source format to the output format after conversion.
+ public AudioFormat Format
+ {
+ get
+ {
+ return _format;
+ }
+ }
+
+ ///
+ /// The current loop length in samples.
+ ///
+ /// This changes from the source loop length to the output loop length after conversion.
+ public int LoopLength
+ {
+ get
+ {
+ return _loopLength;
+ }
+ }
+
+ ///
+ /// The current loop start location in samples.
+ ///
+ /// This changes from the source loop start to the output loop start after conversion.
+ public int LoopStart
+ {
+ get
+ {
+ return _loopStart;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of AudioContent.
+ ///
+ /// Name of the audio source file to be processed.
+ /// Type of the processed audio: WAV, MP3 or WMA.
+ /// Constructs the object from the specified source file, in the format specified.
+ public AudioContent(string audioFileName, AudioFileType audioFileType)
+ {
+ _fileName = audioFileName;
+
+ try
+ {
+ // Get the full path to the file.
+ audioFileName = Path.GetFullPath(audioFileName);
+
+ // Use probe to get the details of the file.
+ DefaultAudioProfile.ProbeFormat(audioFileName, out _fileType, out _format, out _duration, out _loopStart, out _loopLength);
+
+ // Looks like XNA only cares about type mismatch when
+ // the type is WAV... else it is ok.
+ if ( (audioFileType == AudioFileType.Wav || _fileType == AudioFileType.Wav) &&
+ audioFileType != _fileType)
+ throw new ArgumentException("Incorrect file type!", "audioFileType");
+
+ // Only provide the data for WAV files.
+ if (audioFileType == AudioFileType.Wav)
+ {
+ byte[] rawData;
+
+ // Must be opened in read mode otherwise it fails to open
+ // read-only files (found in some source control systems)
+ using (var fs = new FileStream(audioFileName, FileMode.Open, FileAccess.Read))
+ {
+ rawData = new byte[fs.Length];
+ fs.Read(rawData, 0, rawData.Length);
+ }
+
+ AudioFormat riffAudioFormat;
+ var stripped = DefaultAudioProfile.StripRiffWaveHeader(rawData, out riffAudioFormat);
+
+ if (riffAudioFormat != null)
+ {
+ if ((_format.Format != 2 && _format.Format != 17) && _format.BlockAlign != riffAudioFormat.BlockAlign)
+ throw new InvalidOperationException("Calculated block align does not match RIFF " + _format.BlockAlign + " : " + riffAudioFormat.BlockAlign);
+ if (_format.ChannelCount != riffAudioFormat.ChannelCount)
+ throw new InvalidOperationException("Probed channel count does not match RIFF: " + _format.ChannelCount + ", " + riffAudioFormat.ChannelCount);
+ if (_format.Format != riffAudioFormat.Format)
+ throw new InvalidOperationException("Probed audio format does not match RIFF: " + _format.Format + ", " + riffAudioFormat.Format);
+ if (_format.SampleRate != riffAudioFormat.SampleRate)
+ throw new InvalidOperationException("Probed sample rate does not match RIFF: " + _format.SampleRate + ", " + riffAudioFormat.SampleRate);
+ }
+
+ _data = Array.AsReadOnly(stripped);
+ }
+ }
+ catch (Exception ex)
+ {
+ var message = string.Format("Failed to open file {0}. Ensure the file is a valid audio file and is not DRM protected.", Path.GetFileNameWithoutExtension(audioFileName));
+ throw new InvalidContentException(message, ex);
+ }
+ }
+
+ ///
+ /// Transcodes the source audio to the target format and quality.
+ ///
+ /// Format to convert this audio to.
+ /// Quality of the processed output audio. For streaming formats, it can be one of the following: Low (96 kbps), Medium (128 kbps), Best (192 kbps). For WAV formats, it can be one of the following: Low (11kHz ADPCM), Medium (22kHz ADPCM), Best (44kHz PCM)
+ ///
+ /// The name of the file that the converted audio should be saved into. This is used for SongContent, where
+ /// the audio is stored external to the XNB file. If this is null, then the converted audio is stored in
+ /// the Data property.
+ ///
+ [Obsolete("You should prefer to use AudioProfile.")]
+ public void ConvertFormat(ConversionFormat formatType, ConversionQuality quality, string saveToFile)
+ {
+ // Call the legacy conversion code.
+ DefaultAudioProfile.ConvertToFormat(this, formatType, quality, saveToFile);
+ }
+
+ public void SetData(byte[] data, AudioFormat format, TimeSpan duration, int loopStart, int loopLength)
+ {
+ if (data == null)
+ throw new ArgumentNullException("data");
+ if (format == null)
+ throw new ArgumentNullException("format");
+
+ _data = Array.AsReadOnly(data);
+ _format = format;
+ _duration = duration;
+ _loopStart = loopStart;
+ _loopLength = loopLength;
+ }
+
+ public void Dispose()
+ {
+ _disposed = true;
+ _data = null;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioFileType.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioFileType.cs
new file mode 100644
index 000000000..bb3a8905b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioFileType.cs
@@ -0,0 +1,32 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Audio
+{
+ ///
+ /// Type of the audio file.
+ ///
+ public enum AudioFileType
+ {
+ ///
+ /// The MP3 format
+ ///
+ Mp3,
+
+ ///
+ /// The WAV format
+ ///
+ Wav,
+
+ ///
+ /// The WMA format
+ ///
+ Wma,
+
+ ///
+ /// The Ogg format
+ ///
+ Ogg,
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioFormat.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioFormat.cs
new file mode 100644
index 000000000..8a79ed7dc
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioFormat.cs
@@ -0,0 +1,108 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Audio
+{
+ ///
+ /// Encapsulates the native audio format (WAVEFORMATEX) information of the audio content.
+ ///
+ public sealed class AudioFormat
+ {
+ int averageBytesPerSecond;
+ int bitsPerSample;
+ int blockAlign;
+ int channelCount;
+ int format;
+ List nativeWaveFormat;
+ int sampleRate;
+
+ ///
+ /// Gets the average bytes processed per second.
+ ///
+ /// Average bytes processed per second.
+ public int AverageBytesPerSecond { get { return averageBytesPerSecond; } }
+
+ ///
+ /// Gets the bit depth of the audio content.
+ ///
+ /// If the audio has not been processed, the source bit depth; otherwise, the bit depth of the new format.
+ public int BitsPerSample { get { return bitsPerSample; } }
+
+ ///
+ /// Gets the number of bytes per sample block, taking channels into consideration. For example, for 16-bit stereo audio (PCM format), the size of each sample block is 4 bytes.
+ ///
+ /// Number of bytes, per sample block.
+ public int BlockAlign { get { return blockAlign; } }
+
+ ///
+ /// Gets the number of channels.
+ ///
+ /// If the audio has not been processed, the source channel count; otherwise, the new channel count.
+ public int ChannelCount { get { return channelCount; } }
+
+ ///
+ /// Gets the format of the audio content.
+ ///
+ /// If the audio has not been processed, the format tag of the source content; otherwise, the new format tag.
+ public int Format { get { return format; } }
+
+ ///
+ /// Gets the raw byte buffer for the format. For non-PCM formats, this buffer contains important format-specific information beyond the basic format information exposed in other properties of the AudioFormat type.
+ ///
+ /// The raw byte buffer represented in a collection.
+ public ReadOnlyCollection NativeWaveFormat { get { return nativeWaveFormat.AsReadOnly(); } }
+
+ ///
+ /// Gets the sample rate of the audio content.
+ ///
+ /// If the audio has not been processed, the source sample rate; otherwise, the new sample rate.
+ public int SampleRate { get { return sampleRate; } }
+
+ internal AudioFormat(
+ int averageBytesPerSecond,
+ int bitsPerSample,
+ int blockAlign,
+ int channelCount,
+ int format,
+ int sampleRate)
+ {
+ this.averageBytesPerSecond = averageBytesPerSecond;
+ this.bitsPerSample = bitsPerSample;
+ this.blockAlign = blockAlign;
+ this.channelCount = channelCount;
+ this.format = format;
+ this.sampleRate = sampleRate;
+
+ this.nativeWaveFormat = this.ConstructNativeWaveFormat();
+ }
+
+ private List ConstructNativeWaveFormat()
+ {
+ using (var memory = new MemoryStream())
+ {
+ using (var writer = new BinaryWriter(memory))
+ {
+ writer.Write((short)this.format);
+ writer.Write((short)this.channelCount);
+ writer.Write((int)this.sampleRate);
+ writer.Write((int)this.averageBytesPerSecond);
+ writer.Write((short)this.blockAlign);
+ writer.Write((short)this.bitsPerSample);
+ writer.Write((short)0);
+
+ var bytes = new byte[memory.Position];
+ memory.Seek(0, SeekOrigin.Begin);
+ memory.Read(bytes, 0, bytes.Length);
+ return bytes.ToList();
+ }
+ }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioHelper.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioHelper.cs
new file mode 100644
index 000000000..02f05239f
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioHelper.cs
@@ -0,0 +1,25 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Audio
+{
+ ///
+ /// Helper methods for audio importing, conversion and processing.
+ ///
+ class AudioHelper
+ {
+ // This array must remain in sync with the ConversionFormat enum.
+ static string[] conversionFormatExtensions = new[] { "wav", "wav", "wma", "xma", "wav", "m4a", "ogg" };
+
+ ///
+ /// Gets the file extension for an audio format.
+ ///
+ /// The conversion format
+ /// The file extension for the given conversion format.
+ static public string GetExtension(ConversionFormat format)
+ {
+ return conversionFormatExtensions[(int)format];
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioProfile.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioProfile.cs
new file mode 100644
index 000000000..56e66312a
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/AudioProfile.cs
@@ -0,0 +1,81 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Audio
+{
+ public abstract class AudioProfile
+ {
+ private static readonly LoadedTypeCollection _profiles = new LoadedTypeCollection();
+
+ ///
+ /// Find the profile for this target platform.
+ ///
+ /// The platform target for audio.
+ ///
+ public static AudioProfile ForPlatform(TargetPlatform platform)
+ {
+ var profile = _profiles.FirstOrDefault(h => h.Supports(platform));
+ if (profile != null)
+ return profile;
+
+ throw new PipelineException("There is no supported audio profile for the '" + platform + "' platform!");
+ }
+
+ ///
+ /// Returns true if this profile supports audio processing for this platform.
+ ///
+ public abstract bool Supports(TargetPlatform platform);
+
+ ///
+ /// Converts the audio content to work on targeted platform.
+ ///
+ /// The platform to build the audio content for.
+ /// The suggested audio quality level.
+ /// The audio content to convert.
+ /// The quality used for conversion which could be different from the suggested quality.
+ public abstract ConversionQuality ConvertAudio(TargetPlatform platform, ConversionQuality quality, AudioContent content);
+
+ ///
+ /// Converts the audio content to a streaming format that works on targeted platform.
+ ///
+ /// The platform to build the audio content for.
+ /// The suggested audio quality level.
+ /// he audio content to convert.
+ ///
+ /// The quality used for conversion which could be different from the suggested quality.
+ public abstract ConversionQuality ConvertStreamingAudio(TargetPlatform platform, ConversionQuality quality, AudioContent content, ref string outputFileName);
+
+
+ protected static int QualityToSampleRate(ConversionQuality quality, int sourceSampleRate)
+ {
+ switch (quality)
+ {
+ case ConversionQuality.Low:
+ return Math.Max(8000, (int)Math.Floor(sourceSampleRate / 2.0));
+ case ConversionQuality.Medium:
+ return Math.Max(8000, (int)Math.Floor((sourceSampleRate / 4.0) * 3));
+ }
+
+ return Math.Max(8000, sourceSampleRate);
+ }
+
+ protected static int QualityToBitRate(ConversionQuality quality)
+ {
+ switch (quality)
+ {
+ case ConversionQuality.Low:
+ return 96000;
+ case ConversionQuality.Medium:
+ return 128000;
+ }
+
+ return 192000;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/ConversionFormat.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/ConversionFormat.cs
new file mode 100644
index 000000000..8fcc095d7
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/ConversionFormat.cs
@@ -0,0 +1,47 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Audio
+{
+ ///
+ /// Target formats supported for audio source conversions.
+ ///
+ public enum ConversionFormat
+ {
+ ///
+ /// Microsoft ADPCM encoding technique using 4 bits
+ ///
+ Adpcm,
+
+ ///
+ /// 8/16-bit mono/stereo PCM audio 8KHz-48KHz
+ ///
+ Pcm,
+
+ ///
+ /// Windows Media CBR formats (64 kbps, 128 kbps, 192 kbps)
+ ///
+ WindowsMedia,
+
+ ///
+ /// The Xbox compression format
+ ///
+ Xma,
+
+ ///
+ /// QuickTime ADPCM format
+ ///
+ ImaAdpcm,
+
+ ///
+ /// Advanced Audio Coding
+ ///
+ Aac,
+
+ ///
+ /// Vorbis open, patent-free audio encoding
+ ///
+ Vorbis,
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/ConversionQuality.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/ConversionQuality.cs
new file mode 100644
index 000000000..682ffd158
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/ConversionQuality.cs
@@ -0,0 +1,27 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Audio
+{
+ ///
+ /// Compression quality of the audio content.
+ ///
+ public enum ConversionQuality
+ {
+ ///
+ /// High compression yielding lower file size, but could compromise audio quality
+ ///
+ Low,
+
+ ///
+ /// Moderate compression resulting in a compromise between audio quality and file size
+ ///
+ Medium,
+
+ ///
+ /// Lowest compression, but the best audio quality
+ ///
+ Best,
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/DefaultAudioProfile.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/DefaultAudioProfile.cs
new file mode 100644
index 000000000..81c9e053e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Audio/DefaultAudioProfile.cs
@@ -0,0 +1,442 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Audio
+{
+ internal class DefaultAudioProfile : AudioProfile
+ {
+ public override bool Supports(TargetPlatform platform)
+ {
+ return platform == TargetPlatform.Android ||
+ platform == TargetPlatform.DesktopGL ||
+ platform == TargetPlatform.MacOSX ||
+ platform == TargetPlatform.NativeClient ||
+ platform == TargetPlatform.RaspberryPi ||
+ platform == TargetPlatform.Windows ||
+ platform == TargetPlatform.WindowsPhone8 ||
+ platform == TargetPlatform.WindowsStoreApp ||
+ platform == TargetPlatform.iOS;
+ }
+
+ public override ConversionQuality ConvertAudio(TargetPlatform platform, ConversionQuality quality, AudioContent content)
+ {
+ // Default to PCM data, or ADPCM if the source is ADPCM.
+ var targetFormat = ConversionFormat.Pcm;
+ if (quality != ConversionQuality.Best || content.Format.Format == 2 || content.Format.Format == 17)
+ {
+ if (platform == TargetPlatform.iOS || platform == TargetPlatform.MacOSX || platform == TargetPlatform.DesktopGL)
+ targetFormat = ConversionFormat.ImaAdpcm;
+ else
+ targetFormat = ConversionFormat.Adpcm;
+ }
+
+ return ConvertToFormat(content, targetFormat, quality, null);
+ }
+
+ public override ConversionQuality ConvertStreamingAudio(TargetPlatform platform, ConversionQuality quality, AudioContent content, ref string outputFileName)
+ {
+ // Most platforms will use AAC ("mp4") by default
+ var targetFormat = ConversionFormat.Aac;
+
+ if ( platform == TargetPlatform.Windows ||
+ platform == TargetPlatform.WindowsPhone8 ||
+ platform == TargetPlatform.WindowsStoreApp)
+ targetFormat = ConversionFormat.WindowsMedia;
+
+ else if (platform == TargetPlatform.DesktopGL)
+ targetFormat = ConversionFormat.Vorbis;
+
+ // Get the song output path with the target format extension.
+ outputFileName = Path.ChangeExtension(outputFileName, AudioHelper.GetExtension(targetFormat));
+
+ // Make sure the output folder for the file exists.
+ Directory.CreateDirectory(Path.GetDirectoryName(outputFileName));
+
+ return ConvertToFormat(content, targetFormat, quality, outputFileName);
+ }
+
+ public static void ProbeFormat(string sourceFile, out AudioFileType audioFileType, out AudioFormat audioFormat, out TimeSpan duration, out int loopStart, out int loopLength)
+ {
+ string ffprobeStdout, ffprobeStderr;
+ var ffprobeExitCode = ExternalTool.Run(
+ "ffprobe",
+ string.Format("-i \"{0}\" -show_format -show_entries streams -v quiet -of flat", sourceFile),
+ out ffprobeStdout,
+ out ffprobeStderr);
+ if (ffprobeExitCode != 0)
+ throw new InvalidOperationException("ffprobe exited with non-zero exit code.");
+
+ // Set default values if information is not available.
+ int averageBytesPerSecond = 0;
+ int bitsPerSample = 0;
+ int blockAlign = 0;
+ int channelCount = 0;
+ int sampleRate = 0;
+ int format = 0;
+ string sampleFormat = null;
+ double durationInSeconds = 0;
+ var formatName = string.Empty;
+
+ try
+ {
+ var numberFormat = CultureInfo.InvariantCulture.NumberFormat;
+ foreach (var line in ffprobeStdout.Split(new[] {'\r', '\n', '\0'}, StringSplitOptions.RemoveEmptyEntries))
+ {
+ var kv = line.Split(new[] {'='}, 2);
+
+ switch (kv[0])
+ {
+ case "streams.stream.0.sample_rate":
+ sampleRate = int.Parse(kv[1].Trim('"'), numberFormat);
+ break;
+ case "streams.stream.0.bits_per_sample":
+ bitsPerSample = int.Parse(kv[1].Trim('"'), numberFormat);
+ break;
+ case "streams.stream.0.start_time":
+ {
+ double seconds;
+ if (double.TryParse(kv[1].Trim('"'), NumberStyles.Any, numberFormat, out seconds))
+ durationInSeconds += seconds;
+ break;
+ }
+ case "streams.stream.0.duration":
+ durationInSeconds += double.Parse(kv[1].Trim('"'), numberFormat);
+ break;
+ case "streams.stream.0.channels":
+ channelCount = int.Parse(kv[1].Trim('"'), numberFormat);
+ break;
+ case "streams.stream.0.sample_fmt":
+ sampleFormat = kv[1].Trim('"').ToLowerInvariant();
+ break;
+ case "streams.stream.0.bit_rate":
+ averageBytesPerSecond = (int.Parse(kv[1].Trim('"'), numberFormat)/8);
+ break;
+ case "format.format_name":
+ formatName = kv[1].Trim('"').ToLowerInvariant();
+ break;
+ case "streams.stream.0.codec_tag":
+ {
+ var hex = kv[1].Substring(3, kv[1].Length - 4);
+ format = int.Parse(hex, NumberStyles.HexNumber);
+ break;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException("Failed to parse ffprobe output.", ex);
+ }
+
+ // XNA seems to use the sample format for the bits per sample
+ // in the case of non-PCM formats like MP3 and WMA.
+ if (bitsPerSample == 0 && sampleFormat != null)
+ {
+ switch (sampleFormat)
+ {
+ case "u8":
+ case "u8p":
+ bitsPerSample = 8;
+ break;
+ case "s16":
+ case "s16p":
+ bitsPerSample = 16;
+ break;
+ case "s32":
+ case "s32p":
+ case "flt":
+ case "fltp":
+ bitsPerSample = 32;
+ break;
+ case "dbl":
+ case "dblp":
+ bitsPerSample = 64;
+ break;
+ }
+ }
+
+ // Figure out the file type.
+ var durationMs = (int)Math.Floor(durationInSeconds * 1000.0);
+ if (formatName == "wav")
+ {
+ audioFileType = AudioFileType.Wav;
+ }
+ else if (formatName == "mp3")
+ {
+ audioFileType = AudioFileType.Mp3;
+ format = 1;
+ durationMs = (int)Math.Ceiling(durationInSeconds * 1000.0);
+ bitsPerSample = Math.Min(bitsPerSample, 16);
+ }
+ else if (formatName == "wma" || formatName == "asf")
+ {
+ audioFileType = AudioFileType.Wma;
+ format = 1;
+ durationMs = (int)Math.Ceiling(durationInSeconds * 1000.0);
+ bitsPerSample = Math.Min(bitsPerSample, 16);
+ }
+ else if (formatName == "ogg")
+ {
+ audioFileType = AudioFileType.Ogg;
+ format = 1;
+ durationMs = (int)Math.Ceiling(durationInSeconds * 1000.0);
+ bitsPerSample = Math.Min(bitsPerSample, 16);
+ }
+ else
+ audioFileType = (AudioFileType) (-1);
+
+ // XNA seems to calculate the block alignment directly from
+ // the bits per sample and channel count regardless of the
+ // format of the audio data.
+ // ffprobe doesn't report blockAlign for ADPCM and we cannot calculate it like this
+ if (bitsPerSample > 0 && (format != 2 && format != 17))
+ blockAlign = (bitsPerSample * channelCount) / 8;
+
+ // XNA seems to only be accurate to the millisecond.
+ duration = TimeSpan.FromMilliseconds(durationMs);
+
+ // Looks like XNA calculates the average bps from
+ // the sample rate and block alignment.
+ if (blockAlign > 0)
+ averageBytesPerSecond = sampleRate * blockAlign;
+
+ audioFormat = new AudioFormat(
+ averageBytesPerSecond,
+ bitsPerSample,
+ blockAlign,
+ channelCount,
+ format,
+ sampleRate);
+
+ // Loop start and length in number of samples. For some
+ // reason XNA doesn't report loop length for non-WAV sources.
+ loopStart = 0;
+ if (audioFileType != AudioFileType.Wav)
+ loopLength = 0;
+ else
+ loopLength = (int)Math.Floor(sampleRate * durationInSeconds);
+ }
+
+ internal static byte[] StripRiffWaveHeader(byte[] data, out AudioFormat audioFormat)
+ {
+ audioFormat = null;
+
+ using (var reader = new BinaryReader(new MemoryStream(data)))
+ {
+ var signature = new string(reader.ReadChars(4));
+ if (signature != "RIFF")
+ return data;
+
+ reader.ReadInt32(); // riff_chunck_size
+
+ var wformat = new string(reader.ReadChars(4));
+ if (wformat != "WAVE")
+ return data;
+
+ // Look for the data chunk.
+ while (true)
+ {
+ var chunkSignature = new string(reader.ReadChars(4));
+ if (chunkSignature.ToLowerInvariant() == "data")
+ break;
+ if (chunkSignature.ToLowerInvariant() == "fmt ")
+ {
+ int fmtLength = reader.ReadInt32();
+ short formatTag = reader.ReadInt16();
+ short channels = reader.ReadInt16();
+ int sampleRate = reader.ReadInt32();
+ int avgBytesPerSec = reader.ReadInt32();
+ short blockAlign = reader.ReadInt16();
+ short bitsPerSample = reader.ReadInt16();
+ audioFormat = new AudioFormat(avgBytesPerSec, bitsPerSample, blockAlign, channels, formatTag, sampleRate);
+
+ fmtLength -= 2 + 2 + 4 + 4 + 2 + 2;
+ if (fmtLength < 0)
+ throw new InvalidOperationException("riff wave header has unexpected format");
+ reader.BaseStream.Seek(fmtLength, SeekOrigin.Current);
+ }
+ else
+ {
+ reader.BaseStream.Seek(reader.ReadInt32(), SeekOrigin.Current);
+ }
+ }
+
+ var dataSize = reader.ReadInt32();
+ data = reader.ReadBytes(dataSize);
+ }
+
+ return data;
+ }
+
+ public static void WritePcmFile(AudioContent content, string saveToFile, int bitRate = 192000, int? sampeRate = null)
+ {
+ string ffmpegStdout, ffmpegStderr;
+ var ffmpegExitCode = ExternalTool.Run(
+ "ffmpeg",
+ string.Format(
+ "-y -i \"{0}\" -vn -c:a pcm_s16le -b:a {2} {3} -f:a wav -strict experimental \"{1}\"",
+ content.FileName,
+ saveToFile,
+ bitRate,
+ sampeRate != null ? "-ar " + sampeRate.Value : ""
+ ),
+ out ffmpegStdout,
+ out ffmpegStderr);
+ if (ffmpegExitCode != 0)
+ throw new InvalidOperationException("ffmpeg exited with non-zero exit code: \n" + ffmpegStdout + "\n" + ffmpegStderr);
+ }
+
+ public static ConversionQuality ConvertToFormat(AudioContent content, ConversionFormat formatType, ConversionQuality quality, string saveToFile)
+ {
+ var temporaryOutput = Path.GetTempFileName();
+ try
+ {
+ string ffmpegCodecName, ffmpegMuxerName;
+ //int format;
+ switch (formatType)
+ {
+ case ConversionFormat.Adpcm:
+ // ADPCM Microsoft
+ ffmpegCodecName = "adpcm_ms";
+ ffmpegMuxerName = "wav";
+ //format = 0x0002; /* WAVE_FORMAT_ADPCM */
+ break;
+ case ConversionFormat.Pcm:
+ // XNA seems to preserve the bit size of the input
+ // format when converting to PCM.
+ if (content.Format.BitsPerSample == 8)
+ ffmpegCodecName = "pcm_u8";
+ else if (content.Format.BitsPerSample == 32 && content.Format.Format == 3)
+ ffmpegCodecName = "pcm_f32le";
+ else
+ ffmpegCodecName = "pcm_s16le";
+ ffmpegMuxerName = "wav";
+ //format = 0x0001; /* WAVE_FORMAT_PCM */
+ break;
+ case ConversionFormat.WindowsMedia:
+ // Windows Media Audio 2
+ ffmpegCodecName = "wmav2";
+ ffmpegMuxerName = "asf";
+ //format = 0x0161; /* WAVE_FORMAT_WMAUDIO2 */
+ break;
+ case ConversionFormat.Xma:
+ throw new NotSupportedException(
+ "XMA is not a supported encoding format. It is specific to the Xbox 360.");
+ case ConversionFormat.ImaAdpcm:
+ // ADPCM IMA WAV
+ ffmpegCodecName = "adpcm_ima_wav";
+ ffmpegMuxerName = "wav";
+ //format = 0x0011; /* WAVE_FORMAT_IMA_ADPCM */
+ break;
+ case ConversionFormat.Aac:
+ // AAC (Advanced Audio Coding)
+ // Requires -strict experimental
+ ffmpegCodecName = "aac";
+ ffmpegMuxerName = "ipod";
+ //format = 0x0000; /* WAVE_FORMAT_UNKNOWN */
+ break;
+ case ConversionFormat.Vorbis:
+ // Vorbis
+ ffmpegCodecName = "libvorbis";
+ ffmpegMuxerName = "ogg";
+ //format = 0x0000; /* WAVE_FORMAT_UNKNOWN */
+ break;
+ default:
+ // Unknown format
+ throw new NotSupportedException();
+ }
+
+ string ffmpegStdout, ffmpegStderr;
+ int ffmpegExitCode;
+ do
+ {
+ ffmpegExitCode = ExternalTool.Run(
+ "ffmpeg",
+ string.Format(
+ "-y -i \"{0}\" -vn -c:a {1} -b:a {2} -ar {3} -f:a {4} -strict experimental \"{5}\"",
+ content.FileName,
+ ffmpegCodecName,
+ QualityToBitRate(quality),
+ QualityToSampleRate(quality, content.Format.SampleRate),
+ ffmpegMuxerName,
+ temporaryOutput),
+ out ffmpegStdout,
+ out ffmpegStderr);
+ if (ffmpegExitCode != 0)
+ quality--;
+ } while (quality >= 0 && ffmpegExitCode != 0);
+
+ if (ffmpegExitCode != 0)
+ {
+ throw new InvalidOperationException("ffmpeg exited with non-zero exit code: \n" + ffmpegStdout + "\n" + ffmpegStderr);
+ }
+
+ byte[] rawData;
+ using (var fs = new FileStream(temporaryOutput, FileMode.Open, FileAccess.Read))
+ {
+ rawData = new byte[fs.Length];
+ fs.Read(rawData, 0, rawData.Length);
+ }
+
+ if (saveToFile != null)
+ {
+ using (var fs = new FileStream(saveToFile, FileMode.Create, FileAccess.Write))
+ fs.Write(rawData, 0, rawData.Length);
+ }
+
+ // Use probe to get the final format and information on the converted file.
+ AudioFileType audioFileType;
+ AudioFormat audioFormat;
+ TimeSpan duration;
+ int loopStart, loopLength;
+ ProbeFormat(temporaryOutput, out audioFileType, out audioFormat, out duration, out loopStart, out loopLength);
+
+ AudioFormat riffAudioFormat;
+ byte[] data = StripRiffWaveHeader(rawData, out riffAudioFormat);
+
+ // deal with adpcm
+ if (audioFormat.Format == 2 || audioFormat.Format == 17)
+ {
+ // riff contains correct blockAlign
+ audioFormat = riffAudioFormat;
+
+ // fix loopLength -> has to be multiple of sample per block
+ // see https://msdn.microsoft.com/de-de/library/windows/desktop/ee415711(v=vs.85).aspx
+ int samplesPerBlock = SampleAlignment(audioFormat);
+ loopLength = (int)(audioFormat.SampleRate * duration.TotalSeconds);
+ int remainder = loopLength % samplesPerBlock;
+ loopLength += samplesPerBlock - remainder;
+ }
+
+ content.SetData(data, audioFormat, duration, loopStart, loopLength);
+ }
+ finally
+ {
+ ExternalTool.DeleteFile(temporaryOutput);
+ }
+
+ return quality;
+ }
+
+ // Converts block alignment in bytes to sample alignment, primarily for compressed formats
+ // Calculation of sample alignment from http://kcat.strangesoft.net/openal-extensions/SOFT_block_alignment.txt
+ static int SampleAlignment(AudioFormat format)
+ {
+ switch (format.Format)
+ {
+ case 2: // MS-ADPCM
+ return (format.BlockAlign / format.ChannelCount - 7) * 2 + 2;
+ case 17: // IMA/ADPCM
+ return (format.BlockAlign / format.ChannelCount - 4) / 4 * 8 + 1;
+ }
+ return 0;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/Convertors/StringToColorConverter.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/Convertors/StringToColorConverter.cs
new file mode 100644
index 000000000..63d41dff0
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/Convertors/StringToColorConverter.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Builder.Convertors
+{
+ public class StringToColorConverter : TypeConverter
+ {
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ return true;
+
+ return base.CanConvertTo(context, destinationType);
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+ {
+ if (destinationType != typeof (string))
+ return base.ConvertTo(context, culture, value, destinationType);
+
+ var color = (Color)value;
+ return string.Format("{0},{1},{2},{3}", color.R, color.G, color.B, color.A);
+ }
+
+ public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof (string))
+ return true;
+
+ return base.CanConvertFrom (context, sourceType);
+ }
+
+ public override object ConvertFrom (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
+ {
+ if (value.GetType () == typeof (string)) {
+ string[] values = ((string)value).Split(new char[] {','},StringSplitOptions.None);
+ if (values.Length == 4)
+ {
+ var r = int.Parse(values[0].Trim());
+ var g = int.Parse(values[1].Trim());
+ var b = int.Parse(values[2].Trim());
+ var a = int.Parse(values[3].Trim());
+ return new Microsoft.Xna.Framework.Color(r, g, b, a);
+ }
+ else
+ {
+ throw new ArgumentException(string.Format("Could not convert from string({0}) to Color, expected format is 'r,g,b,a'", value));
+ }
+ }
+
+ return base.ConvertFrom (context, culture, value);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/FileHelper.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/FileHelper.cs
new file mode 100644
index 000000000..53802986b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/FileHelper.cs
@@ -0,0 +1,20 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System.IO;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ public static class FileHelper
+ {
+ ///
+ /// Checks deletes a file from disk without throwing exceptions.
+ ///
+ public static void DeleteIfExists(string path)
+ {
+ if (File.Exists(path))
+ File.Delete(path);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PathHelper.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PathHelper.cs
new file mode 100644
index 000000000..8728a0c44
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PathHelper.cs
@@ -0,0 +1,60 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ public static class PathHelper
+ {
+ ///
+ /// The/universal/standard/directory/seperator.
+ ///
+ public const char DirectorySeparator = '/';
+
+ ///
+ /// Returns a path string normalized to the/universal/standard.
+ ///
+ public static string Normalize(string path)
+ {
+ return path.Replace('\\', '/');
+ }
+
+ ///
+ /// Returns a directory path string normalized to the/universal/standard
+ /// with a trailing seperator.
+ ///
+ public static string NormalizeDirectory(string path)
+ {
+ return path.Replace('\\', '/').TrimEnd('/') + '/';
+ }
+
+ ///
+ /// Returns a path string normalized to the\Windows\standard.
+ ///
+ public static string NormalizeWindows(string path)
+ {
+ return path.Replace('/', '\\');
+ }
+
+ ///
+ /// Returns a path relative to the base path.
+ ///
+ /// The path to make relative to. Must end with directory seperator.
+ /// The path to be made relative to the basePath.
+ /// The relative path or the original string if it is not absolute or cannot be made relative.
+ public static string GetRelativePath(string basePath, string path)
+ {
+ Uri uri;
+ if (!Uri.TryCreate(path, UriKind.Absolute, out uri))
+ return path;
+
+ uri = new Uri(basePath).MakeRelativeUri(uri);
+ var str = Uri.UnescapeDataString(uri.ToString());
+
+ return Normalize(str);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineBuildEvent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineBuildEvent.cs
new file mode 100644
index 000000000..c8bb9c970
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineBuildEvent.cs
@@ -0,0 +1,303 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Xml.Serialization;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ public class PipelineBuildEvent
+ {
+ private static readonly OpaqueDataDictionary EmptyParameters = new OpaqueDataDictionary();
+ public static readonly string Extension = ".mgcontent";
+
+ public PipelineBuildEvent()
+ {
+ SourceFile = string.Empty;
+ DestFile = string.Empty;
+ Importer = string.Empty;
+ Processor = string.Empty;
+ Parameters = new OpaqueDataDictionary();
+ ParametersXml = new List();
+ Dependencies = new List();
+ BuildAsset = new List();
+ BuildOutput = new List();
+ }
+
+ ///
+ /// Absolute path to the source file.
+ ///
+ public string SourceFile { get; set; }
+
+ ///
+ /// The date/time stamp of the source file.
+ ///
+ public DateTime SourceTime { get; set; }
+
+ ///
+ /// Absolute path to the output file.
+ ///
+ public string DestFile { get; set; }
+
+ ///
+ /// The date/time stamp of the destination file.
+ ///
+ public DateTime DestTime { get; set; }
+
+ public string Importer { get; set; }
+
+ ///
+ /// The date/time stamp of the DLL containing the importer.
+ ///
+ public DateTime ImporterTime { get; set; }
+
+ public string Processor { get; set; }
+
+ ///
+ /// The date/time stamp of the DLL containing the processor.
+ ///
+ public DateTime ProcessorTime { get; set; }
+
+ [XmlIgnore]
+ public OpaqueDataDictionary Parameters { get; set; }
+
+ public class Pair
+ {
+ public string Key { get; set; }
+ public string Value { get; set; }
+ }
+
+ [XmlElement("Parameters")]
+ public List ParametersXml { get; set; }
+
+ ///
+ /// Gets or sets the dependencies.
+ ///
+ /// The dependencies.
+ ///
+ /// Dependencies are extra files that are required in addition to the .
+ /// Dependencies are added using . Changes
+ /// to the dependent file causes a rebuilt of the content.
+ ///
+ public List Dependencies { get; set; }
+
+ ///
+ /// Gets or sets the additional (nested) assets.
+ ///
+ /// The additional (nested) assets.
+ ///
+ ///
+ /// Additional assets are built by using an and calling
+ ///
+ /// or .
+ ///
+ ///
+ /// Examples: The mesh processor may build textures and effects in addition to the mesh.
+ ///
+ ///
+ public List BuildAsset { get; set; }
+
+ ///
+ /// Gets or sets the related output files.
+ ///
+ /// The related output files.
+ ///
+ /// Related output files are non-XNB files that are included in addition to the XNB files.
+ /// Related output files need to be copied to the output folder by a content processor and
+ /// registered by calling .
+ ///
+ public List BuildOutput { get; set; }
+
+ public static PipelineBuildEvent Load(string filePath)
+ {
+ var fullFilePath = Path.GetFullPath(filePath);
+ var deserializer = new XmlSerializer(typeof (PipelineBuildEvent));
+ PipelineBuildEvent pipelineEvent;
+ try
+ {
+ using (var textReader = new StreamReader(fullFilePath))
+ pipelineEvent = (PipelineBuildEvent) deserializer.Deserialize(textReader);
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+
+ // Repopulate the parameters from the serialized state.
+ foreach (var pair in pipelineEvent.ParametersXml)
+ pipelineEvent.Parameters.Add(pair.Key, pair.Value);
+ pipelineEvent.ParametersXml.Clear();
+
+ return pipelineEvent;
+ }
+
+ public void Save(string filePath)
+ {
+ var fullFilePath = Path.GetFullPath(filePath);
+ // Make sure the directory exists.
+ Directory.CreateDirectory(Path.GetDirectoryName(fullFilePath) + Path.DirectorySeparatorChar);
+
+ // Convert the parameters into something we can serialize.
+ ParametersXml.Clear();
+ foreach (var pair in Parameters)
+ ParametersXml.Add(new Pair { Key = pair.Key, Value = ConvertToString(pair.Value) });
+
+ // Serialize our state.
+ var serializer = new XmlSerializer(typeof (PipelineBuildEvent));
+ using (var textWriter = new StreamWriter(fullFilePath, false, new UTF8Encoding(false)))
+ serializer.Serialize(textWriter, this);
+ }
+
+ public bool NeedsRebuild(PipelineManager manager, PipelineBuildEvent cachedEvent)
+ {
+ // If we have no previously cached build event then we cannot
+ // be sure that the state hasn't changed... force a rebuild.
+ if (cachedEvent == null)
+ return true;
+
+ // Verify that the last write time of the source file matches
+ // what we recorded when it was built. If it is different
+ // that means someone modified it and we need to rebuild.
+ var sourceWriteTime = File.GetLastWriteTime(SourceFile);
+ if (cachedEvent.SourceTime != sourceWriteTime)
+ return true;
+
+ // Do the same test for the dest file.
+ var destWriteTime = File.GetLastWriteTime(DestFile);
+ if (cachedEvent.DestTime != destWriteTime)
+ return true;
+
+ // If the source file is newer than the dest file
+ // then it must have been updated and needs a rebuild.
+ if (sourceWriteTime >= destWriteTime)
+ return true;
+
+ // Are any of the dependancy files newer than the dest file?
+ foreach (var depFile in cachedEvent.Dependencies)
+ {
+ if (File.GetLastWriteTime(depFile) >= destWriteTime)
+ return true;
+ }
+
+ // This shouldn't happen... but if the source or dest files changed
+ // then force a rebuild.
+ if (cachedEvent.SourceFile != SourceFile ||
+ cachedEvent.DestFile != DestFile)
+ return true;
+
+ // Did the importer assembly change?
+ if (manager.GetImporterAssemblyTimestamp(cachedEvent.Importer) > cachedEvent.ImporterTime)
+ return true;
+
+ // Did the importer change?
+ if (cachedEvent.Importer != Importer)
+ return true;
+
+ // Did the processor assembly change?
+ if (manager.GetProcessorAssemblyTimestamp(cachedEvent.Processor) > cachedEvent.ProcessorTime)
+ return true;
+
+ // Did the processor change?
+ if (cachedEvent.Processor != Processor)
+ return true;
+
+ // Did the parameters change?
+ var defaultValues = manager.GetProcessorDefaultValues(Processor);
+ if (!AreParametersEqual(cachedEvent.Parameters, Parameters, defaultValues))
+ return true;
+
+ return false;
+ }
+
+ internal static bool AreParametersEqual(OpaqueDataDictionary parameters0, OpaqueDataDictionary parameters1, OpaqueDataDictionary defaultValues)
+ {
+ Debug.Assert(defaultValues != null, "defaultValues must not be empty.");
+ Debug.Assert(EmptyParameters != null && EmptyParameters.Count == 0);
+
+ // Same reference or both null?
+ if (parameters0 == parameters1)
+ return true;
+
+ if (parameters0 == null)
+ parameters0 = EmptyParameters;
+ if (parameters1 == null)
+ parameters1 = EmptyParameters;
+
+ // Are both dictionaries empty?
+ if (parameters0.Count == 0 && parameters1.Count == 0)
+ return true;
+
+ // Compare the values with the second dictionary or
+ // the default values.
+ if (parameters0.Count < parameters1.Count)
+ {
+ var dummy = parameters0;
+ parameters0 = parameters1;
+ parameters1 = dummy;
+ }
+
+ // Compare parameters0 with parameters1 or defaultValues.
+ foreach (var pair in parameters0)
+ {
+ object value0 = pair.Value;
+ object value1;
+
+ // Search for matching parameter.
+ if (!parameters1.TryGetValue(pair.Key, out value1) && !defaultValues.TryGetValue(pair.Key, out value1))
+ return false;
+
+ if (!AreEqual(value0, value1))
+ return false;
+ }
+
+ // Compare parameters which are only in parameters1 with defaultValues.
+ foreach (var pair in parameters1)
+ {
+ if (parameters0.ContainsKey(pair.Key))
+ continue;
+
+ object defaultValue;
+ if (!defaultValues.TryGetValue(pair.Key, out defaultValue))
+ return false;
+
+ if (!AreEqual(pair.Value, defaultValue))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool AreEqual(object value0, object value1)
+ {
+ // Are values equal or both null?
+ if (Equals(value0, value1))
+ return true;
+
+ // Is one value null?
+ if (value0 == null || value1 == null)
+ return false;
+
+ // Values are of different type: Compare string representation.
+ if (ConvertToString(value0) != ConvertToString(value1))
+ return false;
+
+ return true;
+ }
+
+ private static string ConvertToString(object value)
+ {
+ if (value == null)
+ return null;
+
+ var typeConverter = TypeDescriptor.GetConverter(value.GetType());
+ return typeConverter.ConvertToInvariantString(value);
+ }
+ };
+}
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineBuildLogger.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineBuildLogger.cs
new file mode 100644
index 000000000..c370096e8
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineBuildLogger.cs
@@ -0,0 +1,32 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ public class PipelineBuildLogger : ContentBuildLogger
+ {
+ public override void LogMessage(string message, params object[] messageArgs)
+ {
+ System.Diagnostics.Trace.WriteLine(string.Format(message, messageArgs));
+ }
+
+ public override void LogImportantMessage(string message, params object[] messageArgs)
+ {
+ // TODO: How do i make it high importance?
+ System.Diagnostics.Trace.WriteLine(string.Format(message, messageArgs));
+ }
+
+ public override void LogWarning(string helpLink, ContentIdentity contentIdentity, string message, params object[] messageArgs)
+ {
+ var msg = string.Format(message, messageArgs);
+ var fileName = GetCurrentFilename(contentIdentity);
+ System.Diagnostics.Trace.WriteLine(string.Format("{0}: {1}", fileName, msg));
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineImporterContext.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineImporterContext.cs
new file mode 100644
index 000000000..0b51248c8
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineImporterContext.cs
@@ -0,0 +1,26 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ public class PipelineImporterContext : ContentImporterContext
+ {
+ private readonly PipelineManager _manager;
+
+ public PipelineImporterContext(PipelineManager manager)
+ {
+ _manager = manager;
+ }
+
+ public override string IntermediateDirectory { get { return _manager.IntermediateDirectory; } }
+ public override string OutputDirectory { get { return _manager.OutputDirectory; } }
+ public override ContentBuildLogger Logger { get { return _manager.Logger; } }
+
+ public override void AddDependency(string filename)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineManager.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineManager.cs
new file mode 100644
index 000000000..6dd1a0458
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineManager.cs
@@ -0,0 +1,936 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+using Microsoft.Xna.Framework.Graphics;
+using System.Globalization;
+using Microsoft.Xna.Framework.Content.Pipeline.Builder.Convertors;
+using System.Diagnostics;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ public class PipelineManager
+ {
+ [DebuggerDisplay("ImporterInfo: {type.Name}")]
+ private struct ImporterInfo
+ {
+ public ContentImporterAttribute attribute;
+ public Type type;
+ public DateTime assemblyTimestamp;
+ };
+
+ private List _importers;
+
+ [DebuggerDisplay("ProcessorInfo: {type.Name}")]
+ private struct ProcessorInfo
+ {
+ public ContentProcessorAttribute attribute;
+ public Type type;
+ public DateTime assemblyTimestamp;
+ };
+
+ private List _processors;
+
+ private List _writers;
+
+ // Keep track of all built assets. (Required to resolve automatic names "AssetName_n".)
+ // Key = absolute, normalized path of source file
+ // Value = list of build events
+ // (Note: When using external references, an asset may be built multiple times
+ // with different parameters.)
+ private readonly Dictionary> _pipelineBuildEvents;
+
+ // Store default values for content processor parameters. (Necessary to compare processor
+ // parameters. See PipelineBuildEvent.AreParametersEqual.)
+ // Key = name of content processor
+ // Value = processor parameters
+ private readonly Dictionary _processorDefaultValues;
+
+ public string ProjectDirectory { get; private set; }
+ public string OutputDirectory { get; private set; }
+ public string IntermediateDirectory { get; private set; }
+
+ public ContentStatsCollection ContentStats { get; private set; }
+
+ private ContentCompiler _compiler;
+
+ public ContentBuildLogger Logger { get; set; }
+
+ public List Assemblies { get; private set; }
+
+ ///
+ /// The current target graphics profile for which all content is built.
+ ///
+ public GraphicsProfile Profile { get; set; }
+
+ ///
+ /// The current target platform for which all content is built.
+ ///
+ public TargetPlatform Platform { get; set; }
+
+ ///
+ /// The build configuration passed thru to content processors.
+ ///
+ public string Config { get; set; }
+
+ ///
+ /// Gets or sets if the content is compressed.
+ ///
+ public bool CompressContent { get; set; }
+
+ ///
+ /// If true exceptions thrown from within an importer or processor are caught and then
+ /// thrown from the context. Default value is true.
+ ///
+ public bool RethrowExceptions { get; set; }
+
+ public PipelineManager(string projectDir, string outputDir, string intermediateDir)
+ {
+ _pipelineBuildEvents = new Dictionary>();
+ _processorDefaultValues = new Dictionary();
+ RethrowExceptions = true;
+
+ Assemblies = new List();
+ Assemblies.Add(null);
+ Logger = new PipelineBuildLogger();
+
+ ProjectDirectory = PathHelper.NormalizeDirectory(projectDir);
+ OutputDirectory = PathHelper.NormalizeDirectory(outputDir);
+ IntermediateDirectory = PathHelper.NormalizeDirectory(intermediateDir);
+
+ RegisterCustomConverters();
+
+ // Load the previous content stats.
+ ContentStats = new ContentStatsCollection();
+ ContentStats.PreviousStats = ContentStatsCollection.Read(intermediateDir);
+ }
+
+ public void AssignTypeConverter ()
+ {
+ TypeDescriptor.AddAttributes (typeof (TType), new TypeConverterAttribute (typeof (TTypeConverter)));
+ }
+
+ private void RegisterCustomConverters ()
+ {
+ AssignTypeConverter ();
+ }
+
+ public void AddAssembly(string assemblyFilePath)
+ {
+ if (assemblyFilePath == null)
+ throw new ArgumentException("assemblyFilePath cannot be null!");
+ if (!Path.IsPathRooted(assemblyFilePath))
+ throw new ArgumentException("assemblyFilePath must be absolute!");
+
+ // Make sure we're not adding the same assembly twice.
+ assemblyFilePath = PathHelper.Normalize(assemblyFilePath);
+ if (!Assemblies.Contains(assemblyFilePath))
+ {
+ Assemblies.Add(assemblyFilePath);
+
+ //TODO need better way to update caches
+ _processors = null;
+ _importers = null;
+ _writers = null;
+ }
+ }
+
+ private void ResolveAssemblies()
+ {
+ _importers = new List();
+ _processors = new List();
+ _writers = new List();
+
+ // Finally load the pipeline assemblies.
+ foreach (var assemblyPath in Assemblies)
+ {
+ Type[] exportedTypes;
+ DateTime assemblyTimestamp;
+ try
+ {
+ Assembly a;
+ if (string.IsNullOrEmpty(assemblyPath))
+ a = Assembly.GetExecutingAssembly();
+ else
+ a = Assembly.LoadFrom(assemblyPath);
+
+ exportedTypes = a.GetTypes();
+ assemblyTimestamp = File.GetLastWriteTime(a.Location);
+ }
+ catch (BadImageFormatException e)
+ {
+ Logger.LogWarning(null, null, "Assembly is either corrupt or built using a different " +
+ "target platform than this process. Reference another target architecture (x86, x64, " +
+ "AnyCPU, etc.) of this assembly. '{0}': {1}", assemblyPath, e.Message);
+ // The assembly failed to load... nothing
+ // we can do but ignore it.
+ continue;
+ }
+ catch (Exception e)
+ {
+ Logger.LogWarning(null, null, "Failed to load assembly '{0}': {1}", assemblyPath, e.Message);
+ continue;
+ }
+
+ foreach (var t in exportedTypes)
+ {
+ if (t.IsAbstract)
+ continue;
+
+ if (t.GetInterface(@"IContentImporter") != null)
+ {
+ var attributes = t.GetCustomAttributes(typeof (ContentImporterAttribute), false);
+ if (attributes.Length != 0)
+ {
+ var importerAttribute = attributes[0] as ContentImporterAttribute;
+ _importers.Add(new ImporterInfo
+ {
+ attribute = importerAttribute,
+ type = t,
+ assemblyTimestamp = assemblyTimestamp
+ });
+ }
+ else
+ {
+ // If no attribute specify default one
+ var importerAttribute = new ContentImporterAttribute(".*");
+ importerAttribute.DefaultProcessor = "";
+ importerAttribute.DisplayName = t.Name;
+ _importers.Add(new ImporterInfo
+ {
+ attribute = importerAttribute,
+ type = t,
+ assemblyTimestamp = assemblyTimestamp
+ });
+ }
+ }
+ else if (t.GetInterface(@"IContentProcessor") != null)
+ {
+ var attributes = t.GetCustomAttributes(typeof (ContentProcessorAttribute), false);
+ if (attributes.Length != 0)
+ {
+ var processorAttribute = attributes[0] as ContentProcessorAttribute;
+ _processors.Add(new ProcessorInfo
+ {
+ attribute = processorAttribute,
+ type = t,
+ assemblyTimestamp = assemblyTimestamp
+ });
+ }
+ }
+ else if (t.GetInterface(@"ContentTypeWriter") != null)
+ {
+ // TODO: This doesn't work... how do i find these?
+ _writers.Add(t);
+ }
+ }
+ }
+ }
+
+ public Type[] GetImporterTypes()
+ {
+ if (_importers == null)
+ ResolveAssemblies();
+
+ List types = new List();
+
+ foreach (var item in _importers)
+ {
+ types.Add(item.type);
+ }
+
+ return types.ToArray();
+ }
+
+ public Type[] GetProcessorTypes()
+ {
+ if (_processors == null)
+ ResolveAssemblies();
+
+ List types = new List();
+
+ foreach (var item in _processors)
+ {
+ types.Add(item.type);
+ }
+
+ return types.ToArray();
+ }
+
+ public IContentImporter CreateImporter(string name)
+ {
+ if (_importers == null)
+ ResolveAssemblies();
+
+ // Search for the importer.
+ foreach (var info in _importers)
+ {
+ if (info.type.Name.Equals(name))
+ return Activator.CreateInstance(info.type) as IContentImporter;
+ }
+
+ return null;
+ }
+
+ public string FindImporterByExtension(string ext)
+ {
+ if (_importers == null)
+ ResolveAssemblies();
+
+ // Search for the importer.
+ foreach (var info in _importers)
+ {
+ if (info.attribute.FileExtensions.Any(e => e.Equals(ext, StringComparison.InvariantCultureIgnoreCase)))
+ return info.type.Name;
+ }
+
+ return null;
+ }
+
+ public DateTime GetImporterAssemblyTimestamp(string name)
+ {
+ if (_importers == null)
+ ResolveAssemblies();
+
+ // Search for the importer.
+ foreach (var info in _importers)
+ {
+ if (info.type.Name.Equals(name))
+ return info.assemblyTimestamp;
+ }
+
+ return DateTime.MaxValue;
+ }
+
+ public string FindDefaultProcessor(string importer)
+ {
+ if (_importers == null)
+ ResolveAssemblies();
+
+ // Search for the importer.
+ foreach (var info in _importers)
+ {
+ if (info.type.Name == importer)
+ return info.attribute.DefaultProcessor;
+ }
+
+ return null;
+ }
+
+ public Type GetProcessorType(string name)
+ {
+ if (_processors == null)
+ ResolveAssemblies();
+
+ // Search for the processor type.
+ foreach (var info in _processors)
+ {
+ if (info.type.Name.Equals(name))
+ return info.type;
+ }
+
+ return null;
+ }
+
+ public void ResolveImporterAndProcessor(string sourceFilepath, ref string importerName, ref string processorName)
+ {
+ // Resolve the importer name.
+ if (string.IsNullOrEmpty(importerName))
+ importerName = FindImporterByExtension(Path.GetExtension(sourceFilepath));
+ if (string.IsNullOrEmpty(importerName))
+ throw new Exception(string.Format("Couldn't find a default importer for '{0}'!", sourceFilepath));
+
+ // Resolve the processor name.
+ if (string.IsNullOrEmpty(processorName))
+ processorName = FindDefaultProcessor(importerName);
+ if (string.IsNullOrEmpty(processorName))
+ throw new Exception(string.Format("Couldn't find a default processor for importer '{0}'!", importerName));
+ }
+
+ public IContentProcessor CreateProcessor(string name, OpaqueDataDictionary processorParameters)
+ {
+ var processorType = GetProcessorType(name);
+ if (processorType == null)
+ return null;
+
+ // Create the processor.
+ var processor = (IContentProcessor)Activator.CreateInstance(processorType);
+
+ // Convert and set the parameters on the processor.
+ foreach (var param in processorParameters)
+ {
+ var propInfo = processorType.GetProperty(param.Key, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
+ if (propInfo == null || propInfo.GetSetMethod(false) == null)
+ continue;
+
+ // If the property value is already of the correct type then set it.
+ if (propInfo.PropertyType.IsInstanceOfType(param.Value))
+ propInfo.SetValue(processor, param.Value, null);
+ else
+ {
+ // Find a type converter for this property.
+ var typeConverter = TypeDescriptor.GetConverter(propInfo.PropertyType);
+ if (typeConverter.CanConvertFrom(param.Value.GetType()))
+ {
+ var propValue = typeConverter.ConvertFrom(null, CultureInfo.InvariantCulture, param.Value);
+ propInfo.SetValue(processor, propValue, null);
+ }
+ }
+ }
+
+ return processor;
+ }
+
+ ///
+ /// Gets the default values for the content processor parameters.
+ ///
+ /// The name of the content processor.
+ ///
+ /// A dictionary containing the default value for each parameter. Returns
+ /// if the content processor has not been created yet.
+ ///
+ public OpaqueDataDictionary GetProcessorDefaultValues(string processorName)
+ {
+ // null is not allowed as key in dictionary.
+ if (processorName == null)
+ processorName = string.Empty;
+
+ OpaqueDataDictionary defaultValues;
+ if (!_processorDefaultValues.TryGetValue(processorName, out defaultValues))
+ {
+ // Create the content processor instance and read the default values.
+ defaultValues = new OpaqueDataDictionary();
+ var processorType = GetProcessorType(processorName);
+ if (processorType != null)
+ {
+ try
+ {
+ var processor = (IContentProcessor)Activator.CreateInstance(processorType);
+ var properties = processorType.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
+ foreach (var property in properties)
+ defaultValues.Add(property.Name, property.GetValue(processor, null));
+ }
+ catch
+ {
+ // Ignore exception. Will be handled in ProcessContent.
+ }
+ }
+
+ _processorDefaultValues.Add(processorName, defaultValues);
+ }
+
+ return defaultValues;
+ }
+
+ public DateTime GetProcessorAssemblyTimestamp(string name)
+ {
+ if (_processors == null)
+ ResolveAssemblies();
+
+ // Search for the processor.
+ foreach (var info in _processors)
+ {
+ if (info.type.Name.Equals(name))
+ return info.assemblyTimestamp;
+ }
+
+ return DateTime.MaxValue;
+ }
+
+ public OpaqueDataDictionary ValidateProcessorParameters(string name, OpaqueDataDictionary processorParameters)
+ {
+ var result = new OpaqueDataDictionary();
+
+ var processorType = GetProcessorType(name);
+ if (processorType == null || processorParameters == null)
+ {
+ return result;
+ }
+
+ foreach (var param in processorParameters)
+ {
+ var propInfo = processorType.GetProperty(param.Key, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
+ if (propInfo == null || propInfo.GetSetMethod(false) == null)
+ continue;
+
+ // Make sure we can assign the value.
+ if (!propInfo.PropertyType.IsInstanceOfType(param.Value))
+ {
+ // Make sure we can convert the value.
+ var typeConverter = TypeDescriptor.GetConverter(propInfo.PropertyType);
+ if (!typeConverter.CanConvertFrom(param.Value.GetType()))
+ continue;
+ }
+
+ result.Add(param.Key, param.Value);
+ }
+
+ return result;
+ }
+
+ private void ResolveOutputFilepath(string sourceFilepath, ref string outputFilepath)
+ {
+ // If the output path is null... build it from the source file path.
+ if (string.IsNullOrEmpty(outputFilepath))
+ {
+ var filename = Path.GetFileNameWithoutExtension(sourceFilepath) + ".xnb";
+ var directory = PathHelper.GetRelativePath(ProjectDirectory,
+ Path.GetDirectoryName(sourceFilepath) +
+ Path.DirectorySeparatorChar);
+ outputFilepath = Path.Combine(OutputDirectory, directory, filename);
+ }
+ else
+ {
+ // If the extension is not XNB or the source file extension then add XNB.
+ var sourceExt = Path.GetExtension(sourceFilepath);
+ if (outputFilepath.EndsWith(sourceExt, StringComparison.InvariantCultureIgnoreCase))
+ outputFilepath = outputFilepath.Substring(0, outputFilepath.Length - sourceExt.Length);
+ if (!outputFilepath.EndsWith(".xnb", StringComparison.InvariantCultureIgnoreCase))
+ outputFilepath += ".xnb";
+
+ // If the path isn't rooted then put it into the output directory.
+ if (!Path.IsPathRooted(outputFilepath))
+ outputFilepath = Path.Combine(OutputDirectory, outputFilepath);
+ }
+
+ outputFilepath = PathHelper.Normalize(outputFilepath);
+ }
+
+ private PipelineBuildEvent LoadBuildEvent(string destFile, out string eventFilepath)
+ {
+ var contentPath = Path.ChangeExtension(PathHelper.GetRelativePath(OutputDirectory, destFile), PipelineBuildEvent.Extension);
+ eventFilepath = Path.Combine(IntermediateDirectory, contentPath);
+ return PipelineBuildEvent.Load(eventFilepath);
+ }
+
+ public void RegisterContent(string sourceFilepath, string outputFilepath = null, string importerName = null, string processorName = null, OpaqueDataDictionary processorParameters = null)
+ {
+ sourceFilepath = PathHelper.Normalize(sourceFilepath);
+ ResolveOutputFilepath(sourceFilepath, ref outputFilepath);
+
+ ResolveImporterAndProcessor(sourceFilepath, ref importerName, ref processorName);
+
+ var contentEvent = new PipelineBuildEvent
+ {
+ SourceFile = sourceFilepath,
+ DestFile = outputFilepath,
+ Importer = importerName,
+ Processor = processorName,
+ Parameters = ValidateProcessorParameters(processorName, processorParameters),
+ };
+
+ // Register pipeline build event. (Required to correctly resolve external dependencies.)
+ TrackPipelineBuildEvent(contentEvent);
+ }
+
+ public PipelineBuildEvent BuildContent(string sourceFilepath, string outputFilepath = null, string importerName = null, string processorName = null, OpaqueDataDictionary processorParameters = null)
+ {
+ sourceFilepath = PathHelper.Normalize(sourceFilepath);
+ ResolveOutputFilepath(sourceFilepath, ref outputFilepath);
+
+ ResolveImporterAndProcessor(sourceFilepath, ref importerName, ref processorName);
+
+ // Record what we're building and how.
+ var contentEvent = new PipelineBuildEvent
+ {
+ SourceFile = sourceFilepath,
+ DestFile = outputFilepath,
+ Importer = importerName,
+ Processor = processorName,
+ Parameters = ValidateProcessorParameters(processorName, processorParameters),
+ };
+
+ // Load the previous content event if it exists.
+ string eventFilepath;
+ var cachedEvent = LoadBuildEvent(contentEvent.DestFile, out eventFilepath);
+
+ BuildContent(contentEvent, cachedEvent, eventFilepath);
+
+ return contentEvent;
+ }
+
+ private void BuildContent(PipelineBuildEvent pipelineEvent, PipelineBuildEvent cachedEvent, string eventFilepath)
+ {
+ if (!File.Exists(pipelineEvent.SourceFile))
+ {
+ Logger.LogMessage("{0}", pipelineEvent.SourceFile);
+ throw new PipelineException("The source file '{0}' does not exist!", pipelineEvent.SourceFile);
+ }
+
+ Logger.PushFile(pipelineEvent.SourceFile);
+
+ // Keep track of all build events. (Required to resolve automatic names "AssetName_n".)
+ TrackPipelineBuildEvent(pipelineEvent);
+
+ var rebuild = pipelineEvent.NeedsRebuild(this, cachedEvent);
+ if (rebuild)
+ Logger.LogMessage("{0}", pipelineEvent.SourceFile);
+ else
+ Logger.LogMessage("Skipping {0}", pipelineEvent.SourceFile);
+
+ Logger.Indent();
+ try
+ {
+ if (!rebuild)
+ {
+ // While this asset doesn't need to be rebuilt the dependent assets might.
+ foreach (var asset in cachedEvent.BuildAsset)
+ {
+ string assetEventFilepath;
+ var assetCachedEvent = LoadBuildEvent(asset, out assetEventFilepath);
+
+ // If we cannot find the cached event for the dependancy
+ // then we have to trigger a rebuild of the parent content.
+ if (assetCachedEvent == null)
+ {
+ rebuild = true;
+ break;
+ }
+
+ var depEvent = new PipelineBuildEvent
+ {
+ SourceFile = assetCachedEvent.SourceFile,
+ DestFile = assetCachedEvent.DestFile,
+ Importer = assetCachedEvent.Importer,
+ Processor = assetCachedEvent.Processor,
+ Parameters = assetCachedEvent.Parameters,
+ };
+
+ // Give the asset a chance to rebuild.
+ BuildContent(depEvent, assetCachedEvent, assetEventFilepath);
+ }
+ }
+
+ // Do we need to rebuild?
+ if (rebuild)
+ {
+ var startTime = DateTime.UtcNow;
+
+ // Import and process the content.
+ var processedObject = ProcessContent(pipelineEvent);
+
+ // Write the content to disk.
+ WriteXnb(processedObject, pipelineEvent);
+
+ // Store the timestamp of the DLLs containing the importer and processor.
+ pipelineEvent.ImporterTime = GetImporterAssemblyTimestamp(pipelineEvent.Importer);
+ pipelineEvent.ProcessorTime = GetProcessorAssemblyTimestamp(pipelineEvent.Processor);
+
+ // Store the new event into the intermediate folder.
+ pipelineEvent.Save(eventFilepath);
+
+ var buildTime = DateTime.UtcNow - startTime;
+
+ // Record stat for this file.
+ ContentStats.RecordStats(pipelineEvent.SourceFile, pipelineEvent.DestFile, pipelineEvent.Processor, processedObject.GetType(), (float)buildTime.TotalSeconds);
+ }
+ else
+ {
+ // Copy the stats from the previous build.
+ ContentStats.CopyPreviousStats(pipelineEvent.SourceFile);
+ }
+ }
+ finally
+ {
+ Logger.Unindent();
+ Logger.PopFile();
+ }
+ }
+
+ public object ProcessContent(PipelineBuildEvent pipelineEvent)
+ {
+ if (!File.Exists(pipelineEvent.SourceFile))
+ throw new PipelineException("The source file '{0}' does not exist!", pipelineEvent.SourceFile);
+
+ // Store the last write time of the source file
+ // so we can detect if it has been changed.
+ pipelineEvent.SourceTime = File.GetLastWriteTime(pipelineEvent.SourceFile);
+
+ // Make sure we can find the importer and processor.
+ var importer = CreateImporter(pipelineEvent.Importer);
+ if (importer == null)
+ throw new PipelineException("Failed to create importer '{0}'", pipelineEvent.Importer);
+
+ // Try importing the content.
+ object importedObject;
+ if (RethrowExceptions)
+ {
+ try
+ {
+ var importContext = new PipelineImporterContext(this);
+ importedObject = importer.Import(pipelineEvent.SourceFile, importContext);
+ }
+ catch (PipelineException)
+ {
+ throw;
+ }
+ catch (Exception inner)
+ {
+ throw new PipelineException(string.Format("Importer '{0}' had unexpected failure!", pipelineEvent.Importer), inner);
+ }
+ }
+ else
+ {
+ var importContext = new PipelineImporterContext(this);
+ importedObject = importer.Import(pipelineEvent.SourceFile, importContext);
+ }
+
+ // The pipelineEvent.Processor can be null or empty. In this case the
+ // asset should be imported but not processed.
+ if (string.IsNullOrEmpty(pipelineEvent.Processor))
+ return importedObject;
+
+ var processor = CreateProcessor(pipelineEvent.Processor, pipelineEvent.Parameters);
+ if (processor == null)
+ throw new PipelineException("Failed to create processor '{0}'", pipelineEvent.Processor);
+
+ // Make sure the input type is valid.
+ if (!processor.InputType.IsAssignableFrom(importedObject.GetType()))
+ {
+ throw new PipelineException(
+ string.Format("The type '{0}' cannot be processed by {1} as a {2}!",
+ importedObject.GetType().FullName,
+ pipelineEvent.Processor,
+ processor.InputType.FullName));
+ }
+
+ // Process the imported object.
+
+ object processedObject;
+ if (RethrowExceptions)
+ {
+ try
+ {
+ var processContext = new PipelineProcessorContext(this, pipelineEvent);
+ processedObject = processor.Process(importedObject, processContext);
+ }
+ catch (PipelineException)
+ {
+ throw;
+ }
+ catch (InvalidContentException)
+ {
+ throw;
+ }
+ catch (Exception inner)
+ {
+ throw new PipelineException(string.Format("Processor '{0}' had unexpected failure!", pipelineEvent.Processor), inner);
+ }
+ }
+ else
+ {
+ var processContext = new PipelineProcessorContext(this, pipelineEvent);
+ processedObject = processor.Process(importedObject, processContext);
+ }
+
+ return processedObject;
+ }
+
+ public void CleanContent(string sourceFilepath, string outputFilepath = null)
+ {
+ // First try to load the event file.
+ ResolveOutputFilepath(sourceFilepath, ref outputFilepath);
+ string eventFilepath;
+ var cachedEvent = LoadBuildEvent(outputFilepath, out eventFilepath);
+
+ if (cachedEvent != null)
+ {
+ // Recursively clean additional (nested) assets.
+ foreach (var asset in cachedEvent.BuildAsset)
+ {
+ string assetEventFilepath;
+ var assetCachedEvent = LoadBuildEvent(asset, out assetEventFilepath);
+
+ if (assetCachedEvent == null)
+ {
+ Logger.LogMessage("Cleaning {0}", asset);
+
+ // Remove asset (.xnb file) from output folder.
+ FileHelper.DeleteIfExists(asset);
+
+ // Remove event file (.mgcontent file) from intermediate folder.
+ FileHelper.DeleteIfExists(assetEventFilepath);
+ continue;
+ }
+
+ CleanContent(string.Empty, asset);
+ }
+
+ // Remove related output files (non-XNB files) that were copied to the output folder.
+ foreach (var asset in cachedEvent.BuildOutput)
+ {
+ Logger.LogMessage("Cleaning {0}", asset);
+ FileHelper.DeleteIfExists(asset);
+ }
+ }
+
+ Logger.LogMessage("Cleaning {0}", outputFilepath);
+
+ // Remove asset (.xnb file) from output folder.
+ FileHelper.DeleteIfExists(outputFilepath);
+
+ // Remove event file (.mgcontent file) from intermediate folder.
+ FileHelper.DeleteIfExists(eventFilepath);
+
+ _pipelineBuildEvents.Remove(sourceFilepath);
+ }
+
+ private void WriteXnb(object content, PipelineBuildEvent pipelineEvent)
+ {
+ // Make sure the output directory exists.
+ var outputFileDir = Path.GetDirectoryName(pipelineEvent.DestFile);
+
+ Directory.CreateDirectory(outputFileDir);
+
+ if (_compiler == null)
+ _compiler = new ContentCompiler();
+
+ // Write the XNB.
+ using (var stream = new FileStream(pipelineEvent.DestFile, FileMode.Create, FileAccess.Write, FileShare.None))
+ _compiler.Compile(stream, content, Platform, Profile, CompressContent, OutputDirectory, outputFileDir);
+
+ // Store the last write time of the output XNB here
+ // so we can verify it hasn't been tampered with.
+ pipelineEvent.DestTime = File.GetLastWriteTime(pipelineEvent.DestFile);
+ }
+
+ ///
+ /// Stores the pipeline build event (in memory) if no matching event is found.
+ ///
+ /// The pipeline build event.
+ private void TrackPipelineBuildEvent(PipelineBuildEvent pipelineEvent)
+ {
+ List pipelineBuildEvents;
+ bool eventsFound = _pipelineBuildEvents.TryGetValue(pipelineEvent.SourceFile, out pipelineBuildEvents);
+ if (!eventsFound)
+ {
+ pipelineBuildEvents = new List();
+ _pipelineBuildEvents.Add(pipelineEvent.SourceFile, pipelineBuildEvents);
+ }
+
+ if (FindMatchingEvent(pipelineBuildEvents, pipelineEvent.DestFile, pipelineEvent.Importer, pipelineEvent.Processor, pipelineEvent.Parameters) == null)
+ pipelineBuildEvents.Add(pipelineEvent);
+ }
+
+ ///
+ /// Gets an automatic asset name, such as "AssetName_0".
+ ///
+ /// The source file name.
+ /// The name of the content importer. Can be .
+ /// The name of the content processor. Can be .
+ /// The processor parameters. Can be .
+ /// The asset name.
+ public string GetAssetName(string sourceFileName, string importerName, string processorName, OpaqueDataDictionary processorParameters)
+ {
+ Debug.Assert(Path.IsPathRooted(sourceFileName), "Absolute path expected.");
+
+ // Get source file name, which is used for lookup in _pipelineBuildEvents.
+ sourceFileName = PathHelper.Normalize(sourceFileName);
+ string relativeSourceFileName = PathHelper.GetRelativePath(ProjectDirectory, sourceFileName);
+
+ List pipelineBuildEvents;
+ if (_pipelineBuildEvents.TryGetValue(sourceFileName, out pipelineBuildEvents))
+ {
+ // This source file has already been build.
+ // --> Compare pipeline build events.
+ ResolveImporterAndProcessor(sourceFileName, ref importerName, ref processorName);
+
+ var matchingEvent = FindMatchingEvent(pipelineBuildEvents, null, importerName, processorName, processorParameters);
+ if (matchingEvent != null)
+ {
+ // Matching pipeline build event found.
+ string existingName = matchingEvent.DestFile;
+ existingName = PathHelper.GetRelativePath(OutputDirectory, existingName);
+ existingName = existingName.Substring(0, existingName.Length - 4); // Remove ".xnb".
+ return existingName;
+ }
+
+ Logger.LogMessage(string.Format("Warning: Asset {0} built multiple times with different settings.", relativeSourceFileName));
+ }
+
+ // No pipeline build event with matching settings found.
+ // Get default asset name (= output file name relative to output folder without ".xnb").
+ string directoryName = Path.GetDirectoryName(relativeSourceFileName);
+ string fileName = Path.GetFileNameWithoutExtension(relativeSourceFileName);
+ string assetName = Path.Combine(directoryName, fileName);
+ assetName = PathHelper.Normalize(assetName);
+ return AppendAssetNameSuffix(assetName);
+ }
+
+ ///
+ /// Determines whether the specified list contains a matching pipeline build event.
+ ///
+ /// The list of pipeline build events.
+ /// Absolute path to the output file. Can be .
+ /// The name of the content importer. Can be .
+ /// The name of the content processor. Can be .
+ /// The processor parameters. Can be .
+ ///
+ /// The matching pipeline build event, or .
+ ///
+ private PipelineBuildEvent FindMatchingEvent(List pipelineBuildEvents, string destFile, string importerName, string processorName, OpaqueDataDictionary processorParameters)
+ {
+ foreach (var existingBuildEvent in pipelineBuildEvents)
+ {
+ if ((destFile == null || existingBuildEvent.DestFile.Equals(destFile))
+ && existingBuildEvent.Importer == importerName
+ && existingBuildEvent.Processor == processorName)
+ {
+ var defaultValues = GetProcessorDefaultValues(processorName);
+ if (PipelineBuildEvent.AreParametersEqual(existingBuildEvent.Parameters, processorParameters, defaultValues))
+ {
+ return existingBuildEvent;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets the asset name including a suffix, such as "_0". (The number is incremented
+ /// automatically.
+ ///
+ ///
+ /// The asset name without suffix (relative to output folder).
+ ///
+ /// The asset name with suffix.
+ private string AppendAssetNameSuffix(string baseAssetName)
+ {
+ int index = 0;
+ string assetName = baseAssetName + "_0";
+ while (IsAssetNameUsed(assetName))
+ {
+ index++;
+ assetName = baseAssetName + '_' + index;
+ }
+
+ return assetName;
+ }
+
+ ///
+ /// Determines whether the specified asset name is already used.
+ ///
+ /// The asset name (relative to output folder).
+ ///
+ /// if the asset name is already used; otherwise,
+ /// if the name is available.
+ ///
+ private bool IsAssetNameUsed(string assetName)
+ {
+ string destFile = Path.Combine(OutputDirectory, assetName + ".xnb");
+
+ return _pipelineBuildEvents.SelectMany(pair => pair.Value)
+ .Select(pipelineEvent => pipelineEvent.DestFile)
+ .Any(existingDestFile => destFile.Equals(existingDestFile, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineProcessorContext.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineProcessorContext.cs
new file mode 100644
index 000000000..3adbf43c3
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/PipelineProcessorContext.cs
@@ -0,0 +1,112 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ public class PipelineProcessorContext : ContentProcessorContext
+ {
+ private readonly PipelineManager _manager;
+
+ private readonly PipelineBuildEvent _pipelineEvent;
+
+ public PipelineProcessorContext(PipelineManager manager, PipelineBuildEvent pipelineEvent)
+ {
+ _manager = manager;
+ _pipelineEvent = pipelineEvent;
+ }
+
+ public override TargetPlatform TargetPlatform { get { return _manager.Platform; } }
+ public override GraphicsProfile TargetProfile { get { return _manager.Profile; } }
+
+ public override string BuildConfiguration { get { return _manager.Config; } }
+
+ public override string IntermediateDirectory { get { return _manager.IntermediateDirectory; } }
+ public override string OutputDirectory { get { return _manager.OutputDirectory; } }
+ public override string OutputFilename { get { return _pipelineEvent.DestFile; } }
+
+ public override OpaqueDataDictionary Parameters { get { return _pipelineEvent.Parameters; } }
+
+ public override ContentBuildLogger Logger { get { return _manager.Logger; } }
+
+ public override ContentIdentity SourceIdentity { get { return new ContentIdentity(_pipelineEvent.SourceFile); } }
+
+ public override void AddDependency(string filename)
+ {
+ _pipelineEvent.Dependencies.AddUnique(filename);
+ }
+
+ public override void AddOutputFile(string filename)
+ {
+ _pipelineEvent.BuildOutput.AddUnique(filename);
+ }
+
+ public override TOutput Convert( TInput input,
+ string processorName,
+ OpaqueDataDictionary processorParameters)
+ {
+ var processor = _manager.CreateProcessor(processorName, processorParameters);
+ var processContext = new PipelineProcessorContext(_manager, new PipelineBuildEvent { Parameters = processorParameters } );
+ var processedObject = processor.Process(input, processContext);
+
+ // Add its dependencies and built assets to ours.
+ _pipelineEvent.Dependencies.AddRangeUnique(processContext._pipelineEvent.Dependencies);
+ _pipelineEvent.BuildAsset.AddRangeUnique(processContext._pipelineEvent.BuildAsset);
+
+ return (TOutput)processedObject;
+ }
+
+ public override TOutput BuildAndLoadAsset( ExternalReference sourceAsset,
+ string processorName,
+ OpaqueDataDictionary processorParameters,
+ string importerName)
+ {
+ var sourceFilepath = PathHelper.Normalize(sourceAsset.Filename);
+
+ // The processorName can be null or empty. In this case the asset should
+ // be imported but not processed. This is, for example, necessary to merge
+ // animation files as described here:
+ // http://blogs.msdn.com/b/shawnhar/archive/2010/06/18/merging-animation-files.aspx.
+ bool processAsset = !string.IsNullOrEmpty(processorName);
+ _manager.ResolveImporterAndProcessor(sourceFilepath, ref importerName, ref processorName);
+
+ var buildEvent = new PipelineBuildEvent
+ {
+ SourceFile = sourceFilepath,
+ Importer = importerName,
+ Processor = processAsset ? processorName : null,
+ Parameters = _manager.ValidateProcessorParameters(processorName, processorParameters),
+ };
+
+ var processedObject = _manager.ProcessContent(buildEvent);
+
+ // Record that we processed this dependent asset.
+ _pipelineEvent.Dependencies.AddUnique(sourceFilepath);
+
+ return (TOutput)processedObject;
+ }
+
+ public override ExternalReference BuildAsset( ExternalReference sourceAsset,
+ string processorName,
+ OpaqueDataDictionary processorParameters,
+ string importerName,
+ string assetName)
+ {
+ if (string.IsNullOrEmpty(assetName))
+ assetName = _manager.GetAssetName(sourceAsset.Filename, importerName, processorName, processorParameters);
+
+ // Build the content.
+ var buildEvent = _manager.BuildContent(sourceAsset.Filename, assetName, importerName, processorName, processorParameters);
+
+ // Record that we built this dependent asset.
+ _pipelineEvent.BuildAsset.AddUnique(buildEvent.DestFile);
+
+ return new ExternalReference(buildEvent.DestFile);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/TypeExtensions.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/TypeExtensions.cs
new file mode 100644
index 000000000..3f3e2e95d
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/TypeExtensions.cs
@@ -0,0 +1,37 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ static public class TypeExtensions
+ {
+ public static Color ToColor(this System.Drawing.Color color)
+ {
+ return new Color(color.R, color.G, color.B, color.A);
+ }
+
+ public static Vector3 ToVector3(this System.Drawing.Color color)
+ {
+ return new Vector3(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f);
+ }
+
+ public static void AddUnique(this List list, T item)
+ {
+ if (!list.Contains(item))
+ list.Add(item);
+ }
+
+ public static void AddRangeUnique(this List dstList, List list)
+ {
+ foreach (var i in list)
+ {
+ if (!dstList.Contains(i))
+ dstList.Add(i);
+ }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/XmlColor.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/XmlColor.cs
new file mode 100644
index 000000000..6a3e3805b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Builder/XmlColor.cs
@@ -0,0 +1,65 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System.Drawing;
+using System.Xml.Serialization;
+
+namespace MonoGame.Framework.Content.Pipeline.Builder
+{
+ ///
+ /// Helper for serializing color types with the XmlSerializer.
+ ///
+ public class XmlColor
+ {
+ private Color _color;
+
+ public XmlColor()
+ {
+ }
+
+ public XmlColor(Color c)
+ {
+ _color = c;
+ }
+
+ public static implicit operator Color(XmlColor x)
+ {
+ return x._color;
+ }
+
+ public static implicit operator XmlColor(Color c)
+ {
+ return new XmlColor(c);
+ }
+
+ public static string FromColor(Color color)
+ {
+ if (color.IsNamedColor)
+ return color.Name;
+ return string.Format("{0}, {1}, {2}, {3}", color.R, color.G, color.B, color.A);
+ }
+
+ public static Color ToColor(string value)
+ {
+ if (!value.Contains(","))
+ return Color.FromName(value);
+
+ int r, g, b, a;
+ var colors = value.Split(',');
+ int.TryParse(colors.Length > 0 ? colors[0] : string.Empty, out r);
+ int.TryParse(colors.Length > 1 ? colors[1] : string.Empty, out g);
+ int.TryParse(colors.Length > 2 ? colors[2] : string.Empty, out b);
+ int.TryParse(colors.Length > 3 ? colors[3] : string.Empty, out a);
+
+ return Color.FromArgb(a, r, g, b);
+ }
+
+ [XmlText]
+ public string Default
+ {
+ get { return FromColor(_color); }
+ set { _color = ToColor(value); }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ChildCollection.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ChildCollection.cs
new file mode 100644
index 000000000..8c596daba
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ChildCollection.cs
@@ -0,0 +1,104 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.ObjectModel;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides a collection of child objects for a content item.
+ ///
+ /// Links from a child object to its parent are maintained as the collection contents are modified.
+ ///
+ ///
+ ///
+ public abstract class ChildCollection : Collection
+ where TParent : class
+ where TChild : class
+ {
+ TParent parent;
+
+ ///
+ /// Creates an instance of ChildCollection.
+ ///
+ /// Parent object of the child objects returned in the collection.
+ protected ChildCollection(TParent parent)
+ : base()
+ {
+ if (parent == null)
+ throw new ArgumentNullException("parent");
+ this.parent = parent;
+ }
+
+ ///
+ /// Removes all children from the collection.
+ ///
+ protected override void ClearItems()
+ {
+ // Remove parent reference from each child before clearing
+ foreach (TChild child in this)
+ SetParent(child, default(TParent));
+ base.ClearItems();
+ }
+
+ ///
+ /// Gets the parent of a child object.
+ ///
+ /// The child of the parent being retrieved.
+ /// The parent of the child object.
+ protected abstract TParent GetParent(TChild child);
+
+ ///
+ /// Inserts a child object into the collection at the specified location.
+ ///
+ /// The position in the collection.
+ /// The child object being inserted.
+ protected override void InsertItem(int index, TChild item)
+ {
+ // Make sure we have a
+ if (item == null)
+ throw new ArgumentNullException("child");
+ if (GetParent(item) != null)
+ throw new InvalidOperationException("Child already has a parent");
+ SetParent(item, parent);
+ base.InsertItem(index, item);
+ }
+
+ ///
+ /// Removes a child object from the collection.
+ ///
+ /// The index of the item being removed.
+ protected override void RemoveItem(int index)
+ {
+ TChild child = this[index];
+ SetParent(child, default(TParent));
+ base.RemoveItem(index);
+ }
+
+ ///
+ /// Modifies the value of the child object at the specified location.
+ ///
+ /// The index of the child object being modified.
+ /// The new value for the child object.
+ protected override void SetItem(int index, TChild item)
+ {
+ if (item == null)
+ throw new ArgumentNullException("child");
+ if (GetParent(item) != null)
+ throw new InvalidOperationException("Child already has a parent");
+ TChild child = this[index];
+ SetParent(child, default(TParent));
+ SetParent(item, parent);
+ base.SetItem(index, item);
+ }
+
+ ///
+ /// Modifies the value of the parent object of the specified child object.
+ ///
+ /// The child of the parent being modified.
+ /// The new value for the parent object.
+ protected abstract void SetParent(TChild child, TParent parent);
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentBuildLogger.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentBuildLogger.cs
new file mode 100644
index 000000000..148125bc1
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentBuildLogger.cs
@@ -0,0 +1,127 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides methods for reporting informational messages or warnings from content importers and processors.
+ /// Do not use this class to report errors. Instead, report errors by throwing a PipelineException or InvalidContentException.
+ ///
+ public abstract class ContentBuildLogger
+ {
+ Stack filenames = new Stack();
+ private int indentCount = 0;
+
+ protected string IndentString { get { return String.Empty.PadLeft(Math.Max(0, indentCount), '\t'); } }
+
+ ///
+ /// Gets or sets the base reference path used when reporting errors during the content build process.
+ ///
+ public string LoggerRootDirectory { get; set; }
+
+ ///
+ /// Initializes a new instance of ContentBuildLogger.
+ ///
+ protected ContentBuildLogger ()
+ {
+ }
+
+ ///
+ /// Returns the relative path to the filename from the root directory.
+ ///
+ /// The target filename.
+ /// The root directory. If not specified, the current directory is used.
+ /// The relative path.
+ string GetRelativePath(string filename, string rootDirectory)
+ {
+ rootDirectory = Path.GetFullPath(string.IsNullOrEmpty(rootDirectory) ? "." : rootDirectory);
+ filename = Path.GetFullPath(filename);
+ if (filename.StartsWith(rootDirectory))
+ return filename.Substring(rootDirectory.Length);
+ return filename;
+ }
+
+ ///
+ /// Gets the filename currently being processed, for use in warning and error messages.
+ ///
+ /// Identity of a content item. If specified, GetCurrentFilename uses this value to refine the search. If no value is specified, the current PushFile state is used.
+ /// Name of the file being processed.
+ protected string GetCurrentFilename(
+ ContentIdentity contentIdentity
+ )
+ {
+ if ((contentIdentity != null) && !string.IsNullOrEmpty(contentIdentity.SourceFilename))
+ return GetRelativePath(contentIdentity.SourceFilename, LoggerRootDirectory);
+ if (filenames.Count > 0)
+ return GetRelativePath(filenames.Peek(), LoggerRootDirectory);
+ return null;
+ }
+
+ ///
+ /// Outputs a high-priority status message from a content importer or processor.
+ ///
+ /// Message being reported.
+ /// Arguments for the reported message.
+ public abstract void LogImportantMessage(
+ string message,
+ params Object[] messageArgs
+ );
+
+ ///
+ /// Outputs a low priority status message from a content importer or processor.
+ ///
+ /// Message being reported.
+ /// Arguments for the reported message.
+ public abstract void LogMessage(
+ string message,
+ params Object[] messageArgs
+ );
+
+ ///
+ /// Outputs a warning message from a content importer or processor.
+ ///
+ /// Link to an existing online help topic containing related information.
+ /// Identity of the content item that generated the message.
+ /// Message being reported.
+ /// Arguments for the reported message.
+ public abstract void LogWarning(
+ string helpLink,
+ ContentIdentity contentIdentity,
+ string message,
+ params Object[] messageArgs
+ );
+
+ ///
+ /// Outputs a message indicating that a content asset has completed processing.
+ ///
+ public void PopFile()
+ {
+ filenames.Pop();
+ }
+
+ ///
+ /// Outputs a message indicating that a content asset has begun processing.
+ /// All logger warnings or error exceptions from this time forward to the next PopFile call refer to this file.
+ ///
+ /// Name of the file containing future messages.
+ public void PushFile(string filename)
+ {
+ filenames.Push(filename);
+ }
+
+ public void Indent()
+ {
+ indentCount++;
+ }
+
+ public void Unindent()
+ {
+ indentCount--;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentIdentity.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentIdentity.cs
new file mode 100644
index 000000000..5e5beffcb
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentIdentity.cs
@@ -0,0 +1,70 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides properties describing the origin of the game asset, such as the original source file and creation tool. This information is used for error reporting, and by processors that need to determine from what directory the asset was originally loaded.
+ ///
+ [Serializable]
+ public class ContentIdentity
+ {
+ ///
+ /// Gets or sets the specific location of the content item within the larger source file.
+ ///
+ public string FragmentIdentifier { get; set; }
+
+ ///
+ /// Gets or sets the file name of the asset source.
+ ///
+ public string SourceFilename { get; set; }
+
+ ///
+ /// Gets or sets the creation tool of the asset.
+ ///
+ public string SourceTool { get; set; }
+
+ ///
+ /// Initializes a new instance of ContentIdentity.
+ ///
+ public ContentIdentity()
+ : this(string.Empty, string.Empty, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of ContentIdentity with the specified values.
+ ///
+ /// The absolute path to the file name of the asset source.
+ public ContentIdentity(string sourceFilename)
+ : this(sourceFilename, string.Empty, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of ContentIdentity with the specified values.
+ ///
+ /// The absolute path to the file name of the asset source.
+ /// The name of the digital content creation (DCC) tool that created the asset.
+ public ContentIdentity(string sourceFilename, string sourceTool)
+ : this(sourceFilename, sourceTool, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of ContentIdentity with the specified values.
+ ///
+ /// The absolute path to the file name of the asset source.
+ /// The name of the digital content creation (DCC) tool that created the asset.
+ /// Specific location of the content item within the larger source file. For example, this could be a line number in the file.
+ public ContentIdentity(string sourceFilename, string sourceTool, string fragmentIdentifier)
+ {
+ SourceFilename = sourceFilename;
+ SourceTool = sourceTool;
+ FragmentIdentifier = fragmentIdentifier;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporter.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporter.cs
new file mode 100644
index 000000000..7e533548b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporter.cs
@@ -0,0 +1,48 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Implements a file format importer for use with game assets.
+ /// Importers, either provided by the framework or written by a developer, must derive from ContentImporter, as well as being marked with a ContentImporterAttribute.
+ /// An importer should produce results in the standard intermediate object model. If an asset has information not supported by the object model, the importer should output it as opaque data (key/value attributes attached to the relevant object). By following this procedure, a content pipeline can access specialized digital content creation (DCC) tool information, even when that information has not been fully standardized into the official object model.
+ /// You can also design custom importers that accept and import types containing specific third-party extensions to the object model.
+ ///
+ public abstract class ContentImporter : IContentImporter
+ {
+ ///
+ /// Initializes a new instance of ContentImporter.
+ ///
+ protected ContentImporter()
+ {
+
+ }
+
+ ///
+ /// Called by the framework when importing a game asset. This is the method called by XNA when an asset is to be imported into an object that can be recognized by the Content Pipeline.
+ ///
+ /// Name of a game asset file.
+ /// Contains information for importing a game asset, such as a logger interface.
+ /// Resulting game asset.
+ public abstract T Import(string filename, ContentImporterContext context);
+
+ ///
+ /// Called by the framework when importing a game asset. This is the method called by XNA when an asset is to be imported into an object that can be recognized by the Content Pipeline.
+ ///
+ /// Name of a game asset file.
+ /// Contains information for importing a game asset, such as a logger interface.
+ /// Resulting game asset.
+ Object IContentImporter.Import(string filename, ContentImporterContext context)
+ {
+ if (filename == null)
+ throw new ArgumentNullException("filename");
+ if (context == null)
+ throw new ArgumentNullException("context");
+ return Import(filename, context);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporterAttribute.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporterAttribute.cs
new file mode 100644
index 000000000..e0cde8b6b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporterAttribute.cs
@@ -0,0 +1,60 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides properties that identify and provide metadata about the importer, such as supported file extensions and caching information.
+ /// Importers are required to initialize this attribute.
+ ///
+ public class ContentImporterAttribute : Attribute
+ {
+ List extensions = new List();
+
+ ///
+ /// Gets and sets the caching of the content during importation.
+ ///
+ public bool CacheImportedData { get; set; }
+
+ ///
+ /// Gets or sets the name of the default processor for content read by this importer.
+ ///
+ public string DefaultProcessor { get; set; }
+
+ ///
+ /// Gets or sets the string representing the importer in a user interface. This name is not used by the content pipeline and should not be passed to the BuildAssets task (a custom MSBuild task used by XNA Game Studio). It is used for display purposes only.
+ ///
+ public virtual string DisplayName { get; set; }
+
+ ///
+ /// Gets the supported file name extensions of the importer.
+ ///
+ public IEnumerable FileExtensions { get { return extensions; } }
+
+ ///
+ /// Initializes a new instance of ContentImporterAttribute and sets the file name extension supported by the importer.
+ ///
+ /// The list of file name extensions supported by the importer. Prefix each extension with a '.'.
+ public ContentImporterAttribute(
+ string fileExtension
+ )
+ {
+ extensions.Add(fileExtension);
+ }
+
+ ///
+ /// Initializes a new instance of ContentImporterAttribute and sets the file name extensions supported by the importer.
+ ///
+ /// The list of file name extensions supported by the importer. Prefix each extension with a '.'.
+ public ContentImporterAttribute(
+ params string[] fileExtensions
+ )
+ {
+ extensions.AddRange(fileExtensions);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporterContext.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporterContext.cs
new file mode 100644
index 000000000..9919205ae
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentImporterContext.cs
@@ -0,0 +1,41 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides properties that define logging behavior for the importer.
+ ///
+ public abstract class ContentImporterContext
+ {
+ ///
+ /// The absolute path to the root of the build intermediate (object) directory.
+ ///
+ public abstract string IntermediateDirectory { get; }
+
+ ///
+ /// Gets the logger for an importer.
+ ///
+ public abstract ContentBuildLogger Logger { get; }
+
+ ///
+ /// The absolute path to the root of the build output (binaries) directory.
+ ///
+ public abstract string OutputDirectory { get; }
+
+ ///
+ /// Initializes a new instance of ContentImporterContext.
+ ///
+ public ContentImporterContext()
+ {
+
+ }
+
+ ///
+ /// Adds a dependency to the specified file. This causes a rebuild of the file, when modified, on subsequent incremental builds.
+ ///
+ /// Name of an asset file.
+ public abstract void AddDependency(string filename);
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentItem.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentItem.cs
new file mode 100644
index 000000000..fb2a03c9b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentItem.cs
@@ -0,0 +1,39 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides properties that define various aspects of content stored using the intermediate file format of the XNA Framework.
+ ///
+ public class ContentItem
+ {
+ OpaqueDataDictionary opaqueData = new OpaqueDataDictionary();
+
+ ///
+ /// Gets or sets the identity of the content item.
+ ///
+ [ContentSerializer(Optional = true)]
+ public ContentIdentity Identity { get; set; }
+
+ ///
+ /// Gets or sets the name of the content item.
+ ///
+ [ContentSerializer(Optional = true)]
+ public string Name { get; set; }
+
+ ///
+ /// Gets the opaque data of the content item.
+ ///
+ [ContentSerializer(Optional = true)]
+ public OpaqueDataDictionary OpaqueData { get { return opaqueData; } }
+
+ ///
+ /// Initializes a new instance of ContentItem.
+ ///
+ public ContentItem()
+ {
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessor.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessor.cs
new file mode 100644
index 000000000..f87814d66
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessor.cs
@@ -0,0 +1,63 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides a base class to use when developing custom processor components. All processors must derive from this class.
+ ///
+ public abstract class ContentProcessor : IContentProcessor
+ {
+ ///
+ /// Initializes a new instance of the ContentProcessor class.
+ ///
+ protected ContentProcessor()
+ {
+
+ }
+
+ ///
+ /// Processes the specified input data and returns the result.
+ ///
+ /// Existing content object being processed.
+ /// Contains any required custom process parameters.
+ /// A typed object representing the processed input.
+ public abstract TOutput Process(TInput input, ContentProcessorContext context);
+
+ ///
+ /// Gets the expected object type of the input parameter to IContentProcessor.Process.
+ ///
+ Type IContentProcessor.InputType
+ {
+ get { return typeof(TInput); }
+ }
+
+ ///
+ /// Gets the object type returned by IContentProcessor.Process.
+ ///
+ Type IContentProcessor.OutputType
+ {
+ get { return typeof(TOutput); }
+ }
+
+ ///
+ /// Processes the specified input data and returns the result.
+ ///
+ /// Existing content object being processed.
+ /// Contains any required custom process parameters.
+ /// The processed input.
+ object IContentProcessor.Process(object input, ContentProcessorContext context)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (context == null)
+ throw new ArgumentNullException("context");
+ if (!(input is TInput))
+ throw new InvalidOperationException("input is not of the expected type");
+ return Process((TInput)input, context);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessorAttribute.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessorAttribute.cs
new file mode 100644
index 000000000..749d41289
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessorAttribute.cs
@@ -0,0 +1,26 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Gets any existing content processor components.
+ ///
+ public class ContentProcessorAttribute : Attribute
+ {
+ ///
+ /// Gets or sets the string representing the processor in a user interface. This name is not used by the content pipeline and should not be passed to the BuildAssets task (a custom MSBuild task used by XNA Game Studio). It is used for display purposes only.
+ ///
+ public virtual string DisplayName { get; set; }
+
+ ///
+ /// Initializes an instance of ContentProcessorAttribute.
+ ///
+ public ContentProcessorAttribute()
+ {
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessorContext.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessorContext.cs
new file mode 100644
index 000000000..e22a7b35e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentProcessorContext.cs
@@ -0,0 +1,181 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides access to custom processor parameters, methods for converting member data, and triggering nested builds.
+ ///
+ public abstract class ContentProcessorContext
+ {
+ ///
+ /// Gets the name of the current content build configuration.
+ ///
+ public abstract string BuildConfiguration { get; }
+
+ ///
+ /// Gets the path of the directory that will contain any intermediate files generated by the content processor.
+ ///
+ public abstract string IntermediateDirectory { get; }
+
+ ///
+ /// Gets the logger interface used for status messages or warnings.
+ ///
+ public abstract ContentBuildLogger Logger { get; }
+
+ ///
+ /// Gets the ContentIdentity representing the source asset imported.
+ ///
+ public abstract ContentIdentity SourceIdentity { get; }
+
+ ///
+ /// Gets the output path of the content processor.
+ ///
+ public abstract string OutputDirectory { get; }
+
+ ///
+ /// Gets the output file name of the content processor.
+ ///
+ public abstract string OutputFilename { get; }
+
+ ///
+ /// Gets the collection of parameters used by the content processor.
+ ///
+ public abstract OpaqueDataDictionary Parameters { get; }
+
+ ///
+ /// Gets the current content build target platform.
+ ///
+ public abstract TargetPlatform TargetPlatform { get; }
+
+ ///
+ /// Gets the current content build target profile.
+ ///
+ public abstract GraphicsProfile TargetProfile { get; }
+
+ ///
+ /// Initializes a new instance of ContentProcessorContext.
+ ///
+ public ContentProcessorContext()
+ {
+ }
+
+ ///
+ /// Adds a dependency to the specified file. This causes a rebuild of the file, when modified, on subsequent incremental builds.
+ ///
+ /// Name of an asset file.
+ public abstract void AddDependency(string filename);
+
+ ///
+ /// Add a file name to the list of related output files maintained by the build item. This allows tracking build items that build multiple output files.
+ ///
+ /// The name of the file.
+ public abstract void AddOutputFile(string filename);
+
+ ///
+ /// Initiates a nested build of the specified asset and then loads the result into memory.
+ ///
+ /// Type of the input.
+ /// Type of the converted output.
+ /// Reference to the source asset.
+ /// Optional processor for this content.
+ /// Copy of the final converted content.
+ /// An example of usage would be a mesh processor calling BuildAndLoadAsset to build any associated textures and replace the original .tga file references with an embedded copy of the converted texture.
+ public TOutput BuildAndLoadAsset(
+ ExternalReference sourceAsset,
+ string processorName
+ )
+ {
+ return BuildAndLoadAsset(sourceAsset, processorName, null, null);
+ }
+
+ ///
+ /// Initiates a nested build of the specified asset and then loads the result into memory.
+ ///
+ /// Type of the input.
+ /// Type of the converted output.
+ /// Reference to the source asset.
+ /// Optional processor for this content.
+ /// Optional collection of named values available as input to the content processor.
+ /// Optional importer for this content.
+ /// Copy of the final converted content.
+ /// An example of usage would be a mesh processor calling BuildAndLoadAsset to build any associated textures and replace the original .tga file references with an embedded copy of the converted texture.
+ public abstract TOutput BuildAndLoadAsset(
+ ExternalReference sourceAsset,
+ string processorName,
+ OpaqueDataDictionary processorParameters,
+ string importerName
+ );
+
+ ///
+ /// Initiates a nested build of an additional asset.
+ ///
+ /// Type of the input.
+ /// Type of the output.
+ /// Reference to the source asset.
+ /// Optional processor for this content.
+ /// Reference to the final compiled content. The build work is not required to complete before returning. Therefore, this file may not be up to date when BuildAsset returns but it will be available for loading by the game at runtime.
+ /// An example of usage for BuildAsset is being called by a mesh processor to request that any related textures used are also built, replacing the original TGA file references with new references to the converted texture files.
+ public ExternalReference BuildAsset(
+ ExternalReference sourceAsset,
+ string processorName
+ )
+ {
+ return BuildAsset(sourceAsset, processorName, null, null, null);
+ }
+
+ ///
+ /// Initiates a nested build of an additional asset.
+ ///
+ /// Type of the input.
+ /// Type of the output.
+ /// Reference to the source asset.
+ /// Optional processor for this content.
+ /// Optional collection of named values available as input to the content processor.
+ /// Optional importer for this content.
+ /// Optional name of the final compiled content.
+ /// Reference to the final compiled content. The build work is not required to complete before returning. Therefore, this file may not be up to date when BuildAsset returns but it will be available for loading by the game at runtime.
+ /// An example of usage for BuildAsset is being called by a mesh processor to request that any related textures used are also built, replacing the original TGA file references with new references to the converted texture files.
+ public abstract ExternalReference BuildAsset(
+ ExternalReference sourceAsset,
+ string processorName,
+ OpaqueDataDictionary processorParameters,
+ string importerName,
+ string assetName
+ );
+
+ ///
+ /// Converts a content item object using the specified content processor.
+ ///
+ /// Type of the input content.
+ /// Type of the converted output.
+ /// Source content to be converted.
+ /// Optional processor for this content.
+ /// Reference of the final converted content.
+ public TOutput Convert(
+ TInput input,
+ string processorName
+ )
+ {
+ return Convert(input, processorName, new OpaqueDataDictionary());
+ }
+
+ ///
+ /// Converts a content item object using the specified content processor.
+ ///
+ /// Type of the input content.
+ /// Type of the converted output.
+ /// Source content to be converted.
+ /// Optional processor for this content.
+ /// Optional parameters for the processor.
+ /// Reference of the final converted content.
+ public abstract TOutput Convert(
+ TInput input,
+ string processorName,
+ OpaqueDataDictionary processorParameters
+ );
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentStats.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentStats.cs
new file mode 100644
index 000000000..471f73c53
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentStats.cs
@@ -0,0 +1,49 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Content building statistics for a single source content file.
+ ///
+ public struct ContentStats
+ {
+ ///
+ /// The absolute path to the source content file.
+ ///
+ public string SourceFile;
+
+ ///
+ /// The absolute path to the destination content file.
+ ///
+ public string DestFile;
+
+ ///
+ /// The content processor type name.
+ ///
+ public string ProcessorType;
+
+ ///
+ /// The content type name.
+ ///
+ public string ContentType;
+
+ ///
+ /// The source file size in bytes.
+ ///
+ public long SourceFileSize;
+
+ ///
+ /// The destination file size in bytes.
+ ///
+ public long DestFileSize;
+
+ ///
+ /// The content build time in seconds.
+ ///
+ public float BuildSeconds;
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentStatsCollection.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentStatsCollection.cs
new file mode 100644
index 000000000..433d4353b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ContentStatsCollection.cs
@@ -0,0 +1,229 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// A collection of content building statistics for use in diagnosing content issues.
+ ///
+ public class ContentStatsCollection
+ {
+ private static readonly string _header = "Source File,Dest File,Processor Type,Content Type,Source File Size,Dest File Size,Build Seconds";
+ private static readonly Regex _split = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
+
+ private readonly object _locker = new object();
+ private readonly Dictionary _statsBySource = new Dictionary(1024);
+
+ public static readonly string Extension = ".mgstats";
+
+ ///
+ /// Optionally used for copying stats that were stored in another collection.
+ ///
+ public ContentStatsCollection PreviousStats { get; set; }
+
+ ///
+ /// The internal content statistics dictionary.
+ ///
+ public IReadOnlyDictionary Stats
+ {
+ get { return _statsBySource; }
+ }
+
+ ///
+ /// Get the content statistics for a source file and returns true if found.
+ ///
+ public bool TryGetStats(string sourceFile, out ContentStats stats)
+ {
+ lock (_locker)
+ {
+ if (!_statsBySource.TryGetValue(sourceFile, out stats))
+ return false;
+ return true;
+ }
+ }
+
+ ///
+ /// Clears all the content statistics.
+ ///
+ public void Reset()
+ {
+ lock (_locker)
+ _statsBySource.Clear();
+ }
+
+ ///
+ /// Store content building stats for a source file.
+ ///
+ /// The absolute path to the source asset file.
+ /// The absolute path to the destination content file.
+ /// The type name of the content processor.
+ /// The content type object.
+ /// The build time in seconds.
+ public void RecordStats(string sourceFile, string destFile, string processorType, Type contentType, float buildSeconds)
+ {
+ var sourceSize = new FileInfo(sourceFile).Length;
+ var destSize = new FileInfo(destFile).Length;
+
+ lock (_locker)
+ {
+ ContentStats stats;
+ _statsBySource.TryGetValue(sourceFile, out stats);
+
+ stats.SourceFile = sourceFile;
+ stats.DestFile = destFile;
+
+ stats.SourceFileSize = sourceSize;
+ stats.DestFileSize = destSize;
+
+ stats.ContentType = GetFriendlyTypeName(contentType);
+ stats.ProcessorType = processorType;
+
+ stats.BuildSeconds = buildSeconds;
+
+ _statsBySource[stats.SourceFile] = stats;
+ }
+ }
+
+ ///
+ /// Copy content building stats to the current collection from the PreviousStats.
+ ///
+ /// The absolute path to the source asset file.
+ public void CopyPreviousStats(string sourceFile)
+ {
+ if (PreviousStats == null)
+ return;
+
+ lock (_locker)
+ {
+ if (_statsBySource.ContainsKey(sourceFile))
+ return;
+
+ ContentStats stats;
+ if (PreviousStats.TryGetStats(sourceFile, out stats))
+ _statsBySource[stats.SourceFile] = stats;
+ }
+ }
+
+ private static string GetFriendlyTypeName(Type type)
+ {
+ if (type == null)
+ return "";
+ if (type == typeof(int))
+ return "int";
+ else if (type == typeof(short))
+ return "short";
+ else if (type == typeof(byte))
+ return "byte";
+ else if (type == typeof(bool))
+ return "bool";
+ else if (type == typeof(long))
+ return "long";
+ else if (type == typeof(float))
+ return "float";
+ else if (type == typeof(double))
+ return "double";
+ else if (type == typeof(decimal))
+ return "decimal";
+ else if (type == typeof(string))
+ return "string";
+ else if (type.IsArray)
+ return GetFriendlyTypeName(type.GetElementType()) + "[" + new string(',', type.GetArrayRank() - 1) + "]";
+ else if (type.IsGenericType)
+ return type.Name.Split('`')[0] + "<" + string.Join(", ", type.GetGenericArguments().Select(x => GetFriendlyTypeName(x)).ToArray()) + ">";
+ else
+ return type.Name;
+ }
+
+ ///
+ /// Load the content statistics from a folder.
+ ///
+ /// The folder where the .mgstats file can be found.
+ /// Returns the content statistics or an empty collection.
+ public static ContentStatsCollection Read(string outputPath)
+ {
+ var collection = new ContentStatsCollection();
+
+ var filePath = Path.Combine(outputPath, Extension);
+ try
+ {
+ var lines = File.ReadAllLines(filePath);
+
+ // The first line is the CSV header... if it doesn't match then
+ // assume the data is invalid or changed formats.
+ if (lines[0] != _header)
+ return collection;
+
+ for (var i = 1; i < lines.Length; i++)
+ {
+ var columns = _split.Split(lines[i]);
+ if (columns.Length != 7)
+ continue;
+
+ ContentStats stats;
+ stats.SourceFile = columns[0].Trim('"');
+ stats.DestFile = columns[1].Trim('"');
+ stats.ProcessorType = columns[2].Trim('"');
+ stats.ContentType = columns[3].Trim('"');
+ stats.SourceFileSize = long.Parse(columns[4]);
+ stats.DestFileSize = long.Parse(columns[5]);
+ stats.BuildSeconds = float.Parse(columns[6]);
+
+ if (!collection._statsBySource.ContainsKey(stats.SourceFile))
+ collection._statsBySource.Add(stats.SourceFile, stats);
+ }
+ }
+ catch (Exception ex)
+ {
+ // Assume the file didn't exist or was incorrectly
+ // formatted... either way we start from fresh data.
+ collection.Reset();
+ }
+
+ return collection;
+ }
+
+ ///
+ /// Write the content statistics to a folder with the .mgstats file name.
+ ///
+ /// The folder to write the .mgstats file.
+ public void Write(string outputPath)
+ {
+ // ensure the output folder exists
+ Directory.CreateDirectory(outputPath);
+ var filePath = Path.Combine(outputPath, Extension);
+ using (var textWriter = new StreamWriter(filePath, false, new UTF8Encoding(false)))
+ {
+ // Sort the items alphabetically to ensure a consistent output
+ // and better mergability of the resulting file.
+ var contentStats = _statsBySource.Values.OrderBy(c => c.SourceFile, StringComparer.InvariantCulture).ToList();
+
+ textWriter.WriteLine(_header);
+ foreach (var stats in contentStats)
+ textWriter.WriteLine("\"{0}\",\"{1}\",\"{2}\",\"{3}\",{4},{5},{6}", stats.SourceFile, stats.DestFile, stats.ProcessorType, stats.ContentType, stats.SourceFileSize, stats.DestFileSize, stats.BuildSeconds);
+ }
+ }
+
+ ///
+ /// Merge in statistics from PreviousStats that do not exist in this collection.
+ ///
+ public void MergePreviousStats()
+ {
+ if (PreviousStats == null)
+ return;
+
+ foreach (var stats in PreviousStats._statsBySource.Values)
+ {
+ if (!_statsBySource.ContainsKey(stats.SourceFile))
+ _statsBySource.Add(stats.SourceFile, stats);
+ }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/DdsLoader.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/DdsLoader.cs
new file mode 100644
index 000000000..ec8a940ff
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/DdsLoader.cs
@@ -0,0 +1,531 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Graphics.PackedVector;
+using System.IO;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Loader class for DDS format image files.
+ ///
+ class DdsLoader
+ {
+ [Flags]
+ enum Ddsd : uint
+ {
+ Caps = 0x1, // Required in every DDS file
+ Height = 0x2, // Required in every DDS file
+ Width = 0x4, // Required in every DDS file
+ Pitch = 0x8, // Required when pitch is provided for an uncompressed texture
+ PixelFormat = 0x1000, // Required in every DDS file
+ MipMapCount = 0x2000, // Required in a mipmapped texture
+ LinearSize = 0x80000, // Required when pitch is provided for a compressed texture
+ Depth = 0x800000, // Required in a depth texture
+ }
+
+ [Flags]
+ enum DdsCaps : uint
+ {
+ Complex = 0x8, // Optional; must be used on any file that contains more than one surface (a mipmap, a cubic environment map, or mipmapped volume texture)
+ MipMap = 0x400000, // Optional; should be used for a mipmap
+ Texture = 0x1000, // Required
+ }
+
+ [Flags]
+ enum DdsCaps2 : uint
+ {
+ Cubemap = 0x200,
+ CubemapPositiveX = 0x400,
+ CubemapNegativeX = 0x800,
+ CubemapPositiveY = 0x1000,
+ CubemapNegativeY = 0x2000,
+ CubemapPositiveZ = 0x4000,
+ CubemapNegativeZ = 0x8000,
+ Volume = 0x200000,
+
+ CubemapAllFaces = Cubemap | CubemapPositiveX | CubemapNegativeX | CubemapPositiveY | CubemapNegativeY | CubemapPositiveZ | CubemapNegativeZ,
+ }
+
+ [Flags]
+ enum Ddpf : uint
+ {
+ AlphaPixels = 0x1,
+ Alpha = 0x2,
+ FourCC = 0x4,
+ Rgb = 0x40,
+ Yuv = 0x200,
+ Luminance = 0x20000,
+ }
+
+ static uint MakeFourCC(char c1, char c2, char c3, char c4)
+ {
+ return ((uint)c1 << 24) | ((uint)c2 << 16) | ((uint)c3 << 8) | (uint)c4;
+ }
+
+ static uint MakeFourCC(string cc)
+ {
+ return ((uint)cc[0] << 24) | ((uint)cc[1] << 16) | ((uint)cc[2] << 8) | (uint)cc[3];
+ }
+
+ enum FourCC : uint
+ {
+ A32B32G32R32F = 116,
+ Dxt1 = 0x31545844,
+ Dxt2 = 0x32545844,
+ Dxt3 = 0x33545844,
+ Dxt4 = 0x34545844,
+ Dxt5 = 0x35545844,
+ Dx10 = 0x30315844,
+ }
+
+ struct DdsPixelFormat
+ {
+ public uint dwSize;
+ public Ddpf dwFlags;
+ public FourCC dwFourCC;
+ public uint dwRgbBitCount;
+ public uint dwRBitMask;
+ public uint dwGBitMask;
+ public uint dwBBitMask;
+ public uint dwABitMask;
+ }
+
+ struct DdsHeader
+ {
+ public uint dwSize;
+ public Ddsd dwFlags;
+ public uint dwHeight;
+ public uint dwWidth;
+ public uint dwPitchOrLinearSize;
+ public uint dwDepth;
+ public uint dwMipMapCount;
+ public DdsPixelFormat ddspf;
+ public DdsCaps dwCaps;
+ public DdsCaps2 dwCaps2;
+ }
+
+ static SurfaceFormat GetSurfaceFormat(ref DdsPixelFormat pixelFormat, out bool rbSwap)
+ {
+ rbSwap = false;
+ if (pixelFormat.dwFlags.HasFlag(Ddpf.FourCC))
+ {
+ switch (pixelFormat.dwFourCC)
+ {
+ case FourCC.A32B32G32R32F:
+ return SurfaceFormat.Vector4;
+ case FourCC.Dxt1:
+ return SurfaceFormat.Dxt1;
+ case FourCC.Dxt2:
+ throw new ContentLoadException("Unsupported compression format DXT2");
+ case FourCC.Dxt3:
+ return SurfaceFormat.Dxt3;
+ case FourCC.Dxt4:
+ throw new ContentLoadException("Unsupported compression format DXT4");
+ case FourCC.Dxt5:
+ return SurfaceFormat.Dxt5;
+ }
+ }
+ else if (pixelFormat.dwFlags.HasFlag(Ddpf.Rgb))
+ {
+ // Uncompressed format
+ if (pixelFormat.dwFlags.HasFlag(Ddpf.AlphaPixels))
+ {
+ // Format contains RGB and A
+ if (pixelFormat.dwRgbBitCount == 16)
+ {
+ if (pixelFormat.dwABitMask == 0xF)
+ {
+ rbSwap = pixelFormat.dwBBitMask == 0xF0;
+ return SurfaceFormat.Bgra4444;
+ }
+ rbSwap = pixelFormat.dwBBitMask == 0x3E;
+ return SurfaceFormat.Bgra5551;
+ }
+ else if (pixelFormat.dwRgbBitCount == 32)
+ {
+ rbSwap = pixelFormat.dwBBitMask == 0xFF;
+ return SurfaceFormat.Color;
+ }
+ throw new ContentLoadException("Unsupported RGBA pixel format");
+ }
+ else
+ {
+ // Format contains RGB only
+ if (pixelFormat.dwRgbBitCount == 16)
+ {
+ rbSwap = pixelFormat.dwBBitMask == 0x1F;
+ return SurfaceFormat.Bgr565;
+ }
+ else if (pixelFormat.dwRgbBitCount == 24)
+ {
+ rbSwap = pixelFormat.dwBBitMask == 0xFF;
+ return SurfaceFormat.Color;
+ }
+ else if (pixelFormat.dwRgbBitCount == 32)
+ {
+ rbSwap = pixelFormat.dwBBitMask == 0xFF;
+ return SurfaceFormat.Color;
+ }
+ throw new ContentLoadException("Unsupported RGB pixel format");
+ }
+ }
+ //else if (pixelFormat.dwFlags.HasFlag(Ddpf.Luminance))
+ //{
+ // return SurfaceFormat.Alpha8;
+ //}
+ throw new ContentLoadException("Unsupported pixel format");
+ }
+
+ static BitmapContent CreateBitmapContent(SurfaceFormat format, int width, int height)
+ {
+ switch (format)
+ {
+ case SurfaceFormat.Color:
+ return new PixelBitmapContent(width, height);
+
+ case SurfaceFormat.Bgra4444:
+ return new PixelBitmapContent(width, height);
+
+ case SurfaceFormat.Bgra5551:
+ return new PixelBitmapContent(width, height);
+
+ case SurfaceFormat.Bgr565:
+ return new PixelBitmapContent(width, height);
+
+ case SurfaceFormat.Dxt1:
+ return new Dxt1BitmapContent(width, height);
+
+ case SurfaceFormat.Dxt3:
+ return new Dxt3BitmapContent(width, height);
+
+ case SurfaceFormat.Dxt5:
+ return new Dxt5BitmapContent(width, height);
+
+ case SurfaceFormat.Vector4:
+ return new PixelBitmapContent(width, height);
+ }
+ throw new ContentLoadException("Unsupported SurfaceFormat " + format);
+ }
+
+ static int GetBitmapSize(SurfaceFormat format, int width, int height)
+ {
+ // It is recommended that the dwPitchOrLinearSize field is ignored and we calculate it ourselves
+ // https://msdn.microsoft.com/en-us/library/bb943991.aspx
+ int pitch = 0;
+ int rows = 0;
+
+ switch (format)
+ {
+ case SurfaceFormat.Color:
+ case SurfaceFormat.Bgra4444:
+ case SurfaceFormat.Bgra5551:
+ case SurfaceFormat.Bgr565:
+ case SurfaceFormat.Vector4:
+ pitch = width * format.GetSize();
+ rows = height;
+ break;
+
+ case SurfaceFormat.Dxt1:
+ case SurfaceFormat.Dxt3:
+ case SurfaceFormat.Dxt5:
+ pitch = ((width + 3) / 4) * format.GetSize();
+ rows = (height + 3) / 4;
+ break;
+
+ default:
+ throw new ContentLoadException("Unsupported SurfaceFormat " + format);
+ }
+
+ return pitch * rows;
+ }
+
+ static internal TextureContent Import(string filename, ContentImporterContext context)
+ {
+ var identity = new ContentIdentity(filename);
+ TextureContent output = null;
+
+ using (var reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
+ {
+ // Read signature ("DDS ")
+ var valid = reader.ReadByte() == 0x44;
+ valid = valid && reader.ReadByte() == 0x44;
+ valid = valid && reader.ReadByte() == 0x53;
+ valid = valid && reader.ReadByte() == 0x20;
+ if (!valid)
+ throw new ContentLoadException("Invalid file signature");
+
+ var header = new DdsHeader();
+
+ // Read DDS_HEADER
+ header.dwSize = reader.ReadUInt32();
+ if (header.dwSize != 124)
+ throw new ContentLoadException("Invalid DDS_HEADER dwSize value");
+ header.dwFlags = (Ddsd)reader.ReadUInt32();
+ header.dwHeight = reader.ReadUInt32();
+ header.dwWidth = reader.ReadUInt32();
+ header.dwPitchOrLinearSize = reader.ReadUInt32();
+ header.dwDepth = reader.ReadUInt32();
+ header.dwMipMapCount = reader.ReadUInt32();
+ // The next 11 DWORDs are reserved and unused
+ for (int i = 0; i < 11; ++i)
+ reader.ReadUInt32();
+ // Read DDS_PIXELFORMAT
+ header.ddspf.dwSize = reader.ReadUInt32();
+ if (header.ddspf.dwSize != 32)
+ throw new ContentLoadException("Invalid DDS_PIXELFORMAT dwSize value");
+ header.ddspf.dwFlags = (Ddpf)reader.ReadUInt32();
+ header.ddspf.dwFourCC = (FourCC)reader.ReadUInt32();
+ header.ddspf.dwRgbBitCount = reader.ReadUInt32();
+ header.ddspf.dwRBitMask = reader.ReadUInt32();
+ header.ddspf.dwGBitMask = reader.ReadUInt32();
+ header.ddspf.dwBBitMask = reader.ReadUInt32();
+ header.ddspf.dwABitMask = reader.ReadUInt32();
+ // Continue reading DDS_HEADER
+ header.dwCaps = (DdsCaps)reader.ReadUInt32();
+ header.dwCaps2 = (DdsCaps2)reader.ReadUInt32();
+ // dwCaps3 unused
+ reader.ReadUInt32();
+ // dwCaps4 unused
+ reader.ReadUInt32();
+ // dwReserved2 unused
+ reader.ReadUInt32();
+
+ // Check for the existence of the DDS_HEADER_DXT10 struct next
+ if (header.ddspf.dwFlags == Ddpf.FourCC && header.ddspf.dwFourCC == FourCC.Dx10)
+ {
+ throw new ContentLoadException("Unsupported DDS_HEADER_DXT10 struct found");
+ }
+
+ int faceCount = 1;
+ int mipMapCount = (int)(header.dwCaps.HasFlag(DdsCaps.MipMap) ? header.dwMipMapCount : 1);
+ if (header.dwCaps2.HasFlag(DdsCaps2.Cubemap))
+ {
+ if (!header.dwCaps2.HasFlag(DdsCaps2.CubemapAllFaces))
+ throw new ContentLoadException("Incomplete cubemap in DDS file");
+ faceCount = 6;
+ output = new TextureCubeContent() { Identity = identity };
+ }
+ else
+ {
+ output = new Texture2DContent() { Identity = identity };
+ }
+
+ bool rbSwap;
+ var format = GetSurfaceFormat(ref header.ddspf, out rbSwap);
+
+ for (int f = 0; f < faceCount; ++f)
+ {
+ var w = (int)header.dwWidth;
+ var h = (int)header.dwHeight;
+ var mipMaps = new MipmapChain();
+ for (int m = 0; m < mipMapCount; ++m)
+ {
+ var content = CreateBitmapContent(format, w, h);
+ var byteCount = GetBitmapSize(format, w, h);
+ // A 24-bit format is slightly different
+ if (header.ddspf.dwRgbBitCount == 24)
+ byteCount = 3 * w * h;
+ var bytes = reader.ReadBytes(byteCount);
+ if (rbSwap)
+ {
+ switch (format)
+ {
+ case SurfaceFormat.Bgr565:
+ ByteSwapBGR565(bytes);
+ break;
+ case SurfaceFormat.Bgra4444:
+ ByteSwapBGRA4444(bytes);
+ break;
+ case SurfaceFormat.Bgra5551:
+ ByteSwapBGRA5551(bytes);
+ break;
+ case SurfaceFormat.Color:
+ if (header.ddspf.dwRgbBitCount == 32)
+ ByteSwapRGBX(bytes);
+ else if (header.ddspf.dwRgbBitCount == 24)
+ ByteSwapRGB(bytes);
+ break;
+ }
+ }
+ if ((format == SurfaceFormat.Color) && header.ddspf.dwFlags.HasFlag(Ddpf.Rgb) && !header.ddspf.dwFlags.HasFlag(Ddpf.AlphaPixels))
+ {
+ // Fill or add alpha with opaque
+ if (header.ddspf.dwRgbBitCount == 32)
+ ByteFillAlpha(bytes);
+ else if (header.ddspf.dwRgbBitCount == 24)
+ ByteExpandAlpha(ref bytes);
+ }
+ content.SetPixelData(bytes);
+ mipMaps.Add(content);
+ w = MathHelper.Max(1, w / 2);
+ h = MathHelper.Max(1, h / 2);
+ }
+ output.Faces[f] = mipMaps;
+ }
+ }
+
+ return output;
+ }
+
+ static void ByteFillAlpha(byte[] bytes)
+ {
+ for (int i = 0; i < bytes.Length; i += 4)
+ {
+ bytes[i + 3] = 255;
+ }
+ }
+
+ static void ByteExpandAlpha(ref byte[] bytes)
+ {
+ var rgba = new byte[bytes.Length + (bytes.Length / 3)];
+ int j = 0;
+ for (int i = 0; i < bytes.Length; i += 3)
+ {
+ rgba[j] = bytes[i];
+ rgba[j + 1] = bytes[i + 1];
+ rgba[j + 2] = bytes[i + 2];
+ rgba[j + 3] = 255;
+ j += 4;
+ }
+ bytes = rgba;
+ }
+
+ static void ByteSwapRGB(byte[] bytes)
+ {
+ for (int i = 0; i < bytes.Length; i += 3)
+ {
+ byte r = bytes[i];
+ bytes[i] = bytes[i + 2];
+ bytes[i + 2] = r;
+ }
+ }
+
+ static void ByteSwapRGBX(byte[] bytes)
+ {
+ for (int i = 0; i < bytes.Length; i += 4)
+ {
+ byte r = bytes[i];
+ bytes[i] = bytes[i + 2];
+ bytes[i + 2] = r;
+ }
+ }
+
+ static void ByteSwapBGRA4444(byte[] bytes)
+ {
+ for (int i = 0; i < bytes.Length; i += 2)
+ {
+ var r = bytes[i] & 0xF0;
+ var b = bytes[i + 1] & 0xF0;
+ bytes[i] = (byte)((bytes[i] & 0x0F) | b);
+ bytes[i + 1] = (byte)((bytes[i + 1] & 0x0F) | r);
+ }
+ }
+
+ static void ByteSwapBGRA5551(byte[] bytes)
+ {
+ for (int i = 0; i < bytes.Length; i += 2)
+ {
+ var r = (bytes[i] & 0xF8) >> 3;
+ var b = (bytes[i + 1] & 0x3E) >> 1;
+ bytes[i] = (byte)((bytes[i] & 0x07) | (b << 3));
+ bytes[i + 1] = (byte)((bytes[i + 1] & 0xC1) | (r << 1));
+ }
+ }
+
+ static void ByteSwapBGR565(byte[] bytes)
+ {
+ for (int i = 0; i < bytes.Length; i += 2)
+ {
+ var r = (bytes[i] & 0xF8) >> 3;
+ var b = bytes[i + 1] & 0x1F;
+ bytes[i] = (byte)((bytes[i] & 0x07) | (b << 3));
+ bytes[i + 1] = (byte)((bytes[i + 1] & 0xE0) | r);
+ }
+ }
+
+ internal static void WriteUncompressed(string filename, BitmapContent bitmapContent)
+ {
+ using (var writer = new BinaryWriter(new FileStream(filename, FileMode.Create, FileAccess.Write)))
+ {
+ // Write signature ("DDS ")
+ writer.Write((byte)0x44);
+ writer.Write((byte)0x44);
+ writer.Write((byte)0x53);
+ writer.Write((byte)0x20);
+
+ var header = new DdsHeader();
+ header.dwSize = 124;
+ header.dwFlags = Ddsd.Caps | Ddsd.Width | Ddsd.Height | Ddsd.Pitch | Ddsd.PixelFormat;
+ header.dwWidth = (uint)bitmapContent.Width;
+ header.dwHeight = (uint)bitmapContent.Height;
+ header.dwPitchOrLinearSize = (uint)(bitmapContent.Width * 4);
+ header.dwDepth = (uint)0;
+ header.dwMipMapCount = (uint)0;
+
+ writer.Write((uint)header.dwSize);
+ writer.Write((uint)header.dwFlags);
+ writer.Write((uint)header.dwHeight);
+ writer.Write((uint)header.dwWidth);
+ writer.Write((uint)header.dwPitchOrLinearSize);
+ writer.Write((uint)header.dwDepth);
+ writer.Write((uint)header.dwMipMapCount);
+
+ // 11 unsed and reserved DWORDS.
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+
+ SurfaceFormat format;
+ if (!bitmapContent.TryGetFormat(out format) || format != SurfaceFormat.Color)
+ throw new NotSupportedException("Unsupported bitmap content!");
+
+ header.ddspf.dwSize = 32;
+ header.ddspf.dwFlags = Ddpf.AlphaPixels | Ddpf.Rgb;
+ header.ddspf.dwFourCC = 0;
+ header.ddspf.dwRgbBitCount = 32;
+ header.ddspf.dwRBitMask = 0x000000ff;
+ header.ddspf.dwGBitMask = 0x0000ff00;
+ header.ddspf.dwBBitMask = 0x00ff0000;
+ header.ddspf.dwABitMask = 0xff000000;
+
+ // Write the DDS_PIXELFORMAT
+ writer.Write((uint)header.ddspf.dwSize);
+ writer.Write((uint)header.ddspf.dwFlags);
+ writer.Write((uint)header.ddspf.dwFourCC);
+ writer.Write((uint)header.ddspf.dwRgbBitCount);
+ writer.Write((uint)header.ddspf.dwRBitMask);
+ writer.Write((uint)header.ddspf.dwGBitMask);
+ writer.Write((uint)header.ddspf.dwBBitMask);
+ writer.Write((uint)header.ddspf.dwABitMask);
+
+ header.dwCaps = DdsCaps.Texture;
+ header.dwCaps2 = 0;
+
+ // Continue reading DDS_HEADER
+ writer.Write((uint)header.dwCaps);
+ writer.Write((uint)header.dwCaps2);
+
+ // More reserved unused DWORDs.
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+ writer.Write((uint)0);
+
+ // Write out the face data.
+ writer.Write(bitmapContent.GetPixelData());
+ }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/EffectImporter.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/EffectImporter.cs
new file mode 100644
index 000000000..7691d045a
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/EffectImporter.cs
@@ -0,0 +1,38 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides methods for reading effect (.fx) files for use in the Content Pipeline.
+ ///
+ [ContentImporter(".fx", DisplayName = "Effect Importer - MonoGame", DefaultProcessor = "EffectProcessor")]
+ public class EffectImporter : ContentImporter
+ {
+ ///
+ /// Initializes a new instance of EffectImporter.
+ ///
+ public EffectImporter()
+ {
+ }
+
+ ///
+ /// Called by the XNA Framework when importing an .fx file to be used as a game asset. This is the method called by the XNA Framework when an asset is to be imported into an object that can be recognized by the Content Pipeline.
+ ///
+ /// Name of a game asset file.
+ /// Contains information for importing a game asset, such as a logger interface.
+ /// Resulting game asset.
+ public override EffectContent Import(string filename, ContentImporterContext context)
+ {
+ var effect = new EffectContent();
+ effect.Identity = new ContentIdentity(filename);
+ using (var reader = new StreamReader(filename))
+ effect.EffectCode = reader.ReadToEnd();
+ return effect;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ExternalReference.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ExternalReference.cs
new file mode 100644
index 000000000..d40d3ce1e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ExternalReference.cs
@@ -0,0 +1,66 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using MonoGame.Framework.Content.Pipeline.Builder;
+using System;
+using System.IO;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Specifies external references to a data file for the content item.
+ ///
+ /// While the object model is instantiated, reference file names are absolute. When the file containing the external reference is serialized to disk, file names are relative to the file. This allows movement of the content tree to a different location without breaking internal links.
+ ///
+ ///
+ public sealed class ExternalReference : ContentItem
+ {
+ ///
+ /// Gets and sets the file name of an ExternalReference.
+ ///
+ public string Filename { get; set; }
+
+ ///
+ /// Initializes a new instance of ExternalReference.
+ ///
+ public ExternalReference()
+ {
+ Filename = string.Empty;
+ }
+
+ ///
+ /// Initializes a new instance of ExternalReference.
+ ///
+ /// The name of the referenced file.
+ public ExternalReference(string filename)
+ {
+ if (string.IsNullOrEmpty(filename))
+ throw new ArgumentNullException("filename");
+ Filename = filename;
+ }
+
+ ///
+ /// Initializes a new instance of ExternalReference, specifying the file path relative to another content item.
+ ///
+ /// The name of the referenced file.
+ /// The content that the path specified in filename is relative to.
+ public ExternalReference(string filename, ContentIdentity relativeToContent)
+ {
+ if (string.IsNullOrEmpty(filename))
+ throw new ArgumentNullException("filename");
+ if (relativeToContent == null)
+ throw new ArgumentNullException("relativeToContent");
+ if (string.IsNullOrEmpty(relativeToContent.SourceFilename))
+ throw new ArgumentNullException("relativeToContent.SourceFilename");
+
+ // The intermediate serializer from XNA has the external reference
+ // path walking up to the content project directory and then back
+ // down to the asset path. We don't appear to have any way to do
+ // that from here, so we'll work with the absolute path and let the
+ // higher level process sort out any relative paths they need.
+ var basePath = Path.GetDirectoryName(relativeToContent.SourceFilename);
+ Filename = PathHelper.Normalize(Path.GetFullPath(Path.Combine(basePath, filename)));
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ExternalTool.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ExternalTool.cs
new file mode 100644
index 000000000..f47d13490
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/ExternalTool.cs
@@ -0,0 +1,191 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using MonoGame.Utilities;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Helper to run an external tool installed in the system. Useful for when
+ /// we don't want to package the tool ourselves (ffmpeg) or it's provided
+ /// by a third party (console manufacturer).
+ ///
+ internal class ExternalTool
+ {
+ public static int Run(string command, string arguments)
+ {
+ string stdout, stderr;
+ var result = Run(command, arguments, out stdout, out stderr);
+ if (result < 0)
+ throw new Exception(string.Format("{0} returned exit code {1}", command, result));
+
+ return result;
+ }
+
+ public static int Run(string command, string arguments, out string stdout, out string stderr, string stdin = null)
+ {
+ // This particular case is likely to be the most common and thus
+ // warrants its own specific error message rather than falling
+ // back to a general exception from Process.Start()
+ var fullPath = FindCommand(command);
+ if (string.IsNullOrEmpty(fullPath))
+ throw new Exception(string.Format("Couldn't locate external tool '{0}'.", command));
+
+ // We can't reference ref or out parameters from within
+ // lambdas (for the thread functions), so we have to store
+ // the data in a temporary variable and then assign these
+ // variables to the out parameters.
+ var stdoutTemp = string.Empty;
+ var stderrTemp = string.Empty;
+
+ var processInfo = new ProcessStartInfo
+ {
+ Arguments = arguments,
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false,
+ FileName = fullPath,
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ RedirectStandardInput = true,
+ };
+
+ EnsureExecutable(fullPath);
+
+ using (var process = new Process())
+ {
+ process.StartInfo = processInfo;
+
+ process.Start();
+
+ // We have to run these in threads, because using ReadToEnd
+ // on one stream can deadlock if the other stream's buffer is
+ // full.
+ var stdoutThread = new Thread(new ThreadStart(() =>
+ {
+ var memory = new MemoryStream();
+ process.StandardOutput.BaseStream.CopyTo(memory);
+ var bytes = new byte[memory.Position];
+ memory.Seek(0, SeekOrigin.Begin);
+ memory.Read(bytes, 0, bytes.Length);
+ stdoutTemp = System.Text.Encoding.ASCII.GetString(bytes);
+ }));
+ var stderrThread = new Thread(new ThreadStart(() =>
+ {
+ var memory = new MemoryStream();
+ process.StandardError.BaseStream.CopyTo(memory);
+ var bytes = new byte[memory.Position];
+ memory.Seek(0, SeekOrigin.Begin);
+ memory.Read(bytes, 0, bytes.Length);
+ stderrTemp = System.Text.Encoding.ASCII.GetString(bytes);
+ }));
+
+ stdoutThread.Start();
+ stderrThread.Start();
+
+ if (stdin != null)
+ {
+ process.StandardInput.Write(System.Text.Encoding.ASCII.GetBytes(stdin));
+ }
+
+ // Make sure interactive prompts don't block.
+ process.StandardInput.Close();
+
+ process.WaitForExit();
+
+ stdoutThread.Join();
+ stderrThread.Join();
+
+ stdout = stdoutTemp;
+ stderr = stderrTemp;
+
+ return process.ExitCode;
+ }
+ }
+
+ ///
+ /// Returns the fully-qualified path for a command, searching the system path if necessary.
+ ///
+ ///
+ /// It's apparently necessary to use the full path when running on some systems.
+ ///
+ private static string FindCommand(string command)
+ {
+ // Expand any environment variables.
+ command = Environment.ExpandEnvironmentVariables(command);
+
+ // If we have a full path just pass it through.
+ if (File.Exists(command))
+ return command;
+
+ // We don't have a full path, so try running through the system path to find it.
+ var paths = AppDomain.CurrentDomain.BaseDirectory +
+ Path.PathSeparator +
+ Environment.GetEnvironmentVariable("PATH");
+
+ var justTheName = Path.GetFileName(command);
+ foreach (var path in paths.Split(Path.PathSeparator))
+ {
+ var fullName = Path.Combine(path, justTheName);
+ if (File.Exists(fullName))
+ return fullName;
+
+ if (CurrentPlatform.OS == OS.Windows)
+ {
+ var fullExeName = string.Concat(fullName, ".exe");
+ if (File.Exists(fullExeName))
+ return fullExeName;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Ensures the specified executable has the executable bit set. If the
+ /// executable doesn't have the executable bit set on Linux or Mac OS, then
+ /// Mono will refuse to execute it.
+ ///
+ /// The full path to the executable.
+ private static void EnsureExecutable(string path)
+ {
+#if LINUX || MACOS
+ if (path == "/bin/bash")
+ return;
+
+ try
+ {
+
+ var p = Process.Start("chmod", "u+x '" + path + "'");
+ p.WaitForExit();
+ }
+ catch
+ {
+ // This platform may not have chmod in the path, in which case we can't
+ // do anything reasonable here.
+ }
+#endif
+ }
+
+ ///
+ /// Safely deletes the file if it exists.
+ ///
+ /// The path to the file to delete.
+ public static void DeleteFile(string filePath)
+ {
+ try
+ {
+ File.Delete(filePath);
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/FbxImporter.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/FbxImporter.cs
new file mode 100644
index 000000000..f79fa77b0
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/FbxImporter.cs
@@ -0,0 +1,27 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides methods for reading AutoDesk (.fbx) files for use in the Content Pipeline.
+ ///
+ [ContentImporter(".fbx", DisplayName = "Fbx Importer - MonoGame", DefaultProcessor = "ModelProcessor")]
+ public class FbxImporter : ContentImporter
+ {
+ public override NodeContent Import(string filename, ContentImporterContext context)
+ {
+ if (filename == null)
+ throw new ArgumentNullException("filename");
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ var importer = new OpenAssetImporter("FbxImporter", true);
+ return importer.Import(filename, context);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/FontDescriptionImporter.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/FontDescriptionImporter.cs
new file mode 100644
index 000000000..02df72d9d
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/FontDescriptionImporter.cs
@@ -0,0 +1,44 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.IO;
+using System.Xml;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// Provides methods for reading .spritefont files for use in the Content Pipeline.
+ ///
+ [ContentImporter(".spritefont", DisplayName = "Sprite Font Importer - MonoGame", DefaultProcessor = "FontDescriptionProcessor")]
+ public class FontDescriptionImporter : ContentImporter
+ {
+ ///
+ /// Initializes a new instance of FontDescriptionImporter.
+ ///
+ public FontDescriptionImporter()
+ {
+ }
+
+ ///
+ /// Called by the XNA Framework when importing a .spritefont file to be used as a game asset. This is the method called by the XNA Framework when an asset is to be imported into an object that can be recognized by the Content Pipeline.
+ ///
+ /// Name of a game asset file.
+ /// Contains information for importing a game asset, such as a logger interface.
+ /// Resulting game asset.
+ public override FontDescription Import(string filename, ContentImporterContext context)
+ {
+ FontDescription fontDescription = null;
+
+ using (var input = XmlReader.Create(filename))
+ fontDescription = IntermediateSerializer.Deserialize(input, filename);
+
+ fontDescription.Identity = new ContentIdentity(new FileInfo(filename).FullName, "FontDescriptionImporter");
+
+ return fontDescription;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AlphaTestMaterialContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AlphaTestMaterialContent.cs
new file mode 100644
index 000000000..abc0a8870
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AlphaTestMaterialContent.cs
@@ -0,0 +1,54 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class AlphaTestMaterialContent : MaterialContent
+ {
+ public const string AlphaKey = "Alpha";
+ public const string AlphaFunctionKey = "AlphaFunction";
+ public const string DiffuseColorKey = "DiffuseColor";
+ public const string ReferenceAlphaKey = "ReferenceAlpha";
+ public const string TextureKey = "Texture";
+ public const string VertexColorEnabledKey = "VertexColorEnabled";
+
+ public float? Alpha
+ {
+ get { return GetValueTypeProperty(AlphaKey); }
+ set { SetProperty(AlphaKey, value); }
+ }
+
+ public CompareFunction? AlphaFunction
+ {
+ get { return GetValueTypeProperty(AlphaFunctionKey); }
+ set { SetProperty(AlphaFunctionKey, value); }
+ }
+
+ public Vector3? DiffuseColor
+ {
+ get { return GetValueTypeProperty(DiffuseColorKey); }
+ set { SetProperty(DiffuseColorKey, value); }
+ }
+
+ public int? ReferenceAlpha
+ {
+ get { return GetValueTypeProperty(ReferenceAlphaKey); }
+ set { SetProperty(ReferenceAlphaKey, value); }
+ }
+
+ public ExternalReference Texture
+ {
+ get { return GetTexture(TextureKey); }
+ set { SetTexture(TextureKey, value); }
+ }
+
+ public bool? VertexColorEnabled
+ {
+ get { return GetValueTypeProperty(VertexColorEnabledKey); }
+ set { SetProperty(VertexColorEnabledKey, value); }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationChannel.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationChannel.cs
new file mode 100644
index 000000000..bf12940e7
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationChannel.cs
@@ -0,0 +1,183 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides methods and properties for maintaining an animation channel. An animation channel is a collection of keyframes describing the movement of a single bone or rigid object.
+ ///
+ public sealed class AnimationChannel : ICollection, IEnumerable, IEnumerable
+ {
+ List keyframes;
+
+ ///
+ /// Gets the number of keyframes in the collection.
+ ///
+ public int Count
+ {
+ get
+ {
+ return keyframes.Count;
+ }
+ }
+
+ ///
+ /// Gets the keyframe at the specified index position.
+ ///
+ public AnimationKeyframe this[int index]
+ {
+ get
+ {
+ return keyframes[index];
+ }
+ }
+
+ ///
+ /// Returns a value indicating whether the object is read-only.
+ ///
+ bool ICollection.IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of AnimationChannel.
+ ///
+ public AnimationChannel()
+ {
+ keyframes = new List();
+ }
+
+ ///
+ /// To satisfy ICollection
+ ///
+ ///
+ void ICollection.Add(AnimationKeyframe item)
+ {
+ keyframes.Add(item);
+ }
+
+ ///
+ /// Adds a new keyframe to the collection, automatically sorting the contents according to keyframe times.
+ ///
+ /// Keyframe to be added to the channel.
+ /// Index of the new keyframe.
+ public int Add(AnimationKeyframe item)
+ {
+ if (item == null)
+ throw new ArgumentNullException("item");
+
+ // Find the correct place at which to insert it, so we can know the index to return.
+ // The alternative is Add, Sort then return IndexOf, which would be horribly inefficient
+ // and the order returned by Sort would change each time for keyframes with the same time.
+
+ // BinarySearch returns the index of the first item found with the same time, or the bitwise
+ // complement of the next largest item found.
+ int index = keyframes.BinarySearch(item);
+ if (index >= 0)
+ {
+ // If a match is found, we do not know if it is at the start, middle or end of a range of
+ // keyframes with the same time value. So look for the end of the range and insert there
+ // so we have deterministic behaviour.
+ while (index < keyframes.Count)
+ {
+ if (item.CompareTo(keyframes[index]) != 0)
+ break;
+ ++index;
+ }
+ }
+ else
+ {
+ // If BinarySearch returns a negative value, it is the bitwise complement of the next largest
+ // item in the list. So we just do a bitwise complement and insert at that index.
+ index = ~index;
+ }
+ keyframes.Insert(index, item);
+
+ return index;
+ }
+
+ ///
+ /// Removes all keyframes from the collection.
+ ///
+ public void Clear()
+ {
+ keyframes.Clear();
+ }
+
+ ///
+ /// Searches the collection for the specified keyframe.
+ ///
+ /// Keyframe being searched for.
+ /// true if the keyframe exists; false otherwise.
+ public bool Contains(AnimationKeyframe item)
+ {
+ return keyframes.Contains(item);
+ }
+
+ ///
+ /// To satisfy ICollection
+ ///
+ ///
+ ///
+ void ICollection.CopyTo(AnimationKeyframe[] array, int arrayIndex)
+ {
+ keyframes.CopyTo(array, arrayIndex);
+ }
+
+ ///
+ /// Determines the index for the specified keyframe.
+ ///
+ /// Identity of a keyframe.
+ /// Index of the specified keyframe.
+ public int IndexOf(AnimationKeyframe item)
+ {
+ return keyframes.IndexOf(item);
+ }
+
+ ///
+ /// Removes the specified keyframe from the collection.
+ ///
+ /// Keyframe being removed.
+ /// true if the keyframe was removed; false otherwise.
+ public bool Remove(AnimationKeyframe item)
+ {
+ return keyframes.Remove(item);
+ }
+
+ ///
+ /// Removes the keyframe at the specified index position.
+ ///
+ /// Index of the keyframe being removed.
+ public void RemoveAt(int index)
+ {
+ keyframes.RemoveAt(index);
+ }
+
+ ///
+ /// Returns an enumerator that iterates through the keyframes.
+ ///
+ /// Enumerator for the keyframe collection.
+ public IEnumerator GetEnumerator()
+ {
+ return keyframes.GetEnumerator();
+ }
+
+ ///
+ /// To satisfy ICollection
+ ///
+ ///
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return keyframes.GetEnumerator();
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationChannelDictionary.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationChannelDictionary.cs
new file mode 100644
index 000000000..e62a45ec4
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationChannelDictionary.cs
@@ -0,0 +1,19 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Collection of animation data channels, one per bone or rigid object.
+ ///
+ public sealed class AnimationChannelDictionary : NamedValueDictionary
+ {
+ ///
+ /// Initializes a new instance of AnimationChannelDictionary.
+ ///
+ public AnimationChannelDictionary()
+ {
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationContent.cs
new file mode 100644
index 000000000..644bd2f22
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationContent.cs
@@ -0,0 +1,51 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides properties for maintaining an animation.
+ ///
+ public class AnimationContent : ContentItem
+ {
+ AnimationChannelDictionary channels;
+ TimeSpan duration;
+
+ ///
+ /// Gets the collection of animation data channels. Each channel describes the movement of a single bone or rigid object.
+ ///
+ public AnimationChannelDictionary Channels
+ {
+ get
+ {
+ return channels;
+ }
+ }
+
+ ///
+ /// Gets or sets the total length of the animation.
+ ///
+ public TimeSpan Duration
+ {
+ get
+ {
+ return duration;
+ }
+ set
+ {
+ duration = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of AnimationContent.
+ ///
+ public AnimationContent()
+ {
+ channels = new AnimationChannelDictionary();
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationContentDictionary.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationContentDictionary.cs
new file mode 100644
index 000000000..64a684df5
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationContentDictionary.cs
@@ -0,0 +1,19 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Collection of named animations.
+ ///
+ public sealed class AnimationContentDictionary : NamedValueDictionary
+ {
+ ///
+ /// Initializes a new instance of AnimationContentDictionary.
+ ///
+ public AnimationContentDictionary()
+ {
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationKeyframe.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationKeyframe.cs
new file mode 100644
index 000000000..f55fbc845
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AnimationKeyframe.cs
@@ -0,0 +1,69 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides methods and properties for managing a keyframe. A keyframe describes the position of an animation channel at a single point in time.
+ ///
+ public sealed class AnimationKeyframe : IComparable
+ {
+ TimeSpan time;
+ Matrix transform;
+
+ ///
+ /// Gets the time offset from the start of the animation to the position described by this keyframe.
+ ///
+ public TimeSpan Time
+ {
+ get
+ {
+ return time;
+ }
+ }
+
+ ///
+ /// Gets or sets the position described by this keyframe.
+ ///
+ public Matrix Transform
+ {
+ get
+ {
+ return transform;
+ }
+ set
+ {
+ transform = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of AnimationKeyframe with the specified time offsetand transform.
+ ///
+ /// Time offset of the keyframe.
+ /// Position of the keyframe.
+ public AnimationKeyframe(TimeSpan time, Matrix transform)
+ {
+ this.time = time;
+ this.transform = transform;
+ }
+
+ ///
+ /// Compares this instance of a keyframe to another.
+ ///
+ /// Keyframe being compared to.
+ /// Indication of their relative values.
+ public int CompareTo(AnimationKeyframe other)
+ {
+ // No sense in comparing the transform, so compare the time.
+ // This would be used for sorting keyframes in time order.
+ return time.CompareTo(other.time);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcBitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcBitmapContent.cs
new file mode 100644
index 000000000..95fa850fd
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcBitmapContent.cs
@@ -0,0 +1,114 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Graphics;
+using ATI.TextureConverter;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public abstract class AtcBitmapContent : BitmapContent
+ {
+ internal byte[] _bitmapData;
+
+ public AtcBitmapContent()
+ : base()
+ {
+ }
+
+ public AtcBitmapContent(int width, int height)
+ : base(width, height)
+ {
+ }
+
+ public override byte[] GetPixelData()
+ {
+ return _bitmapData;
+ }
+
+ public override void SetPixelData(byte[] sourceData)
+ {
+ _bitmapData = sourceData;
+ }
+
+ protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
+ {
+ SurfaceFormat sourceFormat;
+ if (!sourceBitmap.TryGetFormat(out sourceFormat))
+ return false;
+
+ SurfaceFormat format;
+ TryGetFormat(out format);
+
+ // A shortcut for copying the entire bitmap to another bitmap of the same type and format
+ if (format == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
+ {
+ SetPixelData(sourceBitmap.GetPixelData());
+ return true;
+ }
+
+ // Destination region copy is not yet supported
+ if (destinationRegion != new Rectangle(0, 0, Width, Height))
+ return false;
+
+ // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy
+ if (!(sourceBitmap is PixelBitmapContent) || sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height)
+ {
+ try
+ {
+ BitmapContent.Copy(sourceBitmap, sourceRegion, this, destinationRegion);
+ return true;
+ }
+ catch (InvalidOperationException)
+ {
+ return false;
+ }
+ }
+
+ // Convert to full colour 32-bit format. Floating point would be preferred for processing, but it appears the ATICompressor does not support this
+ var colorBitmap = new PixelBitmapContent(sourceRegion.Width, sourceRegion.Height);
+ BitmapContent.Copy(sourceBitmap, sourceRegion, colorBitmap, new Rectangle(0, 0, colorBitmap.Width, colorBitmap.Height));
+ sourceBitmap = colorBitmap;
+
+ ATICompressor.CompressionFormat targetFormat;
+ switch (format)
+ {
+ case SurfaceFormat.RgbaAtcExplicitAlpha:
+ targetFormat = ATICompressor.CompressionFormat.AtcRgbaExplicitAlpha;
+ break;
+ case SurfaceFormat.RgbaAtcInterpolatedAlpha:
+ targetFormat = ATICompressor.CompressionFormat.AtcRgbaInterpolatedAlpha;
+ break;
+ default:
+ return false;
+ }
+
+ var sourceData = sourceBitmap.GetPixelData();
+ var compressedData = ATICompressor.Compress(sourceData, Width, Height, targetFormat);
+ SetPixelData(compressedData);
+
+ return true;
+ }
+
+ protected override bool TryCopyTo(BitmapContent destinationBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
+ {
+ SurfaceFormat destinationFormat;
+ if (!destinationBitmap.TryGetFormat(out destinationFormat))
+ return false;
+
+ SurfaceFormat format;
+ TryGetFormat(out format);
+
+ // A shortcut for copying the entire bitmap to another bitmap of the same type and format
+ if (format == destinationFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
+ {
+ destinationBitmap.SetPixelData(GetPixelData());
+ return true;
+ }
+
+ // No other support for copying from a ATC texture yet
+ return false;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcExplicitBitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcExplicitBitmapContent.cs
new file mode 100644
index 000000000..019d58fcb
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcExplicitBitmapContent.cs
@@ -0,0 +1,48 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class AtcExplicitBitmapContent : AtcBitmapContent
+ {
+ ///
+ /// Creates an instance of AtcExplicitBitmapContent.
+ ///
+ public AtcExplicitBitmapContent()
+ {
+ }
+
+ ///
+ /// Creates an instance of AtcExplicitBitmapContent with the specified width and height.
+ ///
+ /// The width in pixels of the bitmap.
+ /// The height in pixels of the bitmap.
+ public AtcExplicitBitmapContent(int width, int height)
+ : base(width, height)
+ {
+ }
+
+ ///
+ /// Gets the corresponding GPU texture format for the specified bitmap type.
+ ///
+ /// Format being retrieved.
+ /// The GPU texture format of the bitmap type.
+ public override bool TryGetFormat(out SurfaceFormat format)
+ {
+ format = SurfaceFormat.RgbaAtcExplicitAlpha;
+ return true;
+ }
+
+ ///
+ /// Returns a string description of the bitmap.
+ ///
+ /// Description of the bitmap.
+ public override string ToString()
+ {
+ return "ATITC Explicit Alpha " + Width + "x" + Height;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcInterpolatedBitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcInterpolatedBitmapContent.cs
new file mode 100644
index 000000000..3d4a68913
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/AtcInterpolatedBitmapContent.cs
@@ -0,0 +1,48 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class AtcInterpolatedBitmapContent : AtcBitmapContent
+ {
+ ///
+ /// Creates an instance of AtcInterpolatedBitmapContent.
+ ///
+ public AtcInterpolatedBitmapContent()
+ {
+ }
+
+ ///
+ /// Creates an instance of AtcInterpolatedBitmapContent with the specified width and height.
+ ///
+ /// The width in pixels of the bitmap.
+ /// The height in pixels of the bitmap.
+ public AtcInterpolatedBitmapContent(int width, int height)
+ : base(width, height)
+ {
+ }
+
+ ///
+ /// Gets the corresponding GPU texture format for the specified bitmap type.
+ ///
+ /// Format being retrieved.
+ /// The GPU texture format of the bitmap type.
+ public override bool TryGetFormat(out SurfaceFormat format)
+ {
+ format = SurfaceFormat.RgbaAtcInterpolatedAlpha;
+ return true;
+ }
+
+ ///
+ /// Returns a string description of the bitmap.
+ ///
+ /// Description of the bitmap.
+ public override string ToString()
+ {
+ return "ATITC Interpolated Alpha " + Width + "x" + Height;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BasicMaterialContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BasicMaterialContent.cs
new file mode 100644
index 000000000..569978e74
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BasicMaterialContent.cs
@@ -0,0 +1,59 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class BasicMaterialContent : MaterialContent
+ {
+ public const string AlphaKey = "Alpha";
+ public const string DiffuseColorKey = "DiffuseColor";
+ public const string EmissiveColorKey = "EmissiveColor";
+ public const string SpecularColorKey = "SpecularColor";
+ public const string SpecularPowerKey = "SpecularPower";
+ public const string TextureKey = "Texture";
+ public const string VertexColorEnabledKey = "VertexColorEnabled";
+
+ public float? Alpha
+ {
+ get { return GetValueTypeProperty(AlphaKey); }
+ set { SetProperty(AlphaKey, value); }
+ }
+
+ public Vector3? DiffuseColor
+ {
+ get { return GetValueTypeProperty(DiffuseColorKey); }
+ set { SetProperty(DiffuseColorKey, value); }
+ }
+
+ public Vector3? EmissiveColor
+ {
+ get { return GetValueTypeProperty(EmissiveColorKey); }
+ set { SetProperty(EmissiveColorKey, value); }
+ }
+
+ public Vector3? SpecularColor
+ {
+ get { return GetValueTypeProperty(SpecularColorKey); }
+ set { SetProperty(SpecularColorKey, value); }
+ }
+
+ public float? SpecularPower
+ {
+ get { return GetValueTypeProperty(SpecularPowerKey); }
+ set { SetProperty(SpecularPowerKey, value); }
+ }
+
+ public ExternalReference Texture
+ {
+ get { return GetTexture(TextureKey); }
+ set { SetTexture(TextureKey, value); }
+ }
+
+ public bool? VertexColorEnabled
+ {
+ get { return GetValueTypeProperty(VertexColorEnabledKey); }
+ set { SetProperty(VertexColorEnabledKey, value); }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BitmapContent.cs
new file mode 100644
index 000000000..8a07d4302
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BitmapContent.cs
@@ -0,0 +1,216 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides properties and methods for creating and maintaining a bitmap resource.
+ ///
+ public abstract class BitmapContent : ContentItem
+ {
+ int height;
+ int width;
+
+ ///
+ /// Gets or sets the height of the bitmap, in pixels.
+ ///
+ public int Height
+ {
+ get
+ {
+ return height;
+ }
+ protected set
+ {
+ if (value <= 0)
+ throw new ArgumentOutOfRangeException("height");
+ height = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the width of the bitmap, in pixels.
+ ///
+ public int Width
+ {
+ get
+ {
+ return width;
+ }
+ protected set
+ {
+ if (value <= 0)
+ throw new ArgumentOutOfRangeException("width");
+ width = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of BitmapContent.
+ ///
+ protected BitmapContent()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of BitmapContent with the specified width or height.
+ ///
+ /// Width, in pixels, of the bitmap resource.
+ /// Height, in pixels, of the bitmap resource.
+ protected BitmapContent(int width, int height)
+ {
+ // Write to properties so validation is run.
+ Width = width;
+ Height = height;
+ }
+
+ ///
+ /// Copies one bitmap into another.
+ /// The destination bitmap can be in any format and size. If the destination is larger or smaller, the source bitmap is scaled accordingly.
+ ///
+ /// BitmapContent being copied.
+ /// BitmapContent being overwritten.
+ public static void Copy(BitmapContent sourceBitmap, BitmapContent destinationBitmap)
+ {
+ if (sourceBitmap == null)
+ throw new ArgumentNullException("sourceBitmap");
+ if (destinationBitmap == null)
+ throw new ArgumentNullException("destinationBitmap");
+
+ var sourceRegion = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);
+ var destinationRegion = new Rectangle(0, 0, destinationBitmap.Width, destinationBitmap.Height);
+
+ Copy(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion);
+ }
+
+ ///
+ /// Copies one bitmap into another.
+ /// The destination bitmap can be in any format and size. If the destination is larger or smaller, the source bitmap is scaled accordingly.
+ ///
+ /// BitmapContent being copied.
+ /// Region of sourceBitmap.
+ /// BitmapContent being overwritten.
+ /// Region of bitmap to be overwritten.
+ public static void Copy(BitmapContent sourceBitmap, Rectangle sourceRegion, BitmapContent destinationBitmap, Rectangle destinationRegion)
+ {
+ ValidateCopyArguments(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion);
+
+ SurfaceFormat sourceFormat;
+ if (!sourceBitmap.TryGetFormat(out sourceFormat))
+ throw new InvalidOperationException("Could not retrieve surface format of source bitmap");
+ SurfaceFormat destinationFormat;
+ if (!destinationBitmap.TryGetFormat(out destinationFormat))
+ throw new InvalidOperationException("Could not retrieve surface format of destination bitmap");
+
+ // If the formats are the same and the regions are the full bounds of the bitmaps and they are the same size, do a simpler copy
+ if (sourceFormat == destinationFormat && sourceRegion == destinationRegion
+ && sourceRegion == new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height)
+ && destinationRegion == new Rectangle(0, 0, destinationBitmap.Width, destinationBitmap.Height))
+ {
+ destinationBitmap.SetPixelData(sourceBitmap.GetPixelData());
+ return;
+ }
+
+ // The basic process is
+ // 1. Copy from source bitmap region to a new PixelBitmapContent using sourceBitmap.TryCopyTo()
+ // 2. If source and destination regions are a different size, resize Vector4 version
+ // 3. Copy from Vector4 to destination region using destinationBitmap.TryCopyFrom()
+
+ // Copy from the source to the intermediate Vector4 format
+ var intermediate = new PixelBitmapContent(sourceRegion.Width, sourceRegion.Height);
+ var intermediateRegion = new Rectangle(0, 0, intermediate.Width, intermediate.Height);
+ if (sourceBitmap.TryCopyTo(intermediate, sourceRegion, intermediateRegion))
+ {
+ // Resize the intermediate if required
+ if (intermediate.Width != destinationRegion.Width || intermediate.Height != destinationRegion.Height)
+ intermediate = intermediate.Resize(destinationRegion.Width, destinationRegion.Height) as PixelBitmapContent;
+ // Copy from the intermediate to the destination
+ if (destinationBitmap.TryCopyFrom(intermediate, new Rectangle(0, 0, intermediate.Width, intermediate.Height), destinationRegion))
+ return;
+ }
+
+ // If we got here, one of the above steps didn't work
+ throw new InvalidOperationException("Could not copy between " + sourceFormat + " and " + destinationFormat);
+ }
+
+ ///
+ /// Reads encoded bitmap content.
+ ///
+ /// Array containing encoded bitmap data.
+ public abstract byte[] GetPixelData();
+
+ ///
+ /// Writes encoded bitmap content.
+ ///
+ /// Array containing encoded bitmap data to be set.
+ public abstract void SetPixelData(byte[] sourceData);
+
+ ///
+ /// Returns a string description of the bitmap resource.
+ ///
+ /// Description of the bitmap.
+ public override string ToString()
+ {
+ return string.Format("{0}, {1}x{2}", GetType().Name, Width, Height);
+ }
+
+ ///
+ /// Attempts to copy a region from a specified bitmap.
+ ///
+ /// BitmapContent being copied.
+ /// Location of sourceBitmap.
+ /// Region of destination bitmap to be overwritten.
+ /// true if region copy is supported; false otherwise.
+ protected abstract bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion);
+
+ ///
+ /// Attempts to copy a region of the specified bitmap onto another.
+ ///
+ /// BitmapContent being overwritten.
+ /// Location of the source bitmap.
+ /// Region of destination bitmap to be overwritten.
+ /// true if region copy is supported; false otherwise.
+ protected abstract bool TryCopyTo(BitmapContent destinationBitmap, Rectangle sourceRegion, Rectangle destinationRegion);
+
+ ///
+ /// Gets the corresponding GPU texture format for the specified bitmap type.
+ ///
+ /// Format being retrieved.
+ /// The GPU texture format of the bitmap type.
+ public abstract bool TryGetFormat(out SurfaceFormat format);
+
+ ///
+ /// Validates the arguments to the Copy function.
+ ///
+ /// BitmapContent being copied.
+ /// Location of sourceBitmap.
+ /// BitmapContent being overwritten.
+ /// Region of bitmap to be overwritten.
+ protected static void ValidateCopyArguments(BitmapContent sourceBitmap, Rectangle sourceRegion, BitmapContent destinationBitmap, Rectangle destinationRegion)
+ {
+ if (sourceBitmap == null)
+ throw new ArgumentNullException("sourceBitmap");
+ if (destinationBitmap == null)
+ throw new ArgumentNullException("destinationBitmap");
+ // Make sure regions are within the bounds of the bitmaps
+ if (sourceRegion.Left < 0
+ || sourceRegion.Top < 0
+ || sourceRegion.Width <= 0
+ || sourceRegion.Height <= 0
+ || sourceRegion.Right > sourceBitmap.Width
+ || sourceRegion.Bottom > sourceBitmap.Height)
+ throw new ArgumentOutOfRangeException("sourceRegion");
+ if (destinationRegion.Left < 0
+ || destinationRegion.Top < 0
+ || destinationRegion.Width <= 0
+ || destinationRegion.Height <= 0
+ || destinationRegion.Right > destinationBitmap.Width
+ || destinationRegion.Bottom > destinationBitmap.Height)
+ throw new ArgumentOutOfRangeException("destinationRegion");
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneContent.cs
new file mode 100644
index 000000000..cb3959c4a
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneContent.cs
@@ -0,0 +1,20 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Represents an animation skeleton.
+ ///
+ [System.Diagnostics.DebuggerDisplay("Bone '{Name}'")]
+ public class BoneContent : NodeContent
+ {
+ ///
+ /// Initializes a new instance of BoneContent.
+ ///
+ public BoneContent()
+ {
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneWeight.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneWeight.cs
new file mode 100644
index 000000000..e1b3ba271
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneWeight.cs
@@ -0,0 +1,52 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides properties for managing a bone weight.
+ ///
+ public struct BoneWeight
+ {
+ string boneName;
+ float weight;
+
+ ///
+ /// Gets the name of the bone.
+ ///
+ public string BoneName
+ {
+ get
+ {
+ return boneName;
+ }
+ }
+
+ ///
+ /// Gets the amount of bone influence, ranging from zero to one. The complete set of weights in a BoneWeightCollection should sum to one.
+ ///
+ public float Weight
+ {
+ get
+ {
+ return weight;
+ }
+ internal set
+ {
+ weight = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of BoneWeight with the specified name and weight.
+ ///
+ /// Name of the bone.
+ /// Amount of influence, ranging from zero to one.
+ public BoneWeight(string boneName, float weight)
+ {
+ this.boneName = boneName;
+ this.weight = weight;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneWeightCollection.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneWeightCollection.cs
new file mode 100644
index 000000000..3dfa4f924
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/BoneWeightCollection.cs
@@ -0,0 +1,92 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Collection of bone weights of a vertex.
+ ///
+ public sealed class BoneWeightCollection : Collection
+ {
+ ///
+ /// Initializes a new instance of BoneWeightCollection.
+ ///
+ public BoneWeightCollection()
+ {
+ }
+
+ ///
+ /// Normalizes the contents of the weights list.
+ ///
+ public void NormalizeWeights()
+ {
+ // Normalization does the following:
+ //
+ // - Sorts weights such that the most significant weight is first.
+ // - Removes zero-value entries.
+ // - Adjusts values so the sum equals one.
+ //
+ // Throws InvalidContentException if all weights are zero.
+ NormalizeWeights(int.MaxValue);
+ }
+
+ ///
+ /// Normalizes the contents of the bone weights list.
+ ///
+ /// Maximum number of weights allowed.
+ public void NormalizeWeights(int maxWeights)
+ {
+ // Normalization does the following:
+ //
+ // - Sorts weights such that the most significant weight is first.
+ // - Removes zero-value entries.
+ // - Discards weights with the smallest value until there are maxWeights or less in the list.
+ // - Adjusts values so the sum equals one.
+ //
+ // Throws InvalidContentException if all weights are zero.
+
+ var weights = (List)Items;
+
+ // Sort into descending order
+ weights.Sort((b1, b2) => b2.Weight.CompareTo(b1.Weight));
+
+ // Find the sum to validate we have weights and to normalize the weights
+ float sum = 0.0f;
+ int index = 0;
+ // Cannot use a foreach or for because the index may not always increment and the length of the list may change.
+ while (index < weights.Count)
+ {
+ float weight = weights[index].Weight;
+ if ((weight > 0.0f) && (index < maxWeights))
+ {
+ sum += weight;
+ ++index;
+ }
+ else
+ {
+ // Discard any zero weights or if we have exceeded the maximum number of weights
+ weights.RemoveAt(index);
+ }
+ }
+
+ if (sum == 0.0f)
+ throw new InvalidContentException("Total bone weights in a collection must not be zero");
+
+ // Normalize each weight
+ int count = weights.Count();
+ // Old-school trick. Multiplication is faster than division, so multiply by the inverse.
+ float invSum = 1.0f / sum;
+ for (index = 0; index < count; ++index)
+ {
+ BoneWeight bw = weights[index];
+ bw.Weight *= invSum;
+ weights[index] = bw;
+ }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DefaultTextureProfile.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DefaultTextureProfile.cs
new file mode 100644
index 000000000..6dcdaf612
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DefaultTextureProfile.cs
@@ -0,0 +1,142 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Content.Pipeline.Processors;
+using Microsoft.Xna.Framework.Graphics;
+
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ internal class DefaultTextureProfile : TextureProfile
+ {
+ public override bool Supports(TargetPlatform platform)
+ {
+ return platform == TargetPlatform.Android ||
+ platform == TargetPlatform.DesktopGL ||
+ platform == TargetPlatform.MacOSX ||
+ platform == TargetPlatform.NativeClient ||
+ platform == TargetPlatform.RaspberryPi ||
+ platform == TargetPlatform.Windows ||
+ platform == TargetPlatform.WindowsPhone8 ||
+ platform == TargetPlatform.WindowsStoreApp ||
+ platform == TargetPlatform.iOS;
+ }
+
+ private static bool IsCompressedTextureFormat(TextureProcessorOutputFormat format)
+ {
+ switch (format)
+ {
+ case TextureProcessorOutputFormat.AtcCompressed:
+ case TextureProcessorOutputFormat.DxtCompressed:
+ case TextureProcessorOutputFormat.Etc1Compressed:
+ case TextureProcessorOutputFormat.PvrCompressed:
+ return true;
+ }
+ return false;
+ }
+
+ private static TextureProcessorOutputFormat GetTextureFormatForPlatform(TextureProcessorOutputFormat format, TargetPlatform platform)
+ {
+ // Select the default texture compression format for the target platform
+ if (format == TextureProcessorOutputFormat.Compressed)
+ {
+ if (platform == TargetPlatform.iOS)
+ format = TextureProcessorOutputFormat.PvrCompressed;
+ else if (platform == TargetPlatform.Android)
+ format = TextureProcessorOutputFormat.Etc1Compressed;
+ else
+ format = TextureProcessorOutputFormat.DxtCompressed;
+ }
+
+ if (IsCompressedTextureFormat(format))
+ {
+ // Make sure the target platform supports the selected texture compression format
+ if (platform == TargetPlatform.iOS)
+ {
+ if (format != TextureProcessorOutputFormat.PvrCompressed)
+ throw new PlatformNotSupportedException("iOS platform only supports PVR texture compression");
+ }
+ else if (platform == TargetPlatform.Windows ||
+ platform == TargetPlatform.WindowsPhone8 ||
+ platform == TargetPlatform.WindowsStoreApp ||
+ platform == TargetPlatform.DesktopGL ||
+ platform == TargetPlatform.MacOSX ||
+ platform == TargetPlatform.NativeClient)
+ {
+ if (format != TextureProcessorOutputFormat.DxtCompressed)
+ throw new PlatformNotSupportedException(format + " platform only supports DXT texture compression");
+ }
+ }
+
+ return format;
+ }
+
+ public override void Requirements(ContentProcessorContext context, TextureProcessorOutputFormat format, out bool requiresPowerOfTwo, out bool requiresSquare)
+ {
+ if (format == TextureProcessorOutputFormat.Compressed)
+ format = GetTextureFormatForPlatform(format, context.TargetPlatform);
+
+ // Does it require POT textures?
+ switch (format)
+ {
+ default:
+ requiresPowerOfTwo = false;
+ break;
+
+ case TextureProcessorOutputFormat.DxtCompressed:
+ requiresPowerOfTwo = context.TargetProfile == GraphicsProfile.Reach;
+ break;
+
+ case TextureProcessorOutputFormat.PvrCompressed:
+ case TextureProcessorOutputFormat.Etc1Compressed:
+ requiresPowerOfTwo = true;
+ break;
+ }
+
+ // Does it require square textures?
+ switch (format)
+ {
+ default:
+ requiresSquare = false;
+ break;
+
+ case TextureProcessorOutputFormat.PvrCompressed:
+ requiresSquare = true;
+ break;
+ }
+ }
+
+ protected override void PlatformCompressTexture(ContentProcessorContext context, TextureContent content, TextureProcessorOutputFormat format, bool isSpriteFont)
+ {
+ format = GetTextureFormatForPlatform(format, context.TargetPlatform);
+
+ // Make sure we're in a floating point format
+ content.ConvertBitmapType(typeof(PixelBitmapContent));
+
+ switch (format)
+ {
+ case TextureProcessorOutputFormat.AtcCompressed:
+ GraphicsUtil.CompressAti(context, content, isSpriteFont);
+ break;
+
+ case TextureProcessorOutputFormat.Color16Bit:
+ GraphicsUtil.CompressColor16Bit(context, content);
+ break;
+
+ case TextureProcessorOutputFormat.DxtCompressed:
+ GraphicsUtil.CompressDxt(context, content, isSpriteFont);
+ break;
+
+ case TextureProcessorOutputFormat.Etc1Compressed:
+ GraphicsUtil.CompressEtc1(context, content, isSpriteFont);
+ break;
+
+ case TextureProcessorOutputFormat.PvrCompressed:
+ GraphicsUtil.CompressPvrtc(context, content, isSpriteFont);
+ break;
+ }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DualTextureMaterialContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DualTextureMaterialContent.cs
new file mode 100644
index 000000000..fa16771b1
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DualTextureMaterialContent.cs
@@ -0,0 +1,45 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class DualTextureMaterialContent : MaterialContent
+ {
+ public const string AlphaKey = "Alpha";
+ public const string DiffuseColorKey = "DiffuseColor";
+ public const string TextureKey = "Texture";
+ public const string Texture2Key = "Texture2";
+ public const string VertexColorEnabledKey = "VertexColorEnabled";
+
+ public float? Alpha
+ {
+ get { return GetValueTypeProperty(AlphaKey); }
+ set { SetProperty(AlphaKey, value); }
+ }
+
+ public Vector3? DiffuseColor
+ {
+ get { return GetValueTypeProperty(DiffuseColorKey); }
+ set { SetProperty(DiffuseColorKey, value); }
+ }
+
+ public ExternalReference Texture
+ {
+ get { return GetTexture(TextureKey); }
+ set { SetTexture(TextureKey, value); }
+ }
+
+ public ExternalReference Texture2
+ {
+ get { return GetTexture(Texture2Key); }
+ set { SetTexture(Texture2Key, value); }
+ }
+
+ public bool? VertexColorEnabled
+ {
+ get { return GetValueTypeProperty(VertexColorEnabledKey); }
+ set { SetProperty(VertexColorEnabledKey, value); }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt1BitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt1BitmapContent.cs
new file mode 100644
index 000000000..372004d57
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt1BitmapContent.cs
@@ -0,0 +1,36 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class Dxt1BitmapContent : DxtBitmapContent
+ {
+ public Dxt1BitmapContent(int width, int height)
+ : base(8, width, height)
+ {
+ }
+
+ ///
+ /// Gets the corresponding GPU texture format for the specified bitmap type.
+ ///
+ /// Format being retrieved.
+ /// The GPU texture format of the bitmap type.
+ public override bool TryGetFormat(out SurfaceFormat format)
+ {
+ format = SurfaceFormat.Dxt1;
+ return true;
+ }
+
+ ///
+ /// Returns a string description of the bitmap.
+ ///
+ /// Description of the bitmap.
+ public override string ToString()
+ {
+ return "DXT1 " + Width + "x" + Height;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt3BitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt3BitmapContent.cs
new file mode 100644
index 000000000..8de21363f
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt3BitmapContent.cs
@@ -0,0 +1,36 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class Dxt3BitmapContent : DxtBitmapContent
+ {
+ public Dxt3BitmapContent(int width, int height)
+ : base(16, width, height)
+ {
+ }
+
+ ///
+ /// Gets the corresponding GPU texture format for the specified bitmap type.
+ ///
+ /// Format being retrieved.
+ /// The GPU texture format of the bitmap type.
+ public override bool TryGetFormat(out SurfaceFormat format)
+ {
+ format = SurfaceFormat.Dxt3;
+ return true;
+ }
+
+ ///
+ /// Returns a string description of the bitmap.
+ ///
+ /// Description of the bitmap.
+ public override string ToString()
+ {
+ return "DXT3 " + Width + "x" + Height;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt5BitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt5BitmapContent.cs
new file mode 100644
index 000000000..3e676cc2d
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Dxt5BitmapContent.cs
@@ -0,0 +1,36 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class Dxt5BitmapContent : DxtBitmapContent
+ {
+ public Dxt5BitmapContent(int width, int height)
+ : base(16, width, height)
+ {
+ }
+
+ ///
+ /// Gets the corresponding GPU texture format for the specified bitmap type.
+ ///
+ /// Format being retrieved.
+ /// The GPU texture format of the bitmap type.
+ public override bool TryGetFormat(out SurfaceFormat format)
+ {
+ format = SurfaceFormat.Dxt5;
+ return true;
+ }
+
+ ///
+ /// Returns a string description of the bitmap.
+ ///
+ /// Description of the bitmap.
+ public override string ToString()
+ {
+ return "DXT5 " + Width + "x" + Height;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DxtBitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DxtBitmapContent.cs
new file mode 100644
index 000000000..71ff2620c
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/DxtBitmapContent.cs
@@ -0,0 +1,232 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Graphics;
+using Nvidia.TextureTools;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public abstract class DxtBitmapContent : BitmapContent
+ {
+ private byte[] _bitmapData;
+ private int _blockSize;
+ private SurfaceFormat _format;
+
+ private int _nvttWriteOffset;
+
+ protected DxtBitmapContent(int blockSize)
+ {
+ if (!((blockSize == 8) || (blockSize == 16)))
+ throw new ArgumentException("Invalid block size");
+ _blockSize = blockSize;
+ TryGetFormat(out _format);
+ }
+
+ protected DxtBitmapContent(int blockSize, int width, int height)
+ : this(blockSize)
+ {
+ Width = width;
+ Height = height;
+ }
+
+ public override byte[] GetPixelData()
+ {
+ return _bitmapData;
+ }
+
+ public override void SetPixelData(byte[] sourceData)
+ {
+ _bitmapData = sourceData;
+ }
+
+ private void NvttBeginImage(int size, int width, int height, int depth, int face, int miplevel)
+ {
+ _bitmapData = new byte[size];
+ _nvttWriteOffset = 0;
+ }
+
+ private bool NvttWriteImage(IntPtr data, int length)
+ {
+ Marshal.Copy(data, _bitmapData, _nvttWriteOffset, length);
+ _nvttWriteOffset += length;
+ return true;
+ }
+
+ private void NvttEndImage()
+ {
+ }
+
+ private static void PrepareNVTT(byte[] data)
+ {
+ for (var x = 0; x < data.Length; x += 4)
+ {
+ // NVTT wants BGRA where our source is RGBA so
+ // we swap the red and blue channels.
+ data[x] ^= data[x + 2];
+ data[x + 2] ^= data[x];
+ data[x] ^= data[x + 2];
+ }
+ }
+
+ private static void PrepareNVTT_DXT1(byte[] data, out bool hasTransparency)
+ {
+ hasTransparency = false;
+
+ for (var x = 0; x < data.Length; x += 4)
+ {
+ // NVTT wants BGRA where our source is RGBA so
+ // we swap the red and blue channels.
+ data[x] ^= data[x + 2];
+ data[x + 2] ^= data[x];
+ data[x] ^= data[x + 2];
+
+ // Look for non-opaque pixels.
+ var alpha = data[x + 3];
+ if (alpha < 255)
+ hasTransparency = true;
+ }
+ }
+
+ protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
+ {
+ SurfaceFormat sourceFormat;
+ if (!sourceBitmap.TryGetFormat(out sourceFormat))
+ return false;
+
+ SurfaceFormat format;
+ TryGetFormat(out format);
+
+ // A shortcut for copying the entire bitmap to another bitmap of the same type and format
+ if (format == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
+ {
+ SetPixelData(sourceBitmap.GetPixelData());
+ return true;
+ }
+
+ // TODO: Add a XNA unit test to see what it does
+ // my guess is that this is invalid for DXT.
+ //
+ // Destination region copy is not yet supported
+ if (destinationRegion != new Rectangle(0, 0, Width, Height))
+ return false;
+
+ // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy
+ if (!(sourceBitmap is PixelBitmapContent) || sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height)
+ {
+ try
+ {
+ BitmapContent.Copy(sourceBitmap, sourceRegion, this, destinationRegion);
+ return true;
+ }
+ catch (InvalidOperationException)
+ {
+ return false;
+ }
+ }
+
+ // NVTT wants 8bit data in BGRA format.
+ var colorBitmap = new PixelBitmapContent(sourceBitmap.Width, sourceBitmap.Height);
+ BitmapContent.Copy(sourceBitmap, colorBitmap);
+ var sourceData = colorBitmap.GetPixelData();
+ var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned);
+
+ AlphaMode alphaMode;
+ Format outputFormat;
+ var alphaDither = false;
+ switch (format)
+ {
+ case SurfaceFormat.Dxt1:
+ case SurfaceFormat.Dxt1SRgb:
+ {
+ bool hasTransparency;
+ PrepareNVTT_DXT1(sourceData, out hasTransparency);
+ outputFormat = hasTransparency ? Format.DXT1a : Format.DXT1;
+ alphaMode = hasTransparency ? AlphaMode.Transparency : AlphaMode.None;
+ alphaDither = true;
+ break;
+ }
+ case SurfaceFormat.Dxt3:
+ case SurfaceFormat.Dxt3SRgb:
+ {
+ PrepareNVTT(sourceData);
+ outputFormat = Format.DXT3;
+ alphaMode = AlphaMode.Transparency;
+ break;
+ }
+ case SurfaceFormat.Dxt5:
+ case SurfaceFormat.Dxt5SRgb:
+ {
+ PrepareNVTT(sourceData);
+ outputFormat = Format.DXT5;
+ alphaMode = AlphaMode.Transparency;
+ break;
+ }
+ default:
+ throw new InvalidOperationException("Invalid DXT surface format!");
+ }
+
+ // Do all the calls to the NVTT wrapper within this handler
+ // so we properly clean up if things blow up.
+ try
+ {
+ var dataPtr = dataHandle.AddrOfPinnedObject();
+
+ var inputOptions = new InputOptions();
+ inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1);
+ inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0);
+ inputOptions.SetMipmapGeneration(false);
+ inputOptions.SetGamma(1.0f, 1.0f);
+ inputOptions.SetAlphaMode(alphaMode);
+
+ var compressionOptions = new CompressionOptions();
+ compressionOptions.SetFormat(outputFormat);
+ compressionOptions.SetQuality(Quality.Normal);
+
+ // TODO: This isn't working which keeps us from getting the
+ // same alpha dither behavior on DXT1 as XNA.
+ //
+ // See https://github.com/MonoGame/MonoGame/issues/6259
+ //
+ //if (alphaDither)
+ //compressionOptions.SetQuantization(false, false, true);
+
+ var outputOptions = new OutputOptions();
+ outputOptions.SetOutputHeader(false);
+ outputOptions.SetOutputOptionsOutputHandler(NvttBeginImage, NvttWriteImage, NvttEndImage);
+
+ var dxtCompressor = new Compressor();
+ dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions);
+ }
+ finally
+ {
+ dataHandle.Free();
+ }
+
+ return true;
+ }
+
+ protected override bool TryCopyTo(BitmapContent destinationBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
+ {
+ SurfaceFormat destinationFormat;
+ if (!destinationBitmap.TryGetFormat(out destinationFormat))
+ return false;
+
+ SurfaceFormat format;
+ TryGetFormat(out format);
+
+ // A shortcut for copying the entire bitmap to another bitmap of the same type and format
+ var fullRegion = new Rectangle(0, 0, Width, Height);
+ if ((format == destinationFormat) && (sourceRegion == fullRegion) && (sourceRegion == destinationRegion))
+ {
+ destinationBitmap.SetPixelData(GetPixelData());
+ return true;
+ }
+
+ // No other support for copying from a DXT texture yet
+ return false;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EffectContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EffectContent.cs
new file mode 100644
index 000000000..95c5b1104
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EffectContent.cs
@@ -0,0 +1,25 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Contains the source code for a DirectX Effect, loaded from a .fx file.
+ ///
+ public class EffectContent : ContentItem
+ {
+ ///
+ /// Initializes a new instance of EffectContent.
+ ///
+ public EffectContent()
+ {
+
+ }
+
+ ///
+ /// Gets or sets the effect program source code.
+ ///
+ public string EffectCode { get; set; }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EffectMaterialContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EffectMaterialContent.cs
new file mode 100644
index 000000000..7321956bf
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EffectMaterialContent.cs
@@ -0,0 +1,26 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using Microsoft.Xna.Framework.Content.Pipeline.Processors;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class EffectMaterialContent : MaterialContent
+ {
+ public const string EffectKey = "Effect";
+ public const string CompiledEffectKey = "CompiledEffect";
+
+ public ExternalReference Effect
+ {
+ get { return GetReferenceTypeProperty>(EffectKey); }
+ set { SetProperty(EffectKey, value); }
+ }
+
+ public ExternalReference CompiledEffect
+ {
+ get { return GetReferenceTypeProperty>(CompiledEffectKey); }
+ set { SetProperty(CompiledEffectKey, value); }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EnvironmentMapMaterialContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EnvironmentMapMaterialContent.cs
new file mode 100644
index 000000000..48e94eef6
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/EnvironmentMapMaterialContent.cs
@@ -0,0 +1,66 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class EnvironmentMapMaterialContent : MaterialContent
+ {
+ public const string AlphaKey = "Alpha";
+ public const string DiffuseColorKey = "DiffuseColor";
+ public const string EmissiveColorKey = "EmissiveColor";
+ public const string EnvironmentMapKey = "EnvironmentMap";
+ public const string EnvironmentMapAmountKey = "EnvironmentMapAmount";
+ public const string EnvironmentMapSpecularKey = " EnvironmentMapSpecular";
+ public const string FresnelFactorKey = "FresnelFactor";
+ public const string TextureKey = "Texture";
+
+ public float? Alpha
+ {
+ get { return GetValueTypeProperty(AlphaKey); }
+ set { SetProperty(AlphaKey, value); }
+ }
+
+ public Vector3? DiffuseColor
+ {
+ get { return GetValueTypeProperty(DiffuseColorKey); }
+ set { SetProperty(DiffuseColorKey, value); }
+ }
+
+ public Vector3? EmissiveColor
+ {
+ get { return GetValueTypeProperty(EmissiveColorKey); }
+ set { SetProperty(EmissiveColorKey, value); }
+ }
+
+ public ExternalReference EnvironmentMap
+ {
+ get { return GetTexture(EnvironmentMapKey); }
+ set { SetTexture(EnvironmentMapKey, value); }
+ }
+
+ public float? EnvironmentMapAmount
+ {
+ get { return GetValueTypeProperty(EnvironmentMapAmountKey); }
+ set { SetProperty(EnvironmentMapAmountKey, value); }
+ }
+
+ public Vector3? EnvironmentMapSpecular
+ {
+ get { return GetValueTypeProperty(EnvironmentMapSpecularKey); }
+ set { SetProperty(EnvironmentMapSpecularKey, value); }
+ }
+
+ public float? FresnelFactor
+ {
+ get { return GetValueTypeProperty(FresnelFactorKey); }
+ set { SetProperty(FresnelFactorKey, value); }
+ }
+
+ public ExternalReference Texture
+ {
+ get { return GetTexture(TextureKey); }
+ set { SetTexture(TextureKey, value); }
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Etc1BitmapContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Etc1BitmapContent.cs
new file mode 100644
index 000000000..ac272a93b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Etc1BitmapContent.cs
@@ -0,0 +1,139 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework.Graphics;
+using PVRTexLibNET;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Supports the processing of a texture compressed using ETC1.
+ ///
+ public class Etc1BitmapContent : BitmapContent
+ {
+ byte[] _data;
+
+ ///
+ /// Initializes a new instance of Etc1BitmapContent.
+ ///
+ protected Etc1BitmapContent()
+ : base()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of Etc1BitmapContent with the specified width or height.
+ ///
+ /// Width in pixels of the bitmap resource.
+ /// Height in pixels of the bitmap resource.
+ public Etc1BitmapContent(int width, int height)
+ : base(width, height)
+ {
+ }
+
+ public override byte[] GetPixelData()
+ {
+ return _data;
+ }
+
+ public override void SetPixelData(byte[] sourceData)
+ {
+ int bytesRequired = ((Width + 3) >> 2) * ((Height + 3) >> 2) * SurfaceFormat.RgbEtc1.GetSize();
+ if (bytesRequired != sourceData.Length)
+ throw new ArgumentException("ETC1 bitmap with width " + Width + " and height " + Height + " needs "
+ + bytesRequired + " bytes. Received " + sourceData.Length + " bytes");
+
+ if (_data == null || _data.Length != bytesRequired)
+ _data = new byte[bytesRequired];
+ Buffer.BlockCopy(sourceData, 0, _data, 0, bytesRequired);
+ }
+
+ protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
+ {
+ SurfaceFormat sourceFormat;
+ if (!sourceBitmap.TryGetFormat(out sourceFormat))
+ return false;
+
+ // A shortcut for copying the entire bitmap to another bitmap of the same type and format
+ if (SurfaceFormat.RgbEtc1 == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
+ {
+ SetPixelData(sourceBitmap.GetPixelData());
+ return true;
+ }
+
+ // Destination region copy is not yet supported
+ if (destinationRegion != new Rectangle(0, 0, Width, Height))
+ return false;
+
+ // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy
+ if (!(sourceBitmap is PixelBitmapContent) || sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height)
+ {
+ try
+ {
+ BitmapContent.Copy(sourceBitmap, sourceRegion, this, destinationRegion);
+ return true;
+ }
+ catch (InvalidOperationException)
+ {
+ return false;
+ }
+ }
+
+ // Create the texture object in the PVR library
+ var sourceData = sourceBitmap.GetPixelData();
+ var rgba32F = (PixelFormat)0x2020202061626772; // static const PixelType PVRStandard32PixelType = PixelType('r', 'g', 'b', 'a', 32, 32, 32, 32);
+ using (var pvrTexture = PVRTexture.CreateTexture(sourceData, (uint)sourceBitmap.Width, (uint)sourceBitmap.Height, 1,
+ rgba32F, true, VariableType.Float, ColourSpace.lRGB))
+ {
+ // Resize the bitmap if needed
+ if ((sourceBitmap.Width != Width) || (sourceBitmap.Height != Height))
+ pvrTexture.Resize((uint)Width, (uint)Height, 1, ResizeMode.Cubic);
+ pvrTexture.Transcode(PixelFormat.ETC1, VariableType.UnsignedByte, ColourSpace.lRGB /*, CompressorQuality.ETCMediumPerceptual, true*/);
+ var texDataSize = pvrTexture.GetTextureDataSize(0);
+ var texData = new byte[texDataSize];
+ pvrTexture.GetTextureData(texData, texDataSize);
+ SetPixelData(texData);
+ }
+ return true;
+ }
+
+ protected override bool TryCopyTo(BitmapContent destinationBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
+ {
+ SurfaceFormat destinationFormat;
+ if (!destinationBitmap.TryGetFormat(out destinationFormat))
+ return false;
+
+ // A shortcut for copying the entire bitmap to another bitmap of the same type and format
+ if (SurfaceFormat.RgbEtc1 == destinationFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
+ {
+ destinationBitmap.SetPixelData(GetPixelData());
+ return true;
+ }
+
+ // No other support for copying from a ETC1 texture yet
+ return false;
+ }
+
+ ///
+ /// Gets the corresponding GPU texture format for the specified bitmap type.
+ ///
+ /// Format being retrieved.
+ /// The GPU texture format of the bitmap type.
+ public override bool TryGetFormat(out SurfaceFormat format)
+ {
+ format = SurfaceFormat.RgbEtc1;
+ return true;
+ }
+
+ ///
+ /// Returns a string description of the bitmap.
+ ///
+ /// Description of the bitmap.
+ public override string ToString()
+ {
+ return "ETC1 " + Width + "x" + Height;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/BitmapUtils.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/BitmapUtils.cs
new file mode 100644
index 000000000..9f283df01
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/BitmapUtils.cs
@@ -0,0 +1,49 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ // Assorted helpers for doing useful things with bitmaps.
+ internal static class BitmapUtils
+ {
+ // Checks whether an area of a bitmap contains entirely the specified alpha value.
+ public static bool IsAlphaEntirely(byte expectedAlpha, BitmapContent bitmap, Rectangle? region = null)
+ {
+ var bitmapRegion = region.HasValue ? region.Value : new Rectangle(0, 0, bitmap.Width, bitmap.Height);
+ // Works with PixelBitmapContent at this stage
+ if (bitmap is PixelBitmapContent)
+ {
+ var bmp = bitmap as PixelBitmapContent;
+ for (int y = 0; y < bitmapRegion.Height; y++)
+ {
+ for (int x = 0; x < bitmapRegion.Width; x++)
+ {
+ var alpha = bmp.GetPixel(bitmapRegion.X + x, bitmapRegion.Y + y);
+ if (alpha != expectedAlpha)
+ return false;
+ }
+ }
+ return true;
+ }
+ else if (bitmap is PixelBitmapContent)
+ {
+ var bmp = bitmap as PixelBitmapContent;
+ for (int y = 0; y < bitmapRegion.Height; y++)
+ {
+ for (int x = 0; x < bitmapRegion.Width; x++)
+ {
+ var alpha = bmp.GetPixel(bitmapRegion.X + x, bitmapRegion.Y + y).A;
+ if (alpha != expectedAlpha)
+ return false;
+ }
+ }
+ return true;
+ }
+ throw new ArgumentException("Expected PixelBitmapContent or PixelBitmapContent, got " + bitmap.GetType().Name, "bitmap");
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/CharacterRegion.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/CharacterRegion.cs
new file mode 100644
index 000000000..662d027e1
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/CharacterRegion.cs
@@ -0,0 +1,90 @@
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ // Describes a range of consecutive characters that should be included in the font.
+ [TypeConverter(typeof(CharacterRegionTypeConverter))]
+ public struct CharacterRegion
+ {
+ public char Start;
+ public char End;
+
+ // Enumerates all characters within the region.
+ public IEnumerable Characters()
+ {
+ for (var c = Start; c <= End; c++)
+ {
+ yield return c;
+ }
+ }
+
+ // Constructor.
+ public CharacterRegion(char start, char end)
+ {
+ if (start > end)
+ throw new ArgumentException();
+
+ Start = start;
+ End = end;
+ }
+
+ // Default to just the base ASCII character set.
+ public static CharacterRegion Default = new CharacterRegion(' ', '~');
+
+
+ ///
+ /// Test if there is an element in this enumeration.
+ ///
+ /// Type of the element
+ /// The enumerable source.
+ /// true if there is an element in this enumeration, false otherwise
+ public static bool Any(IEnumerable source)
+ {
+ return source.GetEnumerator().MoveNext();
+ }
+
+
+ ///
+ /// Select elements from an enumeration.
+ ///
+ /// The type of the T source.
+ /// The type of the T result.
+ /// The source.
+ /// The selector.
+ /// A enumeration of selected values
+ public static IEnumerable SelectMany(IEnumerable source, Func> selector)
+ {
+ foreach (TSource sourceItem in source)
+ {
+ foreach (TResult result in selector(sourceItem))
+ yield return result;
+ }
+ }
+
+ ///
+ /// Selects distinct elements from an enumeration.
+ ///
+ /// The type of the T source.
+ /// The source.
+ /// The comparer.
+ /// A enumeration of selected values
+ public static IEnumerable Distinct(IEnumerable source, IEqualityComparer comparer = null)
+ {
+ if (comparer == null)
+ comparer = EqualityComparer.Default;
+
+ // using Dictionary is not really efficient but easy to implement
+ var values = new Dictionary(comparer);
+ foreach (TSource sourceItem in source)
+ {
+ if (!values.ContainsKey(sourceItem))
+ {
+ values.Add(sourceItem, null);
+ yield return sourceItem;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/CharacterRegionTypeConverter.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/CharacterRegionTypeConverter.cs
new file mode 100644
index 000000000..02a9fdd08
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/CharacterRegionTypeConverter.cs
@@ -0,0 +1,71 @@
+using System;
+using System.ComponentModel;
+using System.Globalization;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public class CharacterRegionTypeConverter : TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return sourceType == typeof(string);
+ }
+
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ // Input must be a string.
+ string source = value as string;
+
+ if (string.IsNullOrEmpty(source))
+ {
+ throw new ArgumentException();
+ }
+
+ // Supported input formats:
+ // A
+ // A-Z
+ // 32-127
+ // 0x20-0x7F
+
+ var splitStr = source.Split('-');
+ var split = new char[splitStr.Length];
+ for (int i = 0; i < splitStr.Length; i++)
+ {
+ split[i] = ConvertCharacter(splitStr[i]);
+ }
+
+ switch (split.Length)
+ {
+ case 1:
+ // Only a single character (eg. "a").
+ return new CharacterRegion(split[0], split[0]);
+
+ case 2:
+ // Range of characters (eg. "a-z").
+ return new CharacterRegion(split[0], split[1]);
+
+ default:
+ throw new ArgumentException();
+ }
+ }
+
+
+ static char ConvertCharacter(string value)
+ {
+ if (value.Length == 1)
+ {
+ // Single character directly specifies a codepoint.
+ return value[0];
+ }
+ else
+ {
+ // Otherwise it must be an integer (eg. "32" or "0x20").
+ return (char)(int)intConverter.ConvertFromInvariantString(value);
+ }
+ }
+
+
+ static TypeConverter intConverter = TypeDescriptor.GetConverter(typeof(int));
+ }
+}
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/Glyph.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/Glyph.cs
new file mode 100644
index 000000000..11e11e211
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/Glyph.cs
@@ -0,0 +1,49 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Runtime.InteropServices;
+using Microsoft.Xna.Framework;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ABCFloat
+ {
+ public float A;
+ public float B;
+ public float C;
+ }
+
+ // Represents a single character within a font.
+ internal class Glyph
+ {
+ // Constructor.
+ public Glyph(char character, BitmapContent bitmap, Rectangle? subrect = null)
+ {
+ this.Character = character;
+ this.Bitmap = bitmap;
+ this.Subrect = subrect.GetValueOrDefault(new Rectangle(0, 0, bitmap.Width, bitmap.Height));
+ this.Width = bitmap.Width;
+ this.Height = bitmap.Height;
+ }
+
+ // Unicode codepoint.
+ public char Character;
+
+ // Glyph image data (may only use a portion of a larger bitmap).
+ public BitmapContent Bitmap;
+ public Rectangle Subrect;
+
+ // Layout information.
+ public float XOffset;
+ public float YOffset;
+ public int Width;
+ public int Height;
+
+ public float XAdvance;
+
+ public ABCFloat CharacterWidths;
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/GlyphCropper.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/GlyphCropper.cs
new file mode 100644
index 000000000..472f99f31
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/GlyphCropper.cs
@@ -0,0 +1,49 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using Microsoft.Xna.Framework;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ // Crops unused space from around the edge of a glyph bitmap.
+ internal static class GlyphCropper
+ {
+ public static void Crop(Glyph glyph)
+ {
+ // Crop the top.
+ while ((glyph.Subrect.Height > 1) && BitmapUtils.IsAlphaEntirely(0, glyph.Bitmap, new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, 1)))
+ {
+ glyph.Subrect.Y++;
+ glyph.Subrect.Height--;
+
+ glyph.YOffset++;
+ }
+
+ // Crop the bottom.
+ while ((glyph.Subrect.Height > 1) && BitmapUtils.IsAlphaEntirely(0, glyph.Bitmap, new Rectangle(glyph.Subrect.X, glyph.Subrect.Bottom - 1, glyph.Subrect.Width, 1)))
+ {
+ glyph.Subrect.Height--;
+ }
+
+ // Crop the left.
+ while ((glyph.Subrect.Width > 1) && BitmapUtils.IsAlphaEntirely(0, glyph.Bitmap, new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, 1, glyph.Subrect.Height)))
+ {
+ glyph.Subrect.X++;
+ glyph.Subrect.Width--;
+
+ glyph.XOffset++;
+ }
+
+ // Crop the right.
+ while ((glyph.Subrect.Width > 1) && BitmapUtils.IsAlphaEntirely(0, glyph.Bitmap, new Rectangle(glyph.Subrect.Right - 1, glyph.Subrect.Y, 1, glyph.Subrect.Height)))
+ {
+ glyph.Subrect.Width--;
+
+ glyph.XAdvance++;
+ }
+ }
+ }
+
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/GlyphPacker.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/GlyphPacker.cs
new file mode 100644
index 000000000..26617de58
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/GlyphPacker.cs
@@ -0,0 +1,209 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ // Helper for arranging many small bitmaps onto a single larger surface.
+ internal static class GlyphPacker
+ {
+ public static BitmapContent ArrangeGlyphs(Glyph[] sourceGlyphs, bool requirePOT, bool requireSquare)
+ {
+ // Build up a list of all the glyphs needing to be arranged.
+ var glyphs = new List();
+
+ for (int i = 0; i < sourceGlyphs.Length; i++)
+ {
+ var glyph = new ArrangedGlyph();
+
+ glyph.Source = sourceGlyphs[i];
+
+ // Leave a one pixel border around every glyph in the output bitmap.
+ glyph.Width = sourceGlyphs[i].Subrect.Width + 2;
+ glyph.Height = sourceGlyphs[i].Subrect.Height + 2;
+
+ glyphs.Add(glyph);
+ }
+
+ // Sort so the largest glyphs get arranged first.
+ glyphs.Sort(CompareGlyphSizes);
+
+ // Work out how big the output bitmap should be.
+ int outputWidth = GuessOutputWidth(sourceGlyphs);
+ int outputHeight = 0;
+
+ // Choose positions for each glyph, one at a time.
+ for (int i = 0; i < glyphs.Count; i++)
+ {
+ PositionGlyph(glyphs, i, outputWidth);
+
+ outputHeight = Math.Max(outputHeight, glyphs[i].Y + glyphs[i].Height);
+ }
+
+ // Create the merged output bitmap.
+ outputHeight = MakeValidTextureSize(outputHeight, requirePOT);
+
+ if (requireSquare)
+ {
+ outputHeight = Math.Max (outputWidth, outputHeight);
+ outputWidth = outputHeight;
+ }
+
+ return CopyGlyphsToOutput(glyphs, outputWidth, outputHeight);
+ }
+
+ // Once arranging is complete, copies each glyph to its chosen position in the single larger output bitmap.
+ static BitmapContent CopyGlyphsToOutput(List glyphs, int width, int height)
+ {
+ var output = new PixelBitmapContent(width, height);
+
+ foreach (var glyph in glyphs)
+ {
+ var sourceGlyph = glyph.Source;
+ var sourceRegion = sourceGlyph.Subrect;
+ var destinationRegion = new Rectangle(glyph.X + 1, glyph.Y + 1, sourceRegion.Width, sourceRegion.Height);
+
+ BitmapContent.Copy(sourceGlyph.Bitmap, sourceRegion, output, destinationRegion);
+
+ sourceGlyph.Bitmap = output;
+ sourceGlyph.Subrect = destinationRegion;
+ }
+
+ return output;
+ }
+
+
+ // Internal helper class keeps track of a glyph while it is being arranged.
+ class ArrangedGlyph
+ {
+ public Glyph Source;
+
+ public int X;
+ public int Y;
+
+ public int Width;
+ public int Height;
+ }
+
+
+ // Works out where to position a single glyph.
+ static void PositionGlyph(List glyphs, int index, int outputWidth)
+ {
+ int x = 0;
+ int y = 0;
+
+ while (true)
+ {
+ // Is this position free for us to use?
+ int intersects = FindIntersectingGlyph(glyphs, index, x, y);
+
+ if (intersects < 0)
+ {
+ glyphs[index].X = x;
+ glyphs[index].Y = y;
+
+ return;
+ }
+
+ // Skip past the existing glyph that we collided with.
+ x = glyphs[intersects].X + glyphs[intersects].Width;
+
+ // If we ran out of room to move to the right, try the next line down instead.
+ if (x + glyphs[index].Width > outputWidth)
+ {
+ x = 0;
+ y++;
+ }
+ }
+ }
+
+
+ // Checks if a proposed glyph position collides with anything that we already arranged.
+ static int FindIntersectingGlyph(List glyphs, int index, int x, int y)
+ {
+ int w = glyphs[index].Width;
+ int h = glyphs[index].Height;
+
+ for (int i = 0; i < index; i++)
+ {
+ if (glyphs[i].X >= x + w)
+ continue;
+
+ if (glyphs[i].X + glyphs[i].Width <= x)
+ continue;
+
+ if (glyphs[i].Y >= y + h)
+ continue;
+
+ if (glyphs[i].Y + glyphs[i].Height <= y)
+ continue;
+
+ return i;
+ }
+
+ return -1;
+ }
+
+
+ // Comparison function for sorting glyphs by size.
+ static int CompareGlyphSizes(ArrangedGlyph a, ArrangedGlyph b)
+ {
+ const int heightWeight = 1024;
+
+ int aSize = a.Height * heightWeight + a.Width;
+ int bSize = b.Height * heightWeight + b.Width;
+
+ if (aSize != bSize)
+ return bSize.CompareTo(aSize);
+ else
+ return a.Source.Character.CompareTo(b.Source.Character);
+ }
+
+
+ // Heuristic guesses what might be a good output width for a list of glyphs.
+ static int GuessOutputWidth(Glyph[] sourceGlyphs)
+ {
+ int maxWidth = 0;
+ int totalSize = 0;
+
+ foreach (var glyph in sourceGlyphs)
+ {
+ maxWidth = Math.Max(maxWidth, glyph.Bitmap.Width);
+ totalSize += glyph.Bitmap.Width * glyph.Bitmap.Height;
+ }
+
+ int width = Math.Max((int)Math.Sqrt(totalSize), maxWidth);
+
+ return MakeValidTextureSize(width, true);
+ }
+
+
+ // Rounds a value up to the next larger valid texture size.
+ static int MakeValidTextureSize(int value, bool requirePowerOfTwo)
+ {
+ // In case we want to compress the texture, make sure the size is a multiple of 4.
+ const int blockSize = 4;
+
+ if (requirePowerOfTwo)
+ {
+ // Round up to a power of two.
+ int powerOfTwo = blockSize;
+
+ while (powerOfTwo < value)
+ powerOfTwo <<= 1;
+
+ return powerOfTwo;
+ }
+ else
+ {
+ // Round up to the specified block size.
+ return (value + blockSize - 1) & ~(blockSize - 1);
+ }
+ }
+ }
+
+}
+
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/IFontImporter.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/IFontImporter.cs
new file mode 100644
index 000000000..cc69accff
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/IFontImporter.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ // Importer interface allows the conversion tool to support multiple source font formats.
+ internal interface IFontImporter
+ {
+ void Import(FontDescription options, string fontName);
+
+ IEnumerable Glyphs { get; }
+
+ float LineSpacing { get; }
+
+ int YOffsetMin { get; }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/SharpFontImporter.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/SharpFontImporter.cs
new file mode 100644
index 000000000..33bbec162
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/Font/SharpFontImporter.cs
@@ -0,0 +1,184 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using SharpFont;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ // Uses FreeType to rasterize TrueType fonts into a series of glyph bitmaps.
+ internal class SharpFontImporter : IFontImporter
+ {
+ // Properties hold the imported font data.
+ public IEnumerable Glyphs { get; private set; }
+
+ public float LineSpacing { get; private set; }
+
+ public int YOffsetMin { get; private set; }
+
+ // Size of the temp surface used for GDI+ rasterization.
+ const int MaxGlyphSize = 1024;
+
+ Library lib = null;
+
+ public void Import(FontDescription options, string fontName)
+ {
+ lib = new Library();
+ // Create a bunch of GDI+ objects.
+ var face = CreateFontFace(options, fontName);
+ try
+ {
+ // Which characters do we want to include?
+ var characters = options.Characters;
+
+ var glyphList = new List();
+ // Rasterize each character in turn.
+ foreach (char character in characters)
+ {
+ var glyph = ImportGlyph(character, face);
+ glyphList.Add(glyph);
+ }
+ Glyphs = glyphList;
+
+ // Store the font height.
+ LineSpacing = face.Size.Metrics.Height >> 6;
+
+ // The height used to calculate the Y offset for each character.
+ YOffsetMin = -face.Size.Metrics.Ascender >> 6;
+ }
+ finally
+ {
+ if (face != null)
+ face.Dispose();
+ if (lib != null)
+ {
+ lib.Dispose();
+ lib = null;
+ }
+ }
+ }
+
+
+ // Attempts to instantiate the requested GDI+ font object.
+ private Face CreateFontFace(FontDescription options, string fontName)
+ {
+ try
+ {
+ const uint dpi = 96;
+ var face = lib.NewFace(fontName, 0);
+ var fixedSize = ((int)options.Size) << 6;
+ face.SetCharSize(0, fixedSize, dpi, dpi);
+
+ if (face.FamilyName == "Microsoft Sans Serif" && options.FontName != "Microsoft Sans Serif")
+ throw new PipelineException(string.Format("Font {0} is not installed on this computer.", options.FontName));
+
+ return face;
+
+ // A font substitution must have occurred.
+ //throw new Exception(string.Format("Can't find font '{0}'.", options.FontName));
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ // Rasterizes a single character glyph.
+ private Glyph ImportGlyph(char character, Face face)
+ {
+ uint glyphIndex = face.GetCharIndex(character);
+ face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
+ face.Glyph.RenderGlyph(RenderMode.Normal);
+
+ // Render the character.
+ BitmapContent glyphBitmap = null;
+ if (face.Glyph.Bitmap.Width > 0 && face.Glyph.Bitmap.Rows > 0)
+ {
+ glyphBitmap = new PixelBitmapContent(face.Glyph.Bitmap.Width, face.Glyph.Bitmap.Rows);
+ byte[] gpixelAlphas = new byte[face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows];
+ //if the character bitmap has 1bpp we have to expand the buffer data to get the 8bpp pixel data
+ //each byte in bitmap.bufferdata contains the value of to 8 pixels in the row
+ //if bitmap is of width 10, each row has 2 bytes with 10 valid bits, and the last 6 bits of 2nd byte must be discarded
+ if(face.Glyph.Bitmap.PixelMode == PixelMode.Mono)
+ {
+ //variables needed for the expansion, amount of written data, length of the data to write
+ int written = 0, length = face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows;
+ for(int i = 0; written < length; i++)
+ {
+ //width in pixels of each row
+ int width = face.Glyph.Bitmap.Width;
+ while(width > 0)
+ {
+ //valid data in the current byte
+ int stride = MathHelper.Min(8, width);
+ //copy the valid bytes to pixeldata
+ //System.Array.Copy(ExpandByte(face.Glyph.Bitmap.BufferData[i]), 0, gpixelAlphas, written, stride);
+ ExpandByteAndCopy(face.Glyph.Bitmap.BufferData[i], stride, gpixelAlphas, written);
+ written += stride;
+ width -= stride;
+ if(width > 0)
+ i++;
+ }
+ }
+ }
+ else
+ Marshal.Copy(face.Glyph.Bitmap.Buffer, gpixelAlphas, 0, gpixelAlphas.Length);
+ glyphBitmap.SetPixelData(gpixelAlphas);
+ }
+
+ if (glyphBitmap == null)
+ {
+ var gHA = face.Glyph.Metrics.HorizontalAdvance >> 6;
+ var gVA = face.Size.Metrics.Height >> 6;
+
+ gHA = gHA > 0 ? gHA : gVA;
+ gVA = gVA > 0 ? gVA : gHA;
+
+ glyphBitmap = new PixelBitmapContent(gHA, gVA);
+ }
+
+ // not sure about this at all
+ var abc = new ABCFloat ();
+ abc.A = face.Glyph.Metrics.HorizontalBearingX >> 6;
+ abc.B = face.Glyph.Metrics.Width >> 6;
+ abc.C = (face.Glyph.Metrics.HorizontalAdvance >> 6) - (abc.A + abc.B);
+
+ // Construct the output Glyph object.
+ return new Glyph(character, glyphBitmap)
+ {
+ XOffset = -(face.Glyph.Advance.X >> 6),
+ XAdvance = face.Glyph.Metrics.HorizontalAdvance >> 6,
+ YOffset = -(face.Glyph.Metrics.HorizontalBearingY >> 6),
+ CharacterWidths = abc
+ };
+ }
+
+
+ ///
+ /// Reads each individual bit of a byte from left to right and expands it to a full byte,
+ /// ones get byte.maxvalue, and zeros get byte.minvalue.
+ ///
+ /// Byte to expand and copy
+ /// Number of Bits of the Byte to copy, from 1 to 8
+ /// Byte array where to copy the results
+ /// Position where to begin copying the results in destination
+ private static void ExpandByteAndCopy(byte origin, int length, byte[] destination, int startIndex)
+ {
+ byte tmp;
+ for(int i = 7; i > 7 - length; i--)
+ {
+ tmp = (byte) (1 << i);
+ if(origin / tmp == 1)
+ {
+ destination[startIndex + 7 - i] = byte.MaxValue;
+ origin -= tmp;
+ }
+ else
+ destination[startIndex + 7 - i] = byte.MinValue;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/FontDescription.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/FontDescription.cs
new file mode 100644
index 000000000..e9514c87e
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/FontDescription.cs
@@ -0,0 +1,290 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ internal class CharacterCollection : ICollection
+ {
+ private List _items;
+
+ public CharacterCollection()
+ {
+ _items = new List();
+ }
+
+ public CharacterCollection(IEnumerable characters)
+ {
+ _items = new List();
+ foreach (var c in characters)
+ Add(c);
+ }
+
+ #region ICollection Members
+
+ public void Add(char item)
+ {
+ if (!_items.Contains(item))
+ _items.Add(item);
+ }
+
+ public void Clear()
+ {
+ _items.Clear();
+ }
+
+ public bool Contains(char item)
+ {
+ return _items.Contains(item);
+ }
+
+ public void CopyTo(char[] array, int arrayIndex)
+ {
+ _items.CopyTo(array, arrayIndex);
+ }
+
+ public int Count
+ {
+ get { return _items.Count; }
+ }
+
+ public bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ public bool Remove(char item)
+ {
+ return _items.Remove(item);
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ public IEnumerator GetEnumerator()
+ {
+ return _items.GetEnumerator();
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return _items.GetEnumerator();
+ }
+
+ #endregion
+ }
+
+ ///
+ /// Provides information to the FontDescriptionProcessor describing which font to rasterize, which font size to utilize, and which Unicode characters to include in the processor output.
+ ///
+ public class FontDescription : ContentItem
+ {
+ private char? defaultCharacter;
+ private string fontName;
+ private float size;
+ private float spacing;
+ private FontDescriptionStyle style;
+ private bool useKerning;
+ private CharacterCollection characters = new CharacterCollection();
+
+ ///
+ /// Gets or sets the name of the font, such as "Times New Roman" or "Arial". This value cannot be null or empty.
+ ///
+ [ContentSerializer(AllowNull = false)]
+ public string FontName
+ {
+ get
+ {
+ return fontName;
+ }
+ set
+ {
+ if (string.IsNullOrEmpty(value))
+ throw new ArgumentNullException("FontName is null or an empty string.");
+ fontName = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the size, in points, of the font.
+ ///
+ public float Size
+ {
+ get
+ {
+ return size;
+ }
+ set
+ {
+ if (value <= 0.0f)
+ throw new ArgumentOutOfRangeException("Size must be greater than zero.");
+ size = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the amount of space, in pixels, to insert between letters in a string.
+ ///
+ [ContentSerializer(Optional = true)]
+ public float Spacing
+ {
+ get
+ {
+ return spacing;
+ }
+ set
+ {
+ spacing = value;
+ }
+ }
+
+ ///
+ /// Indicates if kerning information is used when drawing characters.
+ ///
+ [ContentSerializer(Optional = true)]
+ public bool UseKerning
+ {
+ get
+ {
+ return useKerning;
+ }
+ set
+ {
+ useKerning = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the style of the font, expressed as a combination of one or more FontDescriptionStyle flags.
+ ///
+ public FontDescriptionStyle Style
+ {
+ get
+ {
+ return style;
+ }
+ set
+ {
+ style = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the default character for the font.
+ ///
+ [ContentSerializer(Optional = true)]
+ public Nullable DefaultCharacter
+ {
+ get
+ {
+ return defaultCharacter;
+ }
+ set
+ {
+ defaultCharacter = value;
+ }
+ }
+
+ [ContentSerializer(CollectionItemName = "CharacterRegion")]
+ internal CharacterRegion[] CharacterRegions
+ {
+ get
+ {
+ var regions = new List();
+ var chars = Characters.ToList();
+ chars.Sort();
+
+ var start = chars[0];
+ var end = chars[0];
+
+ for (var i=1; i < chars.Count; i++)
+ {
+ if (chars[i] != (end+1))
+ {
+ regions.Add(new CharacterRegion(start, end));
+ start = chars[i];
+ }
+ end = chars[i];
+ }
+
+ regions.Add(new CharacterRegion(start, end));
+
+ return regions.ToArray();
+ }
+
+ set
+ {
+ for (int index = 0; index < value.Length; ++index)
+ {
+ CharacterRegion characterRegion = value[index];
+ if (characterRegion.End < characterRegion.Start)
+ throw new ArgumentException("CharacterRegion.End must be greater than CharacterRegion.Start");
+
+ for (var start = characterRegion.Start; start <= characterRegion.End; start++)
+ Characters.Add(start);
+ }
+ }
+ }
+
+ [ContentSerializerIgnore]
+ public ICollection Characters
+ {
+ get { return characters; }
+ internal set { characters = new CharacterCollection(value); }
+ }
+
+ internal FontDescription()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of FontDescription and initializes its members to the specified font, size, and spacing, using FontDescriptionStyle.Regular as the default value for Style.
+ ///
+ /// The name of the font, such as Times New Roman.
+ /// The size, in points, of the font.
+ /// The amount of space, in pixels, to insert between letters in a string.
+ public FontDescription(string fontName, float size, float spacing)
+ : this(fontName, size, spacing, FontDescriptionStyle.Regular, false)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of FontDescription and initializes its members to the specified font, size, spacing, and style.
+ ///
+ /// The name of the font, such as Times New Roman.
+ /// The size, in points, of the font.
+ /// The amount of space, in pixels, to insert between letters in a string.
+ /// The font style for the font.
+ public FontDescription(string fontName, float size, float spacing, FontDescriptionStyle fontStyle)
+ : this(fontName, size, spacing, fontStyle, false)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of FontDescription using the specified values.
+ ///
+ /// The name of the font, such as Times New Roman.
+ /// The size, in points, of the font.
+ /// The amount of space, in pixels, to insert between letters in a string.
+ /// The font style for the font.
+ /// true if kerning information is used when drawing characters; false otherwise.
+ public FontDescription(string fontName, float size, float spacing, FontDescriptionStyle fontStyle, bool useKerning)
+ {
+ // Write to the properties so the validation is run
+ FontName = fontName;
+ Size = size;
+ Spacing = spacing;
+ Style = fontStyle;
+ UseKerning = useKerning;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/FontDescriptionStyle.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/FontDescriptionStyle.cs
new file mode 100644
index 000000000..33edee026
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/FontDescriptionStyle.cs
@@ -0,0 +1,31 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Flags that describe style information to be applied to text.
+ /// You can combine these flags by using a bitwise OR operator (|).
+ ///
+ [Flags]
+ public enum FontDescriptionStyle
+ {
+ ///
+ /// Bold text.
+ ///
+ Bold,
+
+ ///
+ /// Italic text.
+ ///
+ Italic,
+
+ ///
+ /// Normal text.
+ ///
+ Regular,
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GeometryContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GeometryContent.cs
new file mode 100644
index 000000000..618b9ad29
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GeometryContent.cs
@@ -0,0 +1,78 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides properties that define various aspects of a geometry batch.
+ ///
+ public class GeometryContent : ContentItem
+ {
+ IndexCollection indices;
+ MaterialContent material;
+ MeshContent parent;
+ VertexContent vertices;
+
+ ///
+ /// Gets the list of triangle indices for this geometry batch. Geometry is stored as an indexed triangle list, where each group of three indices defines a single triangle.
+ ///
+ public IndexCollection Indices
+ {
+ get
+ {
+ return indices;
+ }
+ }
+
+ ///
+ /// Gets or sets the material of the parent mesh.
+ ///
+ public MaterialContent Material
+ {
+ get
+ {
+ return material;
+ }
+ set
+ {
+ material = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the parent MeshContent for this object.
+ ///
+ public MeshContent Parent
+ {
+ get
+ {
+ return parent;
+ }
+ set
+ {
+ parent = value;
+ }
+ }
+
+ ///
+ /// Gets the set of vertex batches for the geometry batch.
+ ///
+ public VertexContent Vertices
+ {
+ get
+ {
+ return vertices;
+ }
+ }
+
+ ///
+ /// Creates an instance of GeometryContent.
+ ///
+ public GeometryContent()
+ {
+ indices = new IndexCollection();
+ vertices = new VertexContent(this);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GeometryContentCollection.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GeometryContentCollection.cs
new file mode 100644
index 000000000..78ca70fb2
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GeometryContentCollection.cs
@@ -0,0 +1,37 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides methods for maintaining a collection of geometry batches that make up a mesh.
+ ///
+ public sealed class GeometryContentCollection : ChildCollection
+ {
+ internal GeometryContentCollection(MeshContent parent)
+ : base(parent)
+ {
+ }
+
+ ///
+ /// Gets the parent of a child object.
+ ///
+ /// The child of the parent being retrieved.
+ /// The parent of the child object.
+ protected override MeshContent GetParent(GeometryContent child)
+ {
+ return child.Parent;
+ }
+
+ ///
+ /// Sets the parent of the specified child object.
+ ///
+ /// The child of the parent being set.
+ /// The parent of the child object.
+ protected override void SetParent(GeometryContent child, MeshContent parent)
+ {
+ child.Parent = parent;
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GraphicsUtil.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GraphicsUtil.cs
new file mode 100644
index 000000000..a8839681b
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/GraphicsUtil.cs
@@ -0,0 +1,489 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.IO;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Graphics.PackedVector;
+using FreeImageAPI;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ public static class GraphicsUtil
+ {
+ internal static BitmapContent Resize(this BitmapContent bitmap, int newWidth, int newHeight)
+ {
+ BitmapContent src = bitmap;
+ SurfaceFormat format;
+ src.TryGetFormat(out format);
+ if (format != SurfaceFormat.Vector4)
+ {
+ var v4 = new PixelBitmapContent(src.Width, src.Height);
+ BitmapContent.Copy(src, v4);
+ src = v4;
+ }
+
+ // Convert to FreeImage bitmap
+ var bytes = src.GetPixelData();
+ var fi = FreeImage.ConvertFromRawBits(bytes, FREE_IMAGE_TYPE.FIT_RGBAF, src.Width, src.Height, SurfaceFormat.Vector4.GetSize() * src.Width, 128, 0, 0, 0, true);
+
+ // Resize
+ var newfi = FreeImage.Rescale(fi, newWidth, newHeight, FREE_IMAGE_FILTER.FILTER_BICUBIC);
+ FreeImage.UnloadEx(ref fi);
+
+ // Convert back to PixelBitmapContent
+ src = new PixelBitmapContent(newWidth, newHeight);
+ bytes = new byte[SurfaceFormat.Vector4.GetSize() * newWidth * newHeight];
+ FreeImage.ConvertToRawBits(bytes, newfi, SurfaceFormat.Vector4.GetSize() * newWidth, 128, 0, 0, 0, true);
+ src.SetPixelData(bytes);
+ FreeImage.UnloadEx(ref newfi);
+ // Convert back to source type if required
+ if (format != SurfaceFormat.Vector4)
+ {
+ var s = (BitmapContent)Activator.CreateInstance(bitmap.GetType(), new object[] { newWidth, newHeight });
+ BitmapContent.Copy(src, s);
+ src = s;
+ }
+
+ return src;
+ }
+
+ public static void BGRAtoRGBA(byte[] data)
+ {
+ for (var x = 0; x < data.Length; x += 4)
+ {
+ data[x] ^= data[x + 2];
+ data[x + 2] ^= data[x];
+ data[x] ^= data[x + 2];
+ }
+ }
+
+ public static bool IsPowerOfTwo(int x)
+ {
+ return (x & (x - 1)) == 0;
+ }
+
+ ///
+ /// Returns the next power of two. Returns same value if already is PoT.
+ ///
+ public static int GetNextPowerOfTwo(int value)
+ {
+ if (IsPowerOfTwo(value))
+ return value;
+
+ var nearestPower = 1;
+ while (nearestPower < value)
+ nearestPower = nearestPower << 1;
+
+ return nearestPower;
+ }
+
+ enum AlphaRange
+ {
+ ///
+ /// Pixel data has no alpha values below 1.0.
+ ///
+ Opaque,
+
+ ///
+ /// Pixel data contains alpha values that are either 0.0 or 1.0.
+ ///
+ Cutout,
+
+ ///
+ /// Pixel data contains alpha values that cover the full range of 0.0 to 1.0.
+ ///
+ Full,
+ }
+
+ ///
+ /// Gets the alpha range in a set of pixels.
+ ///
+ /// A bitmap of full-colour floating point pixel data in RGBA or BGRA order.
+ /// A member of the AlphaRange enum to describe the range of alpha in the pixel data.
+ static AlphaRange CalculateAlphaRange(BitmapContent bitmap)
+ {
+ AlphaRange result = AlphaRange.Opaque;
+ var pixelBitmap = bitmap as PixelBitmapContent;
+ if (pixelBitmap != null)
+ {
+ for (int y = 0; y < pixelBitmap.Height; ++y)
+ {
+ var row = pixelBitmap.GetRow(y);
+ foreach (var pixel in row)
+ {
+ if (pixel.W == 0.0)
+ result = AlphaRange.Cutout;
+ else if (pixel.W < 1.0)
+ return AlphaRange.Full;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static void CompressPvrtc(ContentProcessorContext context, TextureContent content, bool isSpriteFont)
+ {
+ // If sharp alpha is required (for a font texture page), use 16-bit color instead of PVR
+ if (isSpriteFont)
+ {
+ CompressColor16Bit(context, content);
+ return;
+ }
+
+ // Calculate number of mip levels
+ var width = content.Faces[0][0].Height;
+ var height = content.Faces[0][0].Width;
+
+ if (!IsPowerOfTwo(width) || !IsPowerOfTwo(height) || (width != height))
+ {
+ context.Logger.LogWarning(null, content.Identity, "PVR compression requires width and height to be powers of two and equal. Falling back to 16-bit color.");
+ CompressColor16Bit(context, content);
+ return;
+ }
+
+ var face = content.Faces[0][0];
+
+ var alphaRange = CalculateAlphaRange(face);
+
+ if (alphaRange == AlphaRange.Opaque)
+ content.ConvertBitmapType(typeof(PvrtcRgb4BitmapContent));
+ else
+ content.ConvertBitmapType(typeof(PvrtcRgba4BitmapContent));
+ }
+
+ public static void CompressDxt(ContentProcessorContext context, TextureContent content, bool isSpriteFont)
+ {
+ var face = content.Faces[0][0];
+
+ if (context.TargetProfile == GraphicsProfile.Reach)
+ {
+ if (!IsPowerOfTwo(face.Width) || !IsPowerOfTwo(face.Height))
+ throw new PipelineException("DXT compression requires width and height must be powers of two in Reach graphics profile.");
+ }
+
+ // Test the alpha channel to figure out if we have alpha.
+ var alphaRange = CalculateAlphaRange(face);
+
+ // TODO: This isn't quite right.
+ //
+ // We should be generating DXT1 textures for cutout alpha
+ // as DXT1 supports 1bit alpha and it uses less memory.
+ //
+ // XNA never generated DXT3 for textures... it always picked
+ // between DXT1 for cutouts and DXT5 for fractional alpha.
+ //
+ // DXT3 however can produce better results for high frequency
+ // alpha like a chain link fence where is DXT5 is better for
+ // low frequency alpha like clouds. I don't know how we can
+ // pick the right thing in this case without a hint.
+ //
+ if (isSpriteFont)
+ CompressFontDXT3(content);
+ else if (alphaRange == AlphaRange.Opaque)
+ content.ConvertBitmapType(typeof(Dxt1BitmapContent));
+ else if (alphaRange == AlphaRange.Cutout)
+ content.ConvertBitmapType(typeof(Dxt3BitmapContent));
+ else
+ content.ConvertBitmapType(typeof(Dxt5BitmapContent));
+ }
+
+ static public void CompressAti(ContentProcessorContext context, TextureContent content, bool isSpriteFont)
+ {
+ // If sharp alpha is required (for a font texture page), use 16-bit color instead of PVR
+ if (isSpriteFont)
+ {
+ CompressColor16Bit(context, content);
+ return;
+ }
+
+ var face = content.Faces[0][0];
+ var alphaRange = CalculateAlphaRange(face);
+
+ if (alphaRange == AlphaRange.Full)
+ content.ConvertBitmapType(typeof(AtcExplicitBitmapContent));
+ else
+ content.ConvertBitmapType(typeof(AtcInterpolatedBitmapContent));
+ }
+
+ static public void CompressEtc1(ContentProcessorContext context, TextureContent content, bool isSpriteFont)
+ {
+ // If sharp alpha is required (for a font texture page), use 16-bit color instead of PVR
+ if (isSpriteFont)
+ {
+ CompressColor16Bit(context, content);
+ return;
+ }
+
+ var face = content.Faces[0][0];
+ var alphaRange = CalculateAlphaRange(face);
+
+ // Use BGRA4444 for textures with non-opaque alpha values
+ if (alphaRange != AlphaRange.Opaque)
+ content.ConvertBitmapType(typeof(PixelBitmapContent));
+ else
+ {
+ // PVR SGX does not handle non-POT ETC1 textures.
+ // https://code.google.com/p/libgdx/issues/detail?id=1310
+ // Since we already enforce POT for PVR and DXT in Reach, we will also enforce POT for ETC1
+ if (!IsPowerOfTwo(face.Width) || !IsPowerOfTwo(face.Height))
+ {
+ context.Logger.LogWarning(null, content.Identity, "ETC1 compression requires width and height to be powers of two due to hardware restrictions on some devices. Falling back to BGR565.");
+ content.ConvertBitmapType(typeof(PixelBitmapContent));
+ }
+ else
+ content.ConvertBitmapType(typeof(Etc1BitmapContent));
+ }
+ }
+
+ static public void CompressColor16Bit(ContentProcessorContext context, TextureContent content)
+ {
+ var face = content.Faces[0][0];
+ var alphaRange = CalculateAlphaRange(face);
+
+ if (alphaRange == AlphaRange.Opaque)
+ content.ConvertBitmapType(typeof(PixelBitmapContent));
+ else if (alphaRange == AlphaRange.Cutout)
+ content.ConvertBitmapType(typeof(PixelBitmapContent));
+ else
+ content.ConvertBitmapType(typeof(PixelBitmapContent));
+ }
+
+ // Compress the greyscale font texture page using a specially-formulated DXT3 mode
+ static public unsafe void CompressFontDXT3(TextureContent content)
+ {
+ if (content.Faces.Count > 1)
+ throw new PipelineException("Font textures should only have one face");
+
+ var block = new Vector4[16];
+ for (int i = 0; i < content.Faces[0].Count; ++i)
+ {
+ var face = content.Faces[0][i];
+ var xBlocks = (face.Width + 3) / 4;
+ var yBlocks = (face.Height + 3) / 4;
+ var dxt3Size = xBlocks * yBlocks * 16;
+ var buffer = new byte[dxt3Size];
+
+ var bytes = face.GetPixelData();
+ fixed (byte* b = bytes)
+ {
+ Vector4* colors = (Vector4*)b;
+
+ int w = 0;
+ int h = 0;
+ int x = 0;
+ int y = 0;
+ while (h < (face.Height & ~3))
+ {
+ w = 0;
+ x = 0;
+
+ var h0 = h * face.Width;
+ var h1 = h0 + face.Width;
+ var h2 = h1 + face.Width;
+ var h3 = h2 + face.Width;
+
+ while (w < (face.Width & ~3))
+ {
+ block[0] = colors[w + h0];
+ block[1] = colors[w + h0 + 1];
+ block[2] = colors[w + h0 + 2];
+ block[3] = colors[w + h0 + 3];
+ block[4] = colors[w + h1];
+ block[5] = colors[w + h1 + 1];
+ block[6] = colors[w + h1 + 2];
+ block[7] = colors[w + h1 + 3];
+ block[8] = colors[w + h2];
+ block[9] = colors[w + h2 + 1];
+ block[10] = colors[w + h2 + 2];
+ block[11] = colors[w + h2 + 3];
+ block[12] = colors[w + h3];
+ block[13] = colors[w + h3 + 1];
+ block[14] = colors[w + h3 + 2];
+ block[15] = colors[w + h3 + 3];
+
+ int offset = (x + y * xBlocks) * 16;
+ CompressFontDXT3Block(block, buffer, offset);
+
+ w += 4;
+ ++x;
+ }
+
+ // Do partial block at end of row
+ if (w < face.Width)
+ {
+ var cols = face.Width - w;
+ Array.Clear(block, 0, 16);
+ for (int r = 0; r < 4; ++r)
+ {
+ h0 = (h + r) * face.Width;
+ for (int c = 0; c < cols; ++c)
+ block[(r * 4) + c] = colors[w + h0 + c];
+ }
+
+ int offset = (x + y * xBlocks) * 16;
+ CompressFontDXT3Block(block, buffer, offset);
+ }
+
+ h += 4;
+ ++y;
+ }
+
+ // Do last partial row
+ if (h < face.Height)
+ {
+ var rows = face.Height - h;
+ w = 0;
+ x = 0;
+ while (w < (face.Width & ~3))
+ {
+ Array.Clear(block, 0, 16);
+ for (int r = 0; r < rows; ++r)
+ {
+ var h0 = (h + r) * face.Width;
+ block[(r * 4) + 0] = colors[w + h0 + 0];
+ block[(r * 4) + 1] = colors[w + h0 + 1];
+ block[(r * 4) + 2] = colors[w + h0 + 2];
+ block[(r * 4) + 3] = colors[w + h0 + 3];
+ }
+
+ int offset = (x + y * xBlocks) * 16;
+ CompressFontDXT3Block(block, buffer, offset);
+
+ w += 4;
+ ++x;
+ }
+
+ // Do last partial block
+ if (w < face.Width)
+ {
+ var cols = face.Width - w;
+ Array.Clear(block, 0, 16);
+ for (int r = 0; r < rows; ++r)
+ {
+ var h0 = (h + r) * face.Width;
+ for (int c = 0; c < cols; ++c)
+ block[(r * 4) + c] = colors[w + h0 + c];
+ }
+
+ int offset = (x + y * xBlocks) * 16;
+ CompressFontDXT3Block(block, buffer, offset);
+ }
+ }
+ }
+
+ var dxt3 = new Dxt3BitmapContent(face.Width, face.Height);
+ dxt3.SetPixelData(buffer);
+ content.Faces[0][i] = dxt3;
+ }
+ }
+
+ // Maps a 2-bit greyscale to the index required for DXT3
+ // 00 = color0
+ // 01 = color1
+ // 10 = 2/3 * color0 + 1/3 * color1
+ // 11 = 1/3 * color0 + 2/3 * color1
+ static byte[] dxt3Map = new byte[] { 0, 2, 3, 1 };
+
+ // Compress a single 4x4 block from colors into buffer at the given offset
+ static void CompressFontDXT3Block(Vector4[] colors, byte[] buffer, int offset)
+ {
+ // Get the alpha into a 0-15 range
+ int a0 = (int)(colors[0].W * 15.0);
+ int a1 = (int)(colors[1].W * 15.0);
+ int a2 = (int)(colors[2].W * 15.0);
+ int a3 = (int)(colors[3].W * 15.0);
+ int a4 = (int)(colors[4].W * 15.0);
+ int a5 = (int)(colors[5].W * 15.0);
+ int a6 = (int)(colors[6].W * 15.0);
+ int a7 = (int)(colors[7].W * 15.0);
+ int a8 = (int)(colors[8].W * 15.0);
+ int a9 = (int)(colors[9].W * 15.0);
+ int a10 = (int)(colors[10].W * 15.0);
+ int a11 = (int)(colors[11].W * 15.0);
+ int a12 = (int)(colors[12].W * 15.0);
+ int a13 = (int)(colors[13].W * 15.0);
+ int a14 = (int)(colors[14].W * 15.0);
+ int a15 = (int)(colors[15].W * 15.0);
+
+ // Duplicate the top two bits into the bottom two bits so we get one of four values: b0000, b0101, b1010, b1111
+ a0 = (a0 & 0xC) | (a0 >> 2);
+ a1 = (a1 & 0xC) | (a1 >> 2);
+ a2 = (a2 & 0xC) | (a2 >> 2);
+ a3 = (a3 & 0xC) | (a3 >> 2);
+ a4 = (a4 & 0xC) | (a4 >> 2);
+ a5 = (a5 & 0xC) | (a5 >> 2);
+ a6 = (a6 & 0xC) | (a6 >> 2);
+ a7 = (a7 & 0xC) | (a7 >> 2);
+ a8 = (a8 & 0xC) | (a8 >> 2);
+ a9 = (a9 & 0xC) | (a9 >> 2);
+ a10 = (a10 & 0xC) | (a10 >> 2);
+ a11 = (a11 & 0xC) | (a11 >> 2);
+ a12 = (a12 & 0xC) | (a12 >> 2);
+ a13 = (a13 & 0xC) | (a13 >> 2);
+ a14 = (a14 & 0xC) | (a14 >> 2);
+ a15 = (a15 & 0xC) | (a15 >> 2);
+
+ // 4-bit alpha
+ buffer[offset + 0] = (byte)((a1 << 4) | a0);
+ buffer[offset + 1] = (byte)((a3 << 4) | a2);
+ buffer[offset + 2] = (byte)((a5 << 4) | a4);
+ buffer[offset + 3] = (byte)((a7 << 4) | a6);
+ buffer[offset + 4] = (byte)((a9 << 4) | a8);
+ buffer[offset + 5] = (byte)((a11 << 4) | a10);
+ buffer[offset + 6] = (byte)((a13 << 4) | a12);
+ buffer[offset + 7] = (byte)((a15 << 4) | a14);
+
+ // color0 (transparent)
+ buffer[offset + 8] = 0;
+ buffer[offset + 9] = 0;
+
+ // color1 (white)
+ buffer[offset + 10] = 255;
+ buffer[offset + 11] = 255;
+
+ // Get the red (to be used for green and blue channels as well) into a 0-15 range
+ a0 = (int)(colors[0].X * 15.0);
+ a1 = (int)(colors[1].X * 15.0);
+ a2 = (int)(colors[2].X * 15.0);
+ a3 = (int)(colors[3].X * 15.0);
+ a4 = (int)(colors[4].X * 15.0);
+ a5 = (int)(colors[5].X * 15.0);
+ a6 = (int)(colors[6].X * 15.0);
+ a7 = (int)(colors[7].X * 15.0);
+ a8 = (int)(colors[8].X * 15.0);
+ a9 = (int)(colors[9].X * 15.0);
+ a10 = (int)(colors[10].X * 15.0);
+ a11 = (int)(colors[11].X * 15.0);
+ a12 = (int)(colors[12].X * 15.0);
+ a13 = (int)(colors[13].X * 15.0);
+ a14 = (int)(colors[14].X * 15.0);
+ a15 = (int)(colors[15].X * 15.0);
+
+ // Duplicate the top two bits into the bottom two bits so we get one of four values: b0000, b0101, b1010, b1111
+ a0 = (a0 & 0xC) | (a0 >> 2);
+ a1 = (a1 & 0xC) | (a1 >> 2);
+ a2 = (a2 & 0xC) | (a2 >> 2);
+ a3 = (a3 & 0xC) | (a3 >> 2);
+ a4 = (a4 & 0xC) | (a4 >> 2);
+ a5 = (a5 & 0xC) | (a5 >> 2);
+ a6 = (a6 & 0xC) | (a6 >> 2);
+ a7 = (a7 & 0xC) | (a7 >> 2);
+ a8 = (a8 & 0xC) | (a8 >> 2);
+ a9 = (a9 & 0xC) | (a9 >> 2);
+ a10 = (a10 & 0xC) | (a10 >> 2);
+ a11 = (a11 & 0xC) | (a11 >> 2);
+ a12 = (a12 & 0xC) | (a12 >> 2);
+ a13 = (a13 & 0xC) | (a13 >> 2);
+ a14 = (a14 & 0xC) | (a14 >> 2);
+ a15 = (a15 & 0xC) | (a15 >> 2);
+
+ // Color indices (00 = color0, 01 = color1, 10 = 2/3 * color0 + 1/3 * color1, 11 = 1/3 * color0 + 2/3 * color1)
+ buffer[offset + 12] = (byte)((dxt3Map[a3 >> 2] << 6) | (dxt3Map[a2 >> 2] << 4) | (dxt3Map[a1 >> 2] << 2) | dxt3Map[a0 >> 2]);
+ buffer[offset + 13] = (byte)((dxt3Map[a7 >> 2] << 6) | (dxt3Map[a6 >> 2] << 4) | (dxt3Map[a5 >> 2] << 2) | dxt3Map[a4 >> 2]);
+ buffer[offset + 14] = (byte)((dxt3Map[a11 >> 2] << 6) | (dxt3Map[a10 >> 2] << 4) | (dxt3Map[a9 >> 2] << 2) | dxt3Map[a8 >> 2]);
+ buffer[offset + 15] = (byte)((dxt3Map[a15 >> 2] << 6) | (dxt3Map[a14 >> 2] << 4) | (dxt3Map[a13 >> 2] << 2) | dxt3Map[a12 >> 2]);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/IndexCollection.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/IndexCollection.cs
new file mode 100644
index 000000000..d7beeec54
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/IndexCollection.cs
@@ -0,0 +1,32 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System.Collections.ObjectModel;
+using System.Collections.Generic;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides methods for maintaining a list of index values.
+ ///
+ public sealed class IndexCollection : Collection
+ {
+ ///
+ /// Initializes a new instance of IndexCollection.
+ ///
+ public IndexCollection()
+ {
+ }
+
+ ///
+ /// Add a range of indices to the collection.
+ ///
+ /// A collection of indices to add.
+ public void AddRange(IEnumerable indices)
+ {
+ foreach (var t in indices)
+ Add(t);
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/IndirectPositionCollection.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/IndirectPositionCollection.cs
new file mode 100644
index 000000000..63b96f4cf
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/IndirectPositionCollection.cs
@@ -0,0 +1,152 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides methods for maintaining a list of vertex positions.
+ ///
+ ///
+ /// This class is designed to collect the vertex positions for a VertexContent object. Use the contents
+ /// of the PositionIndices property (of the contained VertexContent object) to index into the Positions
+ /// property of the parent mesh.
+ ///
+ public sealed class IndirectPositionCollection : IList
+ {
+ private readonly VertexChannel _positionIndices;
+ private readonly GeometryContent _geometry;
+
+ ///
+ /// Number of positions in the collection.
+ ///
+ /// Number of positions.
+ public int Count
+ {
+ get { return _positionIndices.Count; }
+ }
+
+ ///
+ /// Gets or sets the position at the specified index.
+ ///
+ /// Position located at index.
+ public Vector3 this[int index]
+ {
+ get
+ {
+ var remap = _positionIndices[index];
+ return _geometry.Parent.Positions[remap];
+ }
+ set
+ {
+ throw Readonly();
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether this object is read-only.
+ ///
+ /// true if this object is read-only; false otherwise.
+ bool ICollection.IsReadOnly
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Initializes a new instance of IndirectPositionCollection.
+ ///
+ internal IndirectPositionCollection(GeometryContent geom, VertexChannel positionIndices)
+ {
+ _geometry = geom;
+ _positionIndices = positionIndices;
+ }
+
+ ///
+ /// Determines whether the specified position is in the collection.
+ ///
+ /// Position being searched for in the collection.
+ /// true if the position was found; false otherwise.
+ public bool Contains(Vector3 item)
+ {
+ return IndexOf(item) > -1;
+ }
+
+ ///
+ /// Copies the specified positions to an array, starting at the specified index.
+ ///
+ /// Array of positions to be copied.
+ /// Index of the first copied position.
+ public void CopyTo(Vector3[] array, int arrayIndex)
+ {
+ foreach (var vec in this)
+ array[arrayIndex++] = vec;
+ }
+
+ ///
+ /// Gets an enumerator interface for reading the position values.
+ ///
+ /// Interface for enumerating the collection of position values.
+ public IEnumerator GetEnumerator()
+ {
+ for (var i = 0; i < Count; i++)
+ yield return this[i];
+ }
+
+ ///
+ /// Gets the index of the specified position in a collection.
+ ///
+ /// Position being searched for.
+ /// Index of the specified position or -1 if not found.
+ public int IndexOf(Vector3 item)
+ {
+ for (var i = 0; i < Count; i++)
+ if (this[i] == item)
+ return i;
+
+ return -1;
+ }
+
+ internal Exception Readonly()
+ {
+ return new NotSupportedException("The collection is read only!");
+ }
+
+ void ICollection.Add(Vector3 item)
+ {
+ throw Readonly();
+ }
+
+ void ICollection.Clear()
+ {
+ throw Readonly();
+ }
+
+ bool ICollection.Remove(Vector3 item)
+ {
+ throw Readonly();
+ }
+
+ void IList.Insert(int index, Vector3 item)
+ {
+ throw Readonly();
+ }
+
+ void IList.RemoveAt(int index)
+ {
+ throw Readonly();
+ }
+
+ ///
+ /// Returns an enumerator that can iterate through the collection.
+ ///
+ /// Enumerator that can iterate through the collection.
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/LocalizedFontDescription.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/LocalizedFontDescription.cs
new file mode 100644
index 000000000..19faf5b50
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/LocalizedFontDescription.cs
@@ -0,0 +1,53 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// LocalizedFontDescription.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System.Collections.Generic;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+#endregion
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Normally, when you add a .spritefont file to your project, this data is
+ /// deserialized into a FontDescription object, which is then built into a
+ /// SpriteFontContent by the FontDescriptionProcessor. But to localize the
+ /// font, we want to add some additional data, so our custom processor can
+ /// know what .resx files it needs to scan. We do this by defining our own
+ /// custom font description class, deriving from the built in FontDescription
+ /// type, and adding a new property to store the resource filenames.
+ ///
+ public class LocalizedFontDescription : FontDescription
+ {
+ ///
+ /// Constructor.
+ ///
+ public LocalizedFontDescription()
+ : base("Arial", 14, 0)
+ {
+ }
+
+
+ ///
+ /// Add a new property to our font description, which will allow us to
+ /// include a ResourceFiles element in the .spritefont XML. We use the
+ /// ContentSerializer attribute to mark this as optional, so existing
+ /// .spritefont files that do not include this ResourceFiles element
+ /// can be imported as well.
+ ///
+ [ContentSerializer(Optional = true, CollectionItemName = "Resx")]
+ public List ResourceFiles
+ {
+ get { return resourceFiles; }
+ }
+
+ List resourceFiles = new List();
+ }
+}
diff --git a/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/MaterialContent.cs b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/MaterialContent.cs
new file mode 100644
index 000000000..06c2fc1b1
--- /dev/null
+++ b/Libraries/MonoGame.Framework/Src/MonoGame.Framework.Content.Pipeline/Graphics/MaterialContent.cs
@@ -0,0 +1,127 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+
+namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
+{
+ ///
+ /// Provides methods and properties for maintaining a collection of named texture references.
+ ///
+ /// In addition to texture references, opaque data values are stored in the OpaqueData property of the base class.
+ public class MaterialContent : ContentItem
+ {
+ readonly TextureReferenceDictionary _textures;
+
+ ///
+ /// Gets the texture collection of the material.
+ ///
+ /// Collection of textures used by the material.
+ public TextureReferenceDictionary Textures { get { return _textures; } }
+
+ ///
+ /// Initializes a new instance of MaterialContent.
+ ///
+ public MaterialContent()
+ {
+ _textures = new TextureReferenceDictionary();
+ }
+
+ ///
+ /// Gets a reference type from the OpaqueDataDictionary collection.
+ ///
+ /// Type of the related opaque data.
+ /// Key of the property being retrieved.
+ /// The related opaque data.
+ protected T GetReferenceTypeProperty(string key) where T : class
+ {
+ object value;
+ if (OpaqueData.TryGetValue(key, out value))
+ return (T)value;
+ return default(T);
+ }
+
+ ///