1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-11-25 22:18:34 +01:00

Compare commits

..

No commits in common. "9b090c954f0b26b6270ecf64c59907b047ba5d18" and "a1c5b8e2d6a25c63ac11e47f67ba8e8cfa0ef43f" have entirely different histories.

225 changed files with 2336 additions and 4893 deletions

View file

@ -1,113 +0,0 @@
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4
# Microsoft .NET properties
csharp_new_line_before_catch = false
csharp_new_line_before_else = false
csharp_new_line_before_finally = false
csharp_new_line_before_members_in_object_initializers = false
csharp_new_line_before_open_brace = none
csharp_new_line_between_query_expression_clauses = false
csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:suggestion
csharp_space_after_cast = true
csharp_style_var_elsewhere = true:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
dotnet_naming_rule.private_constants_rule.severity = warning
dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style
dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols
dotnet_naming_rule.private_instance_fields_rule.severity = warning
dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style
dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols
dotnet_naming_rule.private_static_fields_rule.severity = warning
dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style
dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols
dotnet_naming_rule.private_static_readonly_rule.severity = warning
dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style
dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols
dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field
dotnet_naming_symbols.private_constants_symbols.required_modifiers = const
dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_qualification_for_event = true:suggestion
dotnet_style_qualification_for_field = true:suggestion
dotnet_style_qualification_for_method = true:suggestion
dotnet_style_qualification_for_property = true:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
# ReSharper properties
resharper_blank_lines_after_block_statements = 0
resharper_blank_lines_around_auto_property = 0
resharper_blank_lines_around_local_method = 0
resharper_blank_lines_around_property = 0
resharper_blank_lines_inside_type = 1
resharper_braces_for_dowhile = required_for_multiline
resharper_braces_for_fixed = required_for_multiline
resharper_braces_for_for = required_for_multiline
resharper_braces_for_foreach = required_for_multiline
resharper_braces_for_ifelse = required_for_multiline
resharper_braces_for_lock = required_for_multiline
resharper_braces_for_using = required_for_multiline
resharper_braces_for_while = required_for_multiline
resharper_braces_redundant = false
resharper_csharp_blank_lines_around_field = 0
resharper_csharp_blank_lines_around_single_line_invocable = 1
resharper_csharp_empty_block_style = together
resharper_csharp_keep_blank_lines_in_code = 1
resharper_csharp_keep_blank_lines_in_declarations = 1
resharper_csharp_max_line_length = unset
resharper_csharp_stick_comment = false
resharper_csharp_wrap_before_ternary_opsigns = false
resharper_csharp_wrap_multiple_declaration_style = wrap_if_long
resharper_csharp_wrap_multiple_type_parameter_constraints_style = wrap_if_long
resharper_csharp_wrap_ternary_expr_style = wrap_if_long
resharper_force_attribute_style = join
resharper_indent_nested_fixed_stmt = true
resharper_indent_nested_foreach_stmt = true
resharper_indent_nested_for_stmt = true
resharper_indent_nested_lock_stmt = true
resharper_indent_nested_usings_stmt = true
resharper_indent_nested_while_stmt = true
resharper_indent_preprocessor_if = usual_indent
resharper_indent_preprocessor_other = usual_indent
resharper_keep_existing_declaration_parens_arrangement = false
resharper_keep_existing_embedded_arrangement = false
resharper_keep_existing_expr_member_arrangement = false
resharper_keep_existing_property_patterns_arrangement = false
resharper_keep_existing_switch_expression_arrangement = false
resharper_parentheses_redundancy_style = remove
resharper_place_attribute_on_same_line = false
resharper_place_expr_accessor_on_single_line = true
resharper_place_expr_method_on_single_line = true
resharper_place_expr_property_on_single_line = true
resharper_place_simple_accessor_on_single_line = false
resharper_place_simple_anonymousmethod_on_single_line = false
resharper_place_simple_embedded_statement_on_same_line = false
resharper_space_around_arrow_op = true
resharper_space_within_empty_braces = false
resharper_space_within_single_line_array_initializer_braces = false
resharper_static_members_qualify_members = field, property, event, method
resharper_wrap_for_stmt_header_style = wrap_if_long
resharper_wrap_object_and_collection_initializer_style = wrap_if_long
resharper_xmldoc_attribute_indent = align_by_first_attribute
resharper_xmldoc_attribute_style = on_single_line
resharper_xmldoc_pi_attribute_style = on_single_line

6
.gitmodules vendored
View file

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

View file

@ -2,98 +2,11 @@
MLEM tries to adhere to [semantic versioning](https://semver.org/). Breaking changes are written in **bold**.
Jump to version:
- [6.0.0](#600)
- [5.3.0](#530)
- [5.2.0](#520)
- [5.1.0](#510)
- [5.0.0](#500)
## 6.0.0
### MLEM
Additions
- Added consuming variants of IsPressed methods to InputHandler and Keybind
- Added SpriteBatchContext struct and extensions
- Added InputHandler.InvertPressBehavior
- Added ReverseInput, ReverseOutput and AndThen to Easings
- Added an Enum constructor to GenericInput
- Added RandomPitchModifier and GetRandomPitch to SoundEffectInfo
- Added TextInput class, which is an isolated version of MLEM.Ui's TextField logic
- Added MLEM.FNA, which is fully compatible with FNA
- Added TryGetUpTime, GetUpTime, TryGetTimeSincePress and GetTimeSincePress to InputHandler
Improvements
- Allow comparing Keybind and Combination based on the amount of modifiers they have
- Allow using multiple textures in a StaticSpriteBatch
- Added GenericInput support for Buttons.None
- Improved the way terminating formatting codes work by introducing SimpleEndCode
- Allow RandomExtensions to operate on any ICollection
Removals
- Marked AStar.InfiniteCost as obsolete
### MLEM.Ui
Additions
- Added Element.AutoNavGroup which allows forming groups for auto-navigation
- Added UiMarkdownParser
- Added MLEM.Ui.FNA, which is fully compatible with FNA
Improvements
- Ensure that Element.IsMouseOver is always accurate by making it an auto-property
- Started using SpriteBatchContext for Draw and DrawTransformed methods
- Make use of the new consuming variants in InputHandler and Keybind to consume UiControls inputs
- Allow Tooltip to manage more than one paragraph and make it easier to add new lines
- Allow adding dropdown elements at a specified index
- Turned Tooltip paragraph styling into style properties
- Improved ElementHelper.AddTooltip overloads
- Don't query a paragraph's text callback in the constructor
- Allow manually hiding a paragraph without its text overriding the hidden state
- Added optional isKeybindAllowed parameter to KeybindButton
- Allow manually setting a RootElement as CanBeActive
Fixes
- Fixed auto-nav tooltip displaying on the selected element even when not in auto-nav mode
- Fixed radio buttons not unchecking all other radio buttons with the same root element
- Fixed elements not being deselected when removed through RemoveChild
- Fixed elements sometimes staying hidden when they shouldn't in scrolling panels
- Fixed elements' OnDeselected events not being raised when CanBeSelected is set to false while selected
- Fixed gamepad auto-nav angle being incorrect for some elements
Removals
- Marked old Draw and DrawTransformed overloads as obsolete in favor of SpriteBatchContext ones
- Marked Tooltip.Paragraph as obsolete in favor of new Paragraphs collection
### MLEM.Extended
Additions
- Added LayerPositionF
- Added MLEM.Extended.FNA, which is fully compatible with FNA
Improvements
- Allow using a StaticSpriteBatch to render an IndividualTiledMapRenderer
### MLEM.Data
Additions
- Added the ability to add padding to RuntimeTexturePacker texture regions
- Added the ability to pack UniformTextureAtlas and DataTextureAtlas using RuntimeTexturePacker
- Added MLEM.Data.FNA, which is fully compatible with FNA
Improvements
- Premultiply textures when using RawContentManager
- Allow enumerating all region names of a DataTextureAtlas
- Cache RuntimeTexturePacker texture data while packing to improve performance
- Greatly improved RuntimeTexturePacker performance
- Allow specifying multiple names for a DataTextureAtlas region
Fixes
- Fixed SoundEffectReader incorrectly claiming it could read ogg and mp3 files
### MLEM.Startup
Additions
- Added MLEM.Startup.FNA, which is fully compatible with FNA
### MLEM.Templates
Improvements
- Updated to MonoGame 3.8.1
## 5.3.0
### MLEM
Additions
@ -374,4 +287,4 @@ Additions
Fixes
- Fixed some number parsing not using the invariant culture
- Fixed RawContentManager crashing with dynamic assemblies present
- Fixed RawContentManager crashing with dynamic assemblies present

View file

@ -1,36 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.1.263",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-mac"
]
}
}
}

View file

@ -1,55 +1,55 @@
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Net;
using Android.OS;
using Android.Views;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using MLEM.Extensions;
using MLEM.Misc;
using Uri = Android.Net.Uri;
using static Android.Views.SystemUiFlags;
namespace Demos.Android;
namespace Demos.Android {
[Activity(
Label = "@string/app_name",
MainLauncher = true,
Icon = "@drawable/icon",
AlwaysRetainTaskState = true,
LaunchMode = LaunchMode.SingleInstance,
ScreenOrientation = ScreenOrientation.UserLandscape,
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize
)]
public class Activity1 : AndroidGameActivity {
[Activity(
Label = "@string/app_name",
MainLauncher = true,
Icon = "@drawable/icon",
AlwaysRetainTaskState = true,
LaunchMode = LaunchMode.SingleInstance,
ScreenOrientation = ScreenOrientation.UserLandscape,
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize
)]
public class Activity1 : AndroidGameActivity {
private GameImpl game;
private View view;
private GameImpl game;
private View view;
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
// render under notches
if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
this.Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges;
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
// render under notches
if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
this.Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges;
MlemPlatform.Current = new MlemPlatform.Mobile(KeyboardInput.Show, l => this.StartActivity(new Intent(Intent.ActionView, Uri.Parse(l))));
this.game = new GameImpl();
// reset MlemGame width and height to use device's aspect ratio
this.game.GraphicsDeviceManager.ResetWidthAndHeight(this.game.Window);
// disable mouse handling for android to make emulator behavior more coherent
this.game.OnLoadContent += game => game.InputHandler.HandleMouse = false;
// set the game to fullscreen to cause the status bar to be hidden
this.game.GraphicsDeviceManager.IsFullScreen = true;
this.view = this.game.Services.GetService(typeof(View)) as View;
this.SetContentView(this.view);
this.game.Run();
}
public override void OnWindowFocusChanged(bool hasFocus) {
base.OnWindowFocusChanged(hasFocus);
// hide the status bar
if (hasFocus) {
#pragma warning disable CS0618
// TODO this is deprecated, find out how to replace it
this.Window.DecorView.SystemUiVisibility = (StatusBarVisibility) (SystemUiFlags.ImmersiveSticky | SystemUiFlags.LayoutStable | SystemUiFlags.LayoutHideNavigation | SystemUiFlags.LayoutFullscreen | SystemUiFlags.HideNavigation | SystemUiFlags.Fullscreen);
#pragma warning restore CS0618
MlemPlatform.Current = new MlemPlatform.Mobile(KeyboardInput.Show, l => this.StartActivity(new Intent(Intent.ActionView, Uri.Parse(l))));
this.game = new GameImpl();
// reset MlemGame width and height to use device's aspect ratio
this.game.GraphicsDeviceManager.ResetWidthAndHeight(this.game.Window);
// disable mouse handling for android to make emulator behavior more coherent
this.game.OnLoadContent += game => game.InputHandler.HandleMouse = false;
// set the game to fullscreen to cause the status bar to be hidden
this.game.GraphicsDeviceManager.IsFullScreen = true;
this.view = this.game.Services.GetService(typeof(View)) as View;
this.SetContentView(this.view);
this.game.Run();
}
}
}
public override void OnWindowFocusChanged(bool hasFocus) {
base.OnWindowFocusChanged(hasFocus);
// hide the status bar
if (hasFocus)
this.Window.DecorView.SystemUiVisibility = (StatusBarVisibility) (ImmersiveSticky | LayoutStable | LayoutHideNavigation | LayoutFullscreen | HideNavigation | Fullscreen);
}
}
}

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.ellpeck.mlem.demos.android" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="31" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<application android:label="MLEM Android Demos" />
</manifest>

View file

@ -1,22 +1,104 @@
<Project Sdk="Microsoft.NET.Sdk">
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFramework>net6.0-android</TargetFramework>
<SupportedOSPlatformVersion>31</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<ApplicationId>de.ellpeck.mlem.demos.android</ApplicationId>
<ApplicationVersion>1</ApplicationVersion>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ImplicitUsings>true</ImplicitUsings>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{410C0262-131C-4D0E-910D-D01B4F7143E0}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Demos.Android</RootNamespace>
<AssemblyName>Demos.Android</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidStoreUncompressedFileExtensions>.m4a</AndroidStoreUncompressedFileExtensions>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\</OutputPath>
<DefineConstants>DEBUG;TRACE;ANDROID</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\</OutputPath>
<DefineConstants>TRACE;ANDROID</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
<AotAssemblies>false</AotAssemblies>
<EnableLLVM>false</EnableLLVM>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
<BundleAssemblies>false</BundleAssemblies>
<MandroidI18n />
<AndroidPackageFormat>aab</AndroidPackageFormat>
<AndroidUseAapt2>true</AndroidUseAapt2>
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.263" />
<PackageReference Include="MonoGame.Framework.Android" Version="3.8.1.263" />
<ProjectReference Include="..\Demos\Demos.csproj" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml" />
<Reference Include="Mono.Android" />
</ItemGroup>
<ItemGroup>
<Compile Include="Activity1.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\Drawable\Icon.png" />
<AndroidResource Include="Resources\Values\Strings.xml" />
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="..\Demos\Content\Content.mgcb" />
<None Include="..\Demos\Content\*\**" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Coroutine" Version="2.1.3" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
<PackageReference Include="MonoGame.Framework.Android" Version="3.8.0.1641" />
<PackageReference Include="TextCopy" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Demos\Demos.csproj">
<Project>{1bc4682b-aa14-4937-b5c7-707e20fe88ff}</Project>
<Name>Demos</Name>
</ProjectReference>
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj">
<Project>{997f4739-7bec-4621-b9ca-68deb2d74412}</Project>
<Name>MLEM.Startup</Name>
</ProjectReference>
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj">
<Project>{6f00629a-8b87-4264-8896-19983285e32f}</Project>
<Name>MLEM.Ui</Name>
</ProjectReference>
<ProjectReference Include="..\MLEM\MLEM.csproj">
<Project>{1d6ab762-43c4-4775-8924-707c7ec3f142}</Project>
<Name>MLEM</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
</Project>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.ellpeck.mlem.demos.android" android:installLocation="auto" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:label="MLEM Android Demos" android:resizeableActivity="true" />
</manifest>

View file

@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MLEM Android Demos")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MLEM Android Demos")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -0,0 +1,76 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("Demos.Android.Resource", IsApplication=true)]
namespace Demos.Android
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
public partial class Resource
{
static Resource()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
public static void UpdateIdValues()
{
}
public partial class Attribute
{
static Attribute()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Attribute()
{
}
}
public partial class Drawable
{
// aapt resource value: 0x7F010000
public const int Icon = 2130771968;
static Drawable()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Drawable()
{
}
}
public partial class String
{
// aapt resource value: 0x7F020000
public const int app_name = 2130837504;
static String()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private String()
{
}
}
}
}
#pragma warning restore 1591

View file

@ -1,36 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.1.263",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-mac"
]
}
}
}

View file

@ -1,37 +0,0 @@
<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="FnaNative/**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</Content>
</ItemGroup>
</Project>

View file

@ -2,32 +2,28 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<ApplicationIcon>Icon.ico</ApplicationIcon>
<AssemblyName>MLEM Desktop Demos</AssemblyName>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.263" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.263" />
<ProjectReference Include="..\Demos\Demos.csproj" />
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj" />
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
<ProjectReference Include="..\MLEM\MLEM.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="..\Demos\Content\Content.mgcb" />
<Content Include="..\Demos\Content\*\**" />
<EmbeddedResource Include="Icon.ico" />
<EmbeddedResource Include="Icon.bmp" />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" />
<Exec Command="dotnet tool restore" />
</Target>
</Project>
</Project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,20 +1,14 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using MLEM.Misc;
namespace Demos.DesktopGL {
public static class Program {
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);
#endif
using var game = new GameImpl();
game.Run();
}
}
}
}

View file

@ -27,7 +27,7 @@ namespace Demos {
// using it having wrong coordinates and/or sizes
// the regions that are part of the atlas are then referenced by region coordinates rather than texture coordinates
// (as seen below)
var atlas = new UniformTextureAtlas(Demo.LoadContent<Texture2D>("Textures/Anim"), 4, 4);
var atlas = new UniformTextureAtlas(LoadContent<Texture2D>("Textures/Anim"), 4, 4);
// create the four animations by supplying the time per frame, and the four regions used
// note that you don't need to use a texture atlas for this, you can also simply supply the texture and the regions manually here
@ -90,7 +90,7 @@ namespace Demos {
public override void DoDraw(GameTime gameTime) {
this.GraphicsDevice.Clear(Color.CornflowerBlue);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(10));
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(10));
// draw the group's current region
// if not using a group, just draw the animation's CurrentRegion here
this.SpriteBatch.Draw(this.group.CurrentRegion, new Vector2(10, 10), Color.White);
@ -104,4 +104,4 @@ namespace Demos {
}
}
}
}

View file

@ -20,7 +20,7 @@ namespace Demos {
public override void LoadContent() {
base.LoadContent();
// The layout of the texture is important for auto tiling to work correctly, and is explained in the XML docs for the methods used
this.texture = Demo.LoadContent<Texture2D>("Textures/AutoTiling");
this.texture = LoadContent<Texture2D>("Textures/AutoTiling");
// in this example, a simple string array is used for layout purposes. As the AutoTiling method allows any kind of
// comparison, the actual implementation can vary (for instance, based on a more in-depth tile map)
@ -37,7 +37,7 @@ namespace Demos {
this.GraphicsDevice.Clear(Color.Black);
// drawing the auto tiles
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(10));
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(10));
for (var x = 0; x < 6; x++) {
for (var y = 0; y < 5; y++) {
// don't draw non-grass tiles ( )
@ -59,12 +59,12 @@ namespace Demos {
}
// the texture region supplied to the AutoTiling method should only encompass the first filler tile's location and size
AutoTiling.DrawAutoTile(this.SpriteBatch, new Vector2(x + 1, y + 1) * AutoTilingDemo.TileSize, new TextureRegion(this.texture, 0, 0, AutoTilingDemo.TileSize, AutoTilingDemo.TileSize), ConnectsTo, Color.White);
AutoTiling.DrawAutoTile(this.SpriteBatch, new Vector2(x + 1, y + 1) * TileSize, new TextureRegion(this.texture, 0, 0, TileSize, TileSize), ConnectsTo, Color.White);
// when drawing extended auto-tiles, the same rules apply, but the source texture layout is different
var background = new TextureRegion(this.texture, 0, AutoTilingDemo.TileSize * 2, AutoTilingDemo.TileSize, AutoTilingDemo.TileSize);
var overlay = new TextureRegion(this.texture, background.Area.OffsetCopy(new Point(AutoTilingDemo.TileSize, 0)));
AutoTiling.DrawExtendedAutoTile(this.SpriteBatch, new Vector2(x + 8, y + 1) * AutoTilingDemo.TileSize, background, overlay, ConnectsTo, Color.White, Color.White);
var background = new TextureRegion(this.texture, 0, TileSize * 2, TileSize, TileSize);
var overlay = new TextureRegion(this.texture, background.Area.OffsetCopy(new Point(TileSize, 0)));
AutoTiling.DrawExtendedAutoTile(this.SpriteBatch, new Vector2(x + 8, y + 1) * TileSize, background, overlay, ConnectsTo, Color.White, Color.White);
}
}
this.SpriteBatch.End();
@ -73,4 +73,4 @@ namespace Demos {
}
}
}
}

View file

@ -13,13 +13,6 @@
#---------------------------------- Content ---------------------------------#
#begin Fonts/MonospacedFont.spritefont
/importer:FontDescriptionImporter
/processor:FontDescriptionProcessor
/processorParam:PremultiplyAlpha=True
/processorParam:TextureFormat=Compressed
/build:Fonts/MonospacedFont.spritefont
#begin Fonts/TestFont.spritefont
/importer:FontDescriptionImporter
/processor:FontDescriptionProcessor
@ -41,8 +34,12 @@
/processorParam:TextureFormat=Compressed
/build:Fonts/TestFontItalic.spritefont
#begin Markdown.md
/copy:Markdown.md
#begin Fonts/MonospacedFont.spritefont
/importer:FontDescriptionImporter
/processor:FontDescriptionProcessor
/processorParam:PremultiplyAlpha=True
/processorParam:TextureFormat=Compressed
/build:Fonts/MonospacedFont.spritefont
#begin Textures/Anim.png
/importer:TextureImporter

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>JetBrainsMono-Regular.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>JetBrainsMono-Regular.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYETANO.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYETANO.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYTANOB</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYTANOB</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYETANI</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYETANI</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -1,23 +0,0 @@
# H1
## H2
### H3
#### H4
##### H5
###### H6
Italics with *asterisks* or _underscores_.
Bold with **asterisks** or __underscores__.
Strikethrough with ~~two tildes~~.
[I'm an inline-style link](https://www.google.com)
<http://www.example.com>
![](https://raw.githubusercontent.com/Ellpeck/MLEM/main/Media/Logo.png)
Some `inline code` right here
```js
function codeBlock() {
}
```

View file

@ -32,4 +32,4 @@ namespace Demos {
}
}
}
}

View file

@ -1,21 +0,0 @@
<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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
@ -11,7 +11,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.263">
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

View file

@ -13,7 +13,7 @@ namespace Demos {
private static readonly FieldInfo[] EasingFields = typeof(Easings)
.GetFields(BindingFlags.Public | BindingFlags.Static).ToArray();
private static readonly Easings.Easing[] Easings = EasingsDemo.EasingFields
private static readonly Easings.Easing[] Easings = EasingFields
.Select(f => (Easings.Easing) f.GetValue(null)).ToArray();
private Group group;
private int current;
@ -27,11 +27,11 @@ namespace Demos {
this.group = new Group(Anchor.TopCenter, Vector2.One) {CanBeMoused = false};
this.group.AddChild(new Button(Anchor.AutoCenter, new Vector2(30, 10), "Next") {
OnPressed = e => {
this.current = (this.current + 1) % EasingsDemo.Easings.Length;
this.current = (this.current + 1) % Easings.Length;
this.progress = 0;
}
});
this.group.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => EasingsDemo.EasingFields[this.current].Name, true));
this.group.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => EasingFields[this.current].Name, true));
this.UiRoot.AddChild(this.group);
}
@ -43,11 +43,11 @@ namespace Demos {
this.GraphicsDevice.Clear(Color.CornflowerBlue);
base.DoDraw(time);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp);
var view = this.GraphicsDevice.Viewport;
// graph the easing function
var graphEase = EasingsDemo.Easings[this.current].ScaleInput(0, view.Width).ScaleOutput(-view.Height / 3, view.Height / 3);
var graphEase = Easings[this.current].ScaleInput(0, view.Width).ScaleOutput(-view.Height / 3, view.Height / 3);
for (var x = 0; x < view.Width; x++) {
var area = new RectangleF(x - 2, view.Height / 2 - graphEase(x) - 2, 4, 4);
this.SpriteBatch.Draw(this.SpriteBatch.GetBlankTexture(), area, Color.Green);
@ -55,7 +55,7 @@ namespace Demos {
// draw a little dot to show what it would look like
this.progress = (this.progress + (float) time.ElapsedGameTime.TotalSeconds / 2) % 1;
var dotEase = EasingsDemo.Easings[this.current].AndReverse().ScaleOutput(0, view.Height / 4);
var dotEase = Easings[this.current].AndReverse().ScaleOutput(0, view.Height / 4);
var pos = new RectangleF(view.Width / 2 - 4, view.Height - 20 - dotEase(this.progress), 8, 8);
this.SpriteBatch.Draw(this.SpriteBatch.GetBlankTexture(), pos, Color.Red);
@ -63,4 +63,4 @@ namespace Demos {
}
}
}
}

View file

@ -9,9 +9,7 @@ using MLEM.Textures;
using MLEM.Ui;
using MLEM.Ui.Elements;
using MLEM.Ui.Style;
#if !FNA
using MonoGame.Framework.Utilities;
#endif
namespace Demos {
public class GameImpl : MlemGame {
@ -25,12 +23,11 @@ namespace Demos {
private TimeSpan secondCounter;
static GameImpl() {
GameImpl.Demos.Add("Ui", ("An in-depth demonstration of the MLEM.Ui package and its abilities", game => new UiDemo(game)));
GameImpl.Demos.Add("Text Formatting", ("A demonstration of MLEM's text formatting system", game => new TextFormattingDemo(game)));
GameImpl.Demos.Add("Easings", ("An example of MLEM's Easings class, an adaptation of easings.net", game => new EasingsDemo(game)));
GameImpl.Demos.Add("Pathfinding", ("An example of MLEM's A* pathfinding implementation in 2D", game => new PathfindingDemo(game)));
GameImpl.Demos.Add("Animation and Texture Atlas", ("An example of UniformTextureAtlases, SpriteAnimations and SpriteAnimationGroups", game => new AnimationDemo(game)));
GameImpl.Demos.Add("Auto Tiling", ("A demonstration of the AutoTiling class that MLEM provides", game => new AutoTilingDemo(game)));
Demos.Add("Ui", ("An in-depth demonstration of the MLEM.Ui package and its abilities", game => new UiDemo(game)));
Demos.Add("Easings", ("An example of MLEM's Easings class, an adaptation of easings.net", game => new EasingsDemo(game)));
Demos.Add("Pathfinding", ("An example of MLEM's A* pathfinding implementation in 2D", game => new PathfindingDemo(game)));
Demos.Add("Animation and Texture Atlas", ("An example of UniformTextureAtlases, SpriteAnimations and SpriteAnimationGroups", game => new AnimationDemo(game)));
Demos.Add("Auto Tiling", ("A demonstration of the AutoTiling class that MLEM provides", game => new AutoTilingDemo(game)));
}
public GameImpl() {
@ -48,6 +45,13 @@ namespace Demos {
}
protected override void LoadContent() {
// TODO remove with MonoGame 3.8.1 https://github.com/MonoGame/MonoGame/issues/7298
if (PlatformInfo.MonoGamePlatform == MonoGamePlatform.DesktopGL) {
this.GraphicsDeviceManager.PreferredBackBufferWidth = 1280;
this.GraphicsDeviceManager.PreferredBackBufferHeight = 720;
this.GraphicsDeviceManager.ApplyChanges();
}
base.LoadContent();
this.UiSystem.AutoScaleReferenceSize = new Point(1280, 720);
this.UiSystem.AutoScaleWithScreen = true;
@ -70,7 +74,7 @@ namespace Demos {
selection.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Select the demo you want to see below using your mouse, touch input, your keyboard or a controller. Check the demos' <l https://github.com/Ellpeck/MLEM/tree/main/Demos>source code</l> for more in-depth explanations of their functionality or the <l https://mlem.ellpeck.de/>website</l> for tutorials and API documentation."));
selection.AddChild(new VerticalSpace(5));
foreach (var demo in GameImpl.Demos) {
foreach (var demo in Demos) {
selection.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), demo.Key, demo.Value.Item1) {
OnPressed = e => {
selection.IsHidden = true;
@ -88,9 +92,9 @@ namespace Demos {
}
protected override UiStyle InitializeDefaultUiStyle(SpriteBatch batch) {
var tex = MlemGame.LoadContent<Texture2D>("Textures/Test");
var tex = LoadContent<Texture2D>("Textures/Test");
return new UntexturedStyle(this.SpriteBatch) {
Font = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/TestFont")),
Font = new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/TestFont")),
TextScale = 0.1F,
PanelTexture = new NinePatch(new TextureRegion(tex, 0, 8, 24, 24), 8),
ButtonTexture = new NinePatch(new TextureRegion(tex, 24, 8, 16, 16), 4),
@ -124,4 +128,4 @@ namespace Demos {
}
}
}
}

View file

@ -35,14 +35,14 @@ namespace Demos {
// 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
// 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
// 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
float Cost(Point pos, Point nextPos) {
if (nextPos.X < 0 || nextPos.Y < 0 || nextPos.X >= 50 || nextPos.Y >= 50)
return float.PositiveInfinity;
return this.world[nextPos.X, nextPos.Y] ? 1 : float.PositiveInfinity;
return AStar2.InfiniteCost;
return this.world[nextPos.X, nextPos.Y] ? 1 : AStar2.InfiniteCost;
}
// Actually initialize the pathfinder with the cost function, as well as specify if moving diagonally between tiles should be
@ -73,7 +73,7 @@ namespace Demos {
public override void DoDraw(GameTime gameTime) {
this.GraphicsDevice.Clear(Color.White);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(14));
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(14));
var tex = this.SpriteBatch.GetBlankTexture();
// draw the world with simple shapes
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
if (this.path != null) {
for (var i = 1; i < this.path.Count; i++) {
var first = this.path[i - 1];
var second = this.path[i];
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);
var (firstX, firstY) = this.path[i - 1];
var (secondX, secondY) = 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.End();
@ -102,4 +102,4 @@ namespace Demos {
}
}
}
}

View file

@ -1,81 +0,0 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Font;
using MLEM.Formatting;
using MLEM.Formatting.Codes;
using MLEM.Startup;
using MLEM.Textures;
namespace Demos {
public class TextFormattingDemo : Demo {
private const string Text =
"MLEM's text formatting system allows for various <b>formatting codes</b> to be applied in the middle of a string. Here's a demonstration of some of them.\n\n" +
"You can write in <b>bold</i>, <i>italics</i>, <u>with an underline</u>, <st>strikethrough</st>, with a <s #000000 4>drop shadow</s> whose <s #ff0000 4>color</s> and <s #000000 10>offset</s> you can modify in each application of the code, or with various types of <b>combined <c Pink>formatting</c> codes</b>.\n\n" +
"You can apply <c CornflowerBlue>custom</c> <c Yellow>colors</c> to text, including all default <c Orange>MonoGame colors</c> and <c #aabb00>inline custom colors</c>.\n\n" +
"You can also use animations like <a wobbly>a wobbly one</a>, as well as create custom ones using the <a wobbly>Code class</a>.\n\n" +
"You can also display <i grass> icons in your text!\n\n" +
"Additionally, the text formatter has various methods for interacting with the text, like custom behaviors when hovering over certain parts, and more.";
private const float Scale = 0.5F;
private const float Width = 0.9F;
private TextFormatter formatter;
private TokenizedString tokenizedText;
private GenericFont font;
public TextFormattingDemo(MlemGame game) : base(game) {}
public override void LoadContent() {
this.Game.Window.ClientSizeChanged += this.OnResize;
// creating a new text formatter as well as a generic font to draw with
this.formatter = new TextFormatter();
// GenericFont and its subtypes are wrappers around various font classes, including SpriteFont, MonoGame.Extended's BitmapFont and FontStashSharp
// supplying a bold and italic version of the font here allows for the bold and italic formatting codes to be used
this.font = new GenericSpriteFont(
Demo.LoadContent<SpriteFont>("Fonts/TestFont"),
Demo.LoadContent<SpriteFont>("Fonts/TestFontBold"),
Demo.LoadContent<SpriteFont>("Fonts/TestFontItalic"));
// adding the image code used in the example to it
var testTexture = Demo.LoadContent<Texture2D>("Textures/Test");
this.formatter.AddImage("grass", new TextureRegion(testTexture, 0, 0, 8, 8));
// tokenizing our text and splitting it to fit the screen
// we specify our text alignment here too, so that all data is cached correctly for display
this.tokenizedText = this.formatter.Tokenize(this.font, TextFormattingDemo.Text, TextAlignment.Center);
this.tokenizedText.Split(this.font, this.GraphicsDevice.Viewport.Width * TextFormattingDemo.Width, TextFormattingDemo.Scale, TextAlignment.Center);
}
public override void DoDraw(GameTime time) {
this.GraphicsDevice.Clear(Color.DarkSlateGray);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null);
// 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
var size = this.tokenizedText.Measure(this.font) * TextFormattingDemo.Scale;
var pos = new Vector2(this.GraphicsDevice.Viewport.Width / 2, (this.GraphicsDevice.Viewport.Height - size.Y) / 2);
this.tokenizedText.Draw(time, this.SpriteBatch, pos, this.font, Color.White, TextFormattingDemo.Scale, 0);
this.SpriteBatch.End();
}
public override void Update(GameTime time) {
// update our tokenized string to animate the animation codes
this.tokenizedText.Update(time);
}
public override void Clear() {
base.Clear();
this.Game.Window.ClientSizeChanged -= this.OnResize;
}
private void OnResize(object sender, EventArgs e) {
// re-split our text if the window resizes, since it depends on the window size
// this doesn't require re-tokenization of the text, since TokenizedString also stores the un-split version
this.tokenizedText.Split(this.font, this.GraphicsDevice.Viewport.Width * TextFormattingDemo.Width, TextFormattingDemo.Scale, TextAlignment.Center);
}
}
}

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Coroutine;
using Microsoft.Xna.Framework;
@ -8,13 +7,13 @@ using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MLEM.Font;
using MLEM.Formatting;
using MLEM.Formatting.Codes;
using MLEM.Input;
using MLEM.Misc;
using MLEM.Startup;
using MLEM.Textures;
using MLEM.Ui;
using MLEM.Ui.Elements;
using MLEM.Ui.Parsers;
using MLEM.Ui.Style;
namespace Demos {
@ -27,7 +26,7 @@ namespace Demos {
public UiDemo(MlemGame game) : base(game) {}
public override void LoadContent() {
this.testTexture = Demo.LoadContent<Texture2D>("Textures/Test");
this.testTexture = LoadContent<Texture2D>("Textures/Test");
this.testPatch = new NinePatch(new TextureRegion(this.testTexture, 0, 8, 24, 24), 8);
base.LoadContent();
@ -37,10 +36,7 @@ namespace Demos {
// when using a SpriteFont, use GenericSpriteFont. When using a MonoGame.Extended BitmapFont, use GenericBitmapFont.
// Wrapping fonts like this allows for both types to be usable within MLEM.Ui easily
// Supplying a bold and an italic version is optional
Font = new GenericSpriteFont(
Demo.LoadContent<SpriteFont>("Fonts/TestFont"),
Demo.LoadContent<SpriteFont>("Fonts/TestFontBold"),
Demo.LoadContent<SpriteFont>("Fonts/TestFontItalic")),
Font = new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/TestFont"), LoadContent<SpriteFont>("Fonts/TestFontBold"), LoadContent<SpriteFont>("Fonts/TestFontItalic")),
TextScale = 0.1F,
PanelTexture = this.testPatch,
ButtonTexture = new NinePatch(new TextureRegion(this.testTexture, 24, 8, 16, 16), 4),
@ -51,7 +47,7 @@ namespace Demos {
CheckboxCheckmark = new TextureRegion(this.testTexture, 24, 0, 8, 8),
RadioTexture = new NinePatch(new TextureRegion(this.testTexture, 16, 0, 8, 8), 3),
RadioCheckmark = new TextureRegion(this.testTexture, 32, 0, 8, 8),
AdditionalFonts = {{"Monospaced", new GenericSpriteFont(Demo.LoadContent<SpriteFont>("Fonts/MonospacedFont"))}},
AdditionalFonts = {{"Monospaced", new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/MonospacedFont"))}},
LinkColor = Color.CornflowerBlue
};
var untexturedStyle = new UntexturedStyle(this.SpriteBatch) {
@ -73,7 +69,7 @@ namespace Demos {
// add the root to the demos' ui
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 and FNA."));
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."));
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
// (for example, setting the size's x to 0.75 would make the element's width be 0.75*parentWidth)
@ -92,7 +88,12 @@ namespace Demos {
this.root.AddChild(new VerticalSpace(3));
// a paragraph with formatting codes. To see them all or to add more, check the TextFormatting class
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Paragraphs can also contain <c Blue>formatting codes</c>, including colors and <i>text styles</i>. For more info, check out the <b>text formatting demo</b>!"));
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Paragraphs can also contain <c Blue>formatting codes</c>, including colors and <i>text styles</i>. The names of all <c Orange>MonoGame Colors</c> can be used, as well as the codes <i>Italic</i>, <b>Bold</b>, <s>Drop Shadow'd</s> and <s><c Pink>mixed formatting</s></c>. You can also add additional fonts for things like\n<f Monospaced>void Code() {\n // Code\n}</f>\n<i>Even <c #ff611f82>inline custom colors</c> work!</i>"));
// adding some custom image formatting codes
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Additionally, you can create custom formatting codes that contain <i Grass> images and more!"));
this.UiSystem.TextFormatter.AddImage("Grass", image.Texture);
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Defining text animations as formatting codes is also possible, including <a wobbly>wobbly text</a> at <a wobbly 8 0.25>different intensities</a>. Of course, more animations can be added though."));
this.root.AddChild(new VerticalSpace(3));
this.root.AddChild(new Paragraph(Anchor.AutoCenter, 1, "Multiline text input:", true));
@ -155,7 +156,7 @@ namespace Demos {
// Check the WobbleButton method for an explanation of how this button works
this.root.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.5F, 10), "Wobble Me", "This button wobbles around visually when clicked, but this doesn't affect its actual size and positioning") {
OnPressed = element => CoroutineHandler.Start(UiDemo.WobbleButton(element)),
OnPressed = element => CoroutineHandler.Start(WobbleButton(element)),
PositionOffset = new Vector2(0, 1)
});
// Another button that shows animations!
@ -188,13 +189,13 @@ namespace Demos {
this.root.AddChild(new VerticalSpace(3));
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Progress bars!"));
var bar1 = this.root.AddChild(new ProgressBar(Anchor.AutoLeft, new Vector2(1, 8), Direction2.Right, 10) {PositionOffset = new Vector2(0, 1)});
CoroutineHandler.Start(UiDemo.WobbleProgressBar(bar1));
CoroutineHandler.Start(WobbleProgressBar(bar1));
var bar2 = this.root.AddChild(new ProgressBar(Anchor.AutoLeft, new Vector2(1, 8), Direction2.Left, 10) {PositionOffset = new Vector2(0, 1)});
CoroutineHandler.Start(UiDemo.WobbleProgressBar(bar2));
CoroutineHandler.Start(WobbleProgressBar(bar2));
var bar3 = this.root.AddChild(new ProgressBar(Anchor.AutoLeft, new Vector2(8, 30), Direction2.Down, 10) {PositionOffset = new Vector2(0, 1)});
CoroutineHandler.Start(UiDemo.WobbleProgressBar(bar3));
CoroutineHandler.Start(WobbleProgressBar(bar3));
var bar4 = this.root.AddChild(new ProgressBar(Anchor.AutoInline, new Vector2(8, 30), Direction2.Up, 10) {PositionOffset = new Vector2(1, 0)});
CoroutineHandler.Start(UiDemo.WobbleProgressBar(bar4));
CoroutineHandler.Start(WobbleProgressBar(bar4));
this.root.AddChild(new VerticalSpace(3));
var dropdown = this.root.AddChild(new Dropdown(Anchor.AutoLeft, new Vector2(1, 10), "Dropdown Menu"));
@ -222,13 +223,6 @@ namespace Demos {
alignPar.Alignment = alignment;
};
this.root.AddChild(new VerticalSpace(3));
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "MLEM.Ui also contains a simple Markdown parser, which can be useful for displaying things like changelogs in your game."));
this.root.AddChild(new VerticalSpace(3));
var parser = new UiMarkdownParser {GraphicsDevice = this.GraphicsDevice};
using (var reader = new StreamReader(TitleContainer.OpenStream("Content/Markdown.md")))
parser.ParseInto(reader.ReadToEnd(), this.root);
this.root.AddChild(new VerticalSpace(3));
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "The code for this demo contains some examples for how to query element data. This is the output of that:"));
@ -296,4 +290,4 @@ namespace Demos {
}
}
}
}

View file

@ -1,6 +1,6 @@
# MLEM.Ui
**MLEM.Ui** is a Ui framework for MonoGame and FNA that features elements with automatic positioning and sizing. It contains various ready-made element types like buttons, paragraphs, text fields and more, along with the ability to easily create custom controls. It supports **mouse**, **keyboard**, **gamepad** and **touch** input with little to no additional setup work required.
**MLEM.Ui** is a Ui framework for MonoGame that features elements with automatic positioning and sizing. It contains various ready-made element types like buttons, paragraphs, text fields and more, along with the ability to easily create custom controls. It supports **mouse**, **keyboard**, **gamepad** and **touch** input with little to no additional setup work required.
To see some of what MLEM.Ui can do, you can check out [the demo](https://github.com/Ellpeck/MLEM/blob/main/Demos/UiDemo.cs) as well.
@ -11,7 +11,7 @@ public UiSystem UiSystem;
protected override void LoadContent() {
// Load your other content here
// Initialize the Ui system
this.UiSystem = new UiSystem(this.Window, this.GraphicsDevice, new UntexturedStyle(this.SpriteBatch));
}
@ -24,30 +24,26 @@ protected override void Update(GameTime gameTime) {
protected override void Draw(GameTime gameTime) {
this.GraphicsDevice.Clear(Color.CornflowerBlue);
// Do your regular game drawing here
// Call Draw at the end to draw the Ui on top of your game
this.UiSystem.Draw(gameTime, this.SpriteBatch);
}
```
### Text Input
On desktop devices, MonoGame provides the `Window.TextInput` event that gets called automatically with the correct characters for the keys that you're pressing, even for non-American keyboards. However, this function doesn't exist on other devices. Similarly, MonoGame provides the `KeyboardInput` class for showing an on-screen keyboard on mobile devices and consoles, but not on desktop.
On desktop devices, MonoGame provides the `Window.TextInput` event that gets called automatically with the correct characters for the keys that you're pressing, even for non-American keyboards. However, this function doesn't exist on other devices. Similarly, MonoGame provides the `KeyboardInput` class for showing an on-screen keyboard on mobile devices and consoles, but not on desktop.
To make MLEM compatible with all devices without publishing a separate version for each MonoGame platform, you have to set up the `MlemPlatform` class based on the system you're using MLEM.Ui with. This has to be done *before* initializing your `UiSystem`.
DesktopGL and WindowsDX using MonoGame:
DesktopGL:
```cs
MlemPlatform.Current = new MlemPlatform.DesktopGl<TextInputEventArgs>((w, c) => w.TextInput += c);
```
Desktop using FNA:
```cs
MlemPlatform.Current = new MlemPlatform.DesktopFna(a => TextInputEXT.TextInput += a);
```
Mobile devices and consoles:
```cs
MlemPlatform.Current = new MlemPlatform.Mobile(KeyboardInput.Show, l => this.StartActivity(new Intent(Intent.ActionView, Uri.Parse(l))));
```
If you're not using text input, you can leave the platform uninitialized or just set it to a stub one like so:
If you're not using text input, you can just set the platform to a stub one like so:
```cs
MlemPlatform.Current = new MlemPlatform.None();
```
@ -93,4 +89,4 @@ this.UiSystem.Add("InfoBox", box);
Note that, when setting the width and height of any element, there are some things to note:
- Each element has a `SetWidthBasedOnChildren` and a `SetHeightBasedOnChildren` property, which allow them to change their size automatically based on their content
- When specifying a width or height *lower than or equal to 1*, it is seen as a percentage based on the parent's size instead. For example, a paragraph with a width of `0.5F` inside of a panel width a width of `200` will be `100` units wide.
- When specifying a width *lower than 0*, it is seen as a percentage based on the element's height, and vice versa. For example, a panel with a width of `200` and a height of `-2` will be `400` units tall.
- When specifying a width *lower than 0*, it is seen as a percentage based on the element's height, and vice versa. For example, a panel with a width of `200` and a height of `-2` will be `400` units tall.

View file

@ -1,27 +1,27 @@
![The MLEM logo](https://raw.githubusercontent.com/Ellpeck/MLEM/release/Media/Banner.png)
**MLEM Library for Extending MonoGame and FNA** is a set of multipurpose libraries for the game frameworks [MonoGame](https://www.monogame.net/) and [FNA](https://fna-xna.github.io/) that provides abstractions, quality of life improvements and additional features like an extensive ui system and easy input handling.
**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.
# What next?
- Get it on [NuGet](https://www.nuget.org/packages?q=mlem)
- Get prerelease builds on [BaGet](https://nuget.ellpeck.de/?q=mlem)
- Get prerelease builds on [BaGet](https://nuget.ellpeck.de)
- See the source code on [GitHub](https://github.com/Ellpeck/MLEM)
- See tutorials and API documentation on [the website](https://mlem.ellpeck.de/)
- Check out [the demos](https://github.com/Ellpeck/MLEM/tree/release/Demos) on [Desktop](https://github.com/Ellpeck/MLEM/tree/release/Demos.DesktopGL) or [Android](https://github.com/Ellpeck/MLEM/tree/release/Demos.Android)
- See [the changelog](https://mlem.ellpeck.de/CHANGELOG.html) for information on updates
# Packages
- **MLEM** is the base package, which provides various small addons and abstractions for MonoGame and FNA, including a text formatting system and simple input handling
- **MLEM.Ui** provides a mouse, keyboard, gamepad and touch ready Ui system that features automatic anchoring, sizing and several ready-to-use element types
- **MLEM.Extended** ties in with MonoGame.Extended and other MonoGame and FNA libraries
- **MLEM.Data** provides simple loading and processing of textures and other data, including the ability to load non-XNB content files easily
- **MLEM** is the base package, which provides extension methods and additional features for MonoGame
- **MLEM.Ui** features a mouse, keyboard, gamepad and touch ready Ui system that features automatic anchoring, sizing and several ready-to-use element types
- **MLEM.Extended** ties in with MonoGame.Extended and other MonoGame libraries
- **MLEM.Data** provides simple loading and processing of textures and data
- **MLEM.Startup** combines MLEM with some other useful libraries into a quick Game startup class
- **MLEM.Templates** contains cross-platform project templates
# Made with MLEM
- [A Breath of Spring Air](https://ellpeck.itch.io/a-breath-of-spring-air), a short platformer ([Source](https://git.ellpeck.de/Ellpeck/GreatSpringGameJam))
- [Don't Wake Up](https://ellpeck.itch.io/dont-wake-up), a short puzzle game ([Source](https://github.com/Ellpeck/DontLetGo))
- [Pong Clone](https://github.com/luanfagu/pong), a very simple pong clone ([Source](https://github.com/luanfagu/pong))
- [Pong clone](https://github.com/luanfagu/pong), a very simple pong clone ([Source](https://github.com/luanfagu/pong))
- [Tiny Life](https://tinylifegame.com), an isometric life simulation game ([Modding API](https://github.com/Ellpeck/TinyLifeExampleMod))
If you created a game with the help of MLEM, you can get it added to this list by submitting it on the [issue tracker](https://github.com/Ellpeck/MLEM/issues). If its source is public, other people will be able to use your project as an example, too!
@ -38,9 +38,9 @@ MLEM's [text formatting system](https://mlem.ellpeck.de/articles/text_formatting
![An image showing text with various colors and other formatting](https://raw.githubusercontent.com/Ellpeck/MLEM/release/Media/Formatting.png)
# Friends of MLEM
There are several other libraries and tools that work well in combination with MonoGame, FNA and MLEM. Here are some of them:
There are several other libraries and tools that work well in combination with MonoGame and MLEM. Here are some of them:
- [Contentless](https://github.com/Ellpeck/Contentless), a tool that removes the need to add assets to the MonoGame Content Pipeline manually
- [GameBundle](https://github.com/Ellpeck/GameBundle), a tool that packages MonoGame and other .NET applications into several distributable formats
- [GameBundle](https://github.com/Ellpeck/GameBundle), a tool that packages MonoGame and other .NET Core applications into several distributable formats
- [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended), a package that also provides several additional features for MonoGame
- [Coroutine](https://github.com/Ellpeck/Coroutine), a package that implements Unity-style coroutines for any project
- [Illumilib](https://github.com/Ellpeck/Illumilib), a simple keyboard and mouse lighting library with support for Razer, Logitech and Corsair devices

1
FNA

@ -1 +0,0 @@
Subproject commit 102990f514f1e5bfac07d33f7c33e2e712946da4

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

5
Jenkinsfile vendored
View file

@ -1,11 +1,6 @@
pipeline {
agent any
stages {
stage('Submodules') {
steps {
sh 'git submodule update --init --recursive --force'
}
}
stage('Cake Build') {
steps {
sh 'dotnet tool restore'

View file

@ -23,4 +23,4 @@ namespace MLEM.Data.Content {
}
}
}
}

View file

@ -7,22 +7,19 @@ using Microsoft.Xna.Framework.Graphics;
namespace MLEM.Data.Content {
/// <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>
public class RawContentManager : ContentManager, IGameComponent {
private static List<RawContentReader> readers;
private readonly List<IDisposable> disposableAssets = new List<IDisposable>();
/// <summary>
/// The graphics device that this content manager uses
/// </summary>
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>
/// Creates a new content manager with an optionally specified root directory.
/// </summary>
@ -53,19 +50,15 @@ namespace MLEM.Data.Content {
/// <param name="originalAssetName">The original name of the asset.</param>
/// <param name="currentAsset">The current asset instance.</param>
/// <typeparam name="T">The asset's type.</typeparam>
protected
#if !FNA
override
#endif
void ReloadAsset<T>(string originalAssetName, T currentAsset) {
protected override void ReloadAsset<T>(string originalAssetName, T currentAsset) {
this.Read(originalAssetName, currentAsset);
}
private T Read<T>(string assetName, T existing) {
var triedFiles = new List<string>();
if (RawContentManager.readers == null)
RawContentManager.readers = RawContentManager.CollectContentReaders();
foreach (var reader in RawContentManager.readers) {
if (readers == null)
readers = CollectContentReaders();
foreach (var reader in readers) {
if (!reader.CanRead(typeof(T)))
continue;
foreach (var ext in reader.GetFileExtensions()) {
@ -132,4 +125,4 @@ namespace MLEM.Data.Content {
}
}
}
}

View file

@ -58,4 +58,4 @@ namespace MLEM.Data.Content {
protected abstract T Read(RawContentManager manager, string assetPath, Stream stream, T existing);
}
}
}

View file

@ -17,4 +17,4 @@ namespace MLEM.Data.Content {
}
}
}
}

View file

@ -12,8 +12,8 @@ namespace MLEM.Data.Content {
/// <inheritdoc />
public override string[] GetFileExtensions() {
return new[] {"wav"};
return new[] {"ogg", "wav", "mp3"};
}
}
}
}

View file

@ -1,7 +1,5 @@
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
namespace MLEM.Data.Content {
/// <inheritdoc />
@ -9,26 +7,11 @@ namespace MLEM.Data.Content {
/// <inheritdoc />
protected override Texture2D Read(RawContentManager manager, string assetPath, Stream stream, Texture2D existing) {
#if !FNA
if (existing != null) {
existing.Reload(stream);
return existing;
} else
#endif
{
// premultiply the texture's color to be in line with the pipeline's texture reader
using (var texture = Texture2D.FromStream(manager.GraphicsDevice, stream)) {
var ret = new Texture2D(manager.GraphicsDevice, texture.Width, texture.Height);
using (var textureData = texture.GetTextureData()) {
using (var retData = ret.GetTextureData()) {
for (var x = 0; x < ret.Width; x++) {
for (var y = 0; y < ret.Height; y++)
retData[x, y] = Color.FromNonPremultiplied(textureData[x, y].ToVector4());
}
}
}
return ret;
}
} else {
return Texture2D.FromStream(manager.GraphicsDevice, stream);
}
}
@ -38,4 +21,4 @@ namespace MLEM.Data.Content {
}
}
}
}

View file

@ -22,4 +22,4 @@ namespace MLEM.Data.Content {
}
}
}
}

View file

@ -21,7 +21,7 @@ namespace MLEM.Data {
/// <param name="content">The content manager to add the json serializer to</param>
/// <param name="serializer">The json serializer to add</param>
public static void SetJsonSerializer(this ContentManager content, JsonSerializer serializer) {
ContentExtensions.Serializers[content] = serializer;
Serializers[content] = serializer;
}
/// <summary>
@ -31,7 +31,7 @@ namespace MLEM.Data {
/// <param name="content">The content manager whose serializer to get</param>
/// <returns>The content manager's serializer</returns>
public static JsonSerializer GetJsonSerializer(this ContentManager content) {
if (!ContentExtensions.Serializers.TryGetValue(content, out var serializer)) {
if (!Serializers.TryGetValue(content, out var serializer)) {
serializer = JsonConverters.AddAll(new JsonSerializer());
content.SetJsonSerializer(serializer);
}
@ -44,7 +44,7 @@ namespace MLEM.Data {
/// <param name="content">The content manager to add the converter to</param>
/// <param name="converter">The converter to add</param>
public static void AddJsonConverter(this ContentManager content, JsonConverter converter) {
var serializer = content.GetJsonSerializer();
var serializer = GetJsonSerializer(content);
serializer.Converters.Add(converter);
}
@ -60,7 +60,7 @@ namespace MLEM.Data {
public static T LoadJson<T>(this ContentManager content, string name, string[] extensions = null, JsonSerializer serializer = null) {
var triedFiles = new List<string>();
var serializerToUse = serializer ?? content.GetJsonSerializer();
foreach (var extension in extensions ?? ContentExtensions.JsonExtensions) {
foreach (var extension in extensions ?? JsonExtensions) {
var file = Path.Combine(content.RootDirectory, name + extension);
triedFiles.Add(file);
try {
@ -74,4 +74,4 @@ namespace MLEM.Data {
}
}
}
}

View file

@ -23,8 +23,8 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the object to copy</typeparam>
/// <returns>A shallow copy of the object</returns>
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public static T Copy<T>(this T obj, BindingFlags flags = CopyExtensions.DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
var copy = (T) CopyExtensions.Construct(typeof(T), flags);
public static T Copy<T>(this T obj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
var copy = (T) Construct(typeof(T), flags);
obj.CopyInto(copy, flags, fieldInclusion);
return copy;
}
@ -39,8 +39,8 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the object to copy</typeparam>
/// <returns>A deep copy of the object</returns>
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public static T DeepCopy<T>(this T obj, BindingFlags flags = CopyExtensions.DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
var copy = (T) CopyExtensions.Construct(typeof(T), flags);
public static T DeepCopy<T>(this T obj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
var copy = (T) Construct(typeof(T), flags);
obj.DeepCopyInto(copy, flags, fieldInclusion);
return copy;
}
@ -54,7 +54,7 @@ namespace MLEM.Data {
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
/// <typeparam name="T">The type of the object to copy</typeparam>
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public static void CopyInto<T>(this T obj, T otherObj, BindingFlags flags = CopyExtensions.DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
public static void CopyInto<T>(this T obj, T otherObj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
foreach (var field in typeof(T).GetFields(flags)) {
if (fieldInclusion == null || fieldInclusion(field))
field.SetValue(otherObj, field.GetValue(obj));
@ -71,7 +71,7 @@ namespace MLEM.Data {
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
/// <typeparam name="T">The type of the object to copy</typeparam>
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public static void DeepCopyInto<T>(this T obj, T otherObj, BindingFlags flags = CopyExtensions.DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
public static void DeepCopyInto<T>(this T obj, T otherObj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
foreach (var field in obj.GetType().GetFields(flags)) {
if (fieldInclusion != null && !fieldInclusion(field))
continue;
@ -83,7 +83,7 @@ namespace MLEM.Data {
var otherVal = field.GetValue(otherObj);
// if the object we want to copy into doesn't have a value yet, we create one
if (otherVal == null) {
otherVal = CopyExtensions.Construct(field.FieldType, flags);
otherVal = Construct(field.FieldType, flags);
field.SetValue(otherObj, otherVal);
}
val.DeepCopyInto(otherVal, flags);
@ -92,7 +92,7 @@ namespace MLEM.Data {
}
private static object Construct(Type t, BindingFlags flags) {
if (!CopyExtensions.ConstructorCache.TryGetValue(t, out var constructor)) {
if (!ConstructorCache.TryGetValue(t, out var constructor)) {
var constructors = t.GetConstructors(flags);
// find a contructor with the correct attribute
constructor = constructors.FirstOrDefault(c => c.GetCustomAttribute<CopyConstructorAttribute>() != null);
@ -104,7 +104,7 @@ namespace MLEM.Data {
constructor = constructors.FirstOrDefault();
if (constructor == null)
throw new NullReferenceException($"Type {t} does not have a constructor with the required visibility");
CopyExtensions.ConstructorCache.Add(t, constructor);
ConstructorCache.Add(t, constructor);
}
return constructor.Invoke(new object[constructor.GetParameters().Length]);
}
@ -116,4 +116,4 @@ namespace MLEM.Data {
/// </summary>
[AttributeUsage(AttributeTargets.Constructor), Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public class CopyConstructorAttribute : Attribute {}
}
}

View file

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@ -6,13 +5,12 @@ using System.Text.RegularExpressions;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MLEM.Textures;
namespace MLEM.Data {
/// <summary>
/// <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"/>.
/// </para>
/// <para>
@ -52,13 +50,9 @@ namespace MLEM.Data {
}
}
/// <summary>
/// Returns an enumerable of all of the <see cref="TextureRegion"/> values in this atlas.
/// Returns an enumerable of all of the <see cref="TextureRegion"/>s in this atlas.
/// </summary>
public IEnumerable<TextureRegion> Regions => this.regions.Values;
/// <summary>
/// Returns an enumerable of all of the <see cref="TextureRegion"/> names in this atlas.
/// </summary>
public IEnumerable<string> RegionNames => this.regions.Keys;
private readonly Dictionary<string, TextureRegion> regions = new Dictionary<string, TextureRegion>();
@ -85,8 +79,9 @@ namespace MLEM.Data {
}
var atlas = new DataTextureAtlas(texture);
// parse each texture region: "<names> loc <u> <v> <w> <h> [piv <px> <py>] [off <ox> <oy>]"
// parse each texture region: "<name> loc <u> <v> <w> <h> [piv <px> <py>] [off <ox> <oy>]"
foreach (Match match in Regex.Matches(text, @"(.+)\W+loc\W+([0-9]+)\W+([0-9]+)\W+([0-9]+)\W+([0-9]+)\W*(?:piv\W+([0-9.]+)\W+([0-9.]+))?\W*(?:off\W+([0-9.]+)\W+([0-9.]+))?")) {
var name = match.Groups[1].Value.Trim();
// offset
var off = !match.Groups[8].Success ? Vector2.Zero : new Vector2(
float.Parse(match.Groups[8].Value, CultureInfo.InvariantCulture),
@ -96,23 +91,18 @@ namespace MLEM.Data {
var loc = new Rectangle(
int.Parse(match.Groups[2].Value), int.Parse(match.Groups[3].Value),
int.Parse(match.Groups[4].Value), int.Parse(match.Groups[5].Value));
loc.Offset(off.ToPoint());
loc.Offset(off);
// pivot
var piv = !match.Groups[6].Success ? Vector2.Zero : off + new Vector2(
float.Parse(match.Groups[6].Value, CultureInfo.InvariantCulture) - (pivotRelative ? 0 : loc.X),
float.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture) - (pivotRelative ? 0 : loc.Y));
foreach (var name in Regex.Split(match.Groups[1].Value, @"\W")) {
var trimmed = name.Trim();
if (trimmed.Length <= 0)
continue;
var region = new TextureRegion(texture, loc) {
PivotPixels = piv,
Name = trimmed
};
atlas.regions.Add(trimmed, region);
}
var region = new TextureRegion(texture, loc) {
PivotPixels = piv,
Name = name
};
atlas.regions.Add(name, region);
}
return atlas;
@ -139,4 +129,4 @@ namespace MLEM.Data {
}
}
}
}

View file

@ -60,7 +60,7 @@ namespace MLEM.Data {
if (this.allFlagsCache == null)
this.allFlagsCache = new Dictionary<DynamicEnum, bool>();
if (!this.allFlagsCache.TryGetValue(flags, out var ret)) {
ret = (DynamicEnum.GetValue(this) & DynamicEnum.GetValue(flags)) == DynamicEnum.GetValue(flags);
ret = (GetValue(this) & GetValue(flags)) == GetValue(flags);
this.allFlagsCache.Add(flags, ret);
}
return ret;
@ -76,7 +76,7 @@ namespace MLEM.Data {
if (this.anyFlagsCache == null)
this.anyFlagsCache = new Dictionary<DynamicEnum, bool>();
if (!this.anyFlagsCache.TryGetValue(flags, out var ret)) {
ret = (DynamicEnum.GetValue(this) & DynamicEnum.GetValue(flags)) != 0;
ret = (GetValue(this) & GetValue(flags)) != 0;
this.anyFlagsCache.Add(flags, ret);
}
return ret;
@ -87,13 +87,13 @@ namespace MLEM.Data {
public override string ToString() {
if (this.name == null) {
var included = new List<DynamicEnum>();
if (DynamicEnum.GetValue(this) != 0) {
foreach (var v in DynamicEnum.GetValues(this.GetType())) {
if (this.HasFlag(v) && DynamicEnum.GetValue(v) != 0)
if (GetValue(this) != 0) {
foreach (var v in GetValues(this.GetType())) {
if (this.HasFlag(v) && GetValue(v) != 0)
included.Add(v);
}
}
this.name = included.Count > 0 ? string.Join(" | ", included) : DynamicEnum.GetValue(this).ToString();
this.name = included.Count > 0 ? string.Join(" | ", included) : GetValue(this).ToString();
}
return this.name;
}
@ -107,7 +107,7 @@ namespace MLEM.Data {
/// <returns>The newly created enum value</returns>
/// <exception cref="ArgumentException">Thrown if the name or value passed are already present</exception>
public static T Add<T>(string name, BigInteger value) where T : DynamicEnum {
var storage = DynamicEnum.GetStorage(typeof(T));
var storage = GetStorage(typeof(T));
// cached parsed values and names might be incomplete with new values
storage.ClearCaches();
@ -119,7 +119,7 @@ namespace MLEM.Data {
throw new ArgumentException($"Duplicate name {name}", nameof(name));
}
var ret = DynamicEnum.Construct(typeof(T), name, value);
var ret = Construct(typeof(T), name, value);
storage.Values.Add(value, ret);
return (T) ret;
}
@ -134,9 +134,9 @@ namespace MLEM.Data {
/// <returns>The newly created enum value</returns>
public static T AddValue<T>(string name) where T : DynamicEnum {
BigInteger value = 0;
while (DynamicEnum.GetStorage(typeof(T)).Values.ContainsKey(value))
while (GetStorage(typeof(T)).Values.ContainsKey(value))
value++;
return DynamicEnum.Add<T>(name, value);
return Add<T>(name, value);
}
/// <summary>
@ -149,9 +149,9 @@ namespace MLEM.Data {
/// <returns>The newly created enum value</returns>
public static T AddFlag<T>(string name) where T : DynamicEnum {
BigInteger value = 1;
while (DynamicEnum.GetStorage(typeof(T)).Values.ContainsKey(value))
while (GetStorage(typeof(T)).Values.ContainsKey(value))
value <<= 1;
return DynamicEnum.Add<T>(name, value);
return Add<T>(name, value);
}
/// <summary>
@ -161,7 +161,7 @@ namespace MLEM.Data {
/// <typeparam name="T">The type whose values to get</typeparam>
/// <returns>The defined values for the given type</returns>
public static IEnumerable<T> GetValues<T>() where T : DynamicEnum {
return DynamicEnum.GetValues(typeof(T)).Cast<T>();
return GetValues(typeof(T)).Cast<T>();
}
/// <summary>
@ -171,7 +171,7 @@ namespace MLEM.Data {
/// <param name="type">The type whose values to get</param>
/// <returns>The defined values for the given type</returns>
public static IEnumerable<DynamicEnum> GetValues(Type type) {
return DynamicEnum.GetStorage(type).Values.Values;
return GetStorage(type).Values.Values;
}
/// <summary>
@ -182,9 +182,9 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the values</typeparam>
/// <returns>The bitwise OR (|) combination</returns>
public static T Or<T>(T left, T right) where T : DynamicEnum {
var cache = DynamicEnum.GetStorage(typeof(T)).OrCache;
var cache = GetStorage(typeof(T)).OrCache;
if (!cache.TryGetValue((left, right), out var ret)) {
ret = DynamicEnum.GetEnumValue<T>(DynamicEnum.GetValue(left) | DynamicEnum.GetValue(right));
ret = GetEnumValue<T>(GetValue(left) | GetValue(right));
cache.Add((left, right), ret);
}
return (T) ret;
@ -198,9 +198,9 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the values</typeparam>
/// <returns>The bitwise AND (&amp;) combination</returns>
public static T And<T>(T left, T right) where T : DynamicEnum {
var cache = DynamicEnum.GetStorage(typeof(T)).AndCache;
var cache = GetStorage(typeof(T)).AndCache;
if (!cache.TryGetValue((left, right), out var ret)) {
ret = DynamicEnum.GetEnumValue<T>(DynamicEnum.GetValue(left) & DynamicEnum.GetValue(right));
ret = GetEnumValue<T>(GetValue(left) & GetValue(right));
cache.Add((left, right), ret);
}
return (T) ret;
@ -214,9 +214,9 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the values</typeparam>
/// <returns>The bitwise XOR (^) combination</returns>
public static T Xor<T>(T left, T right) where T : DynamicEnum {
var cache = DynamicEnum.GetStorage(typeof(T)).XorCache;
var cache = GetStorage(typeof(T)).XorCache;
if (!cache.TryGetValue((left, right), out var ret)) {
ret = DynamicEnum.GetEnumValue<T>(DynamicEnum.GetValue(left) ^ DynamicEnum.GetValue(right));
ret = GetEnumValue<T>(GetValue(left) ^ GetValue(right));
cache.Add((left, right), ret);
}
return (T) ret;
@ -229,9 +229,9 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the values</typeparam>
/// <returns>The bitwise NEG (~) value</returns>
public static T Neg<T>(T value) where T : DynamicEnum {
var cache = DynamicEnum.GetStorage(typeof(T)).NegCache;
var cache = GetStorage(typeof(T)).NegCache;
if (!cache.TryGetValue(value, out var ret)) {
ret = DynamicEnum.GetEnumValue<T>(~DynamicEnum.GetValue(value));
ret = GetEnumValue<T>(~GetValue(value));
cache.Add(value, ret);
}
return (T) ret;
@ -253,7 +253,7 @@ namespace MLEM.Data {
/// <typeparam name="T">The type that the returned dynamic enum should have</typeparam>
/// <returns>The defined or combined dynamic enum value</returns>
public static T GetEnumValue<T>(BigInteger value) where T : DynamicEnum {
return (T) DynamicEnum.GetEnumValue(typeof(T), value);
return (T) GetEnumValue(typeof(T), value);
}
/// <summary>
@ -263,7 +263,7 @@ namespace MLEM.Data {
/// <param name="value">The value whose dynamic enum value to get</param>
/// <returns>The defined or combined dynamic enum value</returns>
public static DynamicEnum GetEnumValue(Type type, BigInteger value) {
var storage = DynamicEnum.GetStorage(type);
var storage = GetStorage(type);
// get the defined value if it exists
if (storage.Values.TryGetValue(value, out var defined))
@ -271,7 +271,7 @@ namespace MLEM.Data {
// otherwise, cache the combined value
if (!storage.FlagCache.TryGetValue(value, out var combined)) {
combined = DynamicEnum.Construct(type, null, value);
combined = Construct(type, null, value);
storage.FlagCache.Add(value, combined);
}
return combined;
@ -286,7 +286,7 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the dynamic enum value to parse</typeparam>
/// <returns>The parsed enum value, or null if parsing fails</returns>
public static T Parse<T>(string strg) where T : DynamicEnum {
return (T) DynamicEnum.Parse(typeof(T), strg);
return (T) Parse(typeof(T), strg);
}
/// <summary>
@ -297,28 +297,28 @@ namespace MLEM.Data {
/// <param name="strg">The string to parse into a dynamic enum value</param>
/// <returns>The parsed enum value, or null if parsing fails</returns>
public static DynamicEnum Parse(Type type, string strg) {
var cache = DynamicEnum.GetStorage(type).ParseCache;
var cache = GetStorage(type).ParseCache;
if (!cache.TryGetValue(strg, out var cached)) {
BigInteger? accum = null;
foreach (var val in strg.Split('|')) {
foreach (var defined in DynamicEnum.GetValues(type)) {
foreach (var defined in GetValues(type)) {
if (defined.name == val.Trim()) {
accum = (accum ?? 0) | DynamicEnum.GetValue(defined);
accum = (accum ?? 0) | GetValue(defined);
break;
}
}
}
if (accum != null)
cached = DynamicEnum.GetEnumValue(type, accum.Value);
cached = GetEnumValue(type, accum.Value);
cache.Add(strg, cached);
}
return cached;
}
private static Storage GetStorage(Type type) {
if (!DynamicEnum.Storages.TryGetValue(type, out var storage)) {
if (!Storages.TryGetValue(type, out var storage)) {
storage = new Storage();
DynamicEnum.Storages.Add(type, storage);
Storages.Add(type, storage);
}
return storage;
}
@ -349,4 +349,4 @@ namespace MLEM.Data {
}
}
}
}

View file

@ -29,4 +29,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -27,4 +27,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -21,10 +21,10 @@ namespace MLEM.Data.Json {
/// <param name="serializer">The serializer to add the converters to</param>
/// <returns>The given serializer, for chaining</returns>
public static JsonSerializer AddAll(JsonSerializer serializer) {
foreach (var converter in JsonConverters.Converters)
foreach (var converter in Converters)
serializer.Converters.Add(converter);
return serializer;
}
}
}
}

View file

@ -42,4 +42,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -60,4 +60,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -30,4 +30,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -34,4 +34,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -34,4 +34,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -29,7 +29,7 @@ namespace MLEM.Data.Json {
/// </summary>
/// <param name="type">The type that the dictionary is declared in</param>
/// <param name="memberName">The name of the dictionary itself</param>
public StaticJsonConverter(Type type, string memberName) : this(StaticJsonConverter<T>.GetEntries(type, memberName)) {}
public StaticJsonConverter(Type type, string memberName) : this(GetEntries(type, memberName)) {}
/// <summary>Writes the JSON representation of the object.</summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param>
@ -65,4 +65,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -30,4 +30,4 @@ namespace MLEM.Data.Json {
}
}
}
}

View file

@ -1,45 +0,0 @@
<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,12 +3,11 @@
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<NoWarn>NU1701</NoWarn>
</PropertyGroup>
<PropertyGroup>
<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 data for MLEM Library for Extending MonoGame</Description>
<PackageReleaseNotes>See the full changelog at https://mlem.ellpeck.de/CHANGELOG</PackageReleaseNotes>
<PackageTags>monogame ellpeck mlem utility extensions data serialize</PackageTags>
<PackageProjectUrl>https://mlem.ellpeck.de/</PackageProjectUrl>
@ -16,11 +15,12 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<NoWarn>NU1701</NoWarn>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MLEM\MLEM.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>
@ -35,9 +35,9 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
</ItemGroup>
</Project>
</Project>

View file

@ -100,4 +100,4 @@ namespace MLEM.Data {
}
}
}
}

View file

@ -117,4 +117,4 @@ namespace MLEM.Data {
}
}
}
}

View file

@ -6,7 +6,6 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MLEM.Textures;
using static MLEM.Extensions.TextureExtensions;
namespace MLEM.Data {
/// <summary>
@ -34,10 +33,7 @@ namespace MLEM.Data {
/// </summary>
public TimeSpan LastTotalTime => this.LastCalculationTime + this.LastPackTime;
private readonly List<Request> texturesToPack = new List<Request>();
private readonly List<Request> alreadyPackedTextures = new List<Request>();
private readonly Dictionary<Point, Point> firstPossiblePosForSizeCache = new Dictionary<Point, Point>();
private readonly Dictionary<Texture2D, TextureData> dataCache = new Dictionary<Texture2D, TextureData>();
private readonly List<Request> textures = new List<Request>();
private readonly bool autoIncreaseMaxWidth;
private readonly bool forcePowerOfTwo;
private readonly bool forceSquare;
@ -46,13 +42,13 @@ namespace MLEM.Data {
private int maxWidth;
/// <summary>
/// Creates a new runtime texture packer with the given settings.
/// Creates a new runtime texture packer with the given settings
/// </summary>
/// <param name="maxWidth">The maximum width that the packed texture can have. Defaults to 2048.</param>
/// <param name="autoIncreaseMaxWidth">Whether the maximum width should be increased if there is a texture to be packed that is wider than <see cref="maxWidth"/>. Defaults to false.</param>
/// <param name="forcePowerOfTwo">Whether the resulting <see cref="PackedTexture"/> should have a width and height that is a power of two.</param>
/// <param name="forceSquare">Whether the resulting <see cref="PackedTexture"/> should be square regardless of required size.</param>
/// <param name="disposeTextures">Whether the original textures submitted to this texture packer should be disposed after packing.</param>
/// <param name="forcePowerOfTwo">Whether the resulting <see cref="PackedTexture"/> should have a width and height that is a power of two</param>
/// <param name="forceSquare">Whether the resulting <see cref="PackedTexture"/> should be square regardless of required size</param>
/// <param name="disposeTextures">Whether the original textures submitted to this texture packer should be disposed after packing</param>
public RuntimeTexturePacker(int maxWidth = 2048, bool autoIncreaseMaxWidth = false, bool forcePowerOfTwo = false, bool forceSquare = false, bool disposeTextures = false) {
this.maxWidth = maxWidth;
this.autoIncreaseMaxWidth = autoIncreaseMaxWidth;
@ -62,99 +58,37 @@ namespace MLEM.Data {
}
/// <summary>
/// Adds a new <see cref="UniformTextureAtlas"/> to this texture packer to be packed.
/// The passed <see cref="Action{T}"/> is invoked in <see cref="Pack"/> and provides the caller with the resulting dictionary of texture regions on the <see cref="PackedTexture"/>, mapped to their x and y positions on the original <see cref="UniformTextureAtlas"/>.
/// Note that the resulting data cannot be converted back into a <see cref="UniformTextureAtlas"/>, since the resulting texture regions might be scattered throughout the <see cref="PackedTexture"/>.
/// </summary>
/// <param name="atlas">The texture atlas to pack.</param>
/// <param name="result">The result callback which will receive the resulting texture regions.</param>
/// <param name="padding">The padding that the texture should have around itself. This can be useful if texture bleeding issues occur due to texture coordinate rounding.</param>
/// <param name="padWithPixels">Whether the texture's padding should be filled with a copy of the texture's border, rather than transparent pixels. This value only has an effect if <paramref name="padding"/> is greater than 0.</param>
/// <param name="ignoreTransparent">Whether completely transparent texture regions in the <paramref name="atlas"/> should be ignored. If this is true, they will not be part of the <paramref name="result"/> collection either.</param>
/// <exception cref="InvalidOperationException">Thrown when trying to add data to a packer that has already been packed, or when trying to add a texture width a width greater than the defined max width.</exception>
public void Add(UniformTextureAtlas atlas, Action<Dictionary<Point, TextureRegion>> result, int padding = 0, bool padWithPixels = false, bool ignoreTransparent = false) {
var addedRegions = new List<TextureRegion>();
var resultRegions = new Dictionary<Point, TextureRegion>();
for (var x = 0; x < atlas.RegionAmountX; x++) {
for (var y = 0; y < atlas.RegionAmountY; y++) {
var pos = new Point(x, y);
var region = atlas[pos];
if (ignoreTransparent) {
if (this.IsTransparent(region))
continue;
}
this.Add(region, r => {
resultRegions.Add(pos, r);
if (resultRegions.Count >= addedRegions.Count)
result.Invoke(resultRegions);
}, padding, padWithPixels);
addedRegions.Add(region);
}
}
}
/// <summary>
/// Adds a new <see cref="DataTextureAtlas"/> to this texture packer to be packed.
/// The passed <see cref="Action{T}"/> is invoked in <see cref="Pack"/> and provides the caller with the resulting dictionary of texture regions on the <see cref="PackedTexture"/>, mapped to their name on the original <see cref="DataTextureAtlas"/>.
/// Note that the resulting data cannot be converted back into a <see cref="DataTextureAtlas"/>, since the resulting texture regions might be scattered throughout the <see cref="PackedTexture"/>.
/// </summary>
/// <param name="atlas">The texture atlas to pack.</param>
/// <param name="result">The result callback which will receive the resulting texture regions.</param>
/// <param name="padding">The padding that the texture should have around itself. This can be useful if texture bleeding issues occur due to texture coordinate rounding.</param>
/// <param name="padWithPixels">Whether the texture's padding should be filled with a copy of the texture's border, rather than transparent pixels. This value only has an effect if <paramref name="padding"/> is greater than 0.</param>
/// <exception cref="InvalidOperationException">Thrown when trying to add data to a packer that has already been packed, or when trying to add a texture width a width greater than the defined max width.</exception>
public void Add(DataTextureAtlas atlas, Action<Dictionary<string, TextureRegion>> result, int padding = 0, bool padWithPixels = false) {
var atlasRegions = atlas.RegionNames.ToArray();
var resultRegions = new Dictionary<string, TextureRegion>();
foreach (var region in atlasRegions) {
this.Add(atlas[region], r => {
resultRegions.Add(region, r);
if (resultRegions.Count >= atlasRegions.Length)
result.Invoke(resultRegions);
}, padding, padWithPixels);
}
}
/// <summary>
/// Adds a new <see cref="Texture2D"/> to this texture packer to be packed.
/// Adds a new texture to this texture packer to be packed.
/// The passed <see cref="Action{T}"/> is invoked in <see cref="Pack"/> and provides the caller with the resulting texture region on the <see cref="PackedTexture"/>.
/// </summary>
/// <param name="texture">The texture to pack.</param>
/// <param name="result">The result callback which will receive the resulting texture region.</param>
/// <param name="padding">The padding that the texture should have around itself. This can be useful if texture bleeding issues occur due to texture coordinate rounding.</param>
/// <param name="padWithPixels">Whether the texture's padding should be filled with a copy of the texture's border, rather than transparent pixels. This value only has an effect if <paramref name="padding"/> is greater than 0.</param>
/// <exception cref="InvalidOperationException">Thrown when trying to add data to a packer that has already been packed, or when trying to add a texture width a width greater than the defined max width.</exception>
public void Add(Texture2D texture, Action<TextureRegion> result, int padding = 0, bool padWithPixels = false) {
this.Add(new TextureRegion(texture), result, padding, padWithPixels);
/// <param name="texture">The texture to pack</param>
/// <param name="result">The result callback which will receive the resulting texture region</param>
public void Add(Texture2D texture, Action<TextureRegion> result) {
this.Add(new TextureRegion(texture), result);
}
/// <summary>
/// Adds a new <see cref="TextureRegion"/> to this texture packer to be packed.
/// The passed <see cref="Action{T}"/> is invoked in <see cref="Pack"/> and provides the caller with the resulting texture region on the <see cref="PackedTexture"/>.
/// </summary>
/// <param name="texture">The texture region to pack.</param>
/// <param name="result">The result callback which will receive the resulting texture region.</param>
/// <param name="padding">The padding that the texture should have around itself. This can be useful if texture bleeding issues occur due to texture coordinate rounding.</param>
/// <param name="padWithPixels">Whether the texture's padding should be filled with a copy of the texture's border, rather than transparent pixels. This value only has an effect if <paramref name="padding"/> is greater than 0.</param>
/// <exception cref="InvalidOperationException">Thrown when trying to add data to a packer that has already been packed, or when trying to add a texture width a width greater than the defined max width.</exception>
public void Add(TextureRegion texture, Action<TextureRegion> result, int padding = 0, bool padWithPixels = false) {
/// <param name="texture">The texture to pack</param>
/// <param name="result">The result callback which will receive the resulting texture region</param>
/// <exception cref="InvalidOperationException">Thrown when trying to add data to a packer that has already been packed, or when trying to add a texture width a width greater than the defined max width</exception>
public void Add(TextureRegion texture, Action<TextureRegion> result) {
if (this.PackedTexture != null)
throw new InvalidOperationException("Cannot add texture to a texture packer that is already packed");
var paddedWidth = texture.Width + 2 * padding;
if (paddedWidth > this.maxWidth) {
if (texture.Width > this.maxWidth) {
if (this.autoIncreaseMaxWidth) {
this.maxWidth = paddedWidth;
this.maxWidth = texture.Width;
} else {
throw new InvalidOperationException($"Cannot add texture with width {texture.Width} to a texture packer with max width {this.maxWidth}");
}
}
this.texturesToPack.Add(new Request(texture, result, padding, padWithPixels));
this.textures.Add(new Request(texture, result));
}
/// <summary>
/// Packs all of the textures and texture regions added using <see cref="Add(Microsoft.Xna.Framework.Graphics.Texture2D,System.Action{MLEM.Textures.TextureRegion},int,bool)"/> into one texture.
/// Packs all of the textures and texture regions added using <see cref="Add(Microsoft.Xna.Framework.Graphics.Texture2D,System.Action{MLEM.Textures.TextureRegion})"/> into one texture.
/// The resulting texture will be stored in <see cref="PackedTexture"/>.
/// All of the result callbacks that were added will also be invoked.
/// </summary>
@ -165,23 +99,20 @@ namespace MLEM.Data {
throw new InvalidOperationException("Cannot pack a texture packer that is already packed");
// set pack areas for each request
// we pack larger textures first, so that smaller textures can fit in the gaps that larger ones leave
var stopwatch = Stopwatch.StartNew();
foreach (var request in this.texturesToPack.OrderByDescending(t => t.Texture.Width * t.Texture.Height)) {
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
this.firstPossiblePosForSizeCache[new Point(request.PackedArea.Width, request.PackedArea.Height)] = request.PackedArea.Location;
this.alreadyPackedTextures.Add(request);
foreach (var request in this.textures.OrderByDescending(t => t.Texture.Width * t.Texture.Height)) {
var area = this.FindFreeArea(new Point(request.Texture.Width, request.Texture.Height));
request.PackedArea = area;
}
stopwatch.Stop();
this.LastCalculationTime = stopwatch.Elapsed;
// figure out texture size and generate texture
var width = this.alreadyPackedTextures.Max(t => t.PackedArea.Right);
var height = this.alreadyPackedTextures.Max(t => t.PackedArea.Bottom);
var width = this.textures.Max(t => t.PackedArea.Right);
var height = this.textures.Max(t => t.PackedArea.Bottom);
if (this.forcePowerOfTwo) {
width = RuntimeTexturePacker.ToPowerOfTwo(width);
height = RuntimeTexturePacker.ToPowerOfTwo(height);
width = ToPowerOfTwo(width);
height = ToPowerOfTwo(height);
}
if (this.forceSquare)
width = height = Math.Max(width, height);
@ -190,21 +121,20 @@ namespace MLEM.Data {
// copy texture data onto the packed texture
stopwatch.Restart();
using (var data = this.PackedTexture.GetTextureData()) {
foreach (var request in this.alreadyPackedTextures)
this.CopyRegion(data, request);
foreach (var request in this.textures)
CopyRegion(data, request);
}
stopwatch.Stop();
this.LastPackTime = stopwatch.Elapsed;
// invoke callbacks
foreach (var request in this.alreadyPackedTextures) {
var packedArea = request.PackedArea.Shrink(new Point(request.Padding, request.Padding));
request.Result.Invoke(new TextureRegion(this.PackedTexture, packedArea));
foreach (var request in this.textures) {
request.Result.Invoke(new TextureRegion(this.PackedTexture, request.PackedArea));
if (this.disposeTextures)
request.Texture.Texture.Dispose();
}
this.ClearTempCollections();
this.textures.Clear();
}
/// <summary>
@ -213,9 +143,9 @@ namespace MLEM.Data {
public void Reset() {
this.PackedTexture?.Dispose();
this.PackedTexture = null;
this.textures.Clear();
this.LastCalculationTime = TimeSpan.Zero;
this.LastPackTime = TimeSpan.Zero;
this.ClearTempCollections();
}
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
@ -223,17 +153,13 @@ namespace MLEM.Data {
this.Reset();
}
private Rectangle FindFreeArea(Request request) {
var size = new Point(request.Texture.Width, request.Texture.Height);
size.X += request.Padding * 2;
size.Y += request.Padding * 2;
var pos = this.firstPossiblePosForSizeCache.TryGetValue(size, out var first) ? first : Point.Zero;
private Rectangle FindFreeArea(Point size) {
var pos = new Point(0, 0);
var lowestY = int.MaxValue;
while (true) {
var intersected = false;
var area = new Rectangle(pos.X, pos.Y, size.X, size.Y);
foreach (var tex in this.alreadyPackedTextures) {
var area = new Rectangle(pos, size);
foreach (var tex in this.textures) {
if (tex.PackedArea.Intersects(area)) {
pos.X = tex.PackedArea.Right;
// when we move down, we want to move down by the smallest intersecting texture's height
@ -253,53 +179,18 @@ namespace MLEM.Data {
}
}
private void CopyRegion(TextureData destination, Request request) {
var data = this.GetCachedTextureData(request.Texture.Texture);
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 y = -request.Padding; y < request.Texture.Height + request.Padding; y++) {
Color srcColor;
if (!request.PadWithPixels && (x < 0 || y < 0 || x >= request.Texture.Width || y >= request.Texture.Height)) {
// if we're out of bounds and not padding with pixels, we make it transparent
srcColor = Color.Transparent;
} else {
// otherwise, we just use the closest pixel that is actually in bounds, causing the border pixels to be doubled up
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];
private static void CopyRegion(TextureExtensions.TextureData destination, Request request) {
using (var data = request.Texture.Texture.GetTextureData()) {
for (var x = 0; x < request.Texture.Width; x++) {
for (var y = 0; y < request.Texture.Height; y++) {
var dest = request.PackedArea.Location + new Point(x, y);
var src = request.Texture.Position + new Point(x, y);
destination[dest] = data[src];
}
destination[location + new Point(x, y)] = srcColor;
}
}
}
private TextureData GetCachedTextureData(Texture2D texture) {
// we cache texture data in case multiple requests use the same underlying texture
// this collection doesn't need to be disposed since we don't actually edit these textures
if (!this.dataCache.TryGetValue(texture, out var data)) {
data = texture.GetTextureData();
this.dataCache.Add(texture, data);
}
return data;
}
private bool IsTransparent(TextureRegion region) {
var data = this.GetCachedTextureData(region.Texture);
for (var rX = 0; rX < region.Width; rX++) {
for (var rY = 0; rY < region.Height; rY++) {
if (data[region.U + rX, region.V + rY] != Color.Transparent)
return false;
}
}
return true;
}
private void ClearTempCollections() {
this.texturesToPack.Clear();
this.alreadyPackedTextures.Clear();
this.firstPossiblePosForSizeCache.Clear();
this.dataCache.Clear();
}
private static int ToPowerOfTwo(int value) {
var ret = 1;
while (ret < value)
@ -311,18 +202,14 @@ namespace MLEM.Data {
public readonly TextureRegion Texture;
public readonly Action<TextureRegion> Result;
public readonly int Padding;
public readonly bool PadWithPixels;
public Rectangle PackedArea;
public Request(TextureRegion texture, Action<TextureRegion> result, int padding, bool padWithPixels) {
public Request(TextureRegion texture, Action<TextureRegion> result) {
this.Texture = texture;
this.Result = result;
this.Padding = padding;
this.PadWithPixels = padWithPixels;
}
}
}
}
}

View file

@ -41,4 +41,4 @@ namespace MLEM.Extended.Extensions {
}
}
}
}

View file

@ -40,4 +40,4 @@ namespace MLEM.Extended.Extensions {
}
}
}
}

View file

@ -62,4 +62,4 @@ namespace MLEM.Extended.Extensions {
}
}
}
}

View file

@ -45,4 +45,4 @@ namespace MLEM.Extended.Extensions {
}
}
}
}

View file

@ -43,4 +43,4 @@ namespace MLEM.Extended.Font {
}
}
}
}

View file

@ -43,4 +43,4 @@ namespace MLEM.Extended.Font {
}
}
}
}

View file

@ -1,41 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<RootNamespace>MLEM.Extended</RootNamespace>
<DefineConstants>$(DefineConstants);FNA</DefineConstants>
</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.Core.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">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FontStashSharp.MonoGame" Version="1.1.6">
<PackageReference Include="FontStashSharp.MonoGame" Version="1.0.4">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">

View file

@ -4,7 +4,6 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Cameras;
using MLEM.Extensions;
using MLEM.Graphics;
using MLEM.Misc;
using MonoGame.Extended.Tiled;
using RectangleF = MonoGame.Extended.RectangleF;
@ -93,20 +92,6 @@ namespace MLEM.Extended.Tiled {
}
}
/// <summary>
/// Adds this individual tiled map renderer to the given <see cref="StaticSpriteBatch"/>.
/// Optionally, a frustum can be supplied that determines which positions, in pixel space, are visible at this time. <see cref="Camera"/> provides <see cref="Camera.GetVisibleRectangle"/> for this purpose.
/// </summary>
/// <param name="batch">The static sprite batch to use for drawing.</param>
/// <param name="frustum">The area that is visible, in pixel space.</param>
/// <param name="addFunction">The add function to use, or null to use <see cref="DefaultAdd"/>.</param>
public void Add(StaticSpriteBatch batch, RectangleF? frustum = null, AddDelegate addFunction = null) {
for (var i = 0; i < this.map.TileLayers.Count; i++) {
if (this.map.TileLayers[i].IsVisible)
this.AddLayer(batch, i, frustum, addFunction);
}
}
/// <summary>
/// Draws the given layer of this individual tiled map renderer.
/// Optionally, a frustum can be supplied that determines which positions, in pixel space, are visible at this time. <see cref="Camera"/> provides <see cref="Camera.GetVisibleRectangle"/> for this purpose.
@ -116,8 +101,12 @@ namespace MLEM.Extended.Tiled {
/// <param name="frustum">The area that is visible, in pixel space.</param>
/// <param name="drawFunction">The draw function to use, or null to use <see cref="DefaultDraw"/></param>
public void DrawLayer(SpriteBatch batch, int layerIndex, RectangleF? frustum = null, DrawDelegate drawFunction = null) {
var draw = drawFunction ?? IndividualTiledMapRenderer.DefaultDraw;
var (minX, minY, maxX, maxY) = this.GetFrustum(frustum);
var draw = drawFunction ?? DefaultDraw;
var frust = frustum ?? new RectangleF(0, 0, float.MaxValue, float.MaxValue);
var minX = Math.Max(0, frust.Left / this.map.TileWidth).Floor();
var minY = Math.Max(0, frust.Top / this.map.TileHeight).Floor();
var maxX = Math.Min(this.map.Width, frust.Right / this.map.TileWidth).Ceil();
var maxY = Math.Min(this.map.Height, frust.Bottom / this.map.TileHeight).Ceil();
for (var x = minX; x < maxX; x++) {
for (var y = minY; y < maxY; y++) {
var info = this.drawInfos[layerIndex, x, y];
@ -127,26 +116,6 @@ namespace MLEM.Extended.Tiled {
}
}
/// <summary>
/// Adds the given layer of this individual tiled map renderer to the given <see cref="StaticSpriteBatch"/>.
/// Optionally, a frustum can be supplied that determines which positions, in pixel space, are visible at this time. <see cref="Camera"/> provides <see cref="Camera.GetVisibleRectangle"/> for this purpose.
/// </summary>
/// <param name="batch">The static sprite batch to use for drawing.</param>
/// <param name="layerIndex">The index of the layer in <see cref="TiledMap.TileLayers"/>.</param>
/// <param name="frustum">The area that is visible, in pixel space.</param>
/// <param name="addFunction">The add function to use, or null to use <see cref="DefaultAdd"/>.</param>
public void AddLayer(StaticSpriteBatch batch, int layerIndex, RectangleF? frustum = null, AddDelegate addFunction = null) {
var add = addFunction ?? IndividualTiledMapRenderer.DefaultAdd;
var (minX, minY, maxX, maxY) = this.GetFrustum(frustum);
for (var x = minX; x < maxX; x++) {
for (var y = minY; y < maxY; y++) {
var info = this.drawInfos[layerIndex, x, y];
if (info != null)
add(batch, info);
}
}
}
/// <summary>
/// Update all of the animated tiles in this individual tiled map renderer
/// </summary>
@ -156,17 +125,8 @@ namespace MLEM.Extended.Tiled {
animation.Update(time);
}
private (int MinX, int MinY, int MaxX, int MaxY) GetFrustum(RectangleF? frustum) {
var frust = frustum ?? new RectangleF(0, 0, float.MaxValue, float.MaxValue);
var minX = Math.Max(0, frust.Left / this.map.TileWidth).Floor();
var minY = Math.Max(0, frust.Top / this.map.TileHeight).Floor();
var maxX = Math.Min(this.map.Width, frust.Right / this.map.TileWidth).Ceil();
var maxY = Math.Min(this.map.Height, frust.Bottom / this.map.TileHeight).Ceil();
return (minX, minY, maxX, maxY);
}
/// <summary>
/// The default implementation of <see cref="DrawDelegate"/> that is used by <see cref="Draw"/> if no custom draw function is passed.
/// The default implementation of <see cref="DrawDelegate"/> that is used by <see cref="SetMap"/> if no custom draw function is passed
/// </summary>
/// <param name="batch">The sprite batch to use for drawing</param>
/// <param name="info">The <see cref="TileDrawInfo"/> to draw</param>
@ -177,18 +137,6 @@ namespace MLEM.Extended.Tiled {
batch.Draw(info.Tileset.Texture, drawPos, region, Color.White, 0, Vector2.Zero, 1, effects, info.Depth);
}
/// <summary>
/// The default implementation of <see cref="AddDelegate"/> that is used by <see cref="Add"/> if no custom add function is passed.
/// </summary>
/// <param name="batch">The static sprite batch to use for drawing.</param>
/// <param name="info">The <see cref="TileDrawInfo"/> to add.</param>
public static void DefaultAdd(StaticSpriteBatch batch, TileDrawInfo info) {
var region = info.Tileset.GetTextureRegion(info.TilesetTile);
var effects = info.Tile.GetSpriteEffects();
var drawPos = new Vector2(info.Position.X * info.Renderer.map.TileWidth, info.Position.Y * info.Renderer.map.TileHeight);
batch.Add(info.Tileset.Texture, drawPos, region, Color.White, 0, Vector2.Zero, 1, effects, info.Depth);
}
/// <summary>
/// A delegate method used for <see cref="IndividualTiledMapRenderer.depthFunction"/>.
/// The idea is to return a depth (between 0 and 1) for the given tile that determines where in the sprite batch it should be rendererd.
@ -207,13 +155,6 @@ namespace MLEM.Extended.Tiled {
/// <param name="info">The <see cref="TileDrawInfo"/> to draw</param>
public delegate void DrawDelegate(SpriteBatch batch, TileDrawInfo info);
/// <summary>
/// A delegate method used for adding an <see cref="IndividualTiledMapRenderer"/> to a <see cref="StaticSpriteBatch"/>.
/// </summary>
/// <param name="batch">The static sprite batch to use for drawing.</param>
/// <param name="info">The <see cref="TileDrawInfo"/> to add.</param>
public delegate void AddDelegate(StaticSpriteBatch batch, TileDrawInfo info);
/// <summary>
/// A tile draw info contains information about a tile at a given map location.
/// It caches a lot of data that is required for drawing a tile efficiently.
@ -257,4 +198,4 @@ namespace MLEM.Extended.Tiled {
}
}
}
}

View file

@ -4,8 +4,7 @@ using MonoGame.Extended.Tiled;
namespace MLEM.Extended.Tiled {
/// <summary>
/// A struct that represents a position on a <see cref="TiledMap"/> with multiple layers, where the <see cref="X"/> and <see cref="Y"/> coordinates are 32-bit integer numbers.
/// See <see cref="LayerPositionF"/> for a floating point position.
/// A struct that represents a position on a <see cref="TiledMap"/> with multiple layers.
/// </summary>
[DataContract]
public struct LayerPosition : IEquatable<LayerPosition> {
@ -54,8 +53,8 @@ namespace MLEM.Extended.Tiled {
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode() {
var hashCode = this.Layer.GetHashCode();
hashCode = hashCode * 397 ^ this.X;
hashCode = hashCode * 397 ^ this.Y;
hashCode = (hashCode * 397) ^ this.X;
hashCode = (hashCode * 397) ^ this.Y;
return hashCode;
}
@ -105,7 +104,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="right">The right position.</param>
/// <returns>The sum of the positions.</returns>
public static LayerPosition operator +(LayerPosition left, LayerPosition right) {
return LayerPosition.Add(left, right);
return Add(left, right);
}
/// <summary>
@ -115,17 +114,8 @@ namespace MLEM.Extended.Tiled {
/// <param name="right">The right position.</param>
/// <returns>The difference of the positions.</returns>
public static LayerPosition operator -(LayerPosition left, LayerPosition right) {
return LayerPosition.Add(left, -right);
}
/// <summary>
/// Implicitly converts a <see cref="LayerPosition"/> to a <see cref="LayerPositionF"/>.
/// </summary>
/// <param name="position">The position to convert.</param>
/// <returns>The converted position.</returns>
public static implicit operator LayerPositionF(LayerPosition position) {
return new LayerPositionF(position.Layer, position.X, position.Y);
return Add(left, -right);
}
}
}
}

View file

@ -1,132 +0,0 @@
using System;
using System.Runtime.Serialization;
using MonoGame.Extended.Tiled;
namespace MLEM.Extended.Tiled {
/// <summary>
/// A struct that represents a position on a <see cref="TiledMap"/> with multiple layers, where the <see cref="X"/> and <see cref="Y"/> coordinates are 32-bit floating point numbers.
/// See <see cref="LayerPosition"/> for an integer position.
/// </summary>
[DataContract]
public struct LayerPositionF : IEquatable<LayerPositionF> {
/// <summary>
/// The name of the layer that this position is on
/// </summary>
[DataMember]
public string Layer;
/// <summary>
/// The x coordinate of this position
/// </summary>
[DataMember]
public float X;
/// <summary>
/// The y coordinate of this position
/// </summary>
[DataMember]
public float Y;
/// <summary>
/// Creates a new layer position with the given settings
/// </summary>
/// <param name="layerName">The layer name</param>
/// <param name="x">The x coordinate</param>
/// <param name="y">The y coordinate</param>
public LayerPositionF(string layerName, float x, float y) {
this.Layer = layerName;
this.X = x;
this.Y = y;
}
/// <inheritdoc cref="Equals(object)"/>
public bool Equals(LayerPositionF other) {
return this.Layer == other.Layer && this.X == other.X && this.Y == other.Y;
}
/// <summary>Indicates whether this instance and a specified object are equal.</summary>
/// <param name="obj">The object to compare with the current instance.</param>
/// <returns>true if <paramref name="obj">obj</paramref> and this instance are the same type and represent the same value; otherwise, false.</returns>
public override bool Equals(object obj) {
return obj is LayerPositionF other && this.Equals(other);
}
/// <summary>Returns the hash code for this instance.</summary>
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode() {
var hashCode = this.Layer.GetHashCode();
hashCode = hashCode * 397 ^ this.X.GetHashCode();
hashCode = hashCode * 397 ^ this.Y.GetHashCode();
return hashCode;
}
/// <summary>Returns the fully qualified type name of this instance.</summary>
/// <returns>The fully qualified type name.</returns>
public override string ToString() {
return $"{nameof(this.Layer)}: {this.Layer}, {nameof(this.X)}: {this.X}, {nameof(this.Y)}: {this.Y}";
}
/// <summary>
/// Adds the given layer positions together, returning a new layer position with the sum of their coordinates.
/// If the two layer positions' <see cref="Layer"/> differ, an <see cref="ArgumentException"/> is thrown.
/// </summary>
/// <param name="left">The left position.</param>
/// <param name="right">The right position.</param>
/// <returns>The sum of the positions.</returns>
/// <exception cref="ArgumentException">Thrown if the two positions' <see cref="Layer"/> are not the same.</exception>
public static LayerPositionF Add(LayerPositionF left, LayerPositionF right) {
if (left.Layer != right.Layer)
throw new ArgumentException("Cannot add layer positions on different layers");
return new LayerPositionF(left.Layer, left.X + right.X, left.Y + right.Y);
}
/// <inheritdoc cref="Equals(LayerPositionF)"/>
public static bool operator ==(LayerPositionF left, LayerPositionF right) {
return left.Equals(right);
}
/// <inheritdoc cref="Equals(LayerPositionF)"/>
public static bool operator !=(LayerPositionF left, LayerPositionF right) {
return !left.Equals(right);
}
/// <summary>
/// Returns the negative of the given layer position.
/// </summary>
/// <param name="position">The position to negate.</param>
/// <returns>The negative position.</returns>
public static LayerPositionF operator -(LayerPositionF position) {
return new LayerPositionF(position.Layer, -position.X, -position.Y);
}
/// <summary>
/// Returns the sum of the two layer positions using <see cref="Add"/>.
/// </summary>
/// <param name="left">The left position.</param>
/// <param name="right">The right position.</param>
/// <returns>The sum of the positions.</returns>
public static LayerPositionF operator +(LayerPositionF left, LayerPositionF right) {
return LayerPositionF.Add(left, right);
}
/// <summary>
/// Subtracts the second from the first position using <see cref="Add"/>.
/// </summary>
/// <param name="left">The left position.</param>
/// <param name="right">The right position.</param>
/// <returns>The difference of the positions.</returns>
public static LayerPositionF operator -(LayerPositionF left, LayerPositionF right) {
return LayerPositionF.Add(left, -right);
}
/// <summary>
/// Implicitly converts a <see cref="LayerPositionF"/> to a <see cref="LayerPosition"/>.
/// The coordinates are typecast to 32-bit integers in the process.
/// </summary>
/// <param name="position">The position to convert.</param>
/// <returns>The converted position.</returns>
public static implicit operator LayerPosition(LayerPositionF position) {
return new LayerPosition(position.Layer, (int) position.X, (int) position.Y);
}
}
}

View file

@ -5,6 +5,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended;
using MonoGame.Extended.Tiled;
using static MonoGame.Extended.Tiled.TiledMapTileFlipFlags;
using ColorHelper = MLEM.Extensions.ColorHelper;
namespace MLEM.Extended.Tiled {
@ -143,9 +144,9 @@ namespace MLEM.Extended.Tiled {
public static TiledMapTilesetTile GetTilesetTile(this TiledMapTileset tileset, int localId, bool createStub = true) {
var tilesetTile = tileset.Tiles.FirstOrDefault(t => t.LocalTileIdentifier == localId);
if (tilesetTile == null && createStub) {
if (!TiledExtensions.StubTilesetTiles.TryGetValue(localId, out tilesetTile)) {
if (!StubTilesetTiles.TryGetValue(localId, out tilesetTile)) {
tilesetTile = new TiledMapTilesetTile(localId);
TiledExtensions.StubTilesetTiles.Add(localId, tilesetTile);
StubTilesetTiles.Add(localId, tilesetTile);
}
}
return tilesetTile;
@ -270,12 +271,12 @@ namespace MLEM.Extended.Tiled {
/// <param name="position">The position to add to the object's position</param>
/// <param name="flipFlags">The flipping of the tile that this object belongs to. If set, the returned area will be "flipped" in the tile's space so that it matches the flip flags.</param>
/// <returns>The area that the tile covers</returns>
public static RectangleF GetArea(this TiledMapObject obj, TiledMap map, Vector2? position = null, TiledMapTileFlipFlags flipFlags = TiledMapTileFlipFlags.None) {
public static RectangleF GetArea(this TiledMapObject obj, TiledMap map, Vector2? position = null, TiledMapTileFlipFlags flipFlags = None) {
var tileSize = map.GetTileSize();
var area = new RectangleF(obj.Position / tileSize, obj.Size / tileSize);
if (flipFlags.HasFlag(TiledMapTileFlipFlags.FlipHorizontally))
if (flipFlags.HasFlag(FlipHorizontally))
area.X = 1 - area.X - area.Width;
if (flipFlags.HasFlag(TiledMapTileFlipFlags.FlipVertically))
if (flipFlags.HasFlag(FlipVertically))
area.Y = 1 - area.Y - area.Height;
if (position != null)
area.Offset(position.Value);
@ -360,4 +361,4 @@ namespace MLEM.Extended.Tiled {
}
}
}
}

View file

@ -36,7 +36,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="collisionFunction">The function used to collect the collision info of a tile, or null to use <see cref="DefaultCollectCollisions"/></param>
public void SetMap(TiledMap map, CollectCollisions collisionFunction = null) {
this.map = map;
this.collisionFunction = collisionFunction ?? TiledMapCollisions.DefaultCollectCollisions;
this.collisionFunction = collisionFunction ?? DefaultCollectCollisions;
this.collisionInfos = new TileCollisionInfo[map.Layers.Count, map.Width, map.Height];
for (var i = 0; i < map.TileLayers.Count; i++) {
for (var x = 0; x < map.Width; x++) {
@ -204,4 +204,4 @@ namespace MLEM.Extended.Tiled {
}
}
}
}

View file

@ -1,70 +0,0 @@

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}") = "FNA.Core", "FNA\FNA.Core.csproj", "{06459F72-CEAA-4B45-B2B1-708FC28D04F8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FontStashSharp.FNA.Core", "FontStashSharp\src\XNA\FontStashSharp.FNA.Core.csproj", "{0B410591-3AED-4C82-A07A-516FF493709B}"
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
{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
{0B410591-3AED-4C82-A07A-516FF493709B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B410591-3AED-4C82-A07A-516FF493709B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B410591-3AED-4C82-A07A-516FF493709B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B410591-3AED-4C82-A07A-516FF493709B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View file

@ -24,4 +24,4 @@ namespace MLEM.Startup {
public static readonly Event Draw = new Event();
}
}
}

View file

@ -1,37 +0,0 @@
<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

@ -18,7 +18,7 @@ namespace MLEM.Startup {
/// <summary>
/// The static game instance's input handler
/// </summary>
public static InputHandler Input => MlemGame.instance.InputHandler;
public static InputHandler Input => instance.InputHandler;
/// <summary>
/// This game's graphics device manager, initialized in the constructor
@ -64,14 +64,12 @@ namespace MLEM.Startup {
/// <param name="windowWidth">The default window width</param>
/// <param name="windowHeight">The default window height</param>
public MlemGame(int windowWidth = 1280, int windowHeight = 720) {
MlemGame.instance = this;
instance = this;
this.GraphicsDeviceManager = new GraphicsDeviceManager(this) {
PreferredBackBufferWidth = windowWidth,
PreferredBackBufferHeight = windowHeight,
#if !FNA
HardwareModeSwitch = false
#endif
};
this.Window.AllowUserResizing = true;
this.Content.RootDirectory = "Content";
@ -162,7 +160,7 @@ namespace MLEM.Startup {
/// <typeparam name="T">The type of content to load</typeparam>
/// <returns>The loaded content</returns>
public static T LoadContent<T>(string name) {
return MlemGame.instance.Content.Load<T>(name);
return instance.Content.Load<T>(name);
}
/// <summary>
@ -179,4 +177,4 @@ namespace MLEM.Startup {
public delegate void TimeCallback(MlemGame game, GameTime time);
}
}
}

View file

@ -1,36 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.1.263",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.1.263",
"commands": [
"mgcb-editor-mac"
]
}
}
}

View file

@ -1,13 +1,13 @@
using MLEM.Startup;
namespace TemplateNamespace;
namespace TemplateNamespace {
public class GameImpl : MlemGame {
public class GameImpl : MlemGame {
public static GameImpl Instance { get; private set; }
public static GameImpl Instance { get; private set; }
public GameImpl() {
Instance = this;
}
public GameImpl() {
Instance = this;
}
}

View file

@ -1,14 +1,14 @@
using Microsoft.Xna.Framework;
using MLEM.Misc;
namespace TemplateNamespace;
namespace TemplateNamespace {
public static class Program {
public static class Program {
public static void Main() {
MlemPlatform.Current = new MlemPlatform.DesktopGl<TextInputEventArgs>((w, c) => w.TextInput += c);
using var game = new GameImpl();
game.Run();
}
public static void Main() {
MlemPlatform.Current = new MlemPlatform.DesktopGl<TextInputEventArgs>((w, c) => w.TextInput += c);
using var game = new GameImpl();
game.Run();
}
}

View file

@ -1,27 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Contentless" Version="3.*" />
<PackageReference Include="MLEM.Startup" Version="6.*" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.263" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.263" />
<PackageReference Include="MLEM.Startup" Version="5.*" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="Content\Content.mgcb" />
<Content Include="Content\*\**" />
<EmbeddedResource Include="Icon.ico" />
<EmbeddedResource Include="Icon.bmp" />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" />
<Exec Command="dotnet tool restore" />
</Target>
</Project>
</Project>

View file

@ -1,13 +1,13 @@
using MLEM.Startup;
namespace TemplateNamespace;
namespace TemplateNamespace {
public class GameImpl : MlemGame {
public class GameImpl : MlemGame {
public static GameImpl Instance { get; private set; }
public static GameImpl Instance { get; private set; }
public GameImpl() {
Instance = this;
public GameImpl() {
Instance = this;
}
}
}
}

View file

@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MLEM.Startup" Version="6.*" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.263">
<PackageReference Include="MLEM.Startup" Version="5.*" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
</Project>

Some files were not shown because too many files have changed in this diff Show more