1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-04-29 23:53:22 +02:00

added MLEM.FNA

This commit is contained in:
Ell 2022-06-24 14:01:26 +02:00
parent aff61508c4
commit 5d7d238630
90 changed files with 736 additions and 158 deletions

6
.gitmodules vendored Normal file
View file

@ -0,0 +1,6 @@
[submodule "FNA"]
path = FNA
url = https://github.com/FNA-XNA/FNA
[submodule "FontStashSharp"]
path = FontStashSharp
url = https://github.com/FontStashSharp/FontStashSharp

View file

@ -18,6 +18,7 @@ Additions
- Added an Enum constructor to GenericInput - Added an Enum constructor to GenericInput
- Added RandomPitchModifier and GetRandomPitch to SoundEffectInfo - Added RandomPitchModifier and GetRandomPitch to SoundEffectInfo
- Added TextInput class, which is an isolated version of MLEM.Ui's TextField logic - Added TextInput class, which is an isolated version of MLEM.Ui's TextField logic
- Added MLEM.FNA, which is fully compatible with FNA
Improvements Improvements
- Allow comparing Keybind and Combination based on the amount of modifiers they have - Allow comparing Keybind and Combination based on the amount of modifiers they have
@ -31,6 +32,7 @@ Removals
Additions Additions
- Added Element.AutoNavGroup which allows forming groups for auto-navigation - Added Element.AutoNavGroup which allows forming groups for auto-navigation
- Added UiMarkdownParser - Added UiMarkdownParser
- Added MLEM.Ui.FNA, which is fully compatible with FNA
Improvements Improvements
- Ensure that Element.IsMouseOver is always accurate by making it an auto-property - Ensure that Element.IsMouseOver is always accurate by making it an auto-property
@ -59,6 +61,7 @@ Removals
### MLEM.Extended ### MLEM.Extended
Additions Additions
- Added LayerPositionF - Added LayerPositionF
- Added MLEM.Extended.FNA, which is fully compatible with FNA
Improvements Improvements
- Allow using a StaticSpriteBatch to render an IndividualTiledMapRenderer - Allow using a StaticSpriteBatch to render an IndividualTiledMapRenderer
@ -67,6 +70,7 @@ Improvements
Additions Additions
- Added the ability to add padding to RuntimeTexturePacker texture regions - Added the ability to add padding to RuntimeTexturePacker texture regions
- Added the ability to pack UniformTextureAtlas and DataTextureAtlas using RuntimeTexturePacker - Added the ability to pack UniformTextureAtlas and DataTextureAtlas using RuntimeTexturePacker
- Added MLEM.Data.FNA, which is fully compatible with FNA
Improvements Improvements
- Premultiply textures when using RawContentManager - Premultiply textures when using RawContentManager
@ -77,6 +81,10 @@ Improvements
Fixes Fixes
- Fixed SoundEffectReader incorrectly claiming it could read ogg and mp3 files - Fixed SoundEffectReader incorrectly claiming it could read ogg and mp3 files
### MLEM.Startup
Additions
- Added MLEM.Startup.FNA, which is fully compatible with FNA
## 5.3.0 ## 5.3.0
### MLEM ### MLEM
Additions Additions

View file

@ -80,7 +80,7 @@
<PackageReference Include="Coroutine" Version="2.1.3" /> <PackageReference Include="Coroutine" Version="2.1.3" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" /> <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
<PackageReference Include="MonoGame.Framework.Android" Version="3.8.0.1641" /> <PackageReference Include="MonoGame.Framework.Android" Version="3.8.0.1641" />
<PackageReference Include="TextCopy" Version="4.3.0" /> <PackageReference Include="TextCopy" Version="6.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Demos\Demos.csproj"> <ProjectReference Include="..\Demos\Demos.csproj">

View file

@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<ApplicationIcon>Icon.ico</ApplicationIcon>
<AssemblyName>MLEM Desktop Demos</AssemblyName>
<RootNamespace>Demos.DesktopGL</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
<!-- We still use the MG content builder for ease of compatibility between the MG and FNA demo projects -->
<MonoGamePlatform>DesktopGL</MonoGamePlatform>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Demos\Demos.FNA.csproj" />
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.FNA.csproj" />
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.FNA.csproj" />
<ProjectReference Include="..\MLEM\MLEM.FNA.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
<ProjectReference Include="..\FNA\FNA.Core.csproj" />
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="..\Demos\Content\Content.mgcb" />
<Content Include="..\Demos\Content\*\**" />
<EmbeddedResource Include="Icon.ico" />
<EmbeddedResource Include="Icon.bmp" />
<Content Include="FNA/**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</Content>
</ItemGroup>
</Project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,11 +1,17 @@
using Microsoft.Xna.Framework; using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using MLEM.Misc; using MLEM.Misc;
namespace Demos.DesktopGL { namespace Demos.DesktopGL {
public static class Program { public static class Program {
public static void Main() { public static void Main() {
#if FNA
MlemPlatform.Current = new MlemPlatform.DesktopFna(a => TextInputEXT.TextInput += a);
#else
MlemPlatform.Current = new MlemPlatform.DesktopGl<TextInputEventArgs>((w, c) => w.TextInput += c); MlemPlatform.Current = new MlemPlatform.DesktopGl<TextInputEventArgs>((w, c) => w.TextInput += c);
#endif
using var game = new GameImpl(); using var game = new GameImpl();
game.Run(); game.Run();
} }

View file

@ -90,7 +90,7 @@ namespace Demos {
public override void DoDraw(GameTime gameTime) { public override void DoDraw(GameTime gameTime) {
this.GraphicsDevice.Clear(Color.CornflowerBlue); this.GraphicsDevice.Clear(Color.CornflowerBlue);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(10)); this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(10));
// draw the group's current region // draw the group's current region
// if not using a group, just draw the animation's CurrentRegion here // if not using a group, just draw the animation's CurrentRegion here
this.SpriteBatch.Draw(this.group.CurrentRegion, new Vector2(10, 10), Color.White); this.SpriteBatch.Draw(this.group.CurrentRegion, new Vector2(10, 10), Color.White);

View file

@ -37,7 +37,7 @@ namespace Demos {
this.GraphicsDevice.Clear(Color.Black); this.GraphicsDevice.Clear(Color.Black);
// drawing the auto tiles // drawing the auto tiles
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(10)); this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(10));
for (var x = 0; x < 6; x++) { for (var x = 0; x < 6; x++) {
for (var y = 0; y < 5; y++) { for (var y = 0; y < 5; y++) {
// don't draw non-grass tiles ( ) // don't draw non-grass tiles ( )

21
Demos/Demos.FNA.csproj Normal file
View file

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Demos</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.FNA.csproj" />
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.FNA.csproj" />
<ProjectReference Include="..\MLEM\MLEM.FNA.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FNA\FNA.Core.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
</Project>

View file

@ -43,7 +43,7 @@ namespace Demos {
this.GraphicsDevice.Clear(Color.CornflowerBlue); this.GraphicsDevice.Clear(Color.CornflowerBlue);
base.DoDraw(time); base.DoDraw(time);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp); this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null);
var view = this.GraphicsDevice.Viewport; var view = this.GraphicsDevice.Viewport;
// graph the easing function // graph the easing function

View file

@ -9,7 +9,9 @@ using MLEM.Textures;
using MLEM.Ui; using MLEM.Ui;
using MLEM.Ui.Elements; using MLEM.Ui.Elements;
using MLEM.Ui.Style; using MLEM.Ui.Style;
#if !FNA
using MonoGame.Framework.Utilities; using MonoGame.Framework.Utilities;
#endif
namespace Demos { namespace Demos {
public class GameImpl : MlemGame { public class GameImpl : MlemGame {
@ -47,11 +49,13 @@ namespace Demos {
protected override void LoadContent() { protected override void LoadContent() {
// TODO remove with MonoGame 3.8.1 https://github.com/MonoGame/MonoGame/issues/7298 // TODO remove with MonoGame 3.8.1 https://github.com/MonoGame/MonoGame/issues/7298
#if !FNA
if (PlatformInfo.MonoGamePlatform == MonoGamePlatform.DesktopGL) { if (PlatformInfo.MonoGamePlatform == MonoGamePlatform.DesktopGL) {
this.GraphicsDeviceManager.PreferredBackBufferWidth = 1280; this.GraphicsDeviceManager.PreferredBackBufferWidth = 1280;
this.GraphicsDeviceManager.PreferredBackBufferHeight = 720; this.GraphicsDeviceManager.PreferredBackBufferHeight = 720;
this.GraphicsDeviceManager.ApplyChanges(); this.GraphicsDeviceManager.ApplyChanges();
} }
#endif
base.LoadContent(); base.LoadContent();
this.UiSystem.AutoScaleReferenceSize = new Point(1280, 720); this.UiSystem.AutoScaleReferenceSize = new Point(1280, 720);

View file

@ -35,9 +35,9 @@ namespace Demos {
// Create a cost function, which determines how expensive (or difficult) it should be to move from a given position // Create a cost function, which determines how expensive (or difficult) it should be to move from a given position
// to the next, adjacent position. In our case, the only restriction should be walls and out-of-bounds positions, which // to the next, adjacent position. In our case, the only restriction should be walls and out-of-bounds positions, which
// both have a cost of AStar2.InfiniteCost, meaning they are completely unwalkable. // both have a cost of AStar2.InfiniteCost, meaning they are completely unwalkable.
// If your game contains harder-to-move-on areas like, say, a muddy pit, you can return a higher cost value for those // If your game contains harder-to-move-on areas like, say, a muddy pit, you can return a higher cost value for those
// locations. If you want to scale your cost function differently, you can specify a different default cost in your // locations. If you want to scale your cost function differently, you can specify a different default cost in your
// pathfinder's constructor // pathfinder's constructor
float Cost(Point pos, Point nextPos) { float Cost(Point pos, Point nextPos) {
if (nextPos.X < 0 || nextPos.Y < 0 || nextPos.X >= 50 || nextPos.Y >= 50) if (nextPos.X < 0 || nextPos.Y < 0 || nextPos.X >= 50 || nextPos.Y >= 50)
@ -73,7 +73,7 @@ namespace Demos {
public override void DoDraw(GameTime gameTime) { public override void DoDraw(GameTime gameTime) {
this.GraphicsDevice.Clear(Color.White); this.GraphicsDevice.Clear(Color.White);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(14)); this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(14));
var tex = this.SpriteBatch.GetBlankTexture(); var tex = this.SpriteBatch.GetBlankTexture();
// draw the world with simple shapes // draw the world with simple shapes
for (var x = 0; x < 50; x++) { for (var x = 0; x < 50; x++) {
@ -87,9 +87,9 @@ namespace Demos {
// in a real game, you'd obviously make your characters walk along the path instead of drawing it // in a real game, you'd obviously make your characters walk along the path instead of drawing it
if (this.path != null) { if (this.path != null) {
for (var i = 1; i < this.path.Count; i++) { for (var i = 1; i < this.path.Count; i++) {
var (firstX, firstY) = this.path[i - 1]; var first = this.path[i - 1];
var (secondX, secondY) = this.path[i]; var second = this.path[i];
this.SpriteBatch.Draw(tex, RectangleF.FromCorners(new Vector2(firstX + 0.25F, firstY + 0.25F), new Vector2(secondX + 0.75F, secondY + 0.75F)), Color.Blue); this.SpriteBatch.Draw(tex, RectangleF.FromCorners(new Vector2(first.X + 0.25F, first.Y + 0.25F), new Vector2(second.X + 0.75F, second.Y + 0.75F)), Color.Blue);
} }
} }
this.SpriteBatch.End(); this.SpriteBatch.End();

View file

@ -50,7 +50,7 @@ namespace Demos {
public override void DoDraw(GameTime time) { public override void DoDraw(GameTime time) {
this.GraphicsDevice.Clear(Color.DarkSlateGray); this.GraphicsDevice.Clear(Color.DarkSlateGray);
this.SpriteBatch.Begin(samplerState: SamplerState.PointClamp); this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null);
// we draw the tokenized text in the center of the screen // we draw the tokenized text in the center of the screen
// since the text is already center-aligned, we only need to align it on the y axis here // since the text is already center-aligned, we only need to align it on the y axis here

View file

@ -73,7 +73,7 @@ namespace Demos {
// add the root to the demos' ui // add the root to the demos' ui
this.UiRoot.AddChild(this.root); this.UiRoot.AddChild(this.root);
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "This is a small demo for MLEM.Ui, a user interface library that is part of the MLEM Library for Extending MonoGame.")); this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "This is a small demo for MLEM.Ui, a user interface library that is part of the MLEM Library for Extending MonoGame and FNA."));
var image = this.root.AddChild(new Image(Anchor.AutoCenter, new Vector2(50, 50), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true, Padding = new Padding(3)}); var image = this.root.AddChild(new Image(Anchor.AutoCenter, new Vector2(50, 50), new TextureRegion(this.testTexture, 0, 0, 8, 8)) {IsHidden = true, Padding = new Padding(3)});
// Setting the x or y coordinate of the size to 1 or a lower number causes the width or height to be a percentage of the parent's width or height // Setting the x or y coordinate of the size to 1 or a lower number causes the width or height to be a percentage of the parent's width or height
// (for example, setting the size's x to 0.75 would make the element's width be 0.75*parentWidth) // (for example, setting the size's x to 0.75 would make the element's width be 0.75*parentWidth)

View file

@ -1,6 +1,6 @@
![The MLEM logo](https://raw.githubusercontent.com/Ellpeck/MLEM/release/Media/Banner.png) ![The MLEM logo](https://raw.githubusercontent.com/Ellpeck/MLEM/release/Media/Banner.png)
**MLEM Library for Extending MonoGame** is an addition to the game framework [MonoGame](https://www.monogame.net/) that provides extension methods, quality of life improvements and additional features like a ui system and easy input handling. **MLEM Library for Extending MonoGame and FNA** is an addition to the game frameworks [MonoGame](https://www.monogame.net/) and [FNA](https://fna-xna.github.io/) that provides extension methods, quality of life improvements and additional features like a ui system and easy input handling.
# What next? # What next?
- Get it on [NuGet](https://www.nuget.org/packages?q=mlem) - Get it on [NuGet](https://www.nuget.org/packages?q=mlem)

1
FNA Submodule

@ -0,0 +1 @@
Subproject commit e27bfb5a34112461a6bff960888c0cce2b0c5be2

1
FontStashSharp Submodule

@ -0,0 +1 @@
Subproject commit 460a60ca817e10b6c9bae3e3c05affd1b0bb4ba7

View file

@ -7,19 +7,22 @@ using Microsoft.Xna.Framework.Graphics;
namespace MLEM.Data.Content { namespace MLEM.Data.Content {
/// <summary> /// <summary>
/// Represents a version of <see cref="ContentManager"/> that doesn't load content binary <c>xnb</c> files, but rather as their regular formats. /// Represents a version of <see cref="ContentManager"/> that doesn't load content binary <c>xnb</c> files, but rather as their regular formats.
/// </summary> /// </summary>
public class RawContentManager : ContentManager, IGameComponent { public class RawContentManager : ContentManager, IGameComponent {
private static List<RawContentReader> readers; private static List<RawContentReader> readers;
private readonly List<IDisposable> disposableAssets = new List<IDisposable>();
/// <summary> /// <summary>
/// The graphics device that this content manager uses /// The graphics device that this content manager uses
/// </summary> /// </summary>
public readonly GraphicsDevice GraphicsDevice; public readonly GraphicsDevice GraphicsDevice;
private readonly List<IDisposable> disposableAssets = new List<IDisposable>();
#if FNA
private Dictionary<string, object> LoadedAssets { get; } = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
#endif
/// <summary> /// <summary>
/// Creates a new content manager with an optionally specified root directory. /// Creates a new content manager with an optionally specified root directory.
/// </summary> /// </summary>
@ -50,7 +53,11 @@ namespace MLEM.Data.Content {
/// <param name="originalAssetName">The original name of the asset.</param> /// <param name="originalAssetName">The original name of the asset.</param>
/// <param name="currentAsset">The current asset instance.</param> /// <param name="currentAsset">The current asset instance.</param>
/// <typeparam name="T">The asset's type.</typeparam> /// <typeparam name="T">The asset's type.</typeparam>
protected override void ReloadAsset<T>(string originalAssetName, T currentAsset) { protected
#if !FNA
override
#endif
void ReloadAsset<T>(string originalAssetName, T currentAsset) {
this.Read(originalAssetName, currentAsset); this.Read(originalAssetName, currentAsset);
} }

View file

@ -9,10 +9,13 @@ namespace MLEM.Data.Content {
/// <inheritdoc /> /// <inheritdoc />
protected override Texture2D Read(RawContentManager manager, string assetPath, Stream stream, Texture2D existing) { protected override Texture2D Read(RawContentManager manager, string assetPath, Stream stream, Texture2D existing) {
#if !FNA
if (existing != null) { if (existing != null) {
existing.Reload(stream); existing.Reload(stream);
return existing; return existing;
} else { } else
#endif
{
// premultiply the texture's color to be in line with the pipeline's texture reader // premultiply the texture's color to be in line with the pipeline's texture reader
// TODO this can be converted to use https://github.com/MonoGame/MonoGame/pull/7369 in the future // TODO this can be converted to use https://github.com/MonoGame/MonoGame/pull/7369 in the future
using (var texture = Texture2D.FromStream(manager.GraphicsDevice, stream)) { using (var texture = Texture2D.FromStream(manager.GraphicsDevice, stream)) {

View file

@ -5,12 +5,13 @@ using System.Text.RegularExpressions;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MLEM.Textures; using MLEM.Textures;
namespace MLEM.Data { namespace MLEM.Data {
/// <summary> /// <summary>
/// <para> /// <para>
/// This class represents an atlas of <see cref="TextureRegion"/> objects which are loaded from a special texture atlas file. /// This class represents an atlas of <see cref="TextureRegion"/> objects which are loaded from a special texture atlas file.
/// To load a data texture atlas, you can use <see cref="DataTextureAtlasExtensions.LoadTextureAtlas"/>. /// To load a data texture atlas, you can use <see cref="DataTextureAtlasExtensions.LoadTextureAtlas"/>.
/// </para> /// </para>
/// <para> /// <para>
@ -95,7 +96,7 @@ namespace MLEM.Data {
var loc = new Rectangle( var loc = new Rectangle(
int.Parse(match.Groups[2].Value), int.Parse(match.Groups[3].Value), int.Parse(match.Groups[2].Value), int.Parse(match.Groups[3].Value),
int.Parse(match.Groups[4].Value), int.Parse(match.Groups[5].Value)); int.Parse(match.Groups[4].Value), int.Parse(match.Groups[5].Value));
loc.Offset(off); loc.Offset(off.ToPoint());
// pivot // pivot
var piv = !match.Groups[6].Success ? Vector2.Zero : off + new Vector2( var piv = !match.Groups[6].Success ? Vector2.Zero : off + new Vector2(

View file

@ -0,0 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<RootNamespace>MLEM.Data</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
<NoWarn>NU1701</NoWarn>
</PropertyGroup>
<PropertyGroup>
<Authors>Ellpeck</Authors>
<Description>Simple loading and processing of textures and other data for FNA, including the ability to load non-XNB content files easily</Description>
<PackageReleaseNotes>See the full changelog at https://mlem.ellpeck.de/CHANGELOG</PackageReleaseNotes>
<PackageTags>fna ellpeck mlem utility extensions data serialize</PackageTags>
<PackageProjectUrl>https://mlem.ellpeck.de/</PackageProjectUrl>
<RepositoryUrl>https://github.com/Ellpeck/MLEM</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MLEM\MLEM.FNA.csproj" />
<!--TODO remove lidgren support eventually (methods marked as obsolete since 5.2.0)-->
<PackageReference Include="Lidgren.Network" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<ProjectReference Include="..\FNA\FNA.Core.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
</ItemGroup>
</Project>

View file

@ -3,8 +3,9 @@
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly> <ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<NoWarn>NU1701</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<Authors>Ellpeck</Authors> <Authors>Ellpeck</Authors>
<Description>Simple loading and processing of textures and other data for MonoGame, including the ability to load non-XNB content files easily</Description> <Description>Simple loading and processing of textures and other data for MonoGame, including the ability to load non-XNB content files easily</Description>
@ -15,12 +16,11 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo.png</PackageIcon> <PackageIcon>Logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<NoWarn>NU1701</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MLEM\MLEM.csproj" /> <ProjectReference Include="..\MLEM\MLEM.csproj" />
<!--TODO remove lidgren support eventually (methods marked as obsolete since 5.2.0)--> <!--TODO remove lidgren support eventually (methods marked as obsolete since 5.2.0)-->
<PackageReference Include="Lidgren.Network" Version="1.0.2"> <PackageReference Include="Lidgren.Network" Version="1.0.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
@ -35,9 +35,9 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="../Media/Logo.png" Pack="true" PackagePath="" /> <None Include="../Media/Logo.png" Pack="true" PackagePath="" />
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" /> <None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -170,7 +170,7 @@ namespace MLEM.Data {
foreach (var request in this.texturesToPack.OrderByDescending(t => t.Texture.Width * t.Texture.Height)) { foreach (var request in this.texturesToPack.OrderByDescending(t => t.Texture.Width * t.Texture.Height)) {
request.PackedArea = this.FindFreeArea(request); request.PackedArea = this.FindFreeArea(request);
// if this is the first position that this request fit in, no other requests of the same size will find a position before it // if this is the first position that this request fit in, no other requests of the same size will find a position before it
this.firstPossiblePosForSizeCache[request.PackedArea.Size] = request.PackedArea.Location; this.firstPossiblePosForSizeCache[new Point(request.PackedArea.Width, request.PackedArea.Height)] = request.PackedArea.Location;
this.alreadyPackedTextures.Add(request); this.alreadyPackedTextures.Add(request);
} }
stopwatch.Stop(); stopwatch.Stop();
@ -198,7 +198,7 @@ namespace MLEM.Data {
// invoke callbacks // invoke callbacks
foreach (var request in this.alreadyPackedTextures) { foreach (var request in this.alreadyPackedTextures) {
var packedArea = request.PackedArea.Shrink(new Point(request.Padding)); var packedArea = request.PackedArea.Shrink(new Point(request.Padding, request.Padding));
request.Result.Invoke(new TextureRegion(this.PackedTexture, packedArea)); request.Result.Invoke(new TextureRegion(this.PackedTexture, packedArea));
if (this.disposeTextures) if (this.disposeTextures)
request.Texture.Texture.Dispose(); request.Texture.Texture.Dispose();
@ -232,7 +232,7 @@ namespace MLEM.Data {
var lowestY = int.MaxValue; var lowestY = int.MaxValue;
while (true) { while (true) {
var intersected = false; var intersected = false;
var area = new Rectangle(pos, size); var area = new Rectangle(pos.X, pos.Y, size.X, size.Y);
foreach (var tex in this.alreadyPackedTextures) { foreach (var tex in this.alreadyPackedTextures) {
if (tex.PackedArea.Intersects(area)) { if (tex.PackedArea.Intersects(area)) {
pos.X = tex.PackedArea.Right; pos.X = tex.PackedArea.Right;
@ -255,7 +255,7 @@ namespace MLEM.Data {
private void CopyRegion(TextureData destination, Request request) { private void CopyRegion(TextureData destination, Request request) {
var data = this.GetCachedTextureData(request.Texture.Texture); var data = this.GetCachedTextureData(request.Texture.Texture);
var location = request.PackedArea.Location + new Point(request.Padding); var location = request.PackedArea.Location + new Point(request.Padding, request.Padding);
for (var x = -request.Padding; x < request.Texture.Width + request.Padding; x++) { for (var x = -request.Padding; x < request.Texture.Width + request.Padding; x++) {
for (var y = -request.Padding; y < request.Texture.Height + request.Padding; y++) { for (var y = -request.Padding; y < request.Texture.Height + request.Padding; y++) {
Color srcColor; Color srcColor;
@ -264,7 +264,7 @@ namespace MLEM.Data {
srcColor = Color.Transparent; srcColor = Color.Transparent;
} else { } else {
// otherwise, we just use the closest pixel that is actually in bounds, causing the border pixels to be doubled up // otherwise, we just use the closest pixel that is actually in bounds, causing the border pixels to be doubled up
var src = new Point(MathHelper.Clamp(x, 0, request.Texture.Width - 1), MathHelper.Clamp(y, 0, request.Texture.Height - 1)); var src = new Point((int) MathHelper.Clamp(x, 0, request.Texture.Width - 1), (int) MathHelper.Clamp(y, 0, request.Texture.Height - 1));
srcColor = data[request.Texture.Position + src]; srcColor = data[request.Texture.Position + src];
} }
destination[location + new Point(x, y)] = srcColor; destination[location + new Point(x, y)] = srcColor;

View file

@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<RootNamespace>MLEM.Extended</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
<NoWarn>NU1702</NoWarn>
</PropertyGroup>
<PropertyGroup>
<Authors>Ellpeck</Authors>
<Description>MLEM Library for Extending FNA extension that ties in with other FNA libraries</Description>
<PackageReleaseNotes>See the full changelog at https://mlem.ellpeck.de/CHANGELOG</PackageReleaseNotes>
<PackageTags>fna ellpeck mlem utility extensions extended</PackageTags>
<PackageProjectUrl>https://mlem.ellpeck.de/</PackageProjectUrl>
<RepositoryUrl>https://github.com/Ellpeck/MLEM</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MLEM\MLEM.FNA.csproj" />
<ProjectReference Include="..\FontStashSharp\src\XNA\FontStashSharp.FNA.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
<ProjectReference Include="..\FNA\FNA.Core.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
<Compile Remove="Tiled/**" />
<Compile Remove="Extensions/**" />
<Compile Remove="Font/GenericBitmapFont.cs" />
</ItemGroup>
<ItemGroup>
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
</ItemGroup>
</Project>

View file

@ -26,7 +26,7 @@
<PackageReference Include="MonoGame.Extended.Tiled" Version="3.8.0"> <PackageReference Include="MonoGame.Extended.Tiled" Version="3.8.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="FontStashSharp.MonoGame" Version="1.0.4"> <PackageReference Include="FontStashSharp.MonoGame" Version="1.1.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641"> <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">

76
MLEM.FNA.sln Normal file
View file

@ -0,0 +1,76 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLEM.FNA", "MLEM\MLEM.FNA.csproj", "{C2C88AE6-6274-4395-8B03-52AE898BA070}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLEM.Ui.FNA", "MLEM.Ui\MLEM.Ui.FNA.csproj", "{1B47A40B-3BF6-4933-A7DB-57EADEBDFB61}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLEM.Startup.FNA", "MLEM.Startup\MLEM.Startup.FNA.csproj", "{FBE2C9B5-293D-47A7-9BA1-5A4BD1C4E816}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLEM.Data.FNA", "MLEM.Data\MLEM.Data.FNA.csproj", "{6587BC91-0640-43FB-988A-4F545B8ACFC5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demos.FNA", "Demos\Demos.FNA.csproj", "{D83D7D24-14CB-4A7C-A80B-BA4FEC66AB55}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demos.DesktopGL.FNA", "Demos.DesktopGL\Demos.DesktopGL.FNA.csproj", "{AB08FEC7-3AC3-4FDE-B632-226FAAD7F73F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.FNA", "Tests\Tests.FNA.csproj", "{C74FC4C5-3BE0-42A7-8BA6-4A9AD438A9E2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLEM.Extended.FNA", "MLEM.Extended\MLEM.Extended.FNA.csproj", "{A5B22930-DF4B-4A62-93ED-A6549F7B666B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FontStashSharp.FNA", "FontStashSharp\src\XNA\FontStashSharp.FNA.csproj", "{B805851C-9802-4239-AB16-AE77226771CA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNA", "FNA\FNA.csproj", "{35253CE1-C864-4CD3-8249-4D1319748E8F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNA.Core", "FNA\FNA.Core.csproj", "{06459F72-CEAA-4B45-B2B1-708FC28D04F8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C2C88AE6-6274-4395-8B03-52AE898BA070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2C88AE6-6274-4395-8B03-52AE898BA070}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2C88AE6-6274-4395-8B03-52AE898BA070}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2C88AE6-6274-4395-8B03-52AE898BA070}.Release|Any CPU.Build.0 = Release|Any CPU
{1B47A40B-3BF6-4933-A7DB-57EADEBDFB61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B47A40B-3BF6-4933-A7DB-57EADEBDFB61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B47A40B-3BF6-4933-A7DB-57EADEBDFB61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B47A40B-3BF6-4933-A7DB-57EADEBDFB61}.Release|Any CPU.Build.0 = Release|Any CPU
{FBE2C9B5-293D-47A7-9BA1-5A4BD1C4E816}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FBE2C9B5-293D-47A7-9BA1-5A4BD1C4E816}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FBE2C9B5-293D-47A7-9BA1-5A4BD1C4E816}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FBE2C9B5-293D-47A7-9BA1-5A4BD1C4E816}.Release|Any CPU.Build.0 = Release|Any CPU
{6587BC91-0640-43FB-988A-4F545B8ACFC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6587BC91-0640-43FB-988A-4F545B8ACFC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6587BC91-0640-43FB-988A-4F545B8ACFC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6587BC91-0640-43FB-988A-4F545B8ACFC5}.Release|Any CPU.Build.0 = Release|Any CPU
{D83D7D24-14CB-4A7C-A80B-BA4FEC66AB55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D83D7D24-14CB-4A7C-A80B-BA4FEC66AB55}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D83D7D24-14CB-4A7C-A80B-BA4FEC66AB55}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D83D7D24-14CB-4A7C-A80B-BA4FEC66AB55}.Release|Any CPU.Build.0 = Release|Any CPU
{AB08FEC7-3AC3-4FDE-B632-226FAAD7F73F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB08FEC7-3AC3-4FDE-B632-226FAAD7F73F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB08FEC7-3AC3-4FDE-B632-226FAAD7F73F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB08FEC7-3AC3-4FDE-B632-226FAAD7F73F}.Release|Any CPU.Build.0 = Release|Any CPU
{C74FC4C5-3BE0-42A7-8BA6-4A9AD438A9E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C74FC4C5-3BE0-42A7-8BA6-4A9AD438A9E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C74FC4C5-3BE0-42A7-8BA6-4A9AD438A9E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C74FC4C5-3BE0-42A7-8BA6-4A9AD438A9E2}.Release|Any CPU.Build.0 = Release|Any CPU
{A5B22930-DF4B-4A62-93ED-A6549F7B666B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5B22930-DF4B-4A62-93ED-A6549F7B666B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5B22930-DF4B-4A62-93ED-A6549F7B666B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5B22930-DF4B-4A62-93ED-A6549F7B666B}.Release|Any CPU.Build.0 = Release|Any CPU
{B805851C-9802-4239-AB16-AE77226771CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B805851C-9802-4239-AB16-AE77226771CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B805851C-9802-4239-AB16-AE77226771CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B805851C-9802-4239-AB16-AE77226771CA}.Release|Any CPU.Build.0 = Release|Any CPU
{35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|Any CPU.Build.0 = Release|Any CPU
{06459F72-CEAA-4B45-B2B1-708FC28D04F8}.Debug|Any CPU.ActiveCfg = Debug|x64
{06459F72-CEAA-4B45-B2B1-708FC28D04F8}.Debug|Any CPU.Build.0 = Debug|x64
{06459F72-CEAA-4B45-B2B1-708FC28D04F8}.Release|Any CPU.ActiveCfg = Release|x64
{06459F72-CEAA-4B45-B2B1-708FC28D04F8}.Release|Any CPU.Build.0 = Release|x64
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<RootNamespace>MLEM.Startup</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<Authors>Ellpeck</Authors>
<Description>MLEM Library for Extending FNA combined with some other useful libraries into a quick Game startup class</Description>
<PackageReleaseNotes>See the full changelog at https://mlem.ellpeck.de/CHANGELOG</PackageReleaseNotes>
<PackageTags>fna ellpeck mlem utility extensions</PackageTags>
<PackageProjectUrl>https://mlem.ellpeck.de/</PackageProjectUrl>
<RepositoryUrl>https://github.com/Ellpeck/MLEM</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Coroutine" Version="2.1.3" />
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.FNA.csproj" />
<ProjectReference Include="..\MLEM\MLEM.FNA.csproj" />
<ProjectReference Include="..\FNA\FNA.Core.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
</ItemGroup>
</Project>

View file

@ -69,7 +69,9 @@ namespace MLEM.Startup {
this.GraphicsDeviceManager = new GraphicsDeviceManager(this) { this.GraphicsDeviceManager = new GraphicsDeviceManager(this) {
PreferredBackBufferWidth = windowWidth, PreferredBackBufferWidth = windowWidth,
PreferredBackBufferHeight = windowHeight, PreferredBackBufferHeight = windowHeight,
#if !FNA
HardwareModeSwitch = false HardwareModeSwitch = false
#endif
}; };
this.Window.AllowUserResizing = true; this.Window.AllowUserResizing = true;
this.Content.RootDirectory = "Content"; this.Content.RootDirectory = "Content";

View file

@ -70,7 +70,7 @@ namespace MLEM.Ui.Elements {
/// <summary> /// <summary>
/// The size of this element, where X represents the width and Y represents the height. /// The size of this element, where X represents the width and Y represents the height.
/// If the x or y value of the size is between 0 and 1, the size will be seen as a percentage of its parent's size rather than as an absolute value. /// If the x or y value of the size is between 0 and 1, the size will be seen as a percentage of its parent's size rather than as an absolute value.
/// If the x (or y) value of the size is negative, the width (or height) is seen as a percentage of the element's resulting height (or width). /// If the x (or y) value of the size is negative, the width (or height) is seen as a percentage of the element's resulting height (or width).
/// </summary> /// </summary>
/// <example> /// <example>
/// The following example combines both types of percentage-based sizing. /// The following example combines both types of percentage-based sizing.
@ -178,12 +178,12 @@ namespace MLEM.Ui.Elements {
/// <summary> /// <summary>
/// This element's transform matrix. /// This element's transform matrix.
/// Can easily be scaled using <see cref="ScaleTransform"/>. /// Can easily be scaled using <see cref="ScaleTransform"/>.
/// Note that, when this is non-null, a new <see cref="SpriteBatch.Begin"/> call is used for this element. /// Note that, when this is non-null, a new <c>SpriteBatch.Begin</c> call is used for this element.
/// </summary> /// </summary>
public Matrix Transform = Matrix.Identity; public Matrix Transform = Matrix.Identity;
/// <summary> /// <summary>
/// The call that this element should make to <see cref="SpriteBatch"/> to begin drawing. /// The call that this element should make to <see cref="SpriteBatch"/> to begin drawing.
/// Note that, when this is non-null, a new <see cref="SpriteBatch.Begin"/> call is used for this element. /// Note that, when this is non-null, a new <c>SpriteBatch.Begin</c> call is used for this element.
/// </summary> /// </summary>
#pragma warning disable CS0618 #pragma warning disable CS0618
[Obsolete("BeginImpl is deprecated. You can create a custom element class and override Draw instead.")] [Obsolete("BeginImpl is deprecated. You can create a custom element class and override Draw instead.")]
@ -927,7 +927,7 @@ namespace MLEM.Ui.Elements {
/// <summary> /// <summary>
/// Draws this element by calling <see cref="Draw(Microsoft.Xna.Framework.GameTime,Microsoft.Xna.Framework.Graphics.SpriteBatch,float,MLEM.Graphics.SpriteBatchContext)"/> internally. /// Draws this element by calling <see cref="Draw(Microsoft.Xna.Framework.GameTime,Microsoft.Xna.Framework.Graphics.SpriteBatch,float,MLEM.Graphics.SpriteBatchContext)"/> internally.
/// If <see cref="Transform"/> or <see cref="BeginImpl"/> is set, a new <see cref="SpriteBatch.Begin"/> call is also started. /// If <see cref="Transform"/> or <see cref="BeginImpl"/> is set, a new <c>SpriteBatch.Begin</c> call is also started.
/// </summary> /// </summary>
/// <param name="time">The game's time</param> /// <param name="time">The game's time</param>
/// <param name="batch">The sprite batch to use for drawing</param> /// <param name="batch">The sprite batch to use for drawing</param>
@ -944,7 +944,7 @@ namespace MLEM.Ui.Elements {
/// <summary> /// <summary>
/// Draws this element by calling <see cref="Draw(Microsoft.Xna.Framework.GameTime,Microsoft.Xna.Framework.Graphics.SpriteBatch,float,MLEM.Graphics.SpriteBatchContext)"/> internally. /// Draws this element by calling <see cref="Draw(Microsoft.Xna.Framework.GameTime,Microsoft.Xna.Framework.Graphics.SpriteBatch,float,MLEM.Graphics.SpriteBatchContext)"/> internally.
/// If <see cref="Transform"/> or <see cref="BeginImpl"/> is set, a new <see cref="SpriteBatch.Begin"/> call is also started. /// If <see cref="Transform"/> or <see cref="BeginImpl"/> is set, a new <c>SpriteBatch.Begin</c> call is also started.
/// </summary> /// </summary>
/// <param name="time">The game's time</param> /// <param name="time">The game's time</param>
/// <param name="batch">The sprite batch to use for drawing</param> /// <param name="batch">The sprite batch to use for drawing</param>
@ -981,7 +981,7 @@ namespace MLEM.Ui.Elements {
/// <summary> /// <summary>
/// Draws this element and all of its children. Override this method to draw the content of custom elements. /// Draws this element and all of its children. Override this method to draw the content of custom elements.
/// Note that, when this is called, <see cref="SpriteBatch.Begin"/> has already been called with custom <see cref="Transform"/> etc. applied. /// Note that, when this is called, <c>SpriteBatch.Begin</c> has already been called with custom <see cref="Transform"/> etc. applied.
/// </summary> /// </summary>
/// <param name="time">The game's time</param> /// <param name="time">The game's time</param>
/// <param name="batch">The sprite batch to use for drawing</param> /// <param name="batch">The sprite batch to use for drawing</param>
@ -998,7 +998,7 @@ namespace MLEM.Ui.Elements {
/// <summary> /// <summary>
/// Draws this element and all of its children. Override this method to draw the content of custom elements. /// Draws this element and all of its children. Override this method to draw the content of custom elements.
/// Note that, when this is called, <see cref="SpriteBatch.Begin"/> has already been called with custom <see cref="Transform"/> etc. applied. /// Note that, when this is called, <c>SpriteBatch.Begin</c> has already been called with custom <see cref="Transform"/> etc. applied.
/// </summary> /// </summary>
/// <param name="time">The game's time</param> /// <param name="time">The game's time</param>
/// <param name="batch">The sprite batch to use for drawing</param> /// <param name="batch">The sprite batch to use for drawing</param>
@ -1021,7 +1021,7 @@ namespace MLEM.Ui.Elements {
/// <summary> /// <summary>
/// Draws this element and all of its <see cref="GetRelevantChildren"/> early. /// Draws this element and all of its <see cref="GetRelevantChildren"/> early.
/// Drawing early involves drawing onto <see cref="RenderTarget2D"/> instances rather than onto the screen. /// Drawing early involves drawing onto <see cref="RenderTarget2D"/> instances rather than onto the screen.
/// Note that, when this is called, <see cref="SpriteBatch.Begin"/> has not yet been called. /// Note that, when this is called, <c>SpriteBatch.Begin</c> has not yet been called.
/// </summary> /// </summary>
/// <param name="time">The game's time</param> /// <param name="time">The game's time</param>
/// <param name="batch">The sprite batch to use for drawing</param> /// <param name="batch">The sprite batch to use for drawing</param>

View file

@ -1,6 +1,7 @@
using System; using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MLEM.Graphics; using MLEM.Graphics;
using MLEM.Misc; using MLEM.Misc;
using MLEM.Textures; using MLEM.Textures;

View file

@ -135,8 +135,8 @@ namespace MLEM.Ui.Elements {
protected override Vector2 CalcActualSize(RectangleF parentArea) { protected override Vector2 CalcActualSize(RectangleF parentArea) {
var size = base.CalcActualSize(parentArea); var size = base.CalcActualSize(parentArea);
this.ParseText(size); this.ParseText(size);
var (w, h) = this.TokenizedText.Measure(this.RegularFont) * this.TextScale * this.TextScaleMultiplier * this.Scale; var textSize = this.TokenizedText.Measure(this.RegularFont) * this.TextScale * this.TextScaleMultiplier * this.Scale;
return new Vector2(this.AutoAdjustWidth ? w + this.ScaledPadding.Width : size.X, h + this.ScaledPadding.Height); return new Vector2(this.AutoAdjustWidth ? textSize.X + this.ScaledPadding.Width : size.X, textSize.Y + this.ScaledPadding.Height);
} }
/// <inheritdoc /> /// <inheritdoc />

View file

@ -3,6 +3,7 @@ using System.Linq;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch; using Microsoft.Xna.Framework.Input.Touch;
using MLEM.Extensions;
using MLEM.Graphics; using MLEM.Graphics;
using MLEM.Input; using MLEM.Input;
using MLEM.Misc; using MLEM.Misc;
@ -195,13 +196,13 @@ namespace MLEM.Ui.Elements {
} }
private void ScrollToPos(Vector2 position) { private void ScrollToPos(Vector2 position) {
var (width, height) = this.ScrollerSize * this.Scale; var size = this.ScrollerSize * this.Scale;
if (this.Horizontal) { if (this.Horizontal) {
var offset = this.scrollStartOffset.X >= 0 && this.scrollStartOffset.X <= width ? this.scrollStartOffset.X : width / 2; var offset = this.scrollStartOffset.X >= 0 && this.scrollStartOffset.X <= size.X ? this.scrollStartOffset.X : size.X / 2;
this.CurrentValue = (position.X - this.Area.X - offset) / (this.Area.Width - width) * this.MaxValue; this.CurrentValue = (position.X - this.Area.X - offset) / (this.Area.Width - size.X) * this.MaxValue;
} else { } else {
var offset = this.scrollStartOffset.Y >= 0 && this.scrollStartOffset.Y <= height ? this.scrollStartOffset.Y : height / 2; var offset = this.scrollStartOffset.Y >= 0 && this.scrollStartOffset.Y <= size.Y ? this.scrollStartOffset.Y : size.Y / 2;
this.CurrentValue = (position.Y - this.Area.Y - offset) / (this.Area.Height - height) * this.MaxValue; this.CurrentValue = (position.Y - this.Area.Y - offset) / (this.Area.Height - size.Y) * this.MaxValue;
} }
} }

View file

@ -1,3 +1,4 @@
using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Font; using MLEM.Font;

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using MLEM.Extensions;
using MLEM.Input; using MLEM.Input;
using MLEM.Ui.Style; using MLEM.Ui.Style;

View file

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<RootNamespace>MLEM.Ui</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<Authors>Ellpeck</Authors>
<Description>A mouse, keyboard, gamepad and touch ready Ui system for FNA that features automatic anchoring, sizing and several ready-to-use element types</Description>
<PackageReleaseNotes>See the full changelog at https://mlem.ellpeck.de/CHANGELOG</PackageReleaseNotes>
<PackageTags>fna ellpeck mlem ui user interface graphical gui system mouse keyboard gamepad touch</PackageTags>
<PackageProjectUrl>https://mlem.ellpeck.de/</PackageProjectUrl>
<RepositoryUrl>https://github.com/Ellpeck/MLEM</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TextCopy" Version="6.1.0" />
<ProjectReference Include="..\MLEM\MLEM.FNA.csproj" />
<ProjectReference Include="..\FNA\FNA.Core.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
</ItemGroup>
</Project>

View file

@ -18,7 +18,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="TextCopy" Version="4.3.1" /> <PackageReference Include="TextCopy" Version="6.1.0" />
<ProjectReference Include="..\MLEM\MLEM.csproj" /> <ProjectReference Include="..\MLEM\MLEM.csproj" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641"> <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">

View file

@ -170,8 +170,13 @@ namespace MLEM.Ui.Parsers {
Texture2D tex; Texture2D tex;
if (loc.StartsWith("http")) { if (loc.StartsWith("http")) {
using (var client = new HttpClient()) { using (var client = new HttpClient()) {
using (var src = await client.GetStreamAsync(loc)) using (var src = await client.GetStreamAsync(loc)) {
tex = Texture2D.FromStream(this.GraphicsDevice, src); using (var memory = new MemoryStream()) {
// download the full stream before passing it to texture
await src.CopyToAsync(memory);
tex = Texture2D.FromStream(this.GraphicsDevice, memory);
}
}
} }
} else { } else {
using (var stream = Path.IsPathRooted(loc) ? File.OpenRead(loc) : TitleContainer.OpenStream(loc)) using (var stream = Path.IsPathRooted(loc) ? File.OpenRead(loc) : TitleContainer.OpenStream(loc))

View file

@ -159,7 +159,7 @@ namespace MLEM.Ui {
// MOUSE INPUT // MOUSE INPUT
if (this.HandleMouse) { if (this.HandleMouse) {
var mousedNow = this.GetElementUnderPos(this.Input.ViewportMousePosition.ToVector2()); var mousedNow = this.GetElementUnderPos(new Vector2(this.Input.ViewportMousePosition.X, this.Input.ViewportMousePosition.Y));
this.SetMousedElement(mousedNow); this.SetMousedElement(mousedNow);
if (this.Input.IsMouseButtonPressedAvailable(MouseButton.Left)) { if (this.Input.IsMouseButtonPressedAvailable(MouseButton.Left)) {
@ -414,8 +414,8 @@ namespace MLEM.Ui {
foreach (var child in children) { foreach (var child in children) {
if (child == this.SelectedElement) if (child == this.SelectedElement)
continue; continue;
var (xOffset, yOffset) = child.Area.Center - this.SelectedElement.Area.Center; var offset = child.Area.Center - this.SelectedElement.Area.Center;
var angle = Math.Abs(MathHelper.WrapAngle(direction.Angle() - (float) Math.Atan2(yOffset, xOffset))); var angle = Math.Abs(MathHelper.WrapAngle(direction.Angle() - (float) Math.Atan2(offset.Y, offset.X)));
if (angle >= MathHelper.PiOver2 - Element.Epsilon) if (angle >= MathHelper.PiOver2 - Element.Epsilon)
continue; continue;
var distSq = child.Area.DistanceSquared(this.SelectedElement.Area); var distSq = child.Area.DistanceSquared(this.SelectedElement.Area);

View file

@ -5,7 +5,6 @@ using MLEM.Ui.Elements;
namespace MLEM.Ui { namespace MLEM.Ui {
/// <summary> /// <summary>
/// A snapshot of update and rendering statistics from <see cref="UiSystem.Metrics"/> to be used for runtime debugging and profiling. /// A snapshot of update and rendering statistics from <see cref="UiSystem.Metrics"/> to be used for runtime debugging and profiling.
/// This metrics struct works similarly to <see cref="GraphicsMetrics"/>.
/// </summary> /// </summary>
public struct UiMetrics { public struct UiMetrics {

View file

@ -88,7 +88,7 @@ namespace MLEM.Ui {
public SamplerState SamplerState; public SamplerState SamplerState;
/// <summary> /// <summary>
/// The depth stencil state that this ui system and all of its elements draw with. /// The depth stencil state that this ui system and all of its elements draw with.
/// The default is <see cref="Microsoft.Xna.Framework.Graphics.DepthStencilState.None"/>, which is also the default for <see cref="SpriteBatch.Begin"/>. /// The default is <see cref="Microsoft.Xna.Framework.Graphics.DepthStencilState.None"/>, which is also the default for <c>SpriteBatch.Begin</c>.
/// </summary> /// </summary>
[Obsolete("Set this through SpriteBatchContext instead")] [Obsolete("Set this through SpriteBatchContext instead")]
public DepthStencilState DepthStencilState; public DepthStencilState DepthStencilState;
@ -241,10 +241,10 @@ namespace MLEM.Ui {
MlemPlatform.Current?.AddTextInputListener(game.Window, (sender, key, character) => this.ApplyToAll(e => e.OnTextInput?.Invoke(e, key, character))); MlemPlatform.Current?.AddTextInputListener(game.Window, (sender, key, character) => this.ApplyToAll(e => e.OnTextInput?.Invoke(e, key, character)));
if (automaticViewport) { if (automaticViewport) {
this.Viewport = new Rectangle(Point.Zero, game.Window.ClientBounds.Size); this.Viewport = new Rectangle(0, 0, game.Window.ClientBounds.Width, game.Window.ClientBounds.Height);
this.AutoScaleReferenceSize = this.Viewport.Size; this.AutoScaleReferenceSize = new Point(this.Viewport.X, this.Viewport.Y);
game.Window.ClientSizeChanged += (sender, args) => { game.Window.ClientSizeChanged += (sender, args) => {
this.Viewport = new Rectangle(Point.Zero, game.Window.ClientBounds.Size); this.Viewport = new Rectangle(0, 0, game.Window.ClientBounds.Width, game.Window.ClientBounds.Height);
}; };
} }
@ -570,11 +570,11 @@ namespace MLEM.Ui {
/// </summary> /// </summary>
public event Element.GenericCallback OnElementRemoved; public event Element.GenericCallback OnElementRemoved;
/// <summary> /// <summary>
/// Event that is invoked when this <see cref="RootElement"/> gets added to a <see cref="UiSystem"/> in <see cref="UiSystem.Add"/> /// Event that is invoked when this <see cref="RootElement"/> gets added to a <see cref="UiSystem"/> in <see cref="UiSystem.Add"/>
/// </summary> /// </summary>
public event Action<UiSystem> OnAddedToUi; public event Action<UiSystem> OnAddedToUi;
/// <summary> /// <summary>
/// Event that is invoked when this <see cref="RootElement"/> gets removed from a <see cref="UiSystem"/> in <see cref="UiSystem.Remove"/> /// Event that is invoked when this <see cref="RootElement"/> gets removed from a <see cref="UiSystem"/> in <see cref="UiSystem.Remove"/>
/// </summary> /// </summary>
public event Action<UiSystem> OnRemovedFromUi; public event Action<UiSystem> OnRemovedFromUi;

View file

@ -58,7 +58,7 @@ namespace MLEM.Cameras {
} }
/// <summary> /// <summary>
/// The matrix that this camera "sees", based on its position and scale. /// The matrix that this camera "sees", based on its position and scale.
/// Use this in your <see cref="SpriteBatch.Begin"/> calls to render based on the camera's viewport. /// Use this in your <c>SpriteBatch.Begin</c> calls to render based on the camera's viewport.
/// </summary> /// </summary>
public Matrix ViewMatrix { public Matrix ViewMatrix {
get { get {
@ -105,7 +105,7 @@ namespace MLEM.Cameras {
/// <param name="roundPosition">Whether the camera's <see cref="Position"/> should be rounded to full integers when calculating the <see cref="ViewMatrix"/></param> /// <param name="roundPosition">Whether the camera's <see cref="Position"/> should be rounded to full integers when calculating the <see cref="ViewMatrix"/></param>
public Camera(GraphicsDevice graphicsDevice, bool roundPosition = true) { public Camera(GraphicsDevice graphicsDevice, bool roundPosition = true) {
this.graphicsDevice = graphicsDevice; this.graphicsDevice = graphicsDevice;
this.AutoScaleReferenceSize = this.Viewport.Size; this.AutoScaleReferenceSize = new Point(this.Viewport.Width, this.Viewport.Height);
this.RoundPosition = roundPosition; this.RoundPosition = roundPosition;
} }
@ -173,7 +173,7 @@ namespace MLEM.Cameras {
/// <param name="delta">The amount to zoom in or out by</param> /// <param name="delta">The amount to zoom in or out by</param>
/// <param name="zoomCenter">The position that should be regarded as the zoom's center, in screen space. The default value is the center.</param> /// <param name="zoomCenter">The position that should be regarded as the zoom's center, in screen space. The default value is the center.</param>
public void Zoom(float delta, Vector2? zoomCenter = null) { public void Zoom(float delta, Vector2? zoomCenter = null) {
var center = (zoomCenter ?? this.Viewport.Size.ToVector2() / 2) / this.ActualScale; var center = (zoomCenter ?? new Vector2(this.Viewport.Width, this.Viewport.Height) / 2) / this.ActualScale;
var lastScale = this.Scale; var lastScale = this.Scale;
this.Scale += delta; this.Scale += delta;
this.Position += center * ((this.Scale - lastScale) / this.Scale); this.Position += center * ((this.Scale - lastScale) / this.Scale);

View file

@ -57,7 +57,7 @@ namespace MLEM.Extensions {
/// <param name="manager">The graphics device manager</param> /// <param name="manager">The graphics device manager</param>
/// <param name="window">The window whose bounds to use</param> /// <param name="window">The window whose bounds to use</param>
public static void ResetWidthAndHeight(this GraphicsDeviceManager manager, GameWindow window) { public static void ResetWidthAndHeight(this GraphicsDeviceManager manager, GameWindow window) {
var (_, _, width, height) = window.ClientBounds; var (width, height) = (window.ClientBounds.Width, window.ClientBounds.Height);
manager.PreferredBackBufferWidth = Math.Max(height, width); manager.PreferredBackBufferWidth = Math.Max(height, width);
manager.PreferredBackBufferHeight = Math.Min(height, width); manager.PreferredBackBufferHeight = Math.Min(height, width);
manager.ApplyChanges(); manager.ApplyChanges();
@ -90,7 +90,12 @@ namespace MLEM.Extensions {
/// <param name="target">The target to apply</param> /// <param name="target">The target to apply</param>
public TargetContext(GraphicsDevice device, RenderTarget2D target) { public TargetContext(GraphicsDevice device, RenderTarget2D target) {
this.device = device; this.device = device;
#if FNA
// RenderTargetCount doesn't exist in FNA but we still want the optimization in MG
this.lastTargets = device.GetRenderTargets();
#else
this.lastTargets = device.RenderTargetCount <= 0 ? null : device.GetRenderTargets(); this.lastTargets = device.RenderTargetCount <= 0 ? null : device.GetRenderTargets();
#endif
device.SetRenderTarget(target); device.SetRenderTarget(target);
} }

View file

@ -223,13 +223,13 @@ namespace MLEM.Extensions {
/// <param name="matrix">The matrix</param> /// <param name="matrix">The matrix</param>
/// <returns>The rotation of the matrix</returns> /// <returns>The rotation of the matrix</returns>
public static Quaternion Rotation(this Matrix matrix) { public static Quaternion Rotation(this Matrix matrix) {
var (scX, scY, scZ) = matrix.Scale(); var sc = matrix.Scale();
if (scX == 0 || scY == 0 || scZ == 0) if (sc.X == 0 || sc.Y == 0 || sc.Z == 0)
return Quaternion.Identity; return Quaternion.Identity;
return Quaternion.CreateFromRotationMatrix(new Matrix( return Quaternion.CreateFromRotationMatrix(new Matrix(
matrix.M11 / scX, matrix.M12 / scX, matrix.M13 / scX, 0, matrix.M11 / sc.X, matrix.M12 / sc.X, matrix.M13 / sc.X, 0,
matrix.M21 / scY, matrix.M22 / scY, matrix.M23 / scY, 0, matrix.M21 / sc.Y, matrix.M22 / sc.Y, matrix.M23 / sc.Y, 0,
matrix.M31 / scZ, matrix.M32 / scZ, matrix.M33 / scZ, 0, matrix.M31 / sc.Z, matrix.M32 / sc.Z, matrix.M33 / sc.Z, 0,
0, 0, 0, 1)); 0, 0, 0, 1));
} }
@ -250,7 +250,7 @@ namespace MLEM.Extensions {
/// <param name="quaternion">The quaternion</param> /// <param name="quaternion">The quaternion</param>
/// <returns>The rotation of the quaternion</returns> /// <returns>The rotation of the quaternion</returns>
public static Vector3 RotationVector(this Quaternion quaternion) { public static Vector3 RotationVector(this Quaternion quaternion) {
var (x, y, z, w) = quaternion; var (x, y, z, w) = (quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
return new Vector3( return new Vector3(
(float) Math.Atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y)), (float) Math.Atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y)),
(float) Math.Asin(MathHelper.Clamp(2 * (w * y - z * x), -1, 1)), (float) Math.Asin(MathHelper.Clamp(2 * (w * y - z * x), -1, 1)),
@ -268,16 +268,16 @@ namespace MLEM.Extensions {
/// <param name="penetration">The amount that the penetration occured by, in the direction of <paramref name="normal"/></param> /// <param name="penetration">The amount that the penetration occured by, in the direction of <paramref name="normal"/></param>
/// <returns>Whether or not a penetration occured</returns> /// <returns>Whether or not a penetration occured</returns>
public static bool Penetrate(this RectangleF rect, RectangleF other, out Vector2 normal, out float penetration) { public static bool Penetrate(this RectangleF rect, RectangleF other, out Vector2 normal, out float penetration) {
var (offsetX, offsetY) = other.Center - rect.Center; var offset = other.Center - rect.Center;
var overlapX = rect.Width / 2 + other.Width / 2 - Math.Abs(offsetX); var overlapX = rect.Width / 2 + other.Width / 2 - Math.Abs(offset.X);
if (overlapX > 0) { if (overlapX > 0) {
var overlapY = rect.Height / 2 + other.Height / 2 - Math.Abs(offsetY); var overlapY = rect.Height / 2 + other.Height / 2 - Math.Abs(offset.Y);
if (overlapY > 0) { if (overlapY > 0) {
if (overlapX < overlapY) { if (overlapX < overlapY) {
normal = new Vector2(offsetX < 0 ? -1 : 1, 0); normal = new Vector2(offset.X < 0 ? -1 : 1, 0);
penetration = overlapX; penetration = overlapX;
} else { } else {
normal = new Vector2(0, offsetY < 0 ? -1 : 1); normal = new Vector2(0, offset.Y < 0 ? -1 : 1);
penetration = overlapY; penetration = overlapY;
} }
return true; return true;
@ -288,5 +288,23 @@ namespace MLEM.Extensions {
return false; return false;
} }
#if FNA
/// <summary>
/// Gets a <see cref="Point"/> representation for this object.
/// </summary>
/// <returns>A <see cref="Point"/> representation for this object.</returns>
public static Point ToPoint(this Vector2 vector) {
return new Point((int) vector.X, (int) vector.Y);
}
/// <summary>
/// Gets a <see cref="Vector2"/> representation for this object.
/// </summary>
/// <returns>A <see cref="Vector2"/> representation for this object.</returns>
public static Vector2 ToVector2(this Point point) {
return new Vector2(point.X, point.Y);
}
#endif
} }
} }

View file

@ -285,18 +285,18 @@ namespace MLEM.Font {
} }
private void DrawString(SpriteBatch batch, CharSource text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { private void DrawString(SpriteBatch batch, CharSource text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
var (flipX, flipY) = Vector2.Zero; var (flipX, flipY) = (0F, 0F);
var flippedV = (effects & SpriteEffects.FlipVertically) != 0; var flippedV = (effects & SpriteEffects.FlipVertically) != 0;
var flippedH = (effects & SpriteEffects.FlipHorizontally) != 0; var flippedH = (effects & SpriteEffects.FlipHorizontally) != 0;
if (flippedV || flippedH) { if (flippedV || flippedH) {
var (w, h) = this.MeasureString(text, false, null); var size = this.MeasureString(text, false, null);
if (flippedH) { if (flippedH) {
origin.X *= -1; origin.X *= -1;
flipX = -w; flipX = -size.X;
} }
if (flippedV) { if (flippedV) {
origin.Y *= -1; origin.Y *= -1;
flipY = this.LineHeight - h; flipY = this.LineHeight - size.Y;
} }
} }
@ -327,17 +327,17 @@ namespace MLEM.Font {
} }
var cString = c.ToCachedString(); var cString = c.ToCachedString();
var (cW, cH) = this.MeasureString(cString); var cSize = this.MeasureString(cString);
var charPos = offset; var charPos = offset;
if (flippedH) if (flippedH)
charPos.X += cW; charPos.X += cSize.X;
if (flippedV) if (flippedV)
charPos.Y += cH - this.LineHeight; charPos.Y += cSize.Y - this.LineHeight;
Vector2.Transform(ref charPos, ref trans, out charPos); Vector2.Transform(ref charPos, ref trans, out charPos);
this.DrawChar(batch, cString, charPos, color, rotation, scale, effects, layerDepth); this.DrawChar(batch, cString, charPos, color, rotation, scale, effects, layerDepth);
offset.X += cW; offset.X += cSize.X;
} }
} }

View file

@ -42,6 +42,10 @@ namespace MLEM.Font {
} }
private static SpriteFont SetDefaults(SpriteFont font) { private static SpriteFont SetDefaults(SpriteFont font) {
#if FNA
// none of the copying is available with FNA
return font;
#else
// we copy the font here to set the default character to a space // we copy the font here to set the default character to a space
return new SpriteFont( return new SpriteFont(
font.Texture, font.Texture,
@ -52,6 +56,7 @@ namespace MLEM.Font {
font.Spacing, font.Spacing,
font.Glyphs.Select(g => new Vector3(g.LeftSideBearing, g.Width, g.RightSideBearing)).ToList(), font.Glyphs.Select(g => new Vector3(g.LeftSideBearing, g.Width, g.RightSideBearing)).ToList(),
' '); ' ');
#endif
} }
} }

View file

@ -23,9 +23,9 @@ namespace MLEM.Formatting.Codes {
// don't underline spaces at the end of lines // don't underline spaces at the end of lines
if (c == ' ' && token.DisplayString.Length > indexInToken + 1 && token.DisplayString[indexInToken + 1] == '\n') if (c == ' ' && token.DisplayString.Length > indexInToken + 1 && token.DisplayString[indexInToken + 1] == '\n')
return false; return false;
var (w, h) = font.MeasureString(cString) * scale; var size = font.MeasureString(cString) * scale;
var t = h * this.thickness; var t = size.Y * this.thickness;
batch.Draw(batch.GetBlankTexture(), new RectangleF(pos.X, pos.Y + this.yOffset * h - t, w, t), color); batch.Draw(batch.GetBlankTexture(), new RectangleF(pos.X, pos.Y + this.yOffset * size.Y - t, size.X, t), color);
return false; return false;
} }

View file

@ -62,8 +62,8 @@ namespace MLEM.Graphics {
/// <summary> /// <summary>
/// This method allows for a tiled texture to be drawn in an auto-tiling mode. /// This method allows for a tiled texture to be drawn in an auto-tiling mode.
/// This allows, for example, a grass patch on a tilemap to have nice looking edges that transfer over into a path without any hard edges between tiles. /// This allows, for example, a grass patch on a tilemap to have nice looking edges that transfer over into a path without any hard edges between tiles.
/// ///
/// This method is a more complex version of <see cref="DrawAutoTile"/> that overlays separate border textures on a background texture region, which also allows for non-rectangular texture areas to be used easily. /// This method is a more complex version of <see cref="DrawAutoTile"/> that overlays separate border textures on a background texture region, which also allows for non-rectangular texture areas to be used easily.
/// For auto-tiling in this way to work, the overlay sections have to be laid out as follows: 16 sections aligned horizontally within the texture file, with the following information: /// For auto-tiling in this way to work, the overlay sections have to be laid out as follows: 16 sections aligned horizontally within the texture file, with the following information:
/// <list type="number"> /// <list type="number">
/// <item><description>The texture used for straight, horizontal borders, with the borders facing away from the center, split up into four parts: top left, then top right, then bottom left, then bottom right</description></item> /// <item><description>The texture used for straight, horizontal borders, with the borders facing away from the center, split up into four parts: top left, then top right, then bottom left, then bottom right</description></item>
@ -138,8 +138,8 @@ namespace MLEM.Graphics {
var xUr = up && right ? connectsTo(1, -1) ? 0 : 4 : right ? 1 : up ? 3 : 2; var xUr = up && right ? connectsTo(1, -1) ? 0 : 4 : right ? 1 : up ? 3 : 2;
var xDl = down && left ? connectsTo(-1, 1) ? 0 : 4 : left ? 1 : down ? 3 : 2; var xDl = down && left ? connectsTo(-1, 1) ? 0 : 4 : left ? 1 : down ? 3 : 2;
var xDr = down && right ? connectsTo(1, 1) ? 0 : 4 : right ? 1 : down ? 3 : 2; var xDr = down && right ? connectsTo(1, 1) ? 0 : 4 : right ? 1 : down ? 3 : 2;
var (w, h) = textureRegion.Size; var (w, h) = (textureRegion.Width, textureRegion.Height);
var (w2, h2) = new Point(w / 2, h / 2); var (w2, h2) = (w / 2, h / 2);
return ( return (
new Vector2(pos.X, pos.Y), new Rectangle(textureRegion.X + xUl * w, textureRegion.Y, w2, h2), new Vector2(pos.X, pos.Y), new Rectangle(textureRegion.X + xUl * w, textureRegion.Y, w2, h2),
new Vector2(pos.X + w2 * scale.X, pos.Y), new Rectangle(textureRegion.X + w2 + xUr * w, textureRegion.Y, w2, h2), new Vector2(pos.X + w2 * scale.X, pos.Y), new Rectangle(textureRegion.X + w2 + xUr * w, textureRegion.Y, w2, h2),
@ -156,7 +156,7 @@ namespace MLEM.Graphics {
var xUr = up && right ? connectsTo(1, -1) ? -1 : 13 : right ? 1 : up ? 9 : 5; var xUr = up && right ? connectsTo(1, -1) ? -1 : 13 : right ? 1 : up ? 9 : 5;
var xDl = down && left ? connectsTo(-1, 1) ? -1 : 14 : left ? 2 : down ? 10 : 6; var xDl = down && left ? connectsTo(-1, 1) ? -1 : 14 : left ? 2 : down ? 10 : 6;
var xDr = down && right ? connectsTo(1, 1) ? -1 : 15 : right ? 3 : down ? 11 : 7; var xDr = down && right ? connectsTo(1, 1) ? -1 : 15 : right ? 3 : down ? 11 : 7;
var (w, h) = textureRegion.Size; var (w, h) = (textureRegion.Width, textureRegion.Height);
return ( return (
xUl < 0 ? Rectangle.Empty : new Rectangle(textureRegion.X + xUl * w, textureRegion.Y, w, h), xUl < 0 ? Rectangle.Empty : new Rectangle(textureRegion.X + xUl * w, textureRegion.Y, w, h),
xUr < 0 ? Rectangle.Empty : new Rectangle(textureRegion.X + xUr * w, textureRegion.Y, w, h), xUr < 0 ? Rectangle.Empty : new Rectangle(textureRegion.X + xUr * w, textureRegion.Y, w, h),

View file

@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
namespace MLEM.Graphics { namespace MLEM.Graphics {
/// <summary> /// <summary>
/// A sprite batch context is a set of information for a <see cref="SpriteBatch"/> to use, which encapsulates all of the information usually passed directly to <see cref="SpriteBatch.Begin"/>. /// A sprite batch context is a set of information for a <see cref="SpriteBatch"/> to use, which encapsulates all of the information usually passed directly to <c>SpriteBatch.Begin</c>.
/// To use a sprite batch context effectively, the extension methods in <see cref="SpriteBatchContextExtensions"/> should be used. /// To use a sprite batch context effectively, the extension methods in <see cref="SpriteBatchContextExtensions"/> should be used.
/// </summary> /// </summary>
public struct SpriteBatchContext { public struct SpriteBatchContext {
@ -17,7 +17,7 @@ namespace MLEM.Graphics {
/// </summary> /// </summary>
public BlendState BlendState; public BlendState BlendState;
/// <summary> /// <summary>
/// State of the sampler. /// State of the sampler.
/// </summary> /// </summary>
public SamplerState SamplerState; public SamplerState SamplerState;
/// <summary> /// <summary>

View file

@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
namespace MLEM.Graphics { namespace MLEM.Graphics {
/// <summary> /// <summary>
@ -174,18 +176,18 @@ namespace MLEM.Graphics {
for (var i = 0; i < this.FilledBuffers; i++) { for (var i = 0; i < this.FilledBuffers; i++) {
var buffer = this.vertexBuffers[i]; var buffer = this.vertexBuffers[i];
var texture = this.textures[i]; var texture = this.textures[i];
var tris = Math.Min(this.items.Count * 4 - totalIndex, buffer.VertexCount) / 4 * 2; var verts = Math.Min(this.items.Count * 4 - totalIndex, buffer.VertexCount);
this.graphicsDevice.SetVertexBuffer(buffer); this.graphicsDevice.SetVertexBuffer(buffer);
if (effect != null) { if (effect != null) {
foreach (var pass in effect.CurrentTechnique.Passes) { foreach (var pass in effect.CurrentTechnique.Passes) {
pass.Apply(); pass.Apply();
this.graphicsDevice.Textures[0] = texture; this.graphicsDevice.Textures[0] = texture;
this.graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, tris); this.DrawPrimitives(verts);
} }
} else { } else {
this.graphicsDevice.Textures[0] = texture; this.graphicsDevice.Textures[0] = texture;
this.graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, tris); this.DrawPrimitives(verts);
} }
totalIndex += buffer.VertexCount; totalIndex += buffer.VertexCount;
@ -290,10 +292,11 @@ namespace MLEM.Graphics {
if ((effects & SpriteEffects.FlipHorizontally) != 0) if ((effects & SpriteEffects.FlipHorizontally) != 0)
(texBr.X, texTl.X) = (texTl.X, texBr.X); (texBr.X, texTl.X) = (texTl.X, texBr.X);
var destSize = new Vector2(destinationRectangle.Width, destinationRectangle.Height);
if (rotation == 0) { if (rotation == 0) {
return this.Add(texture, destinationRectangle.Location.ToVector2() - origin, destinationRectangle.Size.ToVector2(), color, texTl, texBr, layerDepth); return this.Add(texture, destinationRectangle.Location.ToVector2() - origin, destSize, color, texTl, texBr, layerDepth);
} else { } else {
return this.Add(texture, destinationRectangle.Location.ToVector2(), -origin, destinationRectangle.Size.ToVector2(), (float) Math.Sin(rotation), (float) Math.Cos(rotation), color, texTl, texBr, layerDepth); return this.Add(texture, destinationRectangle.Location.ToVector2(), -origin, destSize, (float) Math.Sin(rotation), (float) Math.Cos(rotation), color, texTl, texBr, layerDepth);
} }
} }
@ -439,6 +442,14 @@ namespace MLEM.Graphics {
this.textures.Insert(index, texture); this.textures.Insert(index, texture);
} }
private void DrawPrimitives(int vertices) {
#if FNA
this.graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices, 0, vertices / 4 * 2);
#else
this.graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices / 4 * 2);
#endif
}
/// <summary> /// <summary>
/// A struct that represents an item added to a <see cref="StaticSpriteBatch"/> using <c>Add</c> or any of its overloads. /// A struct that represents an item added to a <see cref="StaticSpriteBatch"/> using <c>Add</c> or any of its overloads.
/// An item returned after adding can be removed using <see cref="Remove"/>. /// An item returned after adding can be removed using <see cref="Remove"/>.
@ -463,5 +474,58 @@ namespace MLEM.Graphics {
} }
#if FNA
private class SpriteEffect : Effect {
private EffectParameter matrixParam;
private Viewport lastViewport;
private Matrix projection;
public Matrix? TransformMatrix { get; set; }
public SpriteEffect(GraphicsDevice device) : base(device, SpriteEffect.LoadEffectCode()) {
this.CacheEffectParameters();
}
private SpriteEffect(SpriteEffect cloneSource) : base(cloneSource) {
this.CacheEffectParameters();
}
public override Effect Clone() {
return new SpriteEffect(this);
}
private void CacheEffectParameters() {
this.matrixParam = this.Parameters["MatrixTransform"];
}
protected override void OnApply() {
var vp = this.GraphicsDevice.Viewport;
if (vp.Width != this.lastViewport.Width || vp.Height != this.lastViewport.Height) {
Matrix.CreateOrthographicOffCenter(0, vp.Width, vp.Height, 0, 0, -1, out this.projection);
this.projection.M41 += -0.5f * this.projection.M11;
this.projection.M42 += -0.5f * this.projection.M22;
this.lastViewport = vp;
}
if (this.TransformMatrix.HasValue) {
this.matrixParam.SetValue(this.TransformMatrix.GetValueOrDefault() * this.projection);
} else {
this.matrixParam.SetValue(this.projection);
}
}
private static byte[] LoadEffectCode() {
using (var stream = typeof(Effect).Assembly.GetManifestResourceStream("Microsoft.Xna.Framework.Graphics.Effect.Resources.SpriteEffect.fxb")) {
using (var memory = new MemoryStream()) {
stream.CopyTo(memory);
return memory.ToArray();
}
}
}
}
#endif
} }
} }

View file

@ -15,6 +15,12 @@ namespace MLEM.Input {
/// </summary> /// </summary>
public class InputHandler : GameComponent { public class InputHandler : GameComponent {
#if FNA
private const int MaximumGamePadCount = 4;
#else
private static readonly int MaximumGamePadCount = GamePad.MaximumGamePadCount;
#endif
/// <summary> /// <summary>
/// Contains all of the gestures that have finished during the last update call. /// Contains all of the gestures that have finished during the last update call.
/// To easily query these gestures, use <see cref="GetGesture"/> or <see cref="GetViewportGesture"/>. /// To easily query these gestures, use <see cref="GetGesture"/> or <see cref="GetViewportGesture"/>.
@ -80,11 +86,11 @@ namespace MLEM.Input {
/// <summary> /// <summary>
/// Contains the touch state from the last update call /// Contains the touch state from the last update call
/// </summary> /// </summary>
public TouchCollection LastTouchState { get; private set; } public TouchCollection LastTouchState { get; private set; } = new TouchCollection(Array.Empty<TouchLocation>());
/// <summary> /// <summary>
/// Contains the current touch state /// Contains the current touch state
/// </summary> /// </summary>
public TouchCollection TouchState { get; private set; } public TouchCollection TouchState { get; private set; } = new TouchCollection(Array.Empty<TouchLocation>());
/// <summary> /// <summary>
/// Contains the <see cref="LastTouchState"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account. /// Contains the <see cref="LastTouchState"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account.
/// </summary> /// </summary>
@ -109,7 +115,7 @@ namespace MLEM.Input {
/// <summary> /// <summary>
/// Contains the position of the mouse from the last update call, extracted from <see cref="LastMouseState"/> /// Contains the position of the mouse from the last update call, extracted from <see cref="LastMouseState"/>
/// </summary> /// </summary>
public Point LastMousePosition => this.LastMouseState.Position; public Point LastMousePosition => new Point(this.LastMouseState.X, this.LastMouseState.Y);
/// <summary> /// <summary>
/// Contains the <see cref="LastMousePosition"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account. /// Contains the <see cref="LastMousePosition"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account.
/// </summary> /// </summary>
@ -117,7 +123,7 @@ namespace MLEM.Input {
/// <summary> /// <summary>
/// Contains the current position of the mouse, extracted from <see cref="MouseState"/> /// Contains the current position of the mouse, extracted from <see cref="MouseState"/>
/// </summary> /// </summary>
public Point MousePosition => this.MouseState.Position; public Point MousePosition => new Point(this.MouseState.X, this.MouseState.Y);
/// <summary> /// <summary>
/// Contains the <see cref="MousePosition"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account. /// Contains the <see cref="MousePosition"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account.
/// </summary> /// </summary>
@ -139,11 +145,11 @@ namespace MLEM.Input {
/// </summary> /// </summary>
public KeyboardState KeyboardState { get; private set; } public KeyboardState KeyboardState { get; private set; }
private readonly GamePadState[] lastGamepads = new GamePadState[GamePad.MaximumGamePadCount]; private readonly GamePadState[] lastGamepads = new GamePadState[MaximumGamePadCount];
private readonly GamePadState[] gamepads = new GamePadState[GamePad.MaximumGamePadCount]; private readonly GamePadState[] gamepads = new GamePadState[MaximumGamePadCount];
private readonly DateTime[] lastGamepadButtonRepeats = new DateTime[GamePad.MaximumGamePadCount]; private readonly DateTime[] lastGamepadButtonRepeats = new DateTime[MaximumGamePadCount];
private readonly bool[] triggerGamepadButtonRepeat = new bool[GamePad.MaximumGamePadCount]; private readonly bool[] triggerGamepadButtonRepeat = new bool[MaximumGamePadCount];
private readonly Buttons?[] heldGamepadButtons = new Buttons?[GamePad.MaximumGamePadCount]; private readonly Buttons?[] heldGamepadButtons = new Buttons?[MaximumGamePadCount];
private readonly List<GestureSample> gestures = new List<GestureSample>(); private readonly List<GestureSample> gestures = new List<GestureSample>();
private readonly HashSet<(GenericInput, int)> consumedPresses = new HashSet<(GenericInput, int)>(); private readonly HashSet<(GenericInput, int)> consumedPresses = new HashSet<(GenericInput, int)>();
@ -209,7 +215,7 @@ namespace MLEM.Input {
if (this.HandleMouse) { if (this.HandleMouse) {
this.LastMouseState = this.MouseState; this.LastMouseState = this.MouseState;
var state = Mouse.GetState(); var state = Mouse.GetState();
if (active && this.Game.GraphicsDevice.Viewport.Bounds.Contains(state.Position)) { if (active && this.Game.GraphicsDevice.Viewport.Bounds.Contains(state.X, state.Y)) {
this.MouseState = state; this.MouseState = state;
foreach (var button in MouseExtensions.MouseButtons) { foreach (var button in MouseExtensions.MouseButtons) {
if (state.GetState(button) == ButtonState.Pressed) if (state.GetState(button) == ButtonState.Pressed)
@ -217,18 +223,22 @@ namespace MLEM.Input {
} }
} else { } else {
// mouse position and scroll wheel value should be preserved when the mouse is out of bounds // mouse position and scroll wheel value should be preserved when the mouse is out of bounds
#if FNA
this.MouseState = new MouseState(state.X, state.Y, state.ScrollWheelValue, 0, 0, 0, 0, 0);
#else
this.MouseState = new MouseState(state.X, state.Y, state.ScrollWheelValue, 0, 0, 0, 0, 0, state.HorizontalScrollWheelValue); this.MouseState = new MouseState(state.X, state.Y, state.ScrollWheelValue, 0, 0, 0, 0, 0, state.HorizontalScrollWheelValue);
#endif
} }
} }
if (this.HandleGamepads) { if (this.HandleGamepads) {
this.ConnectedGamepads = GamePad.MaximumGamePadCount; this.ConnectedGamepads = MaximumGamePadCount;
for (var i = 0; i < GamePad.MaximumGamePadCount; i++) { for (var i = 0; i < MaximumGamePadCount; i++) {
this.lastGamepads[i] = this.gamepads[i]; this.lastGamepads[i] = this.gamepads[i];
this.gamepads[i] = GamePadState.Default; this.gamepads[i] = default;
if (GamePad.GetCapabilities(i).IsConnected) { if (GamePad.GetCapabilities((PlayerIndex) i).IsConnected) {
if (active) { if (active) {
this.gamepads[i] = GamePad.GetState(i); this.gamepads[i] = GamePad.GetState((PlayerIndex) i);
foreach (var button in EnumHelper.Buttons) { foreach (var button in EnumHelper.Buttons) {
if (this.IsGamepadButtonDown(button, i)) if (this.IsGamepadButtonDown(button, i))
this.AccumulateDown(button, i); this.AccumulateDown(button, i);
@ -263,12 +273,13 @@ namespace MLEM.Input {
this.LastTouchState = this.TouchState; this.LastTouchState = this.TouchState;
this.LastViewportTouchState = this.ViewportTouchState; this.LastViewportTouchState = this.ViewportTouchState;
this.TouchState = active ? TouchPanel.GetState() : default; this.TouchState = active ? TouchPanel.GetState() : new TouchCollection(Array.Empty<TouchLocation>());
if (this.TouchState.Count > 0 && this.ViewportOffset != Point.Zero) { if (this.TouchState.Count > 0 && this.ViewportOffset != Point.Zero) {
this.ViewportTouchState = new List<TouchLocation>(); this.ViewportTouchState = new List<TouchLocation>();
foreach (var touch in this.TouchState) { foreach (var touch in this.TouchState) {
touch.TryGetPreviousLocation(out var previous); touch.TryGetPreviousLocation(out var previous);
this.ViewportTouchState.Add(new TouchLocation(touch.Id, touch.State, touch.Position + this.ViewportOffset.ToVector2(), previous.State, previous.Position + this.ViewportOffset.ToVector2())); var offset = new Vector2(this.ViewportOffset.X, this.ViewportOffset.Y);
this.ViewportTouchState.Add(new TouchLocation(touch.Id, touch.State, touch.Position + offset, previous.State, previous.Position + offset));
} }
} else { } else {
this.ViewportTouchState = this.TouchState; this.ViewportTouchState = this.TouchState;
@ -548,7 +559,7 @@ namespace MLEM.Input {
/// <summary> /// <summary>
/// Returns whether the given key is considered pressed. /// Returns whether the given key is considered pressed.
/// A gamepad button is considered pressed if it was down the last update call, and is up the current update call. If <see cref="InvertPressBehavior"/> is true, this behavior is inverted. /// A gamepad button is considered pressed if it was down the last update call, and is up the current update call. If <see cref="InvertPressBehavior"/> is true, this behavior is inverted.
/// This has the same behavior as <see cref="IsGamepadButtonPressed"/>, but ignores gamepad repeat events. /// This has the same behavior as <see cref="IsGamepadButtonPressed"/>, but ignores gamepad repeat events.
/// If <see cref="HandleGamepadRepeats"/> is false, this method does the same as <see cref="IsGamepadButtonPressed"/>. /// If <see cref="HandleGamepadRepeats"/> is false, this method does the same as <see cref="IsGamepadButtonPressed"/>.
/// </summary> /// </summary>
/// <param name="button">The button to query</param> /// <param name="button">The button to query</param>
@ -613,7 +624,8 @@ namespace MLEM.Input {
/// <returns>True if a gesture of the type was found, otherwise false</returns> /// <returns>True if a gesture of the type was found, otherwise false</returns>
public bool GetViewportGesture(GestureType type, out GestureSample sample) { public bool GetViewportGesture(GestureType type, out GestureSample sample) {
if (this.GetGesture(type, out var original)) { if (this.GetGesture(type, out var original)) {
sample = new GestureSample(original.GestureType, original.Timestamp, original.Position + this.ViewportOffset.ToVector2(), original.Position2 + this.ViewportOffset.ToVector2(), original.Delta, original.Delta2); var offset = new Vector2(this.ViewportOffset.X, this.ViewportOffset.Y);
sample = new GestureSample(original.GestureType, original.Timestamp, original.Position + offset, original.Position2 + offset, original.Delta, original.Delta2);
return true; return true;
} }
sample = default; sample = default;

View file

@ -91,7 +91,7 @@ namespace MLEM.Input {
public int CaretPos { public int CaretPos {
get => this.caretPos; get => this.caretPos;
set { set {
var val = MathHelper.Clamp(value, 0, this.text.Length); var val = (int) MathHelper.Clamp(value, 0F, this.text.Length);
if (this.caretPos != val) { if (this.caretPos != val) {
this.caretPos = val; this.caretPos = val;
this.caretBlinkTimer = 0; this.caretBlinkTimer = 0;
@ -226,12 +226,14 @@ namespace MLEM.Input {
/// <summary> /// <summary>
/// A method that should be called when the given text should be entered into this text input. /// A method that should be called when the given text should be entered into this text input.
/// This method is designed to be used with the <see cref="GameWindow.TextInput"/> event. /// This method is designed to be used with <see cref="MlemPlatform.AddTextInputListener"/> or the TextInput event provided by MonoGame and FNA.
/// </summary> /// </summary>
/// <param name="key">The key that was pressed.</param> /// <param name="key">The key that was pressed.</param>
/// <param name="character">The character that the <paramref name="key"/> represents.</param> /// <param name="character">The character that the <paramref name="key"/> represents.</param>
/// <returns>Whether text was successfully input.</returns> /// <returns>Whether text was successfully input.</returns>
public bool OnTextInput(Keys key, char character) { public bool OnTextInput(Keys key, char character) {
// FNA's text input event doesn't supply keys, so we handle this in Update
#if !FNA
if (key == Keys.Back) { if (key == Keys.Back) {
if (this.CaretPos > 0) { if (this.CaretPos > 0) {
this.CaretPos--; this.CaretPos--;
@ -246,6 +248,9 @@ namespace MLEM.Input {
return this.InsertText(character); return this.InsertText(character);
} }
return false; return false;
#else
return this.InsertText(character);
#endif
} }
/// <summary> /// <summary>
@ -254,26 +259,37 @@ namespace MLEM.Input {
/// <param name="time">The current game time.</param> /// <param name="time">The current game time.</param>
/// <param name="input">The input handler to use for input querying.</param> /// <param name="input">The input handler to use for input querying.</param>
public void Update(GameTime time, InputHandler input) { public void Update(GameTime time, InputHandler input) {
// FNA's text input event doesn't supply keys, so we handle this here
#if FNA
if (this.CaretPos > 0 && input.TryConsumePressed(Keys.Back)) {
this.CaretPos--;
this.RemoveText(this.CaretPos, 1);
} else if (this.CaretPos < this.text.Length && input.TryConsumePressed(Keys.Delete)) {
this.RemoveText(this.CaretPos, 1);
} else if (this.Multiline && input.TryConsumePressed(Keys.Enter)) {
this.InsertText('\n');
} else
#endif
if (this.CaretPos > 0 && input.TryConsumePressed(Keys.Left)) { if (this.CaretPos > 0 && input.TryConsumePressed(Keys.Left)) {
this.CaretPos--; this.CaretPos--;
} else if (this.CaretPos < this.text.Length && input.TryConsumePressed(Keys.Right)) { } else if (this.CaretPos < this.text.Length && input.TryConsumePressed(Keys.Right)) {
this.CaretPos++; this.CaretPos++;
} else if (this.Multiline && input.IsKeyPressedAvailable(Keys.Up) && this.MoveCaretToLine(this.CaretLine - 1)) { } else if (this.Multiline && input.IsKeyPressedAvailable(Keys.Up) && this.MoveCaretToLine(this.CaretLine - 1)) {
input.TryConsumeKeyPressed(Keys.Up); input.TryConsumePressed(Keys.Up);
} else if (this.Multiline && input.IsKeyPressedAvailable(Keys.Down) && this.MoveCaretToLine(this.CaretLine + 1)) { } else if (this.Multiline && input.IsKeyPressedAvailable(Keys.Down) && this.MoveCaretToLine(this.CaretLine + 1)) {
input.TryConsumeKeyPressed(Keys.Down); input.TryConsumePressed(Keys.Down);
} else if (this.CaretPos != 0 && input.TryConsumeKeyPressed(Keys.Home)) { } else if (this.CaretPos != 0 && input.TryConsumePressed(Keys.Home)) {
this.CaretPos = 0; this.CaretPos = 0;
} else if (this.CaretPos != this.text.Length && input.TryConsumeKeyPressed(Keys.End)) { } else if (this.CaretPos != this.text.Length && input.TryConsumePressed(Keys.End)) {
this.CaretPos = this.text.Length; this.CaretPos = this.text.Length;
} else if (input.IsModifierKeyDown(ModifierKey.Control)) { } else if (input.IsModifierKeyDown(ModifierKey.Control)) {
if (input.IsKeyPressedAvailable(Keys.V)) { if (input.IsKeyPressedAvailable(Keys.V)) {
var clip = this.PasteFromClipboardFunction?.Invoke(); var clip = this.PasteFromClipboardFunction?.Invoke();
if (clip != null) { if (clip != null) {
this.InsertText(clip, true); this.InsertText(clip, true);
input.TryConsumeKeyPressed(Keys.V); input.TryConsumePressed(Keys.V);
} }
} else if (input.TryConsumeKeyPressed(Keys.C)) { } else if (input.TryConsumePressed(Keys.C)) {
// until there is text selection, just copy the whole content // until there is text selection, just copy the whole content
this.CopyToClipboardFunction?.Invoke(this.Text); this.CopyToClipboardFunction?.Invoke(this.Text);
} }

32
MLEM/MLEM.FNA.csproj Normal file
View file

@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<RootNamespace>MLEM</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<Authors>Ellpeck</Authors>
<Description>MLEM Library for Extending FNA provides extension methods and additional features for FNA</Description>
<PackageReleaseNotes>See the full changelog at https://mlem.ellpeck.de/CHANGELOG</PackageReleaseNotes>
<PackageTags>fna ellpeck mlem utility extensions</PackageTags>
<PackageProjectUrl>https://mlem.ellpeck.de/</PackageProjectUrl>
<RepositoryUrl>https://github.com/Ellpeck/MLEM</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\FNA\FNA.Core.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
</ItemGroup>
</Project>

View file

@ -182,8 +182,8 @@ namespace MLEM.Misc {
/// <param name="dir">The direction whose angle to get</param> /// <param name="dir">The direction whose angle to get</param>
/// <returns>The direction's angle</returns> /// <returns>The direction's angle</returns>
public static float Angle(this Direction2 dir) { public static float Angle(this Direction2 dir) {
var (x, y) = dir.Offset(); var off = dir.Offset();
return (float) Math.Atan2(y, x); return (float) Math.Atan2(off.Y, off.X);
} }
/// <summary> /// <summary>

View file

@ -57,9 +57,9 @@ namespace MLEM.Misc {
/// <summary> /// <summary>
/// A delegate method that can be used for <see cref="MlemPlatform.AddTextInputListener"/> /// A delegate method that can be used for <see cref="MlemPlatform.AddTextInputListener"/>
/// </summary> /// </summary>
/// <param name="sender">The object that sent the event. The <see cref="MlemPlatform"/> used in most cases.</param> /// <param name="sender">The object that sent the event. The <see cref="GameWindow"/> or <see cref="MlemPlatform"/> used in most cases.</param>
/// <param name="key">The key that was pressed</param> /// <param name="key">The key that was pressed. Note that this is always <see cref="Keys.None"/> on FNA.</param>
/// <param name="character">The character that corresponds to that key</param> /// <param name="character">The character that corresponds to that key.</param>
public delegate void TextInputCallback(object sender, Keys key, char character); public delegate void TextInputCallback(object sender, Keys key, char character);
/// <summary> /// <summary>
@ -78,10 +78,10 @@ namespace MLEM.Misc {
private readonly Action<GameWindow, EventHandler<T>> addListener; private readonly Action<GameWindow, EventHandler<T>> addListener;
/// <summary> /// <summary>
/// Creates a new DesktopGL-based platform /// Creates a new DesktopGL-based platform.
/// See <see cref="MlemPlatform.DesktopGl{T}"/> class documentation for more detailed information. /// See <see cref="MlemPlatform.DesktopGl{T}"/> class documentation for more detailed information.
/// </summary> /// </summary>
/// <param name="addListener">The function that is used to add a text input listener</param> /// <param name="addListener">The function that is used to add a text input listener.</param>
public DesktopGl(Action<GameWindow, EventHandler<T>> addListener) { public DesktopGl(Action<GameWindow, EventHandler<T>> addListener) {
this.addListener = addListener; this.addListener = addListener;
} }
@ -109,6 +109,44 @@ namespace MLEM.Misc {
} }
/// <summary>
/// The MLEM Desktop platform for FNA.
/// This platform uses the built-in FNA TextInputEXT event, which makes this listener work with any keyboard localization natively.
/// This platform is initialized as follows:
/// <code>
/// MlemPlatform.Current = new MlemPlatform.DesktopFna(a => TextInputEXT.TextInput += a);
/// </code>
/// </summary>
public class DesktopFna : MlemPlatform {
private readonly Action<Action<char>> addListener;
/// <summary>
/// Creates a new Desktop for FNA platform.
/// See <see cref="MlemPlatform.DesktopFna"/> class documentation for more detailed information.
/// </summary>
/// <param name="addListener">The function that is used to add a text input listener.</param>
public DesktopFna(Action<Action<char>> addListener) {
this.addListener = addListener;
}
/// <inheritdoc />
public override Task<string> OpenOnScreenKeyboard(string title, string description, string defaultText, bool usePasswordMode) {
return Task.FromResult<string>(null);
}
/// <inheritdoc />
public override void AddTextInputListener(GameWindow window, TextInputCallback callback) {
this.addListener(c => callback(this, Keys.None, c));
}
/// <inheritdoc />
public override void OpenLinkOrFile(string link) {
Process.Start(new ProcessStartInfo(link) {UseShellExecute = true});
}
}
/// <summary> /// <summary>
/// The MLEM platform for mobile platforms as well as consoles. /// The MLEM platform for mobile platforms as well as consoles.
/// This platform opens an on-screen keyboard using the <see cref="Microsoft.Xna.Framework.Input"/> <c>KeyboardInput</c> class on mobile devices. /// This platform opens an on-screen keyboard using the <see cref="Microsoft.Xna.Framework.Input"/> <c>KeyboardInput</c> class on mobile devices.

View file

@ -105,12 +105,12 @@ namespace MLEM.Misc {
this.Height = size.Y; this.Height = size.Y;
} }
/// <inheritdoc cref="Rectangle.Contains(float, float)"/> /// <inheritdoc cref="Rectangle.Contains(int, int)"/>
public bool Contains(float x, float y) { public bool Contains(float x, float y) {
return this.X <= x && x < this.X + this.Width && this.Y <= y && y < this.Y + this.Height; return this.X <= x && x < this.X + this.Width && this.Y <= y && y < this.Y + this.Height;
} }
/// <inheritdoc cref="Rectangle.Contains(Vector2)"/> /// <inheritdoc cref="Rectangle.Contains(Point)"/>
public bool Contains(Vector2 value) { public bool Contains(Vector2 value) {
return this.Contains(value.X, value.Y); return this.Contains(value.X, value.Y);
} }
@ -140,7 +140,7 @@ namespace MLEM.Misc {
return (((17 * 23 + this.X.GetHashCode()) * 23 + this.Y.GetHashCode()) * 23 + this.Width.GetHashCode()) * 23 + this.Height.GetHashCode(); return (((17 * 23 + this.X.GetHashCode()) * 23 + this.Y.GetHashCode()) * 23 + this.Width.GetHashCode()) * 23 + this.Height.GetHashCode();
} }
/// <inheritdoc cref="Rectangle.Inflate(float,float)"/> /// <inheritdoc cref="Rectangle.Inflate(int,int)"/>
public void Inflate(float horizontalAmount, float verticalAmount) { public void Inflate(float horizontalAmount, float verticalAmount) {
this.X -= horizontalAmount; this.X -= horizontalAmount;
this.Y -= verticalAmount; this.Y -= verticalAmount;
@ -153,13 +153,13 @@ namespace MLEM.Misc {
return value.Left < this.Right && this.Left < value.Right && value.Top < this.Bottom && this.Top < value.Bottom; return value.Left < this.Right && this.Left < value.Right && value.Top < this.Bottom && this.Top < value.Bottom;
} }
/// <inheritdoc cref="Rectangle.Offset(float, float)"/> /// <inheritdoc cref="Rectangle.Offset(int, int)"/>
public void Offset(float offsetX, float offsetY) { public void Offset(float offsetX, float offsetY) {
this.X += offsetX; this.X += offsetX;
this.Y += offsetY; this.Y += offsetY;
} }
/// <inheritdoc cref="Rectangle.Offset(Vector2)"/> /// <inheritdoc cref="Rectangle.Offset(Point)"/>
public void Offset(Vector2 amount) { public void Offset(Vector2 amount) {
this.X += amount.X; this.X += amount.X;
this.Y += amount.Y; this.Y += amount.Y;
@ -173,7 +173,7 @@ namespace MLEM.Misc {
/// <returns>The squared distance between the two rectangles.</returns> /// <returns>The squared distance between the two rectangles.</returns>
public float DistanceSquared(RectangleF value) { public float DistanceSquared(RectangleF value) {
// we calculate the distance based on the quadrants that the other rectangle is in using 8 cases: // we calculate the distance based on the quadrants that the other rectangle is in using 8 cases:
// 1 7 4 // 1 7 4
// 3 T 6 // 3 T 6
// 2 8 5 // 2 8 5
var valueIsAbove = value.Bottom < this.Top; var valueIsAbove = value.Bottom < this.Top;
@ -215,7 +215,13 @@ namespace MLEM.Misc {
return "{X:" + this.X + " Y:" + this.Y + " Width:" + this.Width + " Height:" + this.Height + "}"; return "{X:" + this.X + " Y:" + this.Y + " Width:" + this.Width + " Height:" + this.Height + "}";
} }
/// <inheritdoc cref="Rectangle.Deconstruct"/> /// <summary>
/// Deconstruction method for <see cref="RectangleF"/>.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="width"></param>
/// <param name="height"></param>
public void Deconstruct(out float x, out float y, out float width, out float height) { public void Deconstruct(out float x, out float y, out float width, out float height) {
x = this.X; x = this.X;
y = this.Y; y = this.Y;

View file

@ -158,7 +158,8 @@ namespace MLEM.Textures {
for (var x = 0F; x < rect.Width; x += width) { for (var x = 0F; x < rect.Width; x += width) {
for (var y = 0F; y < rect.Height; y += height) { for (var y = 0F; y < rect.Height; y += height) {
var size = new Vector2(Math.Min(rect.Width - x, width), Math.Min(rect.Height - y, height)); var size = new Vector2(Math.Min(rect.Width - x, width), Math.Min(rect.Height - y, height));
batch.Draw(texture.Region.Texture, new RectangleF(rect.Location + new Vector2(x, y), size), new Rectangle(src.Location, (size / patchScale).CeilCopy().ToPoint()), color, rotation, origin, effects, layerDepth); var srcSize = (size / patchScale).CeilCopy().ToPoint();
batch.Draw(texture.Region.Texture, new RectangleF(rect.Location + new Vector2(x, y), size), new Rectangle(src.X, src.Y, srcSize.X, srcSize.Y), color, rotation, origin, effects, layerDepth);
} }
} }
break; break;

View file

@ -33,7 +33,7 @@ namespace MLEM.Textures {
/// <summary> /// <summary>
/// The size of this texture region /// The size of this texture region
/// </summary> /// </summary>
public Point Size => this.Area.Size; public Point Size => new Point(this.Area.Width, this.Area.Height);
/// <summary> /// <summary>
/// The width of this texture region /// The width of this texture region
/// </summary> /// </summary>
@ -51,8 +51,8 @@ namespace MLEM.Textures {
/// The <see cref="Pivot"/> of this texture region, but in absolute pixels rather than percentage. /// The <see cref="Pivot"/> of this texture region, but in absolute pixels rather than percentage.
/// </summary> /// </summary>
public Vector2 PivotPixels { public Vector2 PivotPixels {
get => this.Pivot * this.Size.ToVector2(); get => this.Pivot * new Vector2(this.Size.X, this.Size.Y);
set => this.Pivot = value / this.Size.ToVector2(); set => this.Pivot = value / new Vector2(this.Size.X, this.Size.Y);
} }
/// <summary> /// <summary>
/// The name of this texture region. By default, this name is <see cref="string.Empty"/>. /// The name of this texture region. By default, this name is <see cref="string.Empty"/>.
@ -91,14 +91,14 @@ namespace MLEM.Textures {
/// <param name="texture">The texture to use</param> /// <param name="texture">The texture to use</param>
/// <param name="uv">The top left corner of this area</param> /// <param name="uv">The top left corner of this area</param>
/// <param name="size">The size of this area</param> /// <param name="size">The size of this area</param>
public TextureRegion(Texture2D texture, Point uv, Point size) : this(texture, new Rectangle(uv, size)) {} public TextureRegion(Texture2D texture, Point uv, Point size) : this(texture, new Rectangle(uv.X, uv.Y, size.X, size.Y)) {}
/// <summary> /// <summary>
/// Creates a new texture region which is a sub-region of the given texture region /// Creates a new texture region which is a sub-region of the given texture region
/// </summary> /// </summary>
/// <param name="region">The texture region to create a sub-region of</param> /// <param name="region">The texture region to create a sub-region of</param>
/// <param name="area">The new texture region area</param> /// <param name="area">The new texture region area</param>
public TextureRegion(TextureRegion region, Rectangle area) : this(region, area.Location, area.Size) {} public TextureRegion(TextureRegion region, Rectangle area) : this(region, area.Location, new Point(area.Width, area.Height)) {}
/// <summary> /// <summary>
/// Creates a new texture region which is a sub-region of the given texture region /// Creates a new texture region which is a sub-region of the given texture region

View file

@ -47,7 +47,7 @@ namespace MLEM.Textures {
/// Returns the <see cref="TextureRegion"/> at this texture atlas' given region position /// Returns the <see cref="TextureRegion"/> at this texture atlas' given region position
/// </summary> /// </summary>
/// <param name="point">The region's x and y location</param> /// <param name="point">The region's x and y location</param>
public TextureRegion this[Point point] => this[new Rectangle(point, new Point(1, 1))]; public TextureRegion this[Point point] => this[new Rectangle(point.X, point.Y, 1, 1)];
/// <inheritdoc cref="this[Point]"/> /// <inheritdoc cref="this[Point]"/>
public TextureRegion this[int x, int y] => this[new Point(x, y)]; public TextureRegion this[int x, int y] => this[new Point(x, y)];
/// <summary> /// <summary>

View file

@ -1,6 +1,6 @@
![The MLEM logo](https://raw.githubusercontent.com/Ellpeck/MLEM/main/Media/Banner.png) ![The MLEM logo](https://raw.githubusercontent.com/Ellpeck/MLEM/main/Media/Banner.png)
**MLEM Library for Extending MonoGame** is an addition to the game framework [MonoGame](https://www.monogame.net/) that provides extension methods, quality of life improvements and additional features like a ui system and easy input handling. **MLEM Library for Extending MonoGame and FNA** is an addition to the game frameworks [MonoGame](https://www.monogame.net/) and [FNA](https://fna-xna.github.io/) that provides extension methods, quality of life improvements and additional features like a ui system and easy input handling.
# What next? # What next?
- Get it on [NuGet](https://www.nuget.org/packages?q=mlem) - Get it on [NuGet](https://www.nuget.org/packages?q=mlem)

View file

@ -18,7 +18,7 @@
<PackageReference Include="MonoGame.Extended.Content.Pipeline" Version="3.8.0" /> <PackageReference Include="MonoGame.Extended.Content.Pipeline" Version="3.8.0" />
<PackageReference Include="MonoGame.Extended.Tiled" Version="3.8.0" /> <PackageReference Include="MonoGame.Extended.Tiled" Version="3.8.0" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" /> <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
<PackageReference Include="FontStashSharp.MonoGame" Version="1.0.4" /> <PackageReference Include="FontStashSharp.MonoGame" Version="1.1.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup> </ItemGroup>

BIN
Tests/FNA/FAudio.dll Normal file

Binary file not shown.

BIN
Tests/FNA/FNA3D.dll Normal file

Binary file not shown.

BIN
Tests/FNA/SDL2.dll Normal file

Binary file not shown.

BIN
Tests/FNA/libFAudio.0.dylib Normal file

Binary file not shown.

BIN
Tests/FNA/libFAudio.so.0 Normal file

Binary file not shown.

BIN
Tests/FNA/libFNA3D.0.dylib Normal file

Binary file not shown.

BIN
Tests/FNA/libFNA3D.so.0 Normal file

Binary file not shown.

BIN
Tests/FNA/libMoltenVK.dylib Normal file

Binary file not shown.

Binary file not shown.

BIN
Tests/FNA/libSDL2-2.0.so.0 Normal file

Binary file not shown.

BIN
Tests/FNA/libtheorafile.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
Tests/FNA/libtheorafile.so Normal file

Binary file not shown.

BIN
Tests/FNA/libvulkan.1.dylib Normal file

Binary file not shown.

38
Tests/Tests.FNA.csproj Normal file
View file

@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<VSTestLogger>nunit</VSTestLogger>
<RootNamespace>Tests</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.FNA.csproj" />
<ProjectReference Include="..\MLEM.Data\MLEM.Data.FNA.csproj" />
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.FNA.csproj" />
<ProjectReference Include="..\MLEM\MLEM.FNA.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FNA\FNA.Core.csproj" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NunitXml.TestLogger" Version="3.0.117" />
</ItemGroup>
<ItemGroup>
<Content Include="Content/**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="FNA/**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</Content>
</ItemGroup>
</Project>

View file

@ -13,14 +13,14 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" /> <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
<PackageReference Include="coverlet.collector" Version="3.1.0"> <PackageReference Include="coverlet.collector" Version="3.1.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NunitXml.TestLogger" Version="3.0.117" /> <PackageReference Include="NunitXml.TestLogger" Version="3.0.117" />
</ItemGroup> </ItemGroup>

View file

@ -9,13 +9,13 @@ var config = Argument("configuration", "Release");
Task("Prepare").Does(() => { Task("Prepare").Does(() => {
DotNetCoreRestore("MLEM.sln"); DotNetCoreRestore("MLEM.sln");
if (branch != "release") { if (branch != "release") {
var buildNum = EnvironmentVariable("BUILD_NUMBER"); var buildNum = EnvironmentVariable("BUILD_NUMBER");
if (buildNum != null) if (buildNum != null)
version += "-" + buildNum; version += "-" + buildNum;
} }
DeleteFiles("**/*.nupkg"); DeleteFiles("**/*.nupkg");
}); });
@ -27,13 +27,16 @@ Task("Build").IsDependentOn("Prepare").Does(() =>{
foreach (var project in GetFiles("**/MLEM*.csproj")) foreach (var project in GetFiles("**/MLEM*.csproj"))
DotNetCoreBuild(project.FullPath, settings); DotNetCoreBuild(project.FullPath, settings);
DotNetCoreBuild("Demos/Demos.csproj", settings); DotNetCoreBuild("Demos/Demos.csproj", settings);
DotNetCoreBuild("Demos/Demos.FNA.csproj", settings);
}); });
Task("Test").IsDependentOn("Build").Does(() => { Task("Test").IsDependentOn("Build").Does(() => {
DotNetCoreTest("Tests/Tests.csproj", new DotNetCoreTestSettings { var settings = new DotNetCoreTestSettings {
Configuration = config, Configuration = config,
Collectors = {"XPlat Code Coverage"} Collectors = {"XPlat Code Coverage"}
}); };
DotNetCoreTest("Tests/Tests.csproj", settings);
DotNetCoreTest("Tests/Tests.FNA.csproj", settings);
}); });
Task("Pack").IsDependentOn("Test").Does(() => { Task("Pack").IsDependentOn("Test").Does(() => {
@ -71,4 +74,4 @@ Task("Document").Does(() => {
Task("Default").IsDependentOn("Pack"); Task("Default").IsDependentOn("Pack");
Task("Publish").IsDependentOn("Push"); Task("Publish").IsDependentOn("Push");
RunTarget(target); RunTarget(target);