From acea7b2e728787a0d83bbf83c8c1f042d2c32e7e Mon Sep 17 00:00:00 2001
From: chai <215380520@qq.com>
Date: Mon, 3 Jun 2024 10:15:45 +0800
Subject: + plugins project
---
Plugins/MonoGame.Extended/.editorconfig | 463 +++++++++
Plugins/MonoGame.Extended/.gitattributes | 48 +
Plugins/MonoGame.Extended/.github/FUNDING.yml | 3 +
.../.github/workflows/create-release.yml | 80 ++
.../.github/workflows/pull-request-test.yml | 32 +
Plugins/MonoGame.Extended/.gitignore | 29 +
Plugins/MonoGame.Extended/CONTRIBUTING.md | 70 ++
Plugins/MonoGame.Extended/Directory.Build.props | 46 +
Plugins/MonoGame.Extended/LICENSE | 25 +
Plugins/MonoGame.Extended/MonoGame.Extended.sln | 235 +++++
Plugins/MonoGame.Extended/README.md | 68 ++
.../DifferentPoolSizeCollision.cs | 115 +++
.../MonoGame.Extended.Benchmarks.Collisions.csproj | 19 +
.../Program.cs | 5 +
.../SpaceAlgorithms.cs | 104 ++
.../Utils/Collider.cs | 29 +
.../logos/github-social-media-large.png | Bin 0 -> 52291 bytes
.../MonoGame.Extended/logos/logo-banner-1600.png | Bin 0 -> 26491 bytes
.../MonoGame.Extended/logos/logo-banner-800.png | Bin 0 -> 10682 bytes
.../logos/logo-drop-shadow-512.png | Bin 0 -> 38466 bytes
Plugins/MonoGame.Extended/logos/logo-nuget-128.png | Bin 0 -> 5163 bytes
Plugins/MonoGame.Extended/logos/logo-nuget-32.png | Bin 0 -> 1632 bytes
Plugins/MonoGame.Extended/logos/logo-nuget-400.png | Bin 0 -> 17856 bytes
.../MonoGame.Extended/logos/logo-square-1024.png | Bin 0 -> 72843 bytes
.../MonoGame.Extended/logos/logo-square-128.png | Bin 0 -> 6736 bytes
Plugins/MonoGame.Extended/logos/logo-square-32.png | Bin 0 -> 1840 bytes
.../MonoGame.Extended/logos/logo-square-512.png | Bin 0 -> 31096 bytes
Plugins/MonoGame.Extended/logos/logo-square-64.png | Bin 0 -> 3451 bytes
Plugins/MonoGame.Extended/logos/logo-square.svg | 73 ++
.../MonoGame.Extended/source/Directory.Build.props | 20 +
.../MonoGame.Extended.Animations.csproj | 12 +
.../CollisionComponent.cs | 341 +++++++
.../CollisionEventArgs.cs | 26 +
.../ICollisionActor.cs | 27 +
.../ISpaceAlgorithm.cs | 40 +
.../MonoGame.Extended.Collisions/Layers/Layer.cs | 39 +
.../Layers/UndefinedLayerException.cs | 18 +
.../MonoGame.Extended.Collisions.csproj | 12 +
.../QuadTree/QuadTree.cs | 310 ++++++
.../QuadTree/QuadTreeData.cs | 88 ++
.../QuadTree/QuadTreeSpace.cs | 76 ++
.../MonoGame.Extended.Collisions/SpatialHash.cs | 79 ++
.../MonoGame.Extended.Collisions/packages.config | 4 +
.../Animations/AstridAnimatorAnimation.cs | 24 +
.../Animations/AstridAnimatorFile.cs | 15 +
.../Animations/AstridAnimatorImporter.cs | 18 +
.../Animations/AstridAnimatorProcessor.cs | 24 +
.../Animations/AstridAnimatorProcessorResult.cs | 21 +
.../Animations/AstridAnimatorWriter.cs | 40 +
.../BitmapFonts/BitmapFontChar.cs | 41 +
.../BitmapFonts/BitmapFontCommon.cs | 41 +
.../BitmapFonts/BitmapFontFile.cs | 31 +
.../BitmapFonts/BitmapFontImporter.cs | 22 +
.../BitmapFonts/BitmapFontInfo.cs | 47 +
.../BitmapFonts/BitmapFontKerning.cs | 20 +
.../BitmapFonts/BitmapFontPage.cs | 17 +
.../BitmapFonts/BitmapFontProcessor.cs | 33 +
.../BitmapFonts/BitmapFontProcessorResult.cs | 16 +
.../BitmapFonts/BitmapFontWriter.cs | 52 +
.../ContentImporterContextExtensions.cs | 15 +
.../ContentImporterResult.cs | 14 +
.../ContentItem.cs | 37 +
.../ContentLogger.cs | 14 +
.../ContentWriterExtensions.cs | 79 ++
.../Json/JsonContentImporter.cs | 15 +
.../Json/JsonContentProcessor.cs | 31 +
.../Json/JsonContentProcessorResult.cs | 8 +
.../Json/JsonContentTypeWriter.cs | 27 +
.../MonoGame.Extended.Content.Pipeline.csproj | 25 +
.../PathExtensions.cs | 14 +
.../SpriteFactory/SpriteFactoryContentImporter.cs | 10 +
.../SpriteFactory/SpriteFactoryContentProcessor.cs | 15 +
.../TextureAtlases/TexturePackerJsonImporter.cs | 18 +
.../TextureAtlases/TexturePackerProcessor.cs | 24 +
.../TextureAtlases/TexturePackerProcessorResult.cs | 9 +
.../TextureAtlases/TexturePackerWriter.cs | 45 +
.../Tiled/ContentWriterExtensions.cs | 26 +
.../Tiled/TiledContentItem.cs | 22 +
.../Tiled/TiledMapContentItem.cs | 12 +
.../Tiled/TiledMapImporter.cs | 108 ++
.../Tiled/TiledMapObjectTemplateImporter.cs | 54 +
.../Tiled/TiledMapProcessor.cs | 324 ++++++
.../Tiled/TiledMapTilesetContentItem.cs | 14 +
.../Tiled/TiledMapTilesetImporter.cs | 60 ++
.../Tiled/TiledMapTilesetProcessor.cs | 44 +
.../Tiled/TiledMapTilesetWriter.cs | 145 +++
.../Tiled/TiledMapWriter.cs | 227 +++++
.../MonoGame.Extended.Content.Pipeline/readme.txt | 15 +
.../source/MonoGame.Extended.Entities/Aspect.cs | 48 +
.../MonoGame.Extended.Entities/AspectBuilder.cs | 63 ++
.../BitArrayExtensions.cs | 54 +
.../MonoGame.Extended.Entities/ComponentManager.cs | 90 ++
.../MonoGame.Extended.Entities/ComponentMapper.cs | 69 ++
.../MonoGame.Extended.Entities/ComponentType.cs | 46 +
.../source/MonoGame.Extended.Entities/Entity.cs | 87 ++
.../MonoGame.Extended.Entities/EntityManager.cs | 120 +++
.../EntitySubscription.cs | 61 ++
.../MonoGame.Extended.Entities.csproj | 12 +
.../Systems/DrawSystem.cs | 16 +
.../Systems/EntityDrawSystem.cs | 14 +
.../Systems/EntityProcessingSystem.cs | 26 +
.../Systems/EntitySystem.cs | 51 +
.../Systems/EntityUpdateSystem.cs | 14 +
.../MonoGame.Extended.Entities/Systems/ISystem.cs | 9 +
.../Systems/UpdateSystem.cs | 16 +
.../source/MonoGame.Extended.Entities/World.cs | 84 ++
.../MonoGame.Extended.Entities/WorldBuilder.cs | 26 +
.../source/MonoGame.Extended.Graphics/Batcher.cs | 387 ++++++++
.../source/MonoGame.Extended.Graphics/Batcher2D.cs | 450 +++++++++
.../Effects/DefaultEffect.cs | 203 ++++
.../Effects/EffectResource.cs | 119 +++
.../Effects/ITextureEffect.cs | 18 +
.../Effects/MatrixChainEffect.cs | 155 +++
.../Effects/Resources/DefaultEffect.dx11.mgfxo | Bin 0 -> 4829 bytes
.../Effects/Resources/DefaultEffect.fx | 72 ++
.../Effects/Resources/DefaultEffect.ogl.mgfxo | Bin 0 -> 4833 bytes
.../Effects/Resources/Macros.fxh | 60 ++
.../Effects/Resources/RebuildEffects.bat | 15 +
.../Effects/Resources/Structures.fxh | 51 +
.../source/MonoGame.Extended.Graphics/FlipFlags.cs | 13 +
.../Geometry/GeometryBuilder.cs | 24 +
.../Geometry/GeometryBuilder2D.cs | 119 +++
.../IBatchDrawCallInfo.cs | 19 +
.../IMatrixChainEffect.cs | 30 +
.../MonoGame.Extended.Graphics.csproj | 28 +
.../PrimitiveTypeExtensions.cs | 42 +
.../RenderTarget2DExtensions.cs | 41 +
.../source/MonoGame.Extended.Gui/ControlStyle.cs | 114 +++
.../source/MonoGame.Extended.Gui/Controls/Box.cs | 24 +
.../MonoGame.Extended.Gui/Controls/Button.cs | 92 ++
.../MonoGame.Extended.Gui/Controls/Canvas.cs | 25 +
.../MonoGame.Extended.Gui/Controls/CheckBox.cs | 65 ++
.../MonoGame.Extended.Gui/Controls/ComboBox.cs | 102 ++
.../Controls/CompositeControl.cs | 70 ++
.../Controls/ContentControl.cs | 82 ++
.../MonoGame.Extended.Gui/Controls/Control.cs | 271 +++++
.../Controls/ControlCollection.cs | 15 +
.../MonoGame.Extended.Gui/Controls/Dialog.cs | 41 +
.../MonoGame.Extended.Gui/Controls/DockPanel.cs | 104 ++
.../source/MonoGame.Extended.Gui/Controls/Form.cs | 42 +
.../MonoGame.Extended.Gui/Controls/ItemsControl.cs | 60 ++
.../source/MonoGame.Extended.Gui/Controls/Label.cs | 14 +
.../Controls/LayoutControl.cs | 40 +
.../MonoGame.Extended.Gui/Controls/ListBox.cs | 42 +
.../MonoGame.Extended.Gui/Controls/ProgressBar.cs | 62 ++
.../Controls/SelectorControl.cs | 173 ++++
.../MonoGame.Extended.Gui/Controls/StackPanel.cs | 69 ++
.../MonoGame.Extended.Gui/Controls/TextBox.cs | 331 +++++++
.../MonoGame.Extended.Gui/Controls/TextBox2.cs | 328 +++++++
.../MonoGame.Extended.Gui/Controls/ToggleButton.cs | 98 ++
.../MonoGame.Extended.Gui/Controls/UniformGrid.cs | 86 ++
.../source/MonoGame.Extended.Gui/Cursor.cs | 11 +
.../source/MonoGame.Extended.Gui/Element.cs | 125 +++
.../MonoGame.Extended.Gui/ElementCollection.cs | 98 ++
.../GuiSpriteBatchRenderer.cs | 81 ++
.../source/MonoGame.Extended.Gui/GuiSystem.cs | 265 +++++
.../source/MonoGame.Extended.Gui/LayoutHelper.cs | 65 ++
.../MonoGame.Extended.Gui/Markup/MarkupParser.cs | 147 +++
.../MonoGame.Extended.Gui.csproj | 13 +
.../source/MonoGame.Extended.Gui/Orientation.cs | 4 +
.../MonoGame.Extended.Gui/PointerEventArgs.cs | 42 +
.../source/MonoGame.Extended.Gui/Screen.cs | 140 +++
.../MonoGame.Extended.Gui/ScreenCollection.cs | 10 +
.../Serialization/ControlJsonConverter.cs | 67 ++
.../Serialization/ControlStyleJsonConverter.cs | 89 ++
.../GuiJsonSerializerOptionsProvider.cs | 38 +
.../GuiNinePatchRegion2DJsonConverter.cs | 15 +
.../Serialization/GuiTextureAtlasJsonConverter.cs | 31 +
.../Serialization/GuiTextureRegionService.cs | 16 +
.../Serialization/HorizontalAlignmentConverter.cs | 32 +
.../Serialization/SkinJsonConverter.cs | 57 ++
.../Serialization/VerticalAlignmentConverter.cs | 32 +
.../source/MonoGame.Extended.Gui/Skin.cs | 221 +++++
.../source/MonoGame.Extended.Gui/Window.cs | 42 +
.../MonoGame.Extended.Gui/WindowCollection.cs | 10 +
.../MonoGame.Extended.Input/ExtendedPlayerIndex.cs | 32 +
.../InputListeners/GamePadEventArgs.cs | 62 ++
.../InputListeners/GamePadListener.cs | 529 ++++++++++
.../InputListeners/GamePadListenerSettings.cs | 134 +++
.../InputListeners/IInputService.cs | 13 +
.../InputListeners/InputListener.cs | 13 +
.../InputListeners/InputListenerComponent.cs | 37 +
.../InputListeners/InputListenerSettings.cs | 8 +
.../InputListeners/KeyboardEventArgs.cs | 119 +++
.../InputListeners/KeyboardListener.cs | 104 ++
.../InputListeners/KeyboardListenerSettings.cs | 21 +
.../InputListeners/KeyboardModifiers.cs | 13 +
.../InputListeners/MouseEventArgs.cs | 35 +
.../InputListeners/MouseListener.cs | 193 ++++
.../InputListeners/MouseListenerSettings.cs | 23 +
.../InputListeners/TouchEventArgs.cs | 39 +
.../InputListeners/TouchListener.cs | 57 ++
.../InputListeners/TouchListenerSettings.cs | 18 +
.../MonoGame.Extended.Input/KeyboardExtended.cs | 22 +
.../KeyboardStateExtended.cs | 60 ++
.../MonoGame.Extended.Input.csproj | 12 +
.../source/MonoGame.Extended.Input/MouseButton.cs | 15 +
.../MonoGame.Extended.Input/MouseExtended.cs | 34 +
.../MonoGame.Extended.Input/MouseStateExtended.cs | 149 +++
.../FastRandomExtensions.cs | 17 +
.../MonoGame.Extended.Particles/LineSegment.cs | 77 ++
.../Modifiers/AgeModifier.cs | 26 +
.../Containers/CircleContainerModifier.cs | 52 +
.../Containers/RectangleContainerModifier.cs | 59 ++
.../Containers/RectangleLoopContainerModifier.cs | 42 +
.../Modifiers/DragModifier.cs | 23 +
.../Modifiers/Interpolators/ColorInterpolator.cs | 13 +
.../Modifiers/Interpolators/HueInterpolator.cs | 12 +
.../Modifiers/Interpolators/Interpolator.cs | 26 +
.../Modifiers/Interpolators/OpacityInterpolator.cs | 10 +
.../Interpolators/RotationInterpolator.cs | 10 +
.../Modifiers/Interpolators/ScaleInterpolator.cs | 12 +
.../Modifiers/Interpolators/VelocityInterpolator | 12 +
.../Modifiers/LinearGravityModifier.cs | 23 +
.../Modifiers/Modifier.cs | 18 +
.../Modifiers/OpacityFastFadeModifier.cs | 14 +
.../Modifiers/RotationModifier.cs | 18 +
.../Modifiers/VelocityColorModifier.cs | 36 +
.../Modifiers/VelocityModifier.cs | 43 +
.../Modifiers/VortexModifier.cs | 30 +
.../MonoGame.Extended.Particles.csproj | 12 +
.../source/MonoGame.Extended.Particles/Particle.cs | 24 +
.../MonoGame.Extended.Particles/ParticleBuffer.cs | 152 +++
.../MonoGame.Extended.Particles/ParticleEffect.cs | 83 ++
.../MonoGame.Extended.Particles/ParticleEmitter.cs | 222 +++++
.../ParticleExtensions.cs | 49 +
.../ParticleModifierExecutionStrategy.cs | 54 +
.../ParticleReleaseParameters.cs | 34 +
.../Profiles/BoxFillProfile.cs | 18 +
.../Profiles/BoxProfile.cs | 31 +
.../Profiles/BoxUniformProfile.cs | 32 +
.../Profiles/CircleProfile.cs | 24 +
.../Profiles/LineProfile.cs | 17 +
.../Profiles/PointProfile.cs | 14 +
.../Profiles/Profile.cs | 68 ++
.../Profiles/RingProfile.cs | 32 +
.../Profiles/SprayProfile.cs | 20 +
.../Serialization/InterpolatorJsonConverter.cs | 25 +
.../ModifierExecutionStrategyJsonConverter.cs | 34 +
.../Serialization/ModifierJsonConverter.cs | 25 +
.../ParticleJsonSerializerOptionsProvider.cs | 34 +
.../Serialization/ProfileJsonConverter.cs | 25 +
.../Serialization/TimeSpanJsonConverter.cs | 33 +
.../ContentReaderExtensions.cs | 20 +
.../MonoGame.Extended.Tiled.csproj | 13 +
.../Renderers/TiledMapAnimatedLayerModel.cs | 32 +
.../Renderers/TiledMapAnimatedLayerModelBuilder.cs | 28 +
.../Renderers/TiledMapEffect.cs | 37 +
.../Renderers/TiledMapLayerModel.cs | 38 +
.../Renderers/TiledMapLayerModelBuilder.cs | 125 +++
.../Renderers/TiledMapModel.cs | 41 +
.../Renderers/TiledMapModelBuilder.cs | 126 +++
.../Renderers/TiledMapRenderer.cs | 191 ++++
.../Renderers/TiledMapStaticLayerModel.cs | 22 +
.../Renderers/TiledMapStaticLayerModelBuilder.cs | 16 +
.../Serialization/TiledMapContent.cs | 75 ++
.../Serialization/TiledMapEllipseContent.cs | 6 +
.../Serialization/TiledMapGroupLayerContent.cs | 20 +
.../Serialization/TiledMapImageContent.cs | 44 +
.../Serialization/TiledMapImageLayerContent.cs | 30 +
.../Serialization/TiledMapLayerContent.cs | 61 ++
.../Serialization/TiledMapLayerModelContent.cs | 139 +++
.../Serialization/TiledMapObjectContent.cs | 78 ++
.../TiledMapObjectDrawOrderContent.cs | 10 +
.../Serialization/TiledMapObjectLayerContent.cs | 28 +
.../Serialization/TiledMapObjectTemplateContent.cs | 17 +
.../Serialization/TiledMapOrientationContent.cs | 12 +
.../Serialization/TiledMapPolygonContent.cs | 10 +
.../Serialization/TiledMapPolylineContent.cs | 10 +
.../Serialization/TiledMapPropertyContent.cs | 28 +
.../Serialization/TiledMapStaggerAxisContent.cs | 10 +
.../Serialization/TiledMapStaggerIndexContent.cs | 10 +
.../Serialization/TiledMapTileContent.cs | 9 +
.../Serialization/TiledMapTileDrawOrderContent.cs | 12 +
.../Serialization/TiledMapTileLayerContent.cs | 30 +
.../TiledMapTileLayerDataChunkContent.cs | 26 +
.../Serialization/TiledMapTileLayerDataContent.cs | 33 +
.../Serialization/TiledMapTileOffsetContent.cs | 17 +
.../Serialization/TiledMapTilesetContent.cs | 76 ++
.../Serialization/TiledMapTilesetGridContent.cs | 16 +
.../TiledMapTilesetTileAnimationFrameContent.cs | 18 +
.../Serialization/TiledMapTilesetTileContent.cs | 40 +
.../source/MonoGame.Extended.Tiled/TiledMap.cs | 139 +++
.../TiledMapEllipseObject.cs | 17 +
.../MonoGame.Extended.Tiled/TiledMapGroupLayer.cs | 17 +
.../MonoGame.Extended.Tiled/TiledMapHelper.cs | 51 +
.../MonoGame.Extended.Tiled/TiledMapImageLayer.cs | 18 +
.../MonoGame.Extended.Tiled/TiledMapLayer.cs | 26 +
.../MonoGame.Extended.Tiled/TiledMapLayerType.cs | 10 +
.../MonoGame.Extended.Tiled/TiledMapObject.cs | 35 +
.../TiledMapObjectDrawOrder.cs | 8 +
.../MonoGame.Extended.Tiled/TiledMapObjectLayer.cs | 20 +
.../MonoGame.Extended.Tiled/TiledMapObjectType.cs | 11 +
.../MonoGame.Extended.Tiled/TiledMapOrientation.cs | 9 +
.../TiledMapPolygonObject.cs | 15 +
.../TiledMapPolylineObject.cs | 15 +
.../MonoGame.Extended.Tiled/TiledMapProperties.cs | 14 +
.../TiledMapPropertyValue.cs | 32 +
.../MonoGame.Extended.Tiled/TiledMapReader.cs | 229 +++++
.../TiledMapRectangleObject.cs | 12 +
.../source/MonoGame.Extended.Tiled/TiledMapTile.cs | 28 +
.../TiledMapTileDrawOrder.cs | 10 +
.../TiledMapTileFlipFlags.cs | 14 +
.../MonoGame.Extended.Tiled/TiledMapTileLayer.cs | 66 ++
.../MonoGame.Extended.Tiled/TiledMapTileObject.cs | 18 +
.../MonoGame.Extended.Tiled/TiledMapTileset.cs | 70 ++
.../TiledMapTilesetAnimatedTile.cs | 46 +
.../TiledMapTilesetReader.cs | 150 +++
.../MonoGame.Extended.Tiled/TiledMapTilesetTile.cs | 36 +
.../TiledMapTilesetTileAnimationFrame.cs | 144 +++
.../MonoGame.Extended.Tweening/ColorTween.cs | 15 +
.../MonoGame.Extended.Tweening/EasingFunctions.cs | 120 +++
.../MonoGame.Extended.Tweening/LinearOperations.cs | 21 +
.../MonoGame.Extended.Tweening/LinearTween.cs | 23 +
.../MonoGame.Extended.Tweening.csproj | 12 +
.../source/MonoGame.Extended.Tweening/Tween.cs | 184 ++++
.../MonoGame.Extended.Tweening/TweenFieldMember.cs | 44 +
.../MonoGame.Extended.Tweening/TweenMember.cs | 37 +
.../TweenPropertyMember.cs | 43 +
.../source/MonoGame.Extended.Tweening/Tweener.cs | 133 +++
.../source/MonoGame.Extended/AnimationComponent.cs | 30 +
.../MonoGame.Extended/BitmapFonts/BitmapFont.cs | 354 +++++++
.../BitmapFonts/BitmapFontExtensions.cs | 156 +++
.../BitmapFonts/BitmapFontReader.cs | 65 ++
.../BitmapFonts/BitmapFontRegion.cs | 33 +
.../source/MonoGame.Extended/Camera.cs | 32 +
.../source/MonoGame.Extended/Collections/Bag.cs | 217 ++++
.../source/MonoGame.Extended/Collections/Deque.cs | 837 ++++++++++++++++
.../Collections/DictionaryExtensions.cs | 18 +
.../Collections/IObservableCollection.cs | 26 +
.../MonoGame.Extended/Collections/IPoolable.cs | 12 +
.../MonoGame.Extended/Collections/ItemEventArgs.cs | 20 +
.../Collections/KeyedCollection.cs | 68 ++
.../Collections/ListExtensions.cs | 22 +
.../MonoGame.Extended/Collections/ObjectPool.cs | 157 +++
.../Collections/ObservableCollection.cs | 117 +++
.../source/MonoGame.Extended/Collections/Pool.cs | 51 +
.../source/MonoGame.Extended/ColorExtensions.cs | 85 ++
.../source/MonoGame.Extended/ColorHelper.cs | 83 ++
.../Content/ContentManagerExtensions.cs | 51 +
.../Content/ContentReaderExtensions.cs | 44 +
.../MonoGame.Extended/FramesPerSecondCounter.cs | 34 +
.../FramesPerSecondCounterComponent.cs | 27 +
.../GameComponentCollectionExtensions.cs | 24 +
.../source/MonoGame.Extended/GameTimeExtensions.cs | 12 +
.../source/MonoGame.Extended/HslColor.cs | 270 +++++
.../source/MonoGame.Extended/IColorable.cs | 9 +
.../source/MonoGame.Extended/IEquatableByRef.cs | 21 +
.../source/MonoGame.Extended/IMovable.cs | 9 +
.../source/MonoGame.Extended/IRectangular.cs | 14 +
.../source/MonoGame.Extended/IRotatable.cs | 7 +
.../source/MonoGame.Extended/IScalable.cs | 9 +
.../source/MonoGame.Extended/ISizable.cs | 8 +
.../source/MonoGame.Extended/IUpdate.cs | 9 +
.../source/MonoGame.Extended/Math/Angle.cs | 224 +++++
.../MonoGame.Extended/Math/BoundingRectangle.cs | 579 +++++++++++
.../source/MonoGame.Extended/Math/CircleF.cs | 519 ++++++++++
.../source/MonoGame.Extended/Math/EllipseF.cs | 101 ++
.../source/MonoGame.Extended/Math/FastRandom.cs | 127 +++
.../source/MonoGame.Extended/Math/FloatHelper.cs | 15 +
.../source/MonoGame.Extended/Math/Matrix2.cs | 1038 ++++++++++++++++++++
.../MonoGame.Extended/Math/MatrixExtensions.cs | 28 +
.../MonoGame.Extended/Math/OrientedRectangle.cs | 302 ++++++
.../source/MonoGame.Extended/Math/Point2.cs | 380 +++++++
.../source/MonoGame.Extended/Math/Point3.cs | 379 +++++++
.../MonoGame.Extended/Math/PrimitivesHelper.cs | 143 +++
.../MonoGame.Extended/Math/RandomExtensions.cs | 44 +
.../source/MonoGame.Extended/Math/Range.cs | 84 ++
.../source/MonoGame.Extended/Math/Ray2.cs | 199 ++++
.../MonoGame.Extended/Math/RectangleExtensions.cs | 71 ++
.../source/MonoGame.Extended/Math/RectangleF.cs | 694 +++++++++++++
.../source/MonoGame.Extended/Math/Segment2.cs | 317 ++++++
.../MonoGame.Extended/Math/ShapeExtensions.cs | 332 +++++++
.../source/MonoGame.Extended/Math/ShapeF.cs | 95 ++
.../source/MonoGame.Extended/Math/Size.cs | 252 +++++
.../source/MonoGame.Extended/Math/Size2.cs | 311 ++++++
.../source/MonoGame.Extended/Math/Size3.cs | 289 ++++++
.../source/MonoGame.Extended/Math/Thickness.cs | 101 ++
.../Math/Triangulation/CyclicalList.cs | 50 +
.../Triangulation/IndexableCyclicalLinkedList.cs | 62 ++
.../Math/Triangulation/LineSegment.cs | 61 ++
.../Math/Triangulation/Triangle.cs | 88 ++
.../Math/Triangulation/Triangulator.cs | 567 +++++++++++
.../MonoGame.Extended/Math/Triangulation/Vertex.cs | 47 +
.../MonoGame.Extended/Math/Vector2Extensions.cs | 249 +++++
.../MonoGame.Extended/MonoGame.Extended.csproj | 14 +
.../MonoGame.Extended.csproj.DotSettings | 2 +
.../source/MonoGame.Extended/OrthographicCamera.cs | 209 ++++
.../source/MonoGame.Extended/Screens/GameScreen.cs | 19 +
.../source/MonoGame.Extended/Screens/Screen.cs | 17 +
.../MonoGame.Extended/Screens/ScreenManager.cs | 78 ++
.../Screens/Transitions/ExpandTransition.cs | 42 +
.../Screens/Transitions/FadeTransition.cs | 34 +
.../Screens/Transitions/Transition.cs | 58 ++
.../Serialization/BaseTypeJsonConverter.cs | 86 ++
.../Serialization/ColorJsonConverter.cs | 34 +
.../Serialization/ContentManagerJsonConverter.cs | 49 +
.../Serialization/FloatStringConverter.cs | 34 +
.../Serialization/HslColorJsonConverter.cs | 33 +
.../Serialization/JsonContentLoader.cs | 18 +
.../Serialization/JsonContentTypeReader.cs | 16 +
.../MonoGameJsonSerializerOptionsProvider.cs | 29 +
.../NinePatchRegion2DJsonConverter.cs | 94 ++
.../Serialization/RangeJsonConverter.cs | 50 +
.../Serialization/RectangleFJsonConverter.cs | 31 +
.../Serialization/Size2JsonConverter.cs | 45 +
.../Serialization/SizeJsonConverter.cs | 45 +
.../Serialization/TextContentLoader.cs | 18 +
.../Serialization/TextureRegion2DJsonConverter.cs | 52 +
.../Serialization/TextureRegionService.cs | 35 +
.../Serialization/ThicknessJsonConverter.cs | 31 +
.../Serialization/Utf8JsonReaderExtensions.cs | 89 ++
.../Serialization/Vector2JsonConverter.cs | 46 +
.../source/MonoGame.Extended/Shapes/Polygon.cs | 179 ++++
.../source/MonoGame.Extended/Shapes/Polyline.cs | 42 +
.../SimpleDrawableGameComponent.cs | 47 +
.../MonoGame.Extended/SimpleGameComponent.cs | 80 ++
.../MonoGame.Extended/Sprites/AnimatedSprite.cs | 50 +
.../source/MonoGame.Extended/Sprites/Animation.cs | 86 ++
.../Sprites/ISpriteBatchDrawable.cs | 18 +
.../source/MonoGame.Extended/Sprites/Sprite.cs | 109 ++
.../MonoGame.Extended/Sprites/SpriteExtensions.cs | 36 +
.../MonoGame.Extended/Sprites/SpriteSheet.cs | 27 +
.../Sprites/SpriteSheetAnimation.cs | 107 ++
.../Sprites/SpriteSheetAnimationCycle.cs | 18 +
.../Sprites/SpriteSheetAnimationData.cs | 21 +
.../Sprites/SpriteSheetAnimationFrame.cs | 52 +
.../TextureAtlases/NinePatchRegion2D.cs | 84 ++
.../TextureAtlases/TextureAtlas.cs | 258 +++++
.../TextureAtlases/TextureAtlasExtensions.cs | 113 +++
.../TextureAtlasJsonContentTypeReader.cs | 41 +
.../TextureAtlases/TextureAtlasJsonConverter.cs | 84 ++
.../TextureAtlases/TextureAtlasReader.cs | 30 +
.../TextureAtlases/TexturePackerFile.cs | 14 +
.../TextureAtlases/TexturePackerMeta.cs | 36 +
.../TextureAtlases/TexturePackerPoint.cs | 18 +
.../TextureAtlases/TexturePackerRectangle.cs | 24 +
.../TextureAtlases/TexturePackerRegion.cs | 33 +
.../TextureAtlases/TexturePackerSize.cs | 18 +
.../TextureAtlases/TextureRegion2D.cs | 54 +
.../MonoGame.Extended/Timers/ContinuousClock.cs | 36 +
.../MonoGame.Extended/Timers/CountdownTimer.cs | 42 +
.../source/MonoGame.Extended/Timers/GameTimer.cs | 65 ++
.../source/MonoGame.Extended/Timers/TimerState.cs | 10 +
.../source/MonoGame.Extended/Transform.cs | 456 +++++++++
.../MonoGame.Extended/VectorDraw/PrimitiveBatch.cs | 183 ++++
.../VectorDraw/PrimitiveDrawing.cs | 255 +++++
.../ViewportAdapters/BoxingViewportAdapter.cs | 96 ++
.../ViewportAdapters/DefaultViewportAdapter.cs | 28 +
.../ViewportAdapters/ScalingViewportAdapter.cs | 27 +
.../ViewportAdapters/ViewportAdapter.cs | 46 +
.../ViewportAdapters/WindowViewportAdapter.cs | 36 +
.../MonoGame.Extended/tests/Directory.Build.props | 46 +
.../CollisionComponentTests.cs | 416 ++++++++
.../Implementation/BasicActor.cs | 33 +
.../Implementation/BasicWall.cs | 20 +
.../MonoGame.Extended.Collisions.Tests.csproj | 7 +
.../QuadTreeTests.cs | 446 +++++++++
.../SpatialHashTests.cs | 39 +
.../packages.config | 6 +
...me.Extended.Content.Pipeline.Tests.Tiled.csproj | 24 +
.../TestData/isometric.tmx | 76 ++
.../TestData/isometric_tileset.png | Bin 0 -> 4599 bytes
.../TestData/level01.tmx | 440 +++++++++
.../TestData/template.tx | 4 +
.../TestData/test-object-layer.tmx | 24 +
.../TestData/test-tileset-base64.tmx | 11 +
.../TestData/test-tileset-csv.tmx | 13 +
.../TestData/test-tileset-gzip.tmx | 11 +
.../TestData/test-tileset-xml.tmx | 19 +
.../TestData/test-tileset-zlib.tmx | 11 +
.../TiledMapImporterProcessorTests.cs | 205 ++++
.../AstridAnimatorImporterTests.cs | 34 +
.../AstridAnimatorProcessorTests.cs | 30 +
...MonoGame.Extended.Content.Pipeline.Tests.csproj | 16 +
.../TestData/astrid-animator-atlas.json | 390 ++++++++
.../TestData/astrid-animator.aa | 15 +
.../TestData/test-tileset.json | 93 ++
.../TexturePackerJsonImporterProcessorTests.cs | 33 +
.../AspectBuilderTests.cs | 70 ++
.../AspectTests.cs | 88 ++
.../BitArrayExtensionsTests.cs | 20 +
.../ComponentManagerTests.cs | 47 +
.../ComponentMapperTests.cs | 95 ++
.../ComponentTypeTests.cs | 20 +
.../MonoGame.Extended.Entities.Tests.csproj | 7 +
.../WorldManagerTests.cs | 71 ++
.../Controls/GuiButtonTests.cs | 122 +++
.../Controls/GuiControlCollectionTests.cs | 58 ++
.../GuiRendererTests.cs | 34 +
.../MonoGame.Extended.Gui.Tests.csproj | 7 +
.../tests/MonoGame.Extended.Tests/AngleTest.cs | 92 ++
.../MonoGame.Extended.Tests/AssertExtensions.cs | 21 +
.../BitmapFonts/BitmapFontTests.cs | 79 ++
.../tests/MonoGame.Extended.Tests/Camera2DTests.cs | 97 ++
.../MonoGame.Extended.Tests/CollectionAssert.cs | 14 +
.../Collections/BagTests.cs | 48 +
.../Collections/DequeTests.cs | 408 ++++++++
.../Content/ContentReaderExtensionsTests.cs | 23 +
.../MonoGame.Extended.Tests/MockGameWindow.cs | 42 +
.../MonoGame.Extended.Tests.csproj | 12 +
.../MonoGame.Extended.Tests/OpenTK.dll.config | 26 +
.../Particles/AssertionModifier.cs | 25 +
.../Particles/ColourTests.cs | 126 +++
.../Particles/EmitterTests.cs | 131 +++
.../Particles/ParticleBufferTests.cs | 184 ++++
.../Particles/Profiles/PointProfileTests.cs | 33 +
.../Particles/Profiles/RingProfileTests.cs | 38 +
.../Primitives/BoundingRectangleTests.cs | 396 ++++++++
.../Primitives/CircleFTests.cs | 420 ++++++++
.../Primitives/EllipseFTest.cs | 38 +
.../Primitives/OrientedRectangleTests.cs | 234 +++++
.../Primitives/Point2Tests.cs | 356 +++++++
.../Primitives/Ray2DTests.cs | 217 ++++
.../Primitives/RectangleFTests.cs | 135 +++
.../Primitives/Segment2DTests.cs | 251 +++++
.../Primitives/ShapeTests.cs | 180 ++++
.../Primitives/Size2Tests.cs | 304 ++++++
.../tests/MonoGame.Extended.Tests/RangeTests.cs | 102 ++
.../Serialization/ColorJsonConverterTests.cs | 66 ++
.../Serialization/RectangleFJsonConverterTest.cs | 36 +
.../Shapes/PolygonFTests.cs | 87 ++
.../Sprites/SpriteSheetAnimationTests.cs | 910 +++++++++++++++++
.../MonoGame.Extended.Tests/Sprites/SpriteTests.cs | 91 ++
.../tests/MonoGame.Extended.Tests/TestGame.cs | 21 +
.../MonoGame.Extended.Tests/TestGraphicsDevice.cs | 12 +
.../tests/MonoGame.Extended.Tests/TestHelper.cs | 27 +
.../TextureAtlases/TextureAtlasTests.cs | 236 +++++
.../TextureAtlases/TextureRegion2DTests.cs | 40 +
.../Vector2ExtensionsTests.cs | 101 ++
.../ViewportAdapters/BoxingViewportAdapterTests.cs | 41 +
.../DefaultViewportAdapterTests.cs | 26 +
.../WithinDeltaEqualityComparer.cs | 24 +
.../FullMapRendererTest.cs | 291 ++++++
.../MonoGame.Extended.Tiled.Tests.csproj | 7 +
.../TiledTilesetTests.cs | 130 +++
.../ColorHandler.cs | 8 +
.../MonoGame.Extended.Tweening.Tests.csproj | 7 +
.../TweenerTests.cs | 15 +
539 files changed, 42280 insertions(+)
create mode 100644 Plugins/MonoGame.Extended/.editorconfig
create mode 100644 Plugins/MonoGame.Extended/.gitattributes
create mode 100644 Plugins/MonoGame.Extended/.github/FUNDING.yml
create mode 100644 Plugins/MonoGame.Extended/.github/workflows/create-release.yml
create mode 100644 Plugins/MonoGame.Extended/.github/workflows/pull-request-test.yml
create mode 100644 Plugins/MonoGame.Extended/.gitignore
create mode 100644 Plugins/MonoGame.Extended/CONTRIBUTING.md
create mode 100644 Plugins/MonoGame.Extended/Directory.Build.props
create mode 100644 Plugins/MonoGame.Extended/LICENSE
create mode 100644 Plugins/MonoGame.Extended/MonoGame.Extended.sln
create mode 100644 Plugins/MonoGame.Extended/README.md
create mode 100644 Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/DifferentPoolSizeCollision.cs
create mode 100644 Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/MonoGame.Extended.Benchmarks.Collisions.csproj
create mode 100644 Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/Program.cs
create mode 100644 Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/SpaceAlgorithms.cs
create mode 100644 Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/Utils/Collider.cs
create mode 100644 Plugins/MonoGame.Extended/logos/github-social-media-large.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-banner-1600.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-banner-800.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-drop-shadow-512.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-nuget-128.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-nuget-32.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-nuget-400.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-square-1024.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-square-128.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-square-32.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-square-512.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-square-64.png
create mode 100644 Plugins/MonoGame.Extended/logos/logo-square.svg
create mode 100644 Plugins/MonoGame.Extended/source/Directory.Build.props
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Animations/MonoGame.Extended.Animations.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/CollisionComponent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/CollisionEventArgs.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/ICollisionActor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/ISpaceAlgorithm.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/Layers/Layer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/Layers/UndefinedLayerException.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/MonoGame.Extended.Collisions.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTree.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTreeData.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTreeSpace.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/SpatialHash.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/packages.config
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorAnimation.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorFile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorImporter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessorResult.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorWriter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontChar.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontCommon.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontFile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontImporter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontInfo.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontKerning.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontPage.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessorResult.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontWriter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterContextExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterResult.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentItem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentLogger.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentWriterExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentImporter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessorResult.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentTypeWriter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/MonoGame.Extended.Content.Pipeline.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/PathExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentImporter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentProcessor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerJsonImporter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessorResult.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerWriter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/ContentWriterExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledContentItem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapContentItem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapImporter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapObjectTemplateImporter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapProcessor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetContentItem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetImporter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetProcessor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetWriter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapWriter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/readme.txt
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Aspect.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/AspectBuilder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/BitArrayExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentManager.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentMapper.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentType.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Entity.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/EntityManager.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/EntitySubscription.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/MonoGame.Extended.Entities.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/DrawSystem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityDrawSystem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityProcessingSystem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntitySystem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityUpdateSystem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/ISystem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/UpdateSystem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/World.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/WorldBuilder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Batcher.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Batcher2D.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/DefaultEffect.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/EffectResource.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/ITextureEffect.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/MatrixChainEffect.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.dx11.mgfxo
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.fx
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.ogl.mgfxo
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/Macros.fxh
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/RebuildEffects.bat
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/Structures.fxh
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/FlipFlags.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder2D.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/IBatchDrawCallInfo.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/IMatrixChainEffect.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/MonoGame.Extended.Graphics.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/PrimitiveTypeExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/RenderTarget2DExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/ControlStyle.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/Box.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/Button.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/Canvas.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/CheckBox.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/ComboBox.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/CompositeControl.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/ContentControl.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/Control.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/ControlCollection.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/Dialog.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/DockPanel.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/Form.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/ItemsControl.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/Label.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/LayoutControl.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/ListBox.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/ProgressBar.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/SelectorControl.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/StackPanel.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/TextBox.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/TextBox2.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/ToggleButton.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Controls/UniformGrid.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Cursor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Element.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/ElementCollection.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/GuiSpriteBatchRenderer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/GuiSystem.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/LayoutHelper.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Markup/MarkupParser.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/MonoGame.Extended.Gui.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Orientation.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/PointerEventArgs.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Screen.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/ScreenCollection.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlStyleJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiJsonSerializerOptionsProvider.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiNinePatchRegion2DJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureAtlasJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureRegionService.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/HorizontalAlignmentConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/SkinJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/VerticalAlignmentConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Skin.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Window.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/WindowCollection.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/ExtendedPlayerIndex.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/GamePadEventArgs.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/GamePadListener.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/GamePadListenerSettings.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/IInputService.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/InputListener.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/InputListenerComponent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/InputListenerSettings.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/KeyboardEventArgs.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/KeyboardListener.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/KeyboardListenerSettings.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/KeyboardModifiers.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/MouseEventArgs.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/MouseListener.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/MouseListenerSettings.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/TouchEventArgs.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/TouchListener.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/InputListeners/TouchListenerSettings.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/KeyboardExtended.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/KeyboardStateExtended.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/MonoGame.Extended.Input.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/MouseButton.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/MouseExtended.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Input/MouseStateExtended.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/FastRandomExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/LineSegment.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/AgeModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/CircleContainerModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/RectangleContainerModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/RectangleLoopContainerModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/DragModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/ColorInterpolator.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/HueInterpolator.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/Interpolator.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/OpacityInterpolator.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/RotationInterpolator.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/ScaleInterpolator.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/VelocityInterpolator
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/LinearGravityModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Modifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/OpacityFastFadeModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/RotationModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VelocityColorModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VelocityModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VortexModifier.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/MonoGame.Extended.Particles.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Particle.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/ParticleBuffer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/ParticleEffect.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/ParticleEmitter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/ParticleExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/ParticleModifierExecutionStrategy.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/ParticleReleaseParameters.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/BoxFillProfile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/BoxProfile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/BoxUniformProfile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/CircleProfile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/LineProfile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/PointProfile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/Profile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/RingProfile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Profiles/SprayProfile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Serialization/InterpolatorJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Serialization/ModifierExecutionStrategyJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Serialization/ModifierJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Serialization/ParticleJsonSerializerOptionsProvider.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Serialization/ProfileJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Serialization/TimeSpanJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/ContentReaderExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/MonoGame.Extended.Tiled.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModel.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModelBuilder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapEffect.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapLayerModel.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapLayerModelBuilder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModel.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapStaticLayerModel.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapStaticLayerModelBuilder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapEllipseContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapGroupLayerContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapImageContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapImageLayerContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapLayerContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapLayerModelContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapObjectContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapObjectDrawOrderContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapObjectLayerContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapObjectTemplateContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapOrientationContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapPolygonContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapPolylineContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapPropertyContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapStaggerAxisContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapStaggerIndexContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTileContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTileDrawOrderContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTileLayerContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTileLayerDataChunkContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTileLayerDataContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTileOffsetContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTilesetContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTilesetGridContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTilesetTileAnimationFrameContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Serialization/TiledMapTilesetTileContent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMap.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapEllipseObject.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapGroupLayer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapHelper.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapImageLayer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapLayer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapLayerType.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapObject.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapObjectDrawOrder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapObjectLayer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapObjectType.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapOrientation.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapPolygonObject.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapPolylineObject.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapProperties.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapPropertyValue.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapReader.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapRectangleObject.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTileDrawOrder.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTileFlipFlags.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTileLayer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTileObject.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTileset.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTilesetAnimatedTile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTilesetReader.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTilesetTile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/TiledMapTilesetTileAnimationFrame.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/ColorTween.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/EasingFunctions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/LinearOperations.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/LinearTween.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/MonoGame.Extended.Tweening.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/Tween.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/TweenFieldMember.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/TweenMember.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/TweenPropertyMember.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/Tweener.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/AnimationComponent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/BitmapFonts/BitmapFont.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/BitmapFonts/BitmapFontExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/BitmapFonts/BitmapFontReader.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/BitmapFonts/BitmapFontRegion.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Camera.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/Bag.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/Deque.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/DictionaryExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/IObservableCollection.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/IPoolable.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/ItemEventArgs.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/KeyedCollection.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/ListExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/ObjectPool.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/ObservableCollection.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Collections/Pool.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/ColorExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/ColorHelper.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Content/ContentManagerExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Content/ContentReaderExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/FramesPerSecondCounter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/FramesPerSecondCounterComponent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/GameComponentCollectionExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/GameTimeExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/HslColor.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/IColorable.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/IEquatableByRef.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/IMovable.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/IRectangular.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/IRotatable.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/IScalable.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/ISizable.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/IUpdate.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Angle.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/BoundingRectangle.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/CircleF.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/EllipseF.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/FastRandom.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/FloatHelper.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Matrix2.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/MatrixExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/OrientedRectangle.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Point2.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Point3.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/PrimitivesHelper.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/RandomExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Range.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Ray2.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/RectangleExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/RectangleF.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Segment2.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/ShapeExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/ShapeF.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Size.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Size2.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Size3.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Thickness.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Triangulation/CyclicalList.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Triangulation/IndexableCyclicalLinkedList.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Triangulation/LineSegment.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Triangulation/Triangle.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Triangulation/Triangulator.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Triangulation/Vertex.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Math/Vector2Extensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/MonoGame.Extended.csproj
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/MonoGame.Extended.csproj.DotSettings
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/OrthographicCamera.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Screens/GameScreen.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Screens/Screen.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Screens/ScreenManager.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Screens/Transitions/ExpandTransition.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Screens/Transitions/FadeTransition.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Screens/Transitions/Transition.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/BaseTypeJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/ColorJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/ContentManagerJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/FloatStringConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/HslColorJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/JsonContentLoader.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/JsonContentTypeReader.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/MonoGameJsonSerializerOptionsProvider.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/NinePatchRegion2DJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/RangeJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/RectangleFJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/Size2JsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/SizeJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/TextContentLoader.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/TextureRegion2DJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/TextureRegionService.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/ThicknessJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/Utf8JsonReaderExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Serialization/Vector2JsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Shapes/Polygon.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Shapes/Polyline.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/SimpleDrawableGameComponent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/SimpleGameComponent.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/AnimatedSprite.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/Animation.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/ISpriteBatchDrawable.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/Sprite.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/SpriteExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/SpriteSheet.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/SpriteSheetAnimation.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/SpriteSheetAnimationCycle.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/SpriteSheetAnimationData.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Sprites/SpriteSheetAnimationFrame.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/NinePatchRegion2D.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TextureAtlas.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TextureAtlasExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TextureAtlasJsonContentTypeReader.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TextureAtlasJsonConverter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TextureAtlasReader.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TexturePackerFile.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TexturePackerMeta.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TexturePackerPoint.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TexturePackerRectangle.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TexturePackerRegion.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TexturePackerSize.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/TextureAtlases/TextureRegion2D.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Timers/ContinuousClock.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Timers/CountdownTimer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Timers/GameTimer.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Timers/TimerState.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/Transform.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/VectorDraw/PrimitiveBatch.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/VectorDraw/PrimitiveDrawing.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/ViewportAdapters/BoxingViewportAdapter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/ViewportAdapters/DefaultViewportAdapter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/ViewportAdapters/ScalingViewportAdapter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/ViewportAdapters/ViewportAdapter.cs
create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended/ViewportAdapters/WindowViewportAdapter.cs
create mode 100644 Plugins/MonoGame.Extended/tests/Directory.Build.props
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Collisions.Tests/CollisionComponentTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Collisions.Tests/Implementation/BasicActor.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Collisions.Tests/Implementation/BasicWall.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Collisions.Tests/MonoGame.Extended.Collisions.Tests.csproj
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Collisions.Tests/QuadTreeTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Collisions.Tests/SpatialHashTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Collisions.Tests/packages.config
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/MonoGame.Extended.Content.Pipeline.Tests.Tiled.csproj
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/isometric.tmx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/isometric_tileset.png
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/level01.tmx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/template.tx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/test-object-layer.tmx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/test-tileset-base64.tmx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/test-tileset-csv.tmx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/test-tileset-gzip.tmx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/test-tileset-xml.tmx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TestData/test-tileset-zlib.tmx
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests.Tiled/TiledMapImporterProcessorTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests/AstridAnimatorImporterTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests/AstridAnimatorProcessorTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests/MonoGame.Extended.Content.Pipeline.Tests.csproj
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests/TestData/astrid-animator-atlas.json
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests/TestData/astrid-animator.aa
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests/TestData/test-tileset.json
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Content.Pipeline.Tests/TexturePackerJsonImporterProcessorTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Entities.Tests/AspectBuilderTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Entities.Tests/AspectTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Entities.Tests/BitArrayExtensionsTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Entities.Tests/ComponentManagerTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Entities.Tests/ComponentMapperTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Entities.Tests/ComponentTypeTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Entities.Tests/MonoGame.Extended.Entities.Tests.csproj
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Entities.Tests/WorldManagerTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Gui.Tests/Controls/GuiButtonTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Gui.Tests/Controls/GuiControlCollectionTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Gui.Tests/GuiRendererTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Gui.Tests/MonoGame.Extended.Gui.Tests.csproj
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/AngleTest.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/AssertExtensions.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/BitmapFonts/BitmapFontTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Camera2DTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/CollectionAssert.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Collections/BagTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Collections/DequeTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Content/ContentReaderExtensionsTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/MockGameWindow.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/MonoGame.Extended.Tests.csproj
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/OpenTK.dll.config
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Particles/AssertionModifier.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Particles/ColourTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Particles/EmitterTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Particles/ParticleBufferTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Particles/Profiles/PointProfileTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Particles/Profiles/RingProfileTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/BoundingRectangleTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/CircleFTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/EllipseFTest.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/OrientedRectangleTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/Point2Tests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/Ray2DTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/RectangleFTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/Segment2DTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/ShapeTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Primitives/Size2Tests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/RangeTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Serialization/ColorJsonConverterTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Serialization/RectangleFJsonConverterTest.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Shapes/PolygonFTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Sprites/SpriteSheetAnimationTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Sprites/SpriteTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/TestGame.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/TestGraphicsDevice.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/TestHelper.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/TextureAtlases/TextureAtlasTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/TextureAtlases/TextureRegion2DTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/Vector2ExtensionsTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/ViewportAdapters/BoxingViewportAdapterTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/ViewportAdapters/DefaultViewportAdapterTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tests/WithinDeltaEqualityComparer.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tiled.Tests/FullMapRendererTest.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tiled.Tests/MonoGame.Extended.Tiled.Tests.csproj
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tiled.Tests/TiledTilesetTests.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tweening.Tests/ColorHandler.cs
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tweening.Tests/MonoGame.Extended.Tweening.Tests.csproj
create mode 100644 Plugins/MonoGame.Extended/tests/MonoGame.Extended.Tweening.Tests/TweenerTests.cs
(limited to 'Plugins/MonoGame.Extended')
diff --git a/Plugins/MonoGame.Extended/.editorconfig b/Plugins/MonoGame.Extended/.editorconfig
new file mode 100644
index 0000000..e8cef19
--- /dev/null
+++ b/Plugins/MonoGame.Extended/.editorconfig
@@ -0,0 +1,463 @@
+root = true
+
+################################################################################
+### All files
+################################################################################
+[*]
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+file_header_template = Copyright (c) Christopher Whitley. All rights reserved.\nLicensed under the MIT license.\nSee LICENSE file in the project root for full license information.
+
+################################################################################
+### Xml files
+################################################################################
+[*.xml]
+indent_size = 2
+
+################################################################################
+### Yaml files
+################################################################################
+[*.yml]
+indent_size = 2
+
+################################################################################
+### C# files
+################################################################################
+[*.cs]
+
+################################################################################
+###
+###
+### Core EditorConfig Options
+###
+###
+################################################################################
+
+################################################################################
+### Indentation and spacing
+################################################################################
+indent_size = 4
+tab_width = 4
+
+################################################################################
+### New line preferences
+################################################################################
+end_of_line = crlf
+
+###############################################################################3
+###
+###
+### .NET Coding Conventions
+###
+###
+################################################################################
+[*.{cs,vb}]
+
+################################################################################
+### Organize usings
+################################################################################
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = true
+
+################################################################################
+### this. and Me. preferences
+################################################################################
+dotnet_style_qualification_for_event = false:silent
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_property = false:silent
+
+################################################################################
+### Language keywords vs BCL types preferences
+################################################################################
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+
+################################################################################
+### Parentheses preferences
+################################################################################
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+
+################################################################################
+### Modifier preferences
+################################################################################
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+
+################################################################################
+### Expression-level preferences
+################################################################################
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+
+################################################################################
+### Field preferences
+################################################################################
+dotnet_style_readonly_field = true:warning
+
+################################################################################
+### Parameter preferences
+################################################################################
+dotnet_code_quality_unused_parameters = all:suggestion
+
+################################################################################
+### Suppression preferences
+################################################################################
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+################################################################################
+###
+###
+### C# Coding Conventions
+###
+###
+################################################################################
+[*.cs]
+
+################################################################################
+### var preferences
+################################################################################
+csharp_style_var_elsewhere = false:silent
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_when_type_is_apparent = false:silent
+
+################################################################################
+### Expression-bodied members
+################################################################################
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_lambdas = true:suggestion
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+
+################################################################################
+### Pattern matching preferences
+################################################################################
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_pattern_matching = true:silent
+csharp_style_prefer_switch_expression = true:suggestion
+
+################################################################################
+### Null-checking preferences
+################################################################################
+csharp_style_conditional_delegate_call = true:suggestion
+
+################################################################################
+### Modifier preferences
+################################################################################
+csharp_prefer_static_local_function = true:warning
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
+
+################################################################################
+### Code-block preferences
+################################################################################
+csharp_prefer_braces = true:silent
+csharp_prefer_simple_using_statement = true:suggestion
+
+################################################################################
+### Expression-level preferences
+################################################################################
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+
+################################################################################
+### 'using' directive preferences
+################################################################################
+csharp_using_directive_placement = outside_namespace:silent
+
+################################################################################
+###
+###
+### C# Formatting Rules
+###
+###
+################################################################################
+
+################################################################################
+### New line preferences
+################################################################################
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = all
+csharp_new_line_between_query_expression_clauses = true
+
+################################################################################
+### Indentation preferences
+################################################################################
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = one_less_than_current
+csharp_indent_switch_labels = true
+
+################################################################################
+### Space preferences
+################################################################################
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+################################################################################
+### Wrapping preferences
+################################################################################
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+################################################################################
+###
+###
+### Naming styles
+###
+###
+################################################################################
+[*.{cs,vb}]
+
+################################################################################
+### Naming rules
+################################################################################
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion
+dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces
+dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase
+
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase
+
+dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods
+dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties
+dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.events_should_be_pascalcase.symbols = events
+dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion
+dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables
+dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion
+dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants
+dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion
+dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters
+dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields
+dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion
+dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields
+dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase
+
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase
+
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums
+dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions
+dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase
+
+################################################################################
+### Symbol specifications
+################################################################################
+dotnet_naming_symbols.interfaces.applicable_kinds = interface
+dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interfaces.required_modifiers =
+
+dotnet_naming_symbols.enums.applicable_kinds = enum
+dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.enums.required_modifiers =
+
+dotnet_naming_symbols.events.applicable_kinds = event
+dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.events.required_modifiers =
+
+dotnet_naming_symbols.methods.applicable_kinds = method
+dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.methods.required_modifiers =
+
+dotnet_naming_symbols.properties.applicable_kinds = property
+dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.properties.required_modifiers =
+
+dotnet_naming_symbols.public_fields.applicable_kinds = field
+dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_fields.required_modifiers =
+
+dotnet_naming_symbols.private_fields.applicable_kinds = field
+dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_fields.required_modifiers =
+
+dotnet_naming_symbols.private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_static_fields.required_modifiers = static
+
+dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum
+dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types_and_namespaces.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+dotnet_naming_symbols.type_parameters.applicable_kinds = namespace
+dotnet_naming_symbols.type_parameters.applicable_accessibilities = *
+dotnet_naming_symbols.type_parameters.required_modifiers =
+
+dotnet_naming_symbols.private_constant_fields.applicable_kinds = field
+dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_constant_fields.required_modifiers = const
+
+dotnet_naming_symbols.local_variables.applicable_kinds = local
+dotnet_naming_symbols.local_variables.applicable_accessibilities = local
+dotnet_naming_symbols.local_variables.required_modifiers =
+
+dotnet_naming_symbols.local_constants.applicable_kinds = local
+dotnet_naming_symbols.local_constants.applicable_accessibilities = local
+dotnet_naming_symbols.local_constants.required_modifiers = const
+
+dotnet_naming_symbols.parameters.applicable_kinds = parameter
+dotnet_naming_symbols.parameters.applicable_accessibilities = *
+dotnet_naming_symbols.parameters.required_modifiers =
+
+dotnet_naming_symbols.public_constant_fields.applicable_kinds = field
+dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_constant_fields.required_modifiers = const
+
+dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field
+dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static
+
+dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field
+dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static
+
+dotnet_naming_symbols.local_functions.applicable_kinds = local_function
+dotnet_naming_symbols.local_functions.applicable_accessibilities = *
+dotnet_naming_symbols.local_functions.required_modifiers =
+
+################################################################################
+### Naming styles
+################################################################################
+dotnet_naming_style.pascalcase.required_prefix =
+dotnet_naming_style.pascalcase.required_suffix =
+dotnet_naming_style.pascalcase.word_separator =
+dotnet_naming_style.pascalcase.capitalization = pascal_case
+
+dotnet_naming_style.ipascalcase.required_prefix = I
+dotnet_naming_style.ipascalcase.required_suffix =
+dotnet_naming_style.ipascalcase.word_separator =
+dotnet_naming_style.ipascalcase.capitalization = pascal_case
+
+dotnet_naming_style.tpascalcase.required_prefix = T
+dotnet_naming_style.tpascalcase.required_suffix =
+dotnet_naming_style.tpascalcase.word_separator =
+dotnet_naming_style.tpascalcase.capitalization = pascal_case
+
+dotnet_naming_style._camelcase.required_prefix = _
+dotnet_naming_style._camelcase.required_suffix =
+dotnet_naming_style._camelcase.word_separator =
+dotnet_naming_style._camelcase.capitalization = camel_case
+
+dotnet_naming_style.camelcase.required_prefix =
+dotnet_naming_style.camelcase.required_suffix =
+dotnet_naming_style.camelcase.word_separator =
+dotnet_naming_style.camelcase.capitalization = camel_case
+
+dotnet_naming_style.s_camelcase.required_prefix = s_
+dotnet_naming_style.s_camelcase.required_suffix =
+dotnet_naming_style.s_camelcase.word_separator =
+dotnet_naming_style.s_camelcase.capitalization = camel_case
+
+
+################################################################################
+###
+### Warning Supressions
+###
+################################################################################
+[*.{cs,vb}]
diff --git a/Plugins/MonoGame.Extended/.gitattributes b/Plugins/MonoGame.Extended/.gitattributes
new file mode 100644
index 0000000..e9afe0a
--- /dev/null
+++ b/Plugins/MonoGame.Extended/.gitattributes
@@ -0,0 +1,48 @@
+################################################################################
+### Default behavior
+### - Treat as text
+### - Normalize to Unix-style line endings
+################################################################################
+* text eol=lf
+
+################################################################################
+### C# source file behavior
+### - Treat as text
+### - Normalize to Unix-style line endings
+### - Diff as csharp
+################################################################################
+*.cs text eol=lf diff=csharp
+
+################################################################################
+### csproj file behavior
+### - Treat as text
+### - Normalize to Unix-style line endings
+### - Use a union merge when resolving conflicts
+################################################################################
+.csproj text eol=lf merge=union
+
+################################################################################
+### sln file behavior
+### - Treat as text
+### - Normalize to Windows-style line endings
+### - Use a union merge when resolving conflicts
+################################################################################
+*.sln text eol=crlf merge=union
+
+################################################################################
+### image file behavior
+### - Treat as binary
+################################################################################
+*.bmp binary
+*.gif binary
+*.ico binary
+*.jpg binary
+*.jpeg binary
+*.png binary
+*.webp binary
+
+################################################################################
+### MGFXO file behavior
+### - Treat as binary
+################################################################################
+*.mgfxo binary
diff --git a/Plugins/MonoGame.Extended/.github/FUNDING.yml b/Plugins/MonoGame.Extended/.github/FUNDING.yml
new file mode 100644
index 0000000..e6160fa
--- /dev/null
+++ b/Plugins/MonoGame.Extended/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+github:
+ - aristurtledev
+ - craftworkgames
diff --git a/Plugins/MonoGame.Extended/.github/workflows/create-release.yml b/Plugins/MonoGame.Extended/.github/workflows/create-release.yml
new file mode 100644
index 0000000..f42b96e
--- /dev/null
+++ b/Plugins/MonoGame.Extended/.github/workflows/create-release.yml
@@ -0,0 +1,80 @@
+################################################################################
+### Build MonoGame.Extended (Develop)
+### Clones the `develop` branch and performs a build, test, then pack of the
+### Monogame.Extended source code. Once the build job is finished, the deploy
+### job will upload the nupkg files created to the MonoGame.Extended GitHub
+###
+### - Only runs on a push to the `develop` branch
+################################################################################
+name: "Create Release"
+
+on:
+ workflow_dispatch:
+ inputs:
+ prerelease:
+ description: 'Is this a prerelease?'
+ required: true
+ default: 'true'
+ source-feed:
+ description: |
+ Which source feed to publish to?
+ (Valid values are 'NuGet' or 'GitHub')
+ required: true
+ default: GitHub
+
+jobs:
+ build:
+ name: "Build MonoGame.Extended"
+ runs-on: ubuntu-latest
+ env:
+ IS_PRERELEASE: ${{ inputs.prerelease == 'true' }}
+ BUILD_NUMBER: ${{ inputs.prerelease == 'true' && github.run_number || '' }}
+
+ steps:
+ - name: Clone Repository
+ uses: actions/checkout@v4
+
+ - name: Setup Dotnet
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 6.0.x
+
+ - name: Build MonoGame.Extended
+ run: dotnet build --nologo --verbosity minimal --configuration Release
+
+ - name: Test MonoGame.Extended
+ run: dotnet test --nologo --verbosity minimal --configuration Release
+
+ - name: Pack MonoGame.Extended
+ run: dotnet pack --nologo --verbosity minimal --configuration Release
+
+ - name: Upload Artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-artifacts
+ path: ./.artifacts/source/package/release/*.nupkg
+
+ deploy:
+ name: "Deploy NuGets"
+ runs-on: ubuntu-latest
+ needs: [ build ]
+ permissions:
+ packages: write
+ contents: write
+
+ steps:
+ - name: "Download Artifacts"
+ uses: actions/download-artifact@v4
+ with:
+ name: build-artifacts
+ path: ./.artifacts
+
+ - name: "Push Packages"
+ env:
+ SOURCE_URL: ${{ inputs.source-feed == 'GitHub' && 'https://nuget.pkg.github.com/craftworkgames/index.json' || inputs.source-feed == 'NuGet' && 'https://api.nuget.org/v3/index.json' }}
+ API_KEY: ${{ inputs.source-feed == 'GitHub' && secrets.GITHUB_TOKEN || inputs.source-feed == 'NuGet' && secrets.NUGET_ACCESS_TOKEN }}
+ run: |
+ PACKAGES=(".artifacts/*.nupkg")
+ for PACKAGE in "${PACKAGES[@]}"; do
+ dotnet nuget push "$PACKAGE" --source "$SOURCE_URL" --skip-duplicate --api-key "$API_KEY"
+ done
diff --git a/Plugins/MonoGame.Extended/.github/workflows/pull-request-test.yml b/Plugins/MonoGame.Extended/.github/workflows/pull-request-test.yml
new file mode 100644
index 0000000..e483e3c
--- /dev/null
+++ b/Plugins/MonoGame.Extended/.github/workflows/pull-request-test.yml
@@ -0,0 +1,32 @@
+################################################################################
+### Pull Request Test
+### Executes tests to ensure that the pull request being submitted is valid.
+### - Only runs on pull requests made to the `develop` branch
+### - Only runs if the pull request was opened or synchronized
+################################################################################
+name: Pull Request Test
+
+on:
+ pull_request:
+ branches:
+ - develop
+ - main
+ types:
+ - opened
+ - synchronize
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Clone Repository
+ uses: actions/checkout@v4
+
+ - name: Setup DotNet
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 6.0.x
+
+ - name: Test MonoGame.Extended
+ run: dotnet test --nologo --verbosity minimal --configuration Release
diff --git a/Plugins/MonoGame.Extended/.gitignore b/Plugins/MonoGame.Extended/.gitignore
new file mode 100644
index 0000000..d64f1ef
--- /dev/null
+++ b/Plugins/MonoGame.Extended/.gitignore
@@ -0,0 +1,29 @@
+################################################################################
+### IDE directories
+################################################################################
+.vs/
+.vscode/
+.idea/
+
+################################################################################
+### User specific files that can be generated by Visual Studio
+################################################################################
+*.suo
+*.user
+
+################################################################################
+### Build and Intermediate directories
+################################################################################
+[Bb]in/
+[Oo]bj/
+
+################################################################################
+### Build artifacts directory
+################################################################################
+.artifacts/
+
+################################################################################
+### OS specific auto generated files
+################################################################################
+.DS_Store
+[Tt]humbs.db
diff --git a/Plugins/MonoGame.Extended/CONTRIBUTING.md b/Plugins/MonoGame.Extended/CONTRIBUTING.md
new file mode 100644
index 0000000..85fdd80
--- /dev/null
+++ b/Plugins/MonoGame.Extended/CONTRIBUTING.md
@@ -0,0 +1,70 @@
+# Contributing to MonoGame.Extended
+
+We're happy that you have chosen to contribute to the MonoGame Extended project.
+
+You are joining a team of dedicated volunteers that are building an extension library to the game framework [MonoGame](http://www.monogame.net/).
+
+Please read this document completely before contributing.
+
+
+## How To Contribute
+
+MonoGame.Extended has a `main` branch for stable releases and a `develop` branch for daily development. New features and fixes are always submitted to the `develop` branch.
+
+If you are looking for ways to help you should start by looking at the [Open Issues](https://github.com/craftworkgames/MonoGame.Extended/issues). Please let us know if you plan to work on an issue so that others are not duplicating work.
+
+The MonoGame.Extended project follows standard [GitHub flow](https://guides.github.com/introduction/flow/index.html). You should learn and be familiar with how to [use Git](https://help.github.com/articles/set-up-git/), how to [create a fork of MonoGame.Extended](https://help.github.com/articles/fork-a-repo/), and how to [submit a Pull Request](https://help.github.com/articles/using-pull-requests/).
+
+After you submit a PR the GitHub actions will trigger and build your changes and verify that all tests pass. Project maintainers and contributors will review your changes and provide constructive feedback to improve your submission.
+
+Once satisfied that your changes are good for MonoGame.Extended we will merge it.
+
+## Quick Guidelines
+
+Here are a few simple rules and suggestions to remember when contributing to MonoGame.Extended.
+
+* :bangbang: **NEVER** commit code that you didn't personally write.
+* :bangbang: **NEVER** use decompiler tools to steal code and submit them as your own work.
+* :bangbang: **NEVER** decompile XNA assemblies and steal Microsoft's copyrighted code.
+* **PLEASE** try keep your PRs focused on a single topic and of a reasonable size or we may ask you to break it up.
+* **PLEASE** be sure to write simple and descriptive commit messages.
+* **DO NOT** surprise us with new APIs or big new features. Open an issue to discuss your ideas first.
+* **DO NOT** reorder type members as it makes it difficult to compare code changes in a PR.
+* **DO** give priority to the existing style of the file you're changing.
+* **DO** try to add to our [unit tests](Source/MonoGame.Extended.Tests) when adding new features or fixing bugs.
+* **DO NOT** send PRs for code style changes or make code changes just for the sake of style.
+* **PLEASE** keep a civil and respectful tone when discussing and reviewing contributions.
+* **PLEASE** tell others about MonoGame.Extended and your contributions via social media.
+
+## Decompiler Tools
+
+We prohibit tools like dotPeek, ILSpy, JustDecompiler, or .NET Reflector which convert compiled assemblies into readable code.
+
+It is **NEVER ACCEPTABLE** to decompile copyrighted assemblies and submit that code to the MonoGame.Extended project.
+
+* It **DOES NOT** matter how much you change the code.
+* It **DOES NOT** matter what country you live in or what your local laws say.
+* It **DOES NOT** matter that XNA is discontinued.
+* It **DOES NOT** matter how small the bit of code you have stolen is.
+* It **DOES NOT** matter what your opinion is of stealing code.
+
+If you did not write the code, you do not have ownership of the code, and you shouldn't submit it to MonoGame.Extended.
+
+If we find a contribution in violation of copyright it will be immediately removed. We will bar that contributor from the MonoGame.Extended project.
+
+
+## Licensing
+
+The MonoGame.Extended project is under the [MIT License](https://opensource.org/licenses/MIT) unless a portion of code is explicitly stated elsewhere. See the [LICENSE](LICENSE) for more details. Third-party libraries used by MonoGame.Extended are under their own licenses, we always seek permission from the original author of those libraries.. Please refer to those libraries for details on the license they use.
+
+We accept contributions in "good faith" that it isn't bound to a conflicting license. By submitting a PR you agree to distribute your work under the MonoGame.Extended license and copyright.
+
+
+## Need More Help?
+
+If you need help, please ask questions in our [Discord](https://discord.gg/xPUEkj9), or you can ask questions in the official [MonoGame Discord](https://discord.gg/monogame).
+
+
+Thanks for reading this guide and helping make MonoGame.Extended great!
+
+ :heart: The MonoGame.Extended Team
diff --git a/Plugins/MonoGame.Extended/Directory.Build.props b/Plugins/MonoGame.Extended/Directory.Build.props
new file mode 100644
index 0000000..52d9ed9
--- /dev/null
+++ b/Plugins/MonoGame.Extended/Directory.Build.props
@@ -0,0 +1,46 @@
+
+
+
+
+ net6.0
+ $(MSBuildThisFileDirectory)
+
+
+
+ 3.9.0
+ -prerelease
+ .$(BUILD_NUMBER)
+ $(MonoGameExtendedVersion)$(IsPrerelease)$(BuildNumber)
+
+
+
+ craftworkgames and contributors
+ https://github.com/craftworkgames/MonoGame.Extended
+ https://github.com/craftworkgames/MonoGame.Extended
+ git
+ develop
+ en
+ logo-nuget-128.png
+ README.md
+ MIT
+
+
+
+
+
+
+
+
+
+
+ true
+ AllEnabledByDefault
+ latest
+ true
+ true
+ false
+ false
+ nullable
+
+
+
diff --git a/Plugins/MonoGame.Extended/LICENSE b/Plugins/MonoGame.Extended/LICENSE
new file mode 100644
index 0000000..1055866
--- /dev/null
+++ b/Plugins/MonoGame.Extended/LICENSE
@@ -0,0 +1,25 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-2024:
+- Dylan Wilson (https://github.com/dylanwilson80)
+- Lucas Girouard-Stranks (https://github.com/lithiumtoast)
+- Christopher Whitley (https://github.com/aristurtledev)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/Plugins/MonoGame.Extended/MonoGame.Extended.sln b/Plugins/MonoGame.Extended/MonoGame.Extended.sln
new file mode 100644
index 0000000..2cfd094
--- /dev/null
+++ b/Plugins/MonoGame.Extended/MonoGame.Extended.sln
@@ -0,0 +1,235 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28803.156
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "source", "source", "{2BD6F851-7287-4361-85AB-DAE9DF30D932}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended", "source\MonoGame.Extended\MonoGame.Extended.csproj", "{C8717306-E333-418E-86A7-8D9781D7FDAC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Animations", "source\MonoGame.Extended.Animations\MonoGame.Extended.Animations.csproj", "{71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Collisions", "source\MonoGame.Extended.Collisions\MonoGame.Extended.Collisions.csproj", "{7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Content.Pipeline", "source\MonoGame.Extended.Content.Pipeline\MonoGame.Extended.Content.Pipeline.csproj", "{4A4066EB-B49A-4E80-B424-9E0BD2147886}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Entities", "source\MonoGame.Extended.Entities\MonoGame.Extended.Entities.csproj", "{CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Graphics", "source\MonoGame.Extended.Graphics\MonoGame.Extended.Graphics.csproj", "{56627685-4BA7-44E3-ACA6-F2990DE089F2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Gui", "source\MonoGame.Extended.Gui\MonoGame.Extended.Gui.csproj", "{16E79E22-A41A-47BC-9DC9-287B812A6DD1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Input", "source\MonoGame.Extended.Input\MonoGame.Extended.Input.csproj", "{76B39424-7884-4EEC-A8D5-5126B29941B7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Particles", "source\MonoGame.Extended.Particles\MonoGame.Extended.Particles.csproj", "{BE74938D-9004-4D36-AD50-5C6C141A7180}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Tiled", "source\MonoGame.Extended.Tiled\MonoGame.Extended.Tiled.csproj", "{572C908D-4627-4678-9641-D4950DE43B13}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Tweening", "source\MonoGame.Extended.Tweening\MonoGame.Extended.Tweening.csproj", "{F144A062-4FF3-44EC-9A04-31C654B436B0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{61C82014-E3A9-4AB3-8705-FBBD5F799BA6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Collisions.Tests", "tests\MonoGame.Extended.Collisions.Tests\MonoGame.Extended.Collisions.Tests.csproj", "{58F88A3C-C09F-4664-A34E-60E89252870A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Content.Pipeline.Tests", "tests\MonoGame.Extended.Content.Pipeline.Tests\MonoGame.Extended.Content.Pipeline.Tests.csproj", "{A127A61A-B26E-4A01-BD4C-9896FDB287AE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Content.Pipeline.Tests.Tiled", "tests\MonoGame.Extended.Content.Pipeline.Tests.Tiled\MonoGame.Extended.Content.Pipeline.Tests.Tiled.csproj", "{0426263A-B8DE-43FC-A91E-21544F61D80E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Entities.Tests", "tests\MonoGame.Extended.Entities.Tests\MonoGame.Extended.Entities.Tests.csproj", "{D3B0E350-B92E-4E49-99A3-68E66CB53F16}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Gui.Tests", "tests\MonoGame.Extended.Gui.Tests\MonoGame.Extended.Gui.Tests.csproj", "{AA52F204-3EE7-40CB-B041-0AB36475DAF0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Tests", "tests\MonoGame.Extended.Tests\MonoGame.Extended.Tests.csproj", "{E1339B07-EB0B-454F-9803-E923843DB5C4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Tiled.Tests", "tests\MonoGame.Extended.Tiled.Tests\MonoGame.Extended.Tiled.Tests.csproj", "{BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Extended.Tweening.Tests", "tests\MonoGame.Extended.Tweening.Tests\MonoGame.Extended.Tweening.Tests.csproj", "{C2A9982B-7BF7-4243-9E05-CFD31752B6DC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C8717306-E333-418E-86A7-8D9781D7FDAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C8717306-E333-418E-86A7-8D9781D7FDAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C8717306-E333-418E-86A7-8D9781D7FDAC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C8717306-E333-418E-86A7-8D9781D7FDAC}.Debug|x86.Build.0 = Debug|Any CPU
+ {C8717306-E333-418E-86A7-8D9781D7FDAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C8717306-E333-418E-86A7-8D9781D7FDAC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C8717306-E333-418E-86A7-8D9781D7FDAC}.Release|x86.ActiveCfg = Release|Any CPU
+ {C8717306-E333-418E-86A7-8D9781D7FDAC}.Release|x86.Build.0 = Release|Any CPU
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}.Debug|x86.Build.0 = Debug|Any CPU
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}.Release|x86.ActiveCfg = Release|Any CPU
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3}.Release|x86.Build.0 = Release|Any CPU
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}.Debug|x86.Build.0 = Debug|Any CPU
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}.Release|x86.ActiveCfg = Release|Any CPU
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5}.Release|x86.Build.0 = Release|Any CPU
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886}.Debug|x86.Build.0 = Debug|Any CPU
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886}.Release|x86.ActiveCfg = Release|Any CPU
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886}.Release|x86.Build.0 = Release|Any CPU
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}.Debug|x86.Build.0 = Debug|Any CPU
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}.Release|x86.ActiveCfg = Release|Any CPU
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38}.Release|x86.Build.0 = Release|Any CPU
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2}.Debug|x86.Build.0 = Debug|Any CPU
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2}.Release|x86.ActiveCfg = Release|Any CPU
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2}.Release|x86.Build.0 = Release|Any CPU
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1}.Debug|x86.Build.0 = Debug|Any CPU
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1}.Release|x86.ActiveCfg = Release|Any CPU
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1}.Release|x86.Build.0 = Release|Any CPU
+ {76B39424-7884-4EEC-A8D5-5126B29941B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {76B39424-7884-4EEC-A8D5-5126B29941B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {76B39424-7884-4EEC-A8D5-5126B29941B7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {76B39424-7884-4EEC-A8D5-5126B29941B7}.Debug|x86.Build.0 = Debug|Any CPU
+ {76B39424-7884-4EEC-A8D5-5126B29941B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {76B39424-7884-4EEC-A8D5-5126B29941B7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {76B39424-7884-4EEC-A8D5-5126B29941B7}.Release|x86.ActiveCfg = Release|Any CPU
+ {76B39424-7884-4EEC-A8D5-5126B29941B7}.Release|x86.Build.0 = Release|Any CPU
+ {BE74938D-9004-4D36-AD50-5C6C141A7180}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BE74938D-9004-4D36-AD50-5C6C141A7180}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BE74938D-9004-4D36-AD50-5C6C141A7180}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BE74938D-9004-4D36-AD50-5C6C141A7180}.Debug|x86.Build.0 = Debug|Any CPU
+ {BE74938D-9004-4D36-AD50-5C6C141A7180}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BE74938D-9004-4D36-AD50-5C6C141A7180}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BE74938D-9004-4D36-AD50-5C6C141A7180}.Release|x86.ActiveCfg = Release|Any CPU
+ {BE74938D-9004-4D36-AD50-5C6C141A7180}.Release|x86.Build.0 = Release|Any CPU
+ {572C908D-4627-4678-9641-D4950DE43B13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {572C908D-4627-4678-9641-D4950DE43B13}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {572C908D-4627-4678-9641-D4950DE43B13}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {572C908D-4627-4678-9641-D4950DE43B13}.Debug|x86.Build.0 = Debug|Any CPU
+ {572C908D-4627-4678-9641-D4950DE43B13}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {572C908D-4627-4678-9641-D4950DE43B13}.Release|Any CPU.Build.0 = Release|Any CPU
+ {572C908D-4627-4678-9641-D4950DE43B13}.Release|x86.ActiveCfg = Release|Any CPU
+ {572C908D-4627-4678-9641-D4950DE43B13}.Release|x86.Build.0 = Release|Any CPU
+ {F144A062-4FF3-44EC-9A04-31C654B436B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F144A062-4FF3-44EC-9A04-31C654B436B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F144A062-4FF3-44EC-9A04-31C654B436B0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F144A062-4FF3-44EC-9A04-31C654B436B0}.Debug|x86.Build.0 = Debug|Any CPU
+ {F144A062-4FF3-44EC-9A04-31C654B436B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F144A062-4FF3-44EC-9A04-31C654B436B0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F144A062-4FF3-44EC-9A04-31C654B436B0}.Release|x86.ActiveCfg = Release|Any CPU
+ {F144A062-4FF3-44EC-9A04-31C654B436B0}.Release|x86.Build.0 = Release|Any CPU
+ {58F88A3C-C09F-4664-A34E-60E89252870A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {58F88A3C-C09F-4664-A34E-60E89252870A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {58F88A3C-C09F-4664-A34E-60E89252870A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {58F88A3C-C09F-4664-A34E-60E89252870A}.Debug|x86.Build.0 = Debug|Any CPU
+ {58F88A3C-C09F-4664-A34E-60E89252870A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {58F88A3C-C09F-4664-A34E-60E89252870A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {58F88A3C-C09F-4664-A34E-60E89252870A}.Release|x86.ActiveCfg = Release|Any CPU
+ {58F88A3C-C09F-4664-A34E-60E89252870A}.Release|x86.Build.0 = Release|Any CPU
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE}.Debug|x86.Build.0 = Debug|Any CPU
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE}.Release|x86.ActiveCfg = Release|Any CPU
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE}.Release|x86.Build.0 = Release|Any CPU
+ {0426263A-B8DE-43FC-A91E-21544F61D80E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0426263A-B8DE-43FC-A91E-21544F61D80E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0426263A-B8DE-43FC-A91E-21544F61D80E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0426263A-B8DE-43FC-A91E-21544F61D80E}.Debug|x86.Build.0 = Debug|Any CPU
+ {0426263A-B8DE-43FC-A91E-21544F61D80E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0426263A-B8DE-43FC-A91E-21544F61D80E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0426263A-B8DE-43FC-A91E-21544F61D80E}.Release|x86.ActiveCfg = Release|Any CPU
+ {0426263A-B8DE-43FC-A91E-21544F61D80E}.Release|x86.Build.0 = Release|Any CPU
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16}.Debug|x86.Build.0 = Debug|Any CPU
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16}.Release|x86.ActiveCfg = Release|Any CPU
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16}.Release|x86.Build.0 = Release|Any CPU
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0}.Debug|x86.Build.0 = Debug|Any CPU
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0}.Release|x86.ActiveCfg = Release|Any CPU
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0}.Release|x86.Build.0 = Release|Any CPU
+ {E1339B07-EB0B-454F-9803-E923843DB5C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E1339B07-EB0B-454F-9803-E923843DB5C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E1339B07-EB0B-454F-9803-E923843DB5C4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E1339B07-EB0B-454F-9803-E923843DB5C4}.Debug|x86.Build.0 = Debug|Any CPU
+ {E1339B07-EB0B-454F-9803-E923843DB5C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E1339B07-EB0B-454F-9803-E923843DB5C4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E1339B07-EB0B-454F-9803-E923843DB5C4}.Release|x86.ActiveCfg = Release|Any CPU
+ {E1339B07-EB0B-454F-9803-E923843DB5C4}.Release|x86.Build.0 = Release|Any CPU
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}.Debug|x86.Build.0 = Debug|Any CPU
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}.Release|x86.ActiveCfg = Release|Any CPU
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5}.Release|x86.Build.0 = Release|Any CPU
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC}.Debug|x86.Build.0 = Debug|Any CPU
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC}.Release|x86.ActiveCfg = Release|Any CPU
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {C8717306-E333-418E-86A7-8D9781D7FDAC} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {71A8D50C-DAF1-4D08-99FD-2EACD6EAD5E3} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {7F60B59F-4B84-401F-8A13-AAA3F0B9E4A5} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {4A4066EB-B49A-4E80-B424-9E0BD2147886} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {CD5C1878-13B6-4FAD-91AE-AEA3C1520E38} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {56627685-4BA7-44E3-ACA6-F2990DE089F2} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {16E79E22-A41A-47BC-9DC9-287B812A6DD1} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {76B39424-7884-4EEC-A8D5-5126B29941B7} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {BE74938D-9004-4D36-AD50-5C6C141A7180} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {572C908D-4627-4678-9641-D4950DE43B13} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {F144A062-4FF3-44EC-9A04-31C654B436B0} = {2BD6F851-7287-4361-85AB-DAE9DF30D932}
+ {58F88A3C-C09F-4664-A34E-60E89252870A} = {61C82014-E3A9-4AB3-8705-FBBD5F799BA6}
+ {A127A61A-B26E-4A01-BD4C-9896FDB287AE} = {61C82014-E3A9-4AB3-8705-FBBD5F799BA6}
+ {0426263A-B8DE-43FC-A91E-21544F61D80E} = {61C82014-E3A9-4AB3-8705-FBBD5F799BA6}
+ {D3B0E350-B92E-4E49-99A3-68E66CB53F16} = {61C82014-E3A9-4AB3-8705-FBBD5F799BA6}
+ {AA52F204-3EE7-40CB-B041-0AB36475DAF0} = {61C82014-E3A9-4AB3-8705-FBBD5F799BA6}
+ {E1339B07-EB0B-454F-9803-E923843DB5C4} = {61C82014-E3A9-4AB3-8705-FBBD5F799BA6}
+ {BF0EC593-4BAB-424F-B7E9-BB13EC78A0E5} = {61C82014-E3A9-4AB3-8705-FBBD5F799BA6}
+ {C2A9982B-7BF7-4243-9E05-CFD31752B6DC} = {61C82014-E3A9-4AB3-8705-FBBD5F799BA6}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8ED5A62D-25EC-4331-9F99-BDD1E10C02A0}
+ EndGlobalSection
+EndGlobal
diff --git a/Plugins/MonoGame.Extended/README.md b/Plugins/MonoGame.Extended/README.md
new file mode 100644
index 0000000..3025376
--- /dev/null
+++ b/Plugins/MonoGame.Extended/README.md
@@ -0,0 +1,68 @@
+> [!NOTE]
+> Hi MonoGame community, MonoGame.Extended is currently being updated to resolve outstanding bug issues, included those surrounding Tiled, and to update for MonoGame 3.8.1.303. Please bear with me as I work through the backlog. You can follow the progress in the [v4.0.0 Milestones](https://github.com/craftworkgames/MonoGame.Extended/milestone/8) page.
+>
+> - AristurtleDev
+
+
+
+# MonoGame.Extended
+
+MonoGame.Extended is a set of utilities (in the form of libraries/tools) to [MonoGame](http://www.monogame.net/) that makes it easier to make games. Choose what you want, the rest stays out of your way. It makes MonoGame more awesome.
+
+[](https://github.com/craftworkgames/MonoGame.Extended/actions?query=workflow%3A%22Build%2C+Test%2C+Deploy%22) [](http://www.monogameextended.net/)
+
+## Getting started
+
+Code is distributed as NuGet packages in the form of libraries (`.dll` files). You can easily install the NuGet packages into your existing MonoGame project using the NuGet Package Manager UI in Visual Studio or by using the command line interface (CLI) in a terminal.
+
+**Current Stable Release**
+> [!WARNING]
+> The current stable release is not compatible with MonoGame 3.8.1.303.
+
+```sh
+dotnet add package MonoGame.Extended --version 3.8.0
+```
+
+**Current Prerelease**
+> [!NOTE]
+> Prerelease is based on current `develop` branch snapshot. There it is not considered stable and may contain bugs
+```sh
+dotnet add package MonoGame.Extended --version 3.9.0-prerelease.4
+```
+
+### Using the Content Pipeline Extensions
+To use the content pipeline extensions, you will need to edit your `.mgcb` file to reference the `.dll`. To see an example of how to do this with NuGet see the samples at https://github.com/craftworkgames/MonoGame.Extended-samples. The important pieces are the `NuGet.config` file and the `.mgcb` file.
+
+## Where to next?
+
+- Check out [the samples](https://github.com/craftworkgames/MonoGame.Extended-samples)
+- Join our live [Discord](https://discord.gg/xPUEkj9)
+- Read the [Documentation](http://www.monogameextended.net/docs)
+- Submit an [issue on GitHub](https://github.com/craftworkgames/MonoGame.Extended/issues)
+- Ask a question on [gamedev stack overflow](http://gamedev.stackexchange.com/questions/tagged/monogame-extended)
+- Post on our [MonoGame community forum](http://community.monogame.net/category/extended)
+- Follow development [on Patreon](https://www.patreon.com/craftworkgames)
+
+## News
+
+We're in the process of developing MonoGame.Extended 4.0! Stay tuned.
+
+## Patreon Supporters
+The patreon has been removed. If you would like to support the maintainers of this project, please consider using the GitHub sponsors link for one of the maintainers.
+
+As a special thanks to those that supported this project through Patreon in the past, their websites were linked in this readme and have been preserved below:
+
+- [PRT Studios](http://prt-studios.com/)
+- [optimuspi](http://www.optimuspi.com/)
+
+
+## Special Thanks
+- Matthew-Davey for letting us use the [Mercury Particle Engine](https://github.com/Matthew-Davey/mercury-particle-engine).
+- John McDonald for [2D XNA Primitives](https://bitbucket.org/C3/2d-xna-primitives/wiki/Home)
+- [LibGDX](https://libgdx.badlogicgames.com) for a whole lot of inspiration.
+- [@prime31](https://github.com/prime31) for [`Nez`](https://github.com/prime31/Nez). Both `MonoGame.Extended` and `Nez` are in communication with each other to share ideas.
+- All of our contributors!
+
+## License
+
+MonoGame.Extended is released under the [The MIT License (MIT)](https://github.com/craftworkgames/MonoGame.Extended/blob/master/LICENSE).
diff --git a/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/DifferentPoolSizeCollision.cs b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/DifferentPoolSizeCollision.cs
new file mode 100644
index 0000000..a4ac858
--- /dev/null
+++ b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/DifferentPoolSizeCollision.cs
@@ -0,0 +1,115 @@
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Engines;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Collisions;
+using MonoGame.Extended.Collisions.Layers;
+using MonoGame.Extended.Collisions.QuadTree;
+
+namespace MonoGame.Extended.Benchmarks.Collisions;
+
+[SimpleJob(RunStrategy.ColdStart, launchCount:3)]
+public class DifferentPoolSizeCollision
+{
+ private const int COMPONENT_BOUNDARY_SIZE = 1000;
+
+ private readonly CollisionComponent _collisionComponent;
+ private readonly Random _random = new Random();
+ private readonly GameTime _gameTime = new GameTime(TimeSpan.Zero, TimeSpan.FromMilliseconds(16));
+
+ public DifferentPoolSizeCollision()
+ {
+ var size = new Size2(COMPONENT_BOUNDARY_SIZE, COMPONENT_BOUNDARY_SIZE);
+ _collisionComponent = new CollisionComponent(new RectangleF(Point2.Zero, size));
+ }
+
+ class Collider: ICollisionActor
+ {
+ public Collider(Point2 position)
+ {
+ Bounds = new RectangleF(position, new Size2(1, 1));
+ }
+
+ public IShapeF Bounds { get; set; }
+ public Vector2 Shift { get; set; }
+
+ public Point2 Position {
+ get => Bounds.Position;
+ set => Bounds.Position = value;
+ }
+
+ public void OnCollision(CollisionEventArgs collisionInfo)
+ {
+ }
+ }
+
+ [Params(100, 500, 1000)]
+ public int N { get; set; }
+
+
+ [Params(1, 2)]
+ public int LayersCount { get; set; }
+
+ public int UpdateCount { get; set; } = 100;
+
+
+ private List _colliders = new();
+ private List _layers = new();
+
+ [GlobalSetup]
+ public void GlobalSetup()
+ {
+ if (LayersCount > 1)
+ {
+ for (int i = 0; i < LayersCount; i++)
+ {
+ var size = new Size2(COMPONENT_BOUNDARY_SIZE, COMPONENT_BOUNDARY_SIZE);
+ var layer = new Layer(new SpatialHash(new Size2(5, 5)));//new QuadTreeSpace(new RectangleF(Point2.Zero, size)))));
+ _collisionComponent.Add(i.ToString(), layer);
+ _layers.Add(layer);
+ }
+ for (int i = 0; i < LayersCount - 1; i++)
+ _collisionComponent.AddCollisionBetweenLayer(_layers[i], _layers[i + 1]);
+
+ }
+
+ for (int i = 0; i < N; i++)
+ {
+ var layer = LayersCount == 1
+ ? _collisionComponent.Layers.First().Value
+ : _layers[i % LayersCount];
+
+ var collider = new Collider(new Point2(
+ _random.Next(COMPONENT_BOUNDARY_SIZE),
+ _random.Next(COMPONENT_BOUNDARY_SIZE)))
+ {
+ Shift = new Vector2(
+ _random.Next(4) - 2,
+ _random.Next(4) - 2),
+ };
+ _colliders.Add(collider);
+ layer.Space.Insert(collider);
+ }
+ }
+
+ [GlobalCleanup]
+ public void GlobalCleanup()
+ {
+ foreach (var collider in _colliders)
+ _collisionComponent.Remove(collider);
+ _colliders.Clear();
+ foreach (var layer in _layers)
+ _collisionComponent.Remove(layer: layer);
+ _layers.Clear();
+ }
+
+ [Benchmark]
+ public void Benchmark()
+ {
+ for (int i = 0; i < UpdateCount; i++)
+ {
+ foreach (var collider in _colliders)
+ collider.Position += collider.Shift;
+ //_collisionComponent.Update(_gameTime);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/MonoGame.Extended.Benchmarks.Collisions.csproj b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/MonoGame.Extended.Benchmarks.Collisions.csproj
new file mode 100644
index 0000000..530bd13
--- /dev/null
+++ b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/MonoGame.Extended.Benchmarks.Collisions.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/Program.cs b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/Program.cs
new file mode 100644
index 0000000..647c934
--- /dev/null
+++ b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/Program.cs
@@ -0,0 +1,5 @@
+using BenchmarkDotNet.Running;
+using MonoGame.Extended.Benchmarks.Collisions;
+
+//var summary = BenchmarkRunner.Run();
+var summary = BenchmarkRunner.Run();
diff --git a/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/SpaceAlgorithms.cs b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/SpaceAlgorithms.cs
new file mode 100644
index 0000000..7c82a32
--- /dev/null
+++ b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/SpaceAlgorithms.cs
@@ -0,0 +1,104 @@
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Engines;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Benchmarks.Collisions.Utils;
+using MonoGame.Extended.Collisions;
+using MonoGame.Extended.Collisions.Layers;
+using MonoGame.Extended.Collisions.QuadTree;
+
+namespace MonoGame.Extended.Benchmarks.Collisions;
+
+[SimpleJob(RunStrategy.ColdStart, launchCount:10)]
+public class SpaceAlgorithms
+{
+ private const int COMPONENT_BOUNDARY_SIZE = 1000;
+
+ private readonly Random _random = new ();
+ private ISpaceAlgorithm _space;
+ private ICollisionActor _actor;
+ private RectangleF _bound;
+ private List _colliders = new();
+
+ [Params(10, 100, 1000)]
+ public int N { get; set; }
+
+ [Params("SpatialHash", "QuadTree")]
+ public string Algorithm { get; set; }
+
+
+ [GlobalSetup]
+ public void GlobalSetup()
+ {
+ var size = new Size2(COMPONENT_BOUNDARY_SIZE, COMPONENT_BOUNDARY_SIZE);
+ _space = Algorithm switch
+ {
+ "SpatialHash" => new SpatialHash(new Size2(32, 32)),
+ "QuadTree" => new QuadTreeSpace(new RectangleF(Point2.Zero, size)),
+ _ => _space
+ };
+ for (int i = 0; i < N; i++)
+ {
+
+ var rect = GetRandomRectangleF();
+ var actor = new Collider(rect);
+ _colliders.Add(actor);
+ _space.Insert(actor);
+ }
+ }
+
+ [GlobalCleanup]
+ public void GlobalCleanup()
+ {
+ foreach (var collider in _colliders)
+ _space.Remove(collider);
+ _colliders.Clear();
+ }
+
+ [GlobalSetup(Targets = new[] { nameof(Insert), nameof(Remove) })]
+ public void ActorGlobalSetup()
+ {
+ GlobalSetup();
+ var rect = GetRandomRectangleF();
+ _actor = new Collider(rect);
+ }
+
+ [Benchmark]
+ public void Insert()
+ {
+ _space.Insert(_actor);
+ }
+
+ [Benchmark]
+ public void Remove()
+ {
+ _space.Remove(_actor);
+ }
+
+ [Benchmark]
+ public void Reset()
+ {
+ _space.Reset();
+ }
+
+ [GlobalSetup(Target = nameof(Query))]
+ public void QueryGlobalSetup()
+ {
+ GlobalSetup();
+ _bound = GetRandomRectangleF();
+ }
+
+ private RectangleF GetRandomRectangleF()
+ {
+ return new RectangleF(
+ _random.Next(COMPONENT_BOUNDARY_SIZE),
+ _random.Next(COMPONENT_BOUNDARY_SIZE),
+ _random.Next(32, 128),
+ _random.Next(32, 128));
+ }
+
+ [Benchmark]
+ public List Query()
+ {
+ return _space.Query(_bound).ToList();
+ }
+}
diff --git a/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/Utils/Collider.cs b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/Utils/Collider.cs
new file mode 100644
index 0000000..8005961
--- /dev/null
+++ b/Plugins/MonoGame.Extended/benchmarks/MonoGame.Extended.Benchmarks.Collisions/Utils/Collider.cs
@@ -0,0 +1,29 @@
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Collisions;
+
+namespace MonoGame.Extended.Benchmarks.Collisions.Utils;
+
+public class Collider: ICollisionActor
+{
+ public Collider(Point2 position)
+ {
+ Bounds = new RectangleF(position, new Size2(1, 1));
+ }
+
+ public Collider(IShapeF shape)
+ {
+ Bounds = shape;
+ }
+
+ public IShapeF Bounds { get; set; }
+ public Vector2 Shift { get; set; }
+
+ public Point2 Position {
+ get => Bounds.Position;
+ set => Bounds.Position = value;
+ }
+
+ public void OnCollision(CollisionEventArgs collisionInfo)
+ {
+ }
+}
diff --git a/Plugins/MonoGame.Extended/logos/github-social-media-large.png b/Plugins/MonoGame.Extended/logos/github-social-media-large.png
new file mode 100644
index 0000000..7385d10
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/github-social-media-large.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-banner-1600.png b/Plugins/MonoGame.Extended/logos/logo-banner-1600.png
new file mode 100644
index 0000000..086a3b4
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-banner-1600.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-banner-800.png b/Plugins/MonoGame.Extended/logos/logo-banner-800.png
new file mode 100644
index 0000000..043a4c7
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-banner-800.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-drop-shadow-512.png b/Plugins/MonoGame.Extended/logos/logo-drop-shadow-512.png
new file mode 100644
index 0000000..e29137b
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-drop-shadow-512.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-nuget-128.png b/Plugins/MonoGame.Extended/logos/logo-nuget-128.png
new file mode 100644
index 0000000..6f1cba2
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-nuget-128.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-nuget-32.png b/Plugins/MonoGame.Extended/logos/logo-nuget-32.png
new file mode 100644
index 0000000..2907719
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-nuget-32.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-nuget-400.png b/Plugins/MonoGame.Extended/logos/logo-nuget-400.png
new file mode 100644
index 0000000..03e081a
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-nuget-400.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-square-1024.png b/Plugins/MonoGame.Extended/logos/logo-square-1024.png
new file mode 100644
index 0000000..e5943eb
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-square-1024.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-square-128.png b/Plugins/MonoGame.Extended/logos/logo-square-128.png
new file mode 100644
index 0000000..7d1c9ce
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-square-128.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-square-32.png b/Plugins/MonoGame.Extended/logos/logo-square-32.png
new file mode 100644
index 0000000..26d39a4
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-square-32.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-square-512.png b/Plugins/MonoGame.Extended/logos/logo-square-512.png
new file mode 100644
index 0000000..12c33a8
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-square-512.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-square-64.png b/Plugins/MonoGame.Extended/logos/logo-square-64.png
new file mode 100644
index 0000000..c164dcf
Binary files /dev/null and b/Plugins/MonoGame.Extended/logos/logo-square-64.png differ
diff --git a/Plugins/MonoGame.Extended/logos/logo-square.svg b/Plugins/MonoGame.Extended/logos/logo-square.svg
new file mode 100644
index 0000000..4cba53c
--- /dev/null
+++ b/Plugins/MonoGame.Extended/logos/logo-square.svg
@@ -0,0 +1,73 @@
+
+
diff --git a/Plugins/MonoGame.Extended/source/Directory.Build.props b/Plugins/MonoGame.Extended/source/Directory.Build.props
new file mode 100644
index 0000000..ae50af1
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/Directory.Build.props
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ $(SolutionDirectory).artifacts/source
+ true
+ true
+ NU1701
+ true
+
+
+
+
+
+
+
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Animations/MonoGame.Extended.Animations.csproj b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Animations/MonoGame.Extended.Animations.csproj
new file mode 100644
index 0000000..3745741
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Animations/MonoGame.Extended.Animations.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Animations to make MonoGame more awesome.
+ monogame animations spritesheet sprite
+
+
+
+
+
+
+
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/CollisionComponent.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/CollisionComponent.cs
new file mode 100644
index 0000000..51467d9
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/CollisionComponent.cs
@@ -0,0 +1,341 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Diagnostics;
+using System.Linq;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Collisions.Layers;
+using MonoGame.Extended.Collisions.QuadTree;
+
+namespace MonoGame.Extended.Collisions
+{
+ ///
+ /// Handles basic collision between actors.
+ /// When two actors collide, their OnCollision method is called.
+ ///
+ public class CollisionComponent : SimpleGameComponent
+ {
+ public const string DEFAULT_LAYER_NAME = "default";
+
+ private Dictionary _layers = new();
+
+ ///
+ /// List of collision's layers
+ ///
+ public IReadOnlyDictionary Layers => _layers;
+
+ private HashSet<(Layer, Layer)> _layerCollision = new();
+
+ ///
+ /// Creates component with default layer, which is a collision tree covering the specified area (using .
+ ///
+ /// Boundary of the collision tree.
+ public CollisionComponent(RectangleF boundary)
+ {
+ SetDefaultLayer(new Layer(new QuadTreeSpace(boundary)));
+ }
+
+ ///
+ /// Creates component with specifies default layer.
+ /// If layer is null, method creates component without default layer.
+ ///
+ /// Default layer
+ public CollisionComponent(Layer layer = null)
+ {
+ if (layer is not null)
+ SetDefaultLayer(layer);
+ }
+
+ ///
+ /// The main layer has the name from .
+ /// The main layer collision with itself and all other layers.
+ ///
+ /// Layer to set default
+ public void SetDefaultLayer(Layer layer)
+ {
+ if (_layers.ContainsKey(DEFAULT_LAYER_NAME))
+ Remove(DEFAULT_LAYER_NAME);
+ Add(DEFAULT_LAYER_NAME, layer);
+ foreach (var otherLayer in _layers.Values)
+ AddCollisionBetweenLayer(layer, otherLayer);
+ }
+
+ ///
+ /// Update the collision tree and process collisions.
+ ///
+ ///
+ /// Boundary shapes are updated if they were changed since the last
+ /// update.
+ ///
+ ///
+ public override void Update(GameTime gameTime)
+ {
+ foreach (var layer in _layers.Values)
+ layer.Reset();
+
+ foreach (var (firstLayer, secondLayer) in _layerCollision)
+ foreach (var actor in firstLayer.Space)
+ {
+ var collisions = secondLayer.Space.Query(actor.Bounds.BoundingRectangle);
+ foreach (var other in collisions)
+ if (actor != other && actor.Bounds.Intersects(other.Bounds))
+ {
+ var penetrationVector = CalculatePenetrationVector(actor.Bounds, other.Bounds);
+
+ actor.OnCollision(new CollisionEventArgs
+ {
+ Other = other,
+ PenetrationVector = penetrationVector
+ });
+ other.OnCollision(new CollisionEventArgs
+ {
+ Other = actor,
+ PenetrationVector = -penetrationVector
+ });
+ }
+
+ }
+ }
+
+ ///
+ /// Inserts the target into the collision tree.
+ /// The target will have its OnCollision called when collisions occur.
+ ///
+ /// Target to insert.
+ public void Insert(ICollisionActor target)
+ {
+ var layerName = target.LayerName ?? DEFAULT_LAYER_NAME;
+ if (!_layers.TryGetValue(layerName, out var layer))
+ {
+ throw new UndefinedLayerException(layerName);
+ }
+
+ layer.Space.Insert(target);
+ }
+
+ ///
+ /// Removes the target from the collision tree.
+ ///
+ /// Target to remove.
+ public void Remove(ICollisionActor target)
+ {
+ if (target.LayerName is not null)
+ _layers[target.LayerName].Space.Remove(target);
+ else
+ foreach (var layer in _layers.Values)
+ if (layer.Space.Remove(target))
+ return;
+ }
+
+ #region Layers
+
+ ///
+ /// Add the new layer. The name of layer must be unique.
+ ///
+ /// Name of layer
+ /// The new layer
+ /// is null
+ public void Add(string name, Layer layer)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ throw new ArgumentNullException(nameof(name));
+
+ if (!_layers.TryAdd(name, layer))
+ throw new DuplicateNameException(name);
+
+ if (name != DEFAULT_LAYER_NAME)
+ AddCollisionBetweenLayer(_layers[DEFAULT_LAYER_NAME], layer);
+ }
+
+ ///
+ /// Remove the layer and all layer's collisions.
+ ///
+ /// The name of the layer to delete
+ /// The layer to delete
+ public void Remove(string name = null, Layer layer = null)
+ {
+ name ??= _layers.First(x => x.Value == layer).Key;
+ _layers.Remove(name, out layer);
+ _layerCollision.RemoveWhere(tuple => tuple.Item1 == layer || tuple.Item2 == layer);
+ }
+
+ public void AddCollisionBetweenLayer(Layer a, Layer b)
+ {
+ _layerCollision.Add((a, b));
+ }
+
+ public void AddCollisionBetweenLayer(string nameA, string nameB)
+ {
+ _layerCollision.Add((_layers[nameA], _layers[nameB]));
+ }
+
+ #endregion
+
+ #region Penetration Vectors
+
+ ///
+ /// Calculate a's penetration into b
+ ///
+ /// The penetrating shape.
+ /// The shape being penetrated.
+ /// The distance vector from the edge of b to a's Position
+ private static Vector2 CalculatePenetrationVector(IShapeF a, IShapeF b)
+ {
+ return a switch
+ {
+ CircleF circleA when b is CircleF circleB => PenetrationVector(circleA, circleB),
+ CircleF circleA when b is RectangleF rectangleB => PenetrationVector(circleA, rectangleB),
+ CircleF circleA when b is OrientedRectangle orientedRectangleB => PenetrationVector(circleA, orientedRectangleB),
+
+ RectangleF rectangleA when b is CircleF circleB => PenetrationVector(rectangleA, circleB),
+ RectangleF rectangleA when b is RectangleF rectangleB => PenetrationVector(rectangleA, rectangleB),
+ RectangleF rectangleA when b is OrientedRectangle orientedRectangleB => PenetrationVector(rectangleA, orientedRectangleB),
+
+ OrientedRectangle orientedRectangleA when b is CircleF circleB => PenetrationVector(orientedRectangleA, circleB),
+ OrientedRectangle orientedRectangleA when b is RectangleF rectangleB => PenetrationVector(orientedRectangleA, rectangleB),
+ OrientedRectangle orientedRectangleA when b is OrientedRectangle orientedRectangleB => PenetrationVector(orientedRectangleA, orientedRectangleB),
+
+ _ => throw new ArgumentOutOfRangeException(nameof(a))
+ };
+ }
+
+ private static Vector2 PenetrationVector(CircleF circ1, CircleF circ2)
+ {
+ if (!circ1.Intersects(circ2))
+ {
+ return Vector2.Zero;
+ }
+
+ var displacement = Point2.Displacement(circ1.Center, circ2.Center);
+
+ Vector2 desiredDisplacement;
+ if (displacement != Vector2.Zero)
+ {
+ desiredDisplacement = displacement.NormalizedCopy() * (circ1.Radius + circ2.Radius);
+ }
+ else
+ {
+ desiredDisplacement = -Vector2.UnitY * (circ1.Radius + circ2.Radius);
+ }
+
+
+ var penetration = displacement - desiredDisplacement;
+ return penetration;
+ }
+
+ private static Vector2 PenetrationVector(CircleF circ, RectangleF rect)
+ {
+ var collisionPoint = rect.ClosestPointTo(circ.Center);
+ var cToCollPoint = collisionPoint - circ.Center;
+
+ if (rect.Contains(circ.Center) || cToCollPoint.Equals(Vector2.Zero))
+ {
+ var displacement = Point2.Displacement(circ.Center, rect.Center);
+
+ Vector2 desiredDisplacement;
+ if (displacement != Vector2.Zero)
+ {
+ // Calculate penetration as only in X or Y direction.
+ // Whichever is lower.
+ var dispx = new Vector2(displacement.X, 0);
+ var dispy = new Vector2(0, displacement.Y);
+ dispx.Normalize();
+ dispy.Normalize();
+
+ dispx *= (circ.Radius + rect.Width / 2);
+ dispy *= (circ.Radius + rect.Height / 2);
+
+ if (dispx.LengthSquared() < dispy.LengthSquared())
+ {
+ desiredDisplacement = dispx;
+ displacement.Y = 0;
+ }
+ else
+ {
+ desiredDisplacement = dispy;
+ displacement.X = 0;
+ }
+ }
+ else
+ {
+ desiredDisplacement = -Vector2.UnitY * (circ.Radius + rect.Height / 2);
+ }
+
+ var penetration = displacement - desiredDisplacement;
+ return penetration;
+ }
+ else
+ {
+ var penetration = circ.Radius * cToCollPoint.NormalizedCopy() - cToCollPoint;
+ return penetration;
+ }
+ }
+
+ private static Vector2 PenetrationVector(CircleF circleA, OrientedRectangle orientedRectangleB)
+ {
+ var rotation = Matrix2.CreateRotationZ(orientedRectangleB.Orientation.Rotation);
+ var circleCenterInRectangleSpace = rotation.Transform(circleA.Center - orientedRectangleB.Center);
+ var circleInRectangleSpace = new CircleF(circleCenterInRectangleSpace, circleA.Radius);
+ var boundingRectangle = new BoundingRectangle(new Point2(), orientedRectangleB.Radii);
+
+ var penetrationVector = PenetrationVector(circleInRectangleSpace, boundingRectangle);
+ var inverseRotation = Matrix2.CreateRotationZ(-orientedRectangleB.Orientation.Rotation);
+ var transformedPenetration = inverseRotation.Transform(penetrationVector);
+
+ return transformedPenetration;
+ }
+
+ private static Vector2 PenetrationVector(RectangleF rect, CircleF circ)
+ {
+ return -PenetrationVector(circ, rect);
+ }
+
+ private static Vector2 PenetrationVector(RectangleF rect1, RectangleF rect2)
+ {
+ var intersectingRectangle = RectangleF.Intersection(rect1, rect2);
+ Debug.Assert(!intersectingRectangle.IsEmpty,
+ "Violation of: !intersect.IsEmpty; Rectangles must intersect to calculate a penetration vector.");
+
+ Vector2 penetration;
+ if (intersectingRectangle.Width < intersectingRectangle.Height)
+ {
+ var d = rect1.Center.X < rect2.Center.X
+ ? intersectingRectangle.Width
+ : -intersectingRectangle.Width;
+ penetration = new Vector2(d, 0);
+ }
+ else
+ {
+ var d = rect1.Center.Y < rect2.Center.Y
+ ? intersectingRectangle.Height
+ : -intersectingRectangle.Height;
+ penetration = new Vector2(0, d);
+ }
+
+ return penetration;
+ }
+
+ private static Vector2 PenetrationVector(RectangleF rectangleA, OrientedRectangle orientedRectangleB)
+ {
+ return PenetrationVector((OrientedRectangle)rectangleA, orientedRectangleB);
+ }
+
+ private static Vector2 PenetrationVector(OrientedRectangle orientedRectangleA, CircleF circleB)
+ {
+ return -PenetrationVector(circleB, orientedRectangleA);
+ }
+
+ private static Vector2 PenetrationVector(OrientedRectangle orientedRectangleA, RectangleF rectangleB)
+ {
+ return -PenetrationVector(rectangleB, orientedRectangleA);
+ }
+
+ private static Vector2 PenetrationVector(OrientedRectangle orientedRectangleA, OrientedRectangle orientedRectangleB)
+ {
+ return OrientedRectangle.Intersects(orientedRectangleA, orientedRectangleB)
+ .MinimumTranslationVector;
+ }
+
+ #endregion
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/CollisionEventArgs.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/CollisionEventArgs.cs
new file mode 100644
index 0000000..ca401df
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/CollisionEventArgs.cs
@@ -0,0 +1,26 @@
+using System;
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended.Collisions
+{
+ ///
+ /// This class holds data on a collision. It is passed as a parameter to
+ /// OnCollision methods.
+ ///
+ public class CollisionEventArgs : EventArgs
+ {
+ ///
+ /// Gets the object being collided with.
+ ///
+ public ICollisionActor Other { get; internal set; }
+
+ ///
+ /// Gets a vector representing the overlap between the two objects.
+ ///
+ ///
+ /// This vector starts at the edge of and ends at
+ /// the Actor's location.
+ ///
+ public Vector2 PenetrationVector { get; internal set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/ICollisionActor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/ICollisionActor.cs
new file mode 100644
index 0000000..6a05592
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/ICollisionActor.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace MonoGame.Extended.Collisions
+{
+ ///
+ /// An actor that can be collided with.
+ ///
+ public interface ICollisionActor
+ {
+ ///
+ /// A name of layer, which will contains this actor.
+ /// If it equals null, an actor will insert into a default layer
+ ///
+ string LayerName { get => null; }
+
+ ///
+ /// A bounds of an actor. It is using for collision calculating
+ ///
+ IShapeF Bounds { get; }
+
+ ///
+ /// It will called, when collision with an another actor fires
+ ///
+ /// Data about collision
+ void OnCollision(CollisionEventArgs collisionInfo);
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/ISpaceAlgorithm.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/ISpaceAlgorithm.cs
new file mode 100644
index 0000000..a95f737
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/ISpaceAlgorithm.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+
+namespace MonoGame.Extended.Collisions;
+
+///
+/// Interface, which split space for optimization of collisions.
+///
+public interface ISpaceAlgorithm
+{
+ ///
+ /// Inserts the actor into the space.
+ /// The actor will have its OnCollision called when collisions occur.
+ ///
+ /// Actor to insert.
+ void Insert(ICollisionActor actor);
+
+ ///
+ /// Removes the actor into the space.
+ ///
+ /// Actor to remove.
+ bool Remove(ICollisionActor actor);
+
+ ///
+ /// Removes the actor into the space.
+ /// The actor will have its OnCollision called when collisions occur.
+ ///
+ /// Actor to remove.
+ IEnumerable Query(RectangleF boundsBoundingRectangle);
+
+ ///
+ /// for foreach
+ ///
+ ///
+ List.Enumerator GetEnumerator();
+
+ ///
+ /// Restructure the space with new positions.
+ ///
+ void Reset();
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/Layers/Layer.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/Layers/Layer.cs
new file mode 100644
index 0000000..6e97ac8
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/Layers/Layer.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace MonoGame.Extended.Collisions.Layers;
+
+///
+/// Layer is a group of collision's actors.
+///
+public class Layer
+{
+ ///
+ /// If this property equals true, layer always will reset collision space.
+ ///
+ public bool IsDynamic { get; set; } = true;
+
+
+ ///
+ /// The space, which contain actors.
+ ///
+ public readonly ISpaceAlgorithm Space;
+
+ ///
+ /// Constructor for layer
+ ///
+ /// A space algorithm for actors
+ /// is null
+ public Layer(ISpaceAlgorithm spaceAlgorithm)
+ {
+ Space = spaceAlgorithm ?? throw new ArgumentNullException(nameof(spaceAlgorithm));
+ }
+
+ ///
+ /// Restructure a inner collection, if layer is dynamic, because actors can change own position
+ ///
+ public virtual void Reset()
+ {
+ if (IsDynamic)
+ Space.Reset();
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/Layers/UndefinedLayerException.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/Layers/UndefinedLayerException.cs
new file mode 100644
index 0000000..a27b5b6
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/Layers/UndefinedLayerException.cs
@@ -0,0 +1,18 @@
+namespace MonoGame.Extended.Collisions.Layers;
+
+using System;
+
+///
+/// Thrown when the collision system has no layer defined with the specified name
+///
+public class UndefinedLayerException : Exception
+{
+ ///
+ /// Thrown when the collision system has no layer defined with the specified name
+ ///
+ /// The undefined layer name
+ public UndefinedLayerException(string layerName)
+ : base($"Layer with name '{layerName}' is undefined")
+ {
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/MonoGame.Extended.Collisions.csproj b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/MonoGame.Extended.Collisions.csproj
new file mode 100644
index 0000000..bd0729c
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/MonoGame.Extended.Collisions.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Collisions to make MonoGame more awesome.
+ monogame collisions
+
+
+
+
+
+
+
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTree.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTree.cs
new file mode 100644
index 0000000..a46699a
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTree.cs
@@ -0,0 +1,310 @@
+using System;
+using System.Collections.Generic;
+
+namespace MonoGame.Extended.Collisions.QuadTree
+{
+ ///
+ /// Class for doing collision handling with a quad tree.
+ ///
+ public class QuadTree
+ {
+ ///
+ /// The default maximum depth.
+ ///
+ public const int DefaultMaxDepth = 7;
+
+ ///
+ /// The default maximum objects per node.
+ ///
+ public const int DefaultMaxObjectsPerNode = 25;
+
+ ///
+ /// Contains the children of this node.
+ ///
+ protected List Children = new List();
+
+ ///
+ /// Contains the data for this node in the quadtree.
+ ///
+ protected HashSet Contents = new HashSet();
+
+ ///
+ /// Creates a quad tree with the given bounds.
+ ///
+ /// The bounds of the new quad tree.
+ public QuadTree(RectangleF bounds)
+ {
+ CurrentDepth = 0;
+ NodeBounds = bounds;
+ }
+
+ ///
+ /// Gets or sets the current depth for this node in the quadtree.
+ ///
+ protected int CurrentDepth { get; set; }
+ ///
+ /// Gets or sets the maximum depth of the quadtree.
+ ///
+ protected int MaxDepth { get; set; } = DefaultMaxDepth;
+ ///
+ /// Gets or sets the maximum objects per node in this quadtree.
+ ///
+ protected int MaxObjectsPerNode { get; set; } = DefaultMaxObjectsPerNode;
+
+ ///
+ /// Gets the bounds of the area contained in this quad tree.
+ ///
+ public RectangleF NodeBounds { get; protected set; }
+
+ ///
+ /// Gets whether the current node is a leaf node.
+ ///
+ public bool IsLeaf => Children.Count == 0;
+
+ ///
+ /// Counts the number of unique targets in the current Quadtree.
+ ///
+ /// Returns the targets of objects found.
+ public int NumTargets()
+ {
+ List dirtyItems = new List();
+ var objectCount = 0;
+
+ // Do BFS on nodes to count children.
+ var process = new Queue();
+ process.Enqueue(this);
+ while (process.Count > 0)
+ {
+ var processing = process.Dequeue();
+ if (!processing.IsLeaf)
+ {
+ foreach (var child in processing.Children)
+ {
+ process.Enqueue(child);
+ }
+ }
+ else
+ {
+ foreach (var data in processing.Contents)
+ {
+ if (data.Dirty == false)
+ {
+ objectCount++;
+ data.MarkDirty();
+ dirtyItems.Add(data);
+ }
+ }
+ }
+ }
+ foreach (var quadtreeData in dirtyItems)
+ {
+ quadtreeData.MarkClean();
+ }
+ return objectCount;
+ }
+
+ ///
+ /// Inserts the data into the tree.
+ ///
+ /// Data being inserted.
+ public void Insert(QuadtreeData data)
+ {
+ var actorBounds = data.Bounds;
+
+ // Object doesn't fit into this node.
+ if (!NodeBounds.Intersects(actorBounds))
+ {
+ return;
+ }
+
+ if (IsLeaf && Contents.Count >= MaxObjectsPerNode)
+ {
+ Split();
+ }
+
+ if (IsLeaf)
+ {
+ AddToLeaf(data);
+ }
+ else
+ {
+ foreach (var child in Children)
+ {
+ child.Insert(data);
+ }
+ }
+ }
+
+ ///
+ /// Removes data from the Quadtree
+ ///
+ /// The data to be removed.
+ public void Remove(QuadtreeData data)
+ {
+ if (IsLeaf)
+ {
+ data.RemoveParent(this);
+ Contents.Remove(data);
+ }
+ else
+ {
+ throw new InvalidOperationException($"Cannot remove from a non leaf {nameof(QuadTree)}");
+ }
+ }
+
+ ///
+ /// Removes unnecessary leaf nodes and simplifies the quad tree.
+ ///
+ public void Shake()
+ {
+ if (IsLeaf)
+ {
+ return;
+ }
+
+ List dirtyItems = new List();
+
+ var numObjects = NumTargets();
+ if (numObjects == 0)
+ {
+ Children.Clear();
+ }
+ else if (numObjects < MaxObjectsPerNode)
+ {
+ var process = new Queue();
+ process.Enqueue(this);
+ while (process.Count > 0)
+ {
+ var processing = process.Dequeue();
+ if (!processing.IsLeaf)
+ {
+ foreach (var subTree in processing.Children)
+ {
+ process.Enqueue(subTree);
+ }
+ }
+ else
+ {
+ foreach (var data in processing.Contents)
+ {
+ if (data.Dirty == false)
+ {
+ AddToLeaf(data);
+ data.MarkDirty();
+ dirtyItems.Add(data);
+ }
+ }
+ }
+ }
+ Children.Clear();
+ }
+
+ foreach (var quadtreeData in dirtyItems)
+ {
+ quadtreeData.MarkClean();
+ }
+ }
+
+ private void AddToLeaf(QuadtreeData data)
+ {
+ data.AddParent(this);
+ Contents.Add(data);
+ }
+
+ ///
+ /// Splits a quadtree into quadrants.
+ ///
+ public void Split()
+ {
+ if (CurrentDepth + 1 >= MaxDepth) return;
+
+ var min = NodeBounds.TopLeft;
+ var max = NodeBounds.BottomRight;
+ var center = NodeBounds.Center;
+
+ RectangleF[] childAreas =
+ {
+ RectangleF.CreateFrom(min, center),
+ RectangleF.CreateFrom(new Point2(center.X, min.Y), new Point2(max.X, center.Y)),
+ RectangleF.CreateFrom(center, max),
+ RectangleF.CreateFrom(new Point2(min.X, center.Y), new Point2(center.X, max.Y))
+ };
+
+ for (var i = 0; i < childAreas.Length; ++i)
+ {
+ var node = new QuadTree(childAreas[i]);
+ Children.Add(node);
+ Children[i].CurrentDepth = CurrentDepth + 1;
+ }
+
+ foreach (QuadtreeData contentQuadtree in Contents)
+ {
+ foreach (QuadTree childQuadtree in Children)
+ {
+ childQuadtree.Insert(contentQuadtree);
+ }
+ }
+ Clear();
+ }
+
+ ///
+ /// Clear current node and all children
+ ///
+ public void ClearAll()
+ {
+ foreach (QuadTree childQuadtree in Children)
+ childQuadtree.ClearAll();
+ Clear();
+ }
+
+ private void Clear()
+ {
+ foreach (QuadtreeData quadtreeData in Contents)
+ {
+ quadtreeData.RemoveParent(this);
+ }
+ Contents.Clear();
+ }
+
+ ///
+ /// Queries the quadtree for targets that intersect with the given area.
+ ///
+ /// The area to query for overlapping targets
+ /// A unique list of targets intersected by area.
+ public List Query(ref RectangleF area)
+ {
+ var recursiveResult = new List();
+ QueryWithoutReset(ref area, recursiveResult);
+ foreach (var quadtreeData in recursiveResult)
+ {
+ quadtreeData.MarkClean();
+ }
+ return recursiveResult;
+ }
+
+ private void QueryWithoutReset(ref RectangleF area, List recursiveResult)
+ {
+ if (!NodeBounds.Intersects(area))
+ return;
+
+ if (IsLeaf)
+ {
+ foreach (QuadtreeData quadtreeData in Contents)
+ {
+ if (quadtreeData.Dirty == false && quadtreeData.Bounds.Intersects(area))
+ {
+ recursiveResult.Add(quadtreeData);
+ quadtreeData.MarkDirty();
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0, size = Children.Count; i < size; i++)
+ {
+ Children[i].QueryWithoutReset(ref area, recursiveResult);
+ }
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTreeData.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTreeData.cs
new file mode 100644
index 0000000..db6da3e
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTreeData.cs
@@ -0,0 +1,88 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MonoGame.Extended.Collisions.QuadTree;
+
+///
+/// Data structure for the quad tree.
+/// Holds the entity and collision data for it.
+///
+public class QuadtreeData
+{
+ private readonly ICollisionActor _target;
+ private readonly HashSet _parents = new();
+
+ ///
+ /// Initialize a new instance of QuadTreeData.
+ ///
+ ///
+ public QuadtreeData(ICollisionActor target)
+ {
+ _target = target;
+ Bounds = _target.Bounds.BoundingRectangle;
+ }
+
+ ///
+ /// Remove a parent node.
+ ///
+ ///
+ public void RemoveParent(QuadTree parent)
+ {
+ _parents.Remove(parent);
+ }
+
+ ///
+ /// Add a parent node.
+ ///
+ ///
+ public void AddParent(QuadTree parent)
+ {
+ _parents.Add(parent);
+ Bounds = _target.Bounds.BoundingRectangle;
+ }
+
+ ///
+ /// Remove all parent nodes from this node.
+ ///
+ public void RemoveFromAllParents()
+ {
+ foreach (var parent in _parents.ToList())
+ {
+ parent.Remove(this);
+ }
+
+ _parents.Clear();
+ }
+
+ ///
+ /// Gets the bounding box for collision detection.
+ ///
+ public RectangleF Bounds { get; set; }
+
+ ///
+ /// Gets the collision actor target.
+ ///
+ public ICollisionActor Target => _target;
+
+ ///
+ /// Gets or sets whether Target has had its collision handled this
+ /// iteration.
+ ///
+ public bool Dirty { get; private set; }
+
+ ///
+ /// Mark node as dirty.
+ ///
+ public void MarkDirty()
+ {
+ Dirty = true;
+ }
+
+ ///
+ /// Mark node as clean, i.e. not dirty.
+ ///
+ public void MarkClean()
+ {
+ Dirty = false;
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTreeSpace.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTreeSpace.cs
new file mode 100644
index 0000000..3e9625f
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/QuadTree/QuadTreeSpace.cs
@@ -0,0 +1,76 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MonoGame.Extended.Collisions.QuadTree;
+
+public class QuadTreeSpace: ISpaceAlgorithm
+{
+ private readonly QuadTree _collisionTree;
+ private readonly List _actors = new();
+ private readonly Dictionary _targetDataDictionary = new();
+
+ public QuadTreeSpace(RectangleF boundary)
+ {
+ _collisionTree = new QuadTree(boundary);
+ }
+
+ ///
+ /// Inserts the target into the collision tree.
+ /// The target will have its OnCollision called when collisions occur.
+ ///
+ /// Target to insert.
+ public void Insert(ICollisionActor target)
+ {
+ if (!_targetDataDictionary.ContainsKey(target))
+ {
+ var data = new QuadtreeData(target);
+ _targetDataDictionary.Add(target, data);
+ _collisionTree.Insert(data);
+ _actors.Add(target);
+ }
+ }
+
+ ///
+ /// Removes the target from the collision tree.
+ ///
+ /// Target to remove.
+ public bool Remove(ICollisionActor target)
+ {
+ if (_targetDataDictionary.ContainsKey(target))
+ {
+ var data = _targetDataDictionary[target];
+ data.RemoveFromAllParents();
+ _targetDataDictionary.Remove(target);
+ _collisionTree.Shake();
+ _actors.Remove(target);
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Restructure a inner collection, if layer is dynamic, because actors can change own position
+ ///
+ public void Reset()
+ {
+ _collisionTree.ClearAll();
+ foreach (var value in _targetDataDictionary.Values)
+ {
+ _collisionTree.Insert(value);
+ }
+ _collisionTree.Shake();
+ }
+
+ ///
+ /// foreach support
+ ///
+ ///
+ public List.Enumerator GetEnumerator() => _actors.GetEnumerator();
+
+ ///
+ public IEnumerable Query(RectangleF boundsBoundingRectangle)
+ {
+ return _collisionTree.Query(ref boundsBoundingRectangle).Select(x => x.Target);
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/SpatialHash.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/SpatialHash.cs
new file mode 100644
index 0000000..2b0920e
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/SpatialHash.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+namespace MonoGame.Extended.Collisions;
+
+public class SpatialHash: ISpaceAlgorithm
+{
+ private readonly Dictionary> _dictionary = new();
+ private readonly List _actors = new();
+
+ private readonly Size2 _size;
+
+ public SpatialHash(Size2 size)
+ {
+ _size = size;
+ }
+
+ public void Insert(ICollisionActor actor)
+ {
+ InsertToHash(actor);
+ _actors.Add(actor);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void InsertToHash(ICollisionActor actor)
+ {
+ var rect = actor.Bounds.BoundingRectangle;
+ for (var x = rect.Left; x < rect.Right; x+=_size.Width)
+ for (var y = rect.Top; y < rect.Bottom; y+=_size.Height)
+ AddToCell(x, y, actor);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void AddToCell(float x, float y, ICollisionActor actor)
+ {
+ var index = GetIndex(x, y);
+ if (_dictionary.TryGetValue(index, out var actors))
+ actors.Add(actor);
+ else
+ _dictionary[index] = new() { actor };
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private int GetIndex(float x, float y)
+ {
+ return (int)(x / _size.Width) << 16 + (int)(y / _size.Height);
+ }
+
+ public bool Remove(ICollisionActor actor)
+ {
+ foreach (var actors in _dictionary.Values)
+ actors.Remove(actor);
+ return _actors.Remove(actor);
+ }
+
+ public IEnumerable Query(RectangleF boundsBoundingRectangle)
+ {
+ var results = new HashSet();
+ var bounds = boundsBoundingRectangle.BoundingRectangle;
+
+ for (var x = boundsBoundingRectangle.Left; x < boundsBoundingRectangle.Right; x+=_size.Width)
+ for (var y = boundsBoundingRectangle.Top; y < boundsBoundingRectangle.Bottom; y+=_size.Height)
+ if (_dictionary.TryGetValue(GetIndex(x, y), out var actors))
+ foreach (var actor in actors)
+ if (bounds.Intersects(actor.Bounds))
+ results.Add(actor);
+ return results;
+ }
+
+ public List.Enumerator GetEnumerator() => _actors.GetEnumerator();
+
+ public void Reset()
+ {
+ _dictionary.Clear();
+ foreach (var actor in _actors)
+ InsertToHash(actor);
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/packages.config b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/packages.config
new file mode 100644
index 0000000..28c0144
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Collisions/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorAnimation.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorAnimation.cs
new file mode 100644
index 0000000..14638d4
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorAnimation.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ public class AstridAnimatorAnimation
+ {
+ public string Name { get; set; }
+ public int FramesPerSecond { get; set; }
+ public List Frames { get; set; }
+ public bool IsLooping { get; set; }
+ public bool IsReversed { get; set; }
+ public bool IsPingPong { get; set; }
+
+ public AstridAnimatorAnimation(string name, int framesPerSecond)
+ {
+ Name = name;
+ FramesPerSecond = framesPerSecond;
+ Frames = new List();
+ IsLooping = true;
+ IsReversed = false;
+ IsPingPong = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorFile.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorFile.cs
new file mode 100644
index 0000000..765f2f2
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorFile.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ public class AstridAnimatorFile
+ {
+ public string TextureAtlas { get; set; }
+ public List Animations { get; set; }
+
+ public AstridAnimatorFile()
+ {
+ Animations = new List();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorImporter.cs
new file mode 100644
index 0000000..855a0d3
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorImporter.cs
@@ -0,0 +1,18 @@
+using System.IO;
+using System.Text.Json;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ [ContentImporter(".aa", DefaultProcessor = "AstridAnimatorProcessor",
+ DisplayName = "Astrid Animator Importer - MonoGame.Extended")]
+ public class AstridAnimatorImporter : ContentImporter>
+ {
+ public override ContentImporterResult Import(string filename, ContentImporterContext context)
+ {
+ var json = File.ReadAllText(filename);
+ var data = JsonSerializer.Deserialize(json);
+ return new ContentImporterResult(filename, data);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessor.cs
new file mode 100644
index 0000000..e22d65b
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessor.cs
@@ -0,0 +1,24 @@
+using System.IO;
+using System.Linq;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ [ContentProcessor(DisplayName = "Astrid Animator Processor - MonoGame.Extended")]
+ public class AstridAnimatorProcessor :
+ ContentProcessor, AstridAnimatorProcessorResult>
+ {
+ public override AstridAnimatorProcessorResult Process(ContentImporterResult input,
+ ContentProcessorContext context)
+ {
+ var data = input.Data;
+ var directory = Path.GetDirectoryName(input.FilePath);
+ var frames = data.Animations
+ .SelectMany(i => i.Frames)
+ .OrderBy(f => f)
+ .Distinct();
+
+ return new AstridAnimatorProcessorResult(directory, data, frames);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessorResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessorResult.cs
new file mode 100644
index 0000000..de92ec3
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessorResult.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ public class AstridAnimatorProcessorResult
+ {
+ public string TextureAtlasAssetName { get; private set; }
+ public string Directory { get; private set; }
+ public AstridAnimatorFile Data { get; private set; }
+ public List Frames { get; private set; }
+
+ public AstridAnimatorProcessorResult(string directory, AstridAnimatorFile data, IEnumerable frames)
+ {
+ Directory = directory;
+ Data = data;
+ Frames = new List(frames);
+ TextureAtlasAssetName = Path.GetFileNameWithoutExtension(data.TextureAtlas);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorWriter.cs
new file mode 100644
index 0000000..6f56f3f
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorWriter.cs
@@ -0,0 +1,40 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ [ContentTypeWriter]
+ public class AstridAnimatorWriter : ContentTypeWriter
+ {
+ public override string GetRuntimeReader(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.Animations.SpriteSheets.SpriteSheetAnimationFactoryReader, MonoGame.Extended.Animations";
+ }
+
+ protected override void Write(ContentWriter writer, AstridAnimatorProcessorResult input)
+ {
+ var data = input.Data;
+
+ writer.Write(input.TextureAtlasAssetName);
+ writer.Write(input.Frames.Count);
+
+ foreach (var frame in input.Frames)
+ writer.Write(frame);
+
+ writer.Write(data.Animations.Count);
+
+ foreach (var animation in data.Animations)
+ {
+ writer.Write(animation.Name);
+ writer.Write(animation.FramesPerSecond);
+ writer.Write(animation.IsLooping);
+ writer.Write(animation.IsReversed);
+ writer.Write(animation.IsPingPong);
+ writer.Write(animation.Frames.Count);
+
+ foreach (var frame in animation.Frames)
+ writer.Write(input.Frames.IndexOf(frame));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontChar.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontChar.cs
new file mode 100644
index 0000000..c012da4
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontChar.cs
@@ -0,0 +1,41 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontChar
+ {
+ [XmlAttribute("id")]
+ public int Id { get; set; }
+
+ [XmlAttribute("x")]
+ public int X { get; set; }
+
+ [XmlAttribute("y")]
+ public int Y { get; set; }
+
+ [XmlAttribute("width")]
+ public int Width { get; set; }
+
+ [XmlAttribute("height")]
+ public int Height { get; set; }
+
+ [XmlAttribute("xoffset")]
+ public int XOffset { get; set; }
+
+ [XmlAttribute("yoffset")]
+ public int YOffset { get; set; }
+
+ [XmlAttribute("xadvance")]
+ public int XAdvance { get; set; }
+
+ [XmlAttribute("page")]
+ public int Page { get; set; }
+
+ [XmlAttribute("chnl")]
+ public int Channel { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontCommon.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontCommon.cs
new file mode 100644
index 0000000..6247fcf
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontCommon.cs
@@ -0,0 +1,41 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontCommon
+ {
+ [XmlAttribute("lineHeight")]
+ public int LineHeight { get; set; }
+
+ [XmlAttribute("base")]
+ public int Base { get; set; }
+
+ [XmlAttribute("scaleW")]
+ public int ScaleW { get; set; }
+
+ [XmlAttribute("scaleH")]
+ public int ScaleH { get; set; }
+
+ [XmlAttribute("pages")]
+ public int Pages { get; set; }
+
+ [XmlAttribute("packed")]
+ public int Packed { get; set; }
+
+ [XmlAttribute("alphaChnl")]
+ public int AlphaChannel { get; set; }
+
+ [XmlAttribute("redChnl")]
+ public int RedChannel { get; set; }
+
+ [XmlAttribute("greenChnl")]
+ public int GreenChannel { get; set; }
+
+ [XmlAttribute("blueChnl")]
+ public int BlueChannel { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontFile.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontFile.cs
new file mode 100644
index 0000000..db77270
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontFile.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ [XmlRoot("font")]
+ public class BitmapFontFile
+ {
+ [XmlElement("info")]
+ public BitmapFontInfo Info { get; set; }
+
+ [XmlElement("common")]
+ public BitmapFontCommon Common { get; set; }
+
+ [XmlArray("pages")]
+ [XmlArrayItem("page")]
+ public List Pages { get; set; }
+
+ [XmlArray("chars")]
+ [XmlArrayItem("char")]
+ public List Chars { get; set; }
+
+ [XmlArray("kernings")]
+ [XmlArrayItem("kerning")]
+ public List Kernings { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontImporter.cs
new file mode 100644
index 0000000..ea4c528
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontImporter.cs
@@ -0,0 +1,22 @@
+using System.IO;
+using System.Xml.Serialization;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ [ContentImporter(".fnt", DefaultProcessor = "BitmapFontProcessor",
+ DisplayName = "BMFont Importer - MonoGame.Extended")]
+ public class BitmapFontImporter : ContentImporter
+ {
+ public override BitmapFontFile Import(string filename, ContentImporterContext context)
+ {
+ context.Logger.LogMessage("Importing XML file: {0}", filename);
+
+ using (var streamReader = new StreamReader(filename))
+ {
+ var deserializer = new XmlSerializer(typeof(BitmapFontFile));
+ return (BitmapFontFile)deserializer.Deserialize(streamReader);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontInfo.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontInfo.cs
new file mode 100644
index 0000000..1f50cf8
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontInfo.cs
@@ -0,0 +1,47 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontInfo
+ {
+ [XmlAttribute("face")]
+ public string Face { get; set; }
+
+ [XmlAttribute("size")]
+ public int Size { get; set; }
+
+ [XmlAttribute("bold")]
+ public int Bold { get; set; }
+
+ [XmlAttribute("italic")]
+ public int Italic { get; set; }
+
+ [XmlAttribute("charset")]
+ public string CharSet { get; set; }
+
+ [XmlAttribute("unicode")]
+ public int Unicode { get; set; }
+
+ [XmlAttribute("stretchH")]
+ public int StretchHeight { get; set; }
+
+ [XmlAttribute("smooth")]
+ public int Smooth { get; set; }
+
+ [XmlAttribute("aa")]
+ public int SuperSampling { get; set; }
+
+ [XmlAttribute("padding")]
+ public string Padding { get; set; }
+
+ [XmlAttribute("spacing")]
+ public string Spacing { get; set; }
+
+ [XmlAttribute("outline")]
+ public int OutLine { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontKerning.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontKerning.cs
new file mode 100644
index 0000000..77caf13
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontKerning.cs
@@ -0,0 +1,20 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontKerning
+ {
+ [XmlAttribute("first")]
+ public int First { get; set; }
+
+ [XmlAttribute("second")]
+ public int Second { get; set; }
+
+ [XmlAttribute("amount")]
+ public int Amount { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontPage.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontPage.cs
new file mode 100644
index 0000000..3841ff5
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontPage.cs
@@ -0,0 +1,17 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontPage
+ {
+ [XmlAttribute("id")]
+ public int Id { get; set; }
+
+ [XmlAttribute("file")]
+ public string File { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessor.cs
new file mode 100644
index 0000000..a859eb5
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessor.cs
@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ [ContentProcessor(DisplayName = "BMFont Processor - MonoGame.Extended")]
+ public class BitmapFontProcessor : ContentProcessor
+ {
+ public override BitmapFontProcessorResult Process(BitmapFontFile bitmapFontFile, ContentProcessorContext context)
+ {
+ try
+ {
+ context.Logger.LogMessage("Processing BMFont");
+ var result = new BitmapFontProcessorResult(bitmapFontFile);
+
+ foreach (var fontPage in bitmapFontFile.Pages)
+ {
+ var assetName = Path.GetFileNameWithoutExtension(fontPage.File);
+ context.Logger.LogMessage("Expected texture asset: {0}", assetName);
+ result.TextureAssets.Add(assetName);
+ }
+
+ return result;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogMessage("Error {0}", ex);
+ throw;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessorResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessorResult.cs
new file mode 100644
index 0000000..5841acc
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessorResult.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ public class BitmapFontProcessorResult
+ {
+ public List TextureAssets { get; private set; }
+ public BitmapFontFile FontFile { get; private set; }
+
+ public BitmapFontProcessorResult(BitmapFontFile fontFile)
+ {
+ FontFile = fontFile;
+ TextureAssets = new List();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontWriter.cs
new file mode 100644
index 0000000..343c40c
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontWriter.cs
@@ -0,0 +1,52 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ [ContentTypeWriter]
+ public class BitmapFontWriter : ContentTypeWriter
+ {
+ protected override void Write(ContentWriter writer, BitmapFontProcessorResult result)
+ {
+ writer.Write(result.TextureAssets.Count);
+
+ foreach (var textureAsset in result.TextureAssets)
+ writer.Write(textureAsset);
+
+ var fontFile = result.FontFile;
+ writer.Write(fontFile.Common.LineHeight);
+ writer.Write(fontFile.Chars.Count);
+
+ foreach (var c in fontFile.Chars)
+ {
+ writer.Write(c.Id);
+ writer.Write(c.Page);
+ writer.Write(c.X);
+ writer.Write(c.Y);
+ writer.Write(c.Width);
+ writer.Write(c.Height);
+ writer.Write(c.XOffset);
+ writer.Write(c.YOffset);
+ writer.Write(c.XAdvance);
+ }
+
+ writer.Write(fontFile.Kernings.Count);
+ foreach(var k in fontFile.Kernings)
+ {
+ writer.Write(k.First);
+ writer.Write(k.Second);
+ writer.Write(k.Amount);
+ }
+ }
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.BitmapFonts.BitmapFont, MonoGame.Extended";
+ }
+
+ public override string GetRuntimeReader(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.BitmapFonts.BitmapFontReader, MonoGame.Extended";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterContextExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterContextExtensions.cs
new file mode 100644
index 0000000..7f63815
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterContextExtensions.cs
@@ -0,0 +1,15 @@
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline;
+
+public static class ContentImporterContextExtensions
+{
+ public static string AddDependencyWithLogging(this ContentImporterContext context, string filePath, string source)
+ {
+ source = Path.Combine(Path.GetDirectoryName(filePath), source);
+ ContentLogger.Log($"Adding dependency '{source}'");
+ context.AddDependency(source);
+ return source;
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterResult.cs
new file mode 100644
index 0000000..e302ca7
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterResult.cs
@@ -0,0 +1,14 @@
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public class ContentImporterResult
+ {
+ public ContentImporterResult(string filePath, T data)
+ {
+ FilePath = filePath;
+ Data = data;
+ }
+
+ public string FilePath { get; }
+ public T Data { get; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentItem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentItem.cs
new file mode 100644
index 0000000..e69d48e
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentItem.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public interface IExternalReferenceRepository
+ {
+ ExternalReference GetExternalReference(string source);
+ }
+
+ public class ContentItem : ContentItem, IExternalReferenceRepository
+ {
+ public ContentItem(T data)
+ {
+ Data = data;
+ }
+
+ public T Data { get; }
+
+ private readonly Dictionary _externalReferences = new Dictionary();
+
+ public void BuildExternalReference(ContentProcessorContext context, string source, OpaqueDataDictionary parameters = null)
+ {
+ var sourceAsset = new ExternalReference(source);
+ var externalReference = context.BuildAsset(sourceAsset, "", parameters, "", "");
+ _externalReferences.Add(source, externalReference);
+ }
+
+ public ExternalReference GetExternalReference(string source)
+ {
+ if (source is not null && _externalReferences.TryGetValue(source, out var contentItem))
+ return contentItem as ExternalReference;
+
+ return null;
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentLogger.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentLogger.cs
new file mode 100644
index 0000000..83848a1
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentLogger.cs
@@ -0,0 +1,14 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public class ContentLogger
+ {
+ public static ContentBuildLogger Logger { get; set; }
+
+ public static void Log(string message)
+ {
+ Logger?.LogMessage(message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentWriterExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentWriterExtensions.cs
new file mode 100644
index 0000000..b8cf9d2
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentWriterExtensions.cs
@@ -0,0 +1,79 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public static class ContentWriterExtensions
+ {
+ public static void Write(this ContentWriter contentWriter, Color value)
+ {
+ contentWriter.Write(value.R);
+ contentWriter.Write(value.G);
+ contentWriter.Write(value.B);
+ contentWriter.Write(value.A);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Matrix value)
+ {
+ contentWriter.Write(value.M11);
+ contentWriter.Write(value.M12);
+ contentWriter.Write(value.M13);
+ contentWriter.Write(value.M14);
+ contentWriter.Write(value.M21);
+ contentWriter.Write(value.M22);
+ contentWriter.Write(value.M23);
+ contentWriter.Write(value.M24);
+ contentWriter.Write(value.M31);
+ contentWriter.Write(value.M32);
+ contentWriter.Write(value.M33);
+ contentWriter.Write(value.M34);
+ contentWriter.Write(value.M41);
+ contentWriter.Write(value.M42);
+ contentWriter.Write(value.M43);
+ contentWriter.Write(value.M44);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Quaternion value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ contentWriter.Write(value.Z);
+ contentWriter.Write(value.W);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Vector2 value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Vector3 value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ contentWriter.Write(value.Z);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Vector4 value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ contentWriter.Write(value.Z);
+ contentWriter.Write(value.W);
+ }
+
+ public static void Write(this ContentWriter contentWriter, BoundingSphere value)
+ {
+ contentWriter.Write(value.Center);
+ contentWriter.Write(value.Radius);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Rectangle value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ contentWriter.Write(value.Width);
+ contentWriter.Write(value.Height);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentImporter.cs
new file mode 100644
index 0000000..437d7eb
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentImporter.cs
@@ -0,0 +1,15 @@
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.Json
+{
+ [ContentImporter(".json", DefaultProcessor = nameof(JsonContentProcessor), DisplayName = "JSON Importer - MonoGame.Extended")]
+ public class JsonContentImporter : ContentImporter>
+ {
+ public override ContentImporterResult Import(string filename, ContentImporterContext context)
+ {
+ var json = File.ReadAllText(filename);
+ return new ContentImporterResult(filename, json);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessor.cs
new file mode 100644
index 0000000..6be4ac3
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessor.cs
@@ -0,0 +1,31 @@
+using System;
+using System.ComponentModel;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.Json
+{
+ [ContentProcessor(DisplayName = "JSON Processor - MonoGame.Extended")]
+ public class JsonContentProcessor : ContentProcessor, JsonContentProcessorResult>
+ {
+ [DefaultValue(typeof(Type), "System.Object")]
+ public string ContentType { get; set; }
+
+ public override JsonContentProcessorResult Process(ContentImporterResult input, ContentProcessorContext context)
+ {
+ try
+ {
+ var output = new JsonContentProcessorResult
+ {
+ ContentType = ContentType,
+ Json = input.Data
+ };
+ return output;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogMessage("Error {0}", ex);
+ throw;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessorResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessorResult.cs
new file mode 100644
index 0000000..eaef99e
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessorResult.cs
@@ -0,0 +1,8 @@
+namespace MonoGame.Extended.Content.Pipeline.Json
+{
+ public class JsonContentProcessorResult
+ {
+ public string ContentType { get; set; }
+ public string Json { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentTypeWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentTypeWriter.cs
new file mode 100644
index 0000000..6efa696
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentTypeWriter.cs
@@ -0,0 +1,27 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline.Json
+{
+ [ContentTypeWriter]
+ public class JsonContentTypeWriter : ContentTypeWriter
+ {
+ private string _runtimeType;
+
+ protected override void Write(ContentWriter writer, JsonContentProcessorResult result)
+ {
+ _runtimeType = result.ContentType;
+ writer.Write(result.Json);
+ }
+
+ public override string GetRuntimeReader(TargetPlatform targetPlatform)
+ {
+ return _runtimeType;// "MonoGame.Extended.Serialization.SpriteFactoryContentTypeReader, MonoGame.Extended";
+ }
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform)
+ {
+ return _runtimeType;// "MonoGame.Extended.Serialization.SpriteFactoryContentTypeReader, MonoGame.Extended";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/MonoGame.Extended.Content.Pipeline.csproj b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/MonoGame.Extended.Content.Pipeline.csproj
new file mode 100644
index 0000000..70b81e8
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/MonoGame.Extended.Content.Pipeline.csproj
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+ Content Pipeline importers and processors to make MonoGame more awesome.
+ monogame content importer processor reader tiled texturepacker bmfont animations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/PathExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/PathExtensions.cs
new file mode 100644
index 0000000..b85afb5
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/PathExtensions.cs
@@ -0,0 +1,14 @@
+using System;
+using System.IO;
+
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public static class PathExtensions
+ {
+ public static string GetApplicationFullPath(params string[] pathParts)
+ {
+ var path = Path.Combine(pathParts);
+ return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentImporter.cs
new file mode 100644
index 0000000..3c4607d
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentImporter.cs
@@ -0,0 +1,10 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.Content.Pipeline.Json;
+
+namespace MonoGame.Extended.Content.Pipeline.SpriteFactory
+{
+ [ContentImporter(".sf", DefaultProcessor = nameof(SpriteFactoryContentProcessor), DisplayName = "Sprite Factory Importer - MonoGame.Extended")]
+ public class SpriteFactoryContentImporter : JsonContentImporter
+ {
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentProcessor.cs
new file mode 100644
index 0000000..4920f33
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentProcessor.cs
@@ -0,0 +1,15 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.Content.Pipeline.Json;
+
+namespace MonoGame.Extended.Content.Pipeline.SpriteFactory
+{
+ [ContentProcessor(DisplayName = "Sprite Factory Processor - MonoGame.Extended")]
+ public class SpriteFactoryContentProcessor : JsonContentProcessor
+ {
+ public SpriteFactoryContentProcessor()
+ {
+ ContentType = "MonoGame.Extended MonoGame.Extended.Animations.SpriteFactory.SpriteFactoryFileReader, MonoGame.Extended.Animations";
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerJsonImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerJsonImporter.cs
new file mode 100644
index 0000000..a80e654
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerJsonImporter.cs
@@ -0,0 +1,18 @@
+using System.IO;
+using System.Text.Json;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.TextureAtlases;
+
+
+namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
+{
+ [ContentImporter(".json", DefaultProcessor = "TexturePackerProcessor", DisplayName = "TexturePacker JSON Importer - MonoGame.Extended")]
+ public class TexturePackerJsonImporter : ContentImporter
+ {
+ public override TexturePackerFile Import(string filename, ContentImporterContext context)
+ {
+ var json = File.ReadAllText(filename);
+ return JsonSerializer.Deserialize(json);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessor.cs
new file mode 100644
index 0000000..1f14ee7
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessor.cs
@@ -0,0 +1,24 @@
+using System;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.TextureAtlases;
+
+namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
+{
+ [ContentProcessor(DisplayName = "TexturePacker Processor - MonoGame.Extended")]
+ public class TexturePackerProcessor : ContentProcessor
+ {
+ public override TexturePackerProcessorResult Process(TexturePackerFile input, ContentProcessorContext context)
+ {
+ try
+ {
+ var output = new TexturePackerProcessorResult {Data = input};
+ return output;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogMessage("Error {0}", ex);
+ throw;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessorResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessorResult.cs
new file mode 100644
index 0000000..a996259
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessorResult.cs
@@ -0,0 +1,9 @@
+using MonoGame.Extended.TextureAtlases;
+
+namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
+{
+ public class TexturePackerProcessorResult
+ {
+ public TexturePackerFile Data { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerWriter.cs
new file mode 100644
index 0000000..3fd15ff
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerWriter.cs
@@ -0,0 +1,45 @@
+using System.Diagnostics;
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
+{
+ [ContentTypeWriter]
+ public class TexturePackerWriter : ContentTypeWriter
+ {
+ protected override void Write(ContentWriter writer, TexturePackerProcessorResult result)
+ {
+ var data = result.Data;
+ var metadata = data.Metadata;
+
+ var assetName = Path.GetFileNameWithoutExtension(metadata.Image);
+ Debug.Assert(assetName != null, "assetName != null");
+
+ writer.Write(assetName);
+ writer.Write(data.Regions.Count);
+
+ foreach (var region in data.Regions)
+ {
+ var regionName = Path.ChangeExtension(region.Filename, null);
+ Debug.Assert(regionName != null, "regionName != null");
+
+ writer.Write(regionName);
+ writer.Write(region.Frame.X);
+ writer.Write(region.Frame.Y);
+ writer.Write(region.Frame.Width);
+ writer.Write(region.Frame.Height);
+ }
+ }
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.TextureAtlases.TextureAtlas, MonoGame.Extended";
+ }
+
+ public override string GetRuntimeReader(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.TextureAtlases.TextureAtlasReader, MonoGame.Extended";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/ContentWriterExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/ContentWriterExtensions.cs
new file mode 100644
index 0000000..28ded17
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/ContentWriterExtensions.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ public static class ContentWriterExtensions
+ {
+ // ReSharper disable once SuggestBaseTypeForParameter
+ public static void WriteTiledMapProperties(this ContentWriter writer, IReadOnlyCollection value)
+ {
+ if (value == null)
+ {
+ writer.Write(0);
+ return;
+ }
+ writer.Write(value.Count);
+ foreach (var property in value)
+ {
+ writer.Write(property.Name);
+ writer.Write(property.Value ?? string.Empty);
+ WriteTiledMapProperties(writer, property.Properties);
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledContentItem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledContentItem.cs
new file mode 100644
index 0000000..b376252
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledContentItem.cs
@@ -0,0 +1,22 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled;
+
+public class TiledContentItem: ContentItem
+{
+ public TiledContentItem(T data) : base(data)
+ {
+ }
+
+ public void BuildExternalReference(ContentProcessorContext context, TiledMapImageContent image)
+ {
+ var parameters = new OpaqueDataDictionary
+ {
+ { "ColorKeyColor", image.TransparentColor },
+ { "ColorKeyEnabled", true }
+ };
+ BuildExternalReference(context, image.Source, parameters);
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapContentItem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapContentItem.cs
new file mode 100644
index 0000000..b0b7b5d
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapContentItem.cs
@@ -0,0 +1,12 @@
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ public class TiledMapContentItem : TiledContentItem
+ {
+ public TiledMapContentItem(TiledMapContent data)
+ : base(data)
+ {
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapImporter.cs
new file mode 100644
index 0000000..70e2bee
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapImporter.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml.Serialization;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentImporter(".tmx", DefaultProcessor = "TiledMapProcessor", DisplayName = "Tiled Map Importer - MonoGame.Extended")]
+ public class TiledMapImporter : ContentImporter
+ {
+ public override TiledMapContentItem Import(string filePath, ContentImporterContext context)
+ {
+ try
+ {
+ if (filePath == null)
+ throw new ArgumentNullException(nameof(filePath));
+
+ ContentLogger.Logger = context.Logger;
+ ContentLogger.Log($"Importing '{filePath}'");
+
+ var map = DeserializeTiledMapContent(filePath, context);
+
+ if (map.Width > ushort.MaxValue || map.Height > ushort.MaxValue)
+ throw new InvalidContentException($"The map '{filePath} is much too large. The maximum supported width and height for a Tiled map is {ushort.MaxValue}.");
+
+ ContentLogger.Log($"Imported '{filePath}'");
+
+ return new TiledMapContentItem(map);
+
+ }
+ catch (Exception e)
+ {
+ context.Logger.LogImportantMessage(e.StackTrace);
+ throw;
+ }
+ }
+
+ private static TiledMapContent DeserializeTiledMapContent(string mapFilePath, ContentImporterContext context)
+ {
+ using (var reader = new StreamReader(mapFilePath))
+ {
+ var mapSerializer = new XmlSerializer(typeof(TiledMapContent));
+ var map = (TiledMapContent)mapSerializer.Deserialize(reader);
+
+ map.FilePath = mapFilePath;
+
+ for (var i = 0; i < map.Tilesets.Count; i++)
+ {
+ var tileset = map.Tilesets[i];
+
+ string getTilesetSource(string source)
+ => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(mapFilePath), source));
+
+ if (!string.IsNullOrWhiteSpace(tileset.Source))
+ {
+ tileset.Source = getTilesetSource(tileset.Source);
+ ContentLogger.Log($"Adding dependency for {tileset.Source}");
+ // We depend on the tileset. If the tileset changes, the map also needs to rebuild.
+ context.AddDependency(tileset.Source);
+ }
+ else
+ {
+ tileset.Image.Source = getTilesetSource(tileset.Image.Source);
+ ContentLogger.Log($"Adding dependency for {tileset.Image.Source}");
+ context.AddDependency(tileset.Image.Source);
+ }
+ }
+
+ ImportLayers(context, map.Layers, Path.GetDirectoryName(mapFilePath));
+
+ map.Name = mapFilePath;
+ return map;
+ }
+ }
+
+ private static void ImportLayers(ContentImporterContext context, List layers, string path)
+ {
+ for (var i = 0; i < layers.Count; i++)
+ {
+ if (layers[i] is TiledMapImageLayerContent imageLayer)
+ {
+ imageLayer.Image.Source = Path.Combine(path, imageLayer.Image.Source);
+ ContentLogger.Log($"Adding dependency for '{imageLayer.Image.Source}'");
+
+ // Tell the pipeline that we depend on this image and need to rebuild the map if the image changes.
+ // (Maybe the image is a different size)
+ context.AddDependency(imageLayer.Image.Source);
+ }
+ if (layers[i] is TiledMapObjectLayerContent objectLayer)
+ foreach (var obj in objectLayer.Objects)
+ if (!String.IsNullOrWhiteSpace(obj.TemplateSource))
+ {
+ obj.TemplateSource = Path.Combine(path, obj.TemplateSource);
+ ContentLogger.Log($"Adding dependency for '{obj.TemplateSource}'");
+ // Tell the pipeline that we depend on this template and need to rebuild the map if the template changes.
+ // (Templates are loaded into objects on process, so all objects which depend on the template file
+ // need the change to the template)
+ context.AddDependency(obj.TemplateSource);
+ }
+ if (layers[i] is TiledMapGroupLayerContent groupLayer)
+ // Yay recursion!
+ ImportLayers(context, groupLayer.Layers, path);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapObjectTemplateImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapObjectTemplateImporter.cs
new file mode 100644
index 0000000..eeddcaa
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapObjectTemplateImporter.cs
@@ -0,0 +1,54 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using System;
+using System.IO;
+using System.Xml.Serialization;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentImporter(".tx", DefaultProcessor = "TiledMapObjectTemplateProcessor", DisplayName = "Tiled Map Object Template Importer - MonoGame.Extended")]
+ public class TiledMapObjectTemplateImporter : ContentImporter
+ {
+ public override TiledMapObjectTemplateContent Import(string filePath, ContentImporterContext context)
+ {
+ try
+ {
+ if (filePath == null)
+ throw new ArgumentNullException(nameof(filePath));
+
+ ContentLogger.Logger = context.Logger;
+ ContentLogger.Log($"Importing '{filePath}'");
+
+ var template = DeserializeTileMapObjectTemplateContent(filePath, context);
+
+ ContentLogger.Log($"Imported '{filePath}'");
+
+ return template;
+ }
+ catch (Exception e)
+ {
+ context.Logger.LogImportantMessage(e.StackTrace);
+ return null;
+ }
+ }
+
+ private static TiledMapObjectTemplateContent DeserializeTileMapObjectTemplateContent(string filePath, ContentImporterContext context)
+ {
+ using (var reader = new StreamReader(filePath))
+ {
+ var templateSerializer = new XmlSerializer(typeof(TiledMapObjectTemplateContent));
+ var template = (TiledMapObjectTemplateContent)templateSerializer.Deserialize(reader);
+
+ if (!string.IsNullOrWhiteSpace(template.Tileset?.Source))
+ {
+ template.Tileset.Source = Path.Combine(Path.GetDirectoryName(filePath), template.Tileset.Source);
+ ContentLogger.Log($"Adding dependency '{template.Tileset.Source}'");
+ // We depend on this tileset.
+ context.AddDependency(template.Tileset.Source);
+ }
+
+ return template;
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapProcessor.cs
new file mode 100644
index 0000000..9668a72
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapProcessor.cs
@@ -0,0 +1,324 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using MonoGame.Extended.Tiled;
+using MonoGame.Extended.Tiled.Serialization;
+using MonoGame.Framework.Utilities.Deflate;
+using CompressionMode = System.IO.Compression.CompressionMode;
+using GZipStream = System.IO.Compression.GZipStream;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ public static class TiledMapContentHelper
+ {
+ public static void Process(TiledMapObjectContent obj, ContentProcessorContext context)
+ {
+ if (!string.IsNullOrWhiteSpace(obj.TemplateSource))
+ {
+ var externalReference = new ExternalReference(obj.TemplateSource);
+ var template = context.BuildAndLoadAsset(externalReference, "");
+
+ // Nothing says a template can't reference another template.
+ // Yay recusion!
+ Process(template.Object, context);
+
+ if (!obj._globalIdentifier.HasValue && template.Object._globalIdentifier.HasValue)
+ obj.GlobalIdentifier = template.Object.GlobalIdentifier;
+
+ if (!obj._height.HasValue && template.Object._height.HasValue)
+ obj.Height = template.Object.Height;
+
+ if (!obj._identifier.HasValue && template.Object._identifier.HasValue)
+ obj.Identifier = template.Object.Identifier;
+
+ if (!obj._rotation.HasValue && template.Object._rotation.HasValue)
+ obj.Rotation = template.Object.Rotation;
+
+ if (!obj._visible.HasValue && template.Object._visible.HasValue)
+ obj.Visible = template.Object.Visible;
+
+ if (!obj._width.HasValue && template.Object._width.HasValue)
+ obj.Width = template.Object.Width;
+
+ if (!obj._x.HasValue && template.Object._x.HasValue)
+ obj.X = template.Object.X;
+
+ if (!obj._y.HasValue && template.Object._y.HasValue)
+ obj.Y = template.Object.Y;
+
+ if (obj.Ellipse == null && template.Object.Ellipse != null)
+ obj.Ellipse = template.Object.Ellipse;
+
+ if (string.IsNullOrWhiteSpace(obj.Name) && !string.IsNullOrWhiteSpace(template.Object.Name))
+ obj.Name = template.Object.Name;
+
+ if (obj.Polygon == null && template.Object.Polygon != null)
+ obj.Polygon = template.Object.Polygon;
+
+ if (obj.Polyline == null && template.Object.Polyline != null)
+ obj.Polyline = template.Object.Polyline;
+
+ foreach (var tProperty in template.Object.Properties)
+ {
+ if (!obj.Properties.Exists(p => p.Name == tProperty.Name))
+ obj.Properties.Add(tProperty);
+ }
+
+ if (string.IsNullOrWhiteSpace(obj.Type) && !string.IsNullOrWhiteSpace(template.Object.Type))
+ obj.Type = template.Object.Type;
+
+ if (string.IsNullOrWhiteSpace(obj.Class) && !string.IsNullOrWhiteSpace(template.Object.Class))
+ obj.Class = template.Object.Class;
+ }
+ }
+ }
+
+
+ [ContentProcessor(DisplayName = "Tiled Map Processor - MonoGame.Extended")]
+ public class TiledMapProcessor : ContentProcessor
+ {
+ public override TiledMapContentItem Process(TiledMapContentItem contentItem, ContentProcessorContext context)
+ {
+ try
+ {
+ ContentLogger.Logger = context.Logger;
+ var map = contentItem.Data;
+
+ if (map.Orientation == TiledMapOrientationContent.Hexagonal || map.Orientation == TiledMapOrientationContent.Staggered)
+ throw new NotSupportedException($"{map.Orientation} Tiled Maps are currently not implemented!");
+
+ foreach (var tileset in map.Tilesets)
+ {
+ if (string.IsNullOrWhiteSpace(tileset.Source))
+ {
+ // Load the Texture2DContent for the tileset as it will be saved into the map content file.
+ contentItem.BuildExternalReference(context, tileset.Image);
+ }
+ else
+ {
+ // Link to the tileset for the content loader to load at runtime.
+ //var externalReference = new ExternalReference(tileset.Source);
+ //tileset.Content = context.BuildAsset(externalReference, "");
+ contentItem.BuildExternalReference(context, tileset.Source);
+ }
+ }
+
+ ProcessLayers(contentItem, map, context, map.Layers);
+
+ return contentItem;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogImportantMessage(ex.Message);
+ throw;
+ }
+ }
+
+ private static void ProcessLayers(TiledMapContentItem contentItem, TiledMapContent map, ContentProcessorContext context, List layers)
+ {
+ foreach (var layer in layers)
+ {
+ switch (layer)
+ {
+ case TiledMapImageLayerContent imageLayer:
+ ContentLogger.Log($"Processing image layer '{imageLayer.Name}'");
+ contentItem.BuildExternalReference(context, imageLayer.Image);
+ ContentLogger.Log($"Processed image layer '{imageLayer.Name}'");
+ break;
+
+ case TiledMapTileLayerContent tileLayer when tileLayer.Data.Chunks.Count > 0:
+ throw new NotSupportedException($"{map.FilePath} contains data chunks. These are currently not supported.");
+
+ case TiledMapTileLayerContent tileLayer:
+ var data = tileLayer.Data;
+ var encodingType = data.Encoding ?? "xml";
+ var compressionType = data.Compression ?? "xml";
+
+ ContentLogger.Log($"Processing tile layer '{tileLayer.Name}': Encoding: '{encodingType}', Compression: '{compressionType}'");
+ var tileData = DecodeTileLayerData(encodingType, tileLayer);
+ var tiles = CreateTiles(map.RenderOrder, map.Width, map.Height, tileData);
+ tileLayer.Tiles = tiles;
+ ContentLogger.Log($"Processed tile layer '{tileLayer}': {tiles.Length} tiles");
+ break;
+
+ case TiledMapObjectLayerContent objectLayer:
+ ContentLogger.Log($"Processing object layer '{objectLayer.Name}'");
+
+ foreach (var obj in objectLayer.Objects)
+ TiledMapContentHelper.Process(obj, context);
+
+ ContentLogger.Log($"Processed object layer '{objectLayer.Name}'");
+ break;
+
+ case TiledMapGroupLayerContent groupLayer:
+ ProcessLayers(contentItem, map, context, groupLayer.Layers);
+ break;
+ }
+ }
+ }
+
+ private static List DecodeTileLayerData(string encodingType, TiledMapTileLayerContent tileLayer)
+ {
+ List tiles;
+
+ switch (encodingType)
+ {
+ case "xml":
+ tiles = tileLayer.Data.Tiles;
+ break;
+ case "csv":
+ tiles = DecodeCommaSeperatedValuesData(tileLayer.Data);
+ break;
+ case "base64":
+ tiles = DecodeBase64Data(tileLayer.Data, tileLayer.Width, tileLayer.Height);
+ break;
+ default:
+ throw new NotSupportedException($"The tile layer encoding '{encodingType}' is not supported.");
+ }
+
+ return tiles;
+ }
+
+ private static TiledMapTile[] CreateTiles(TiledMapTileDrawOrderContent renderOrder, int mapWidth, int mapHeight, List tileData)
+ {
+ TiledMapTile[] tiles;
+
+ switch (renderOrder)
+ {
+ case TiledMapTileDrawOrderContent.LeftDown:
+ tiles = CreateTilesInLeftDownOrder(tileData, mapWidth, mapHeight).ToArray();
+ break;
+ case TiledMapTileDrawOrderContent.LeftUp:
+ tiles = CreateTilesInLeftUpOrder(tileData, mapWidth, mapHeight).ToArray();
+ break;
+ case TiledMapTileDrawOrderContent.RightDown:
+ tiles = CreateTilesInRightDownOrder(tileData, mapWidth, mapHeight).ToArray();
+ break;
+ case TiledMapTileDrawOrderContent.RightUp:
+ tiles = CreateTilesInRightUpOrder(tileData, mapWidth, mapHeight).ToArray();
+ break;
+ default:
+ throw new NotSupportedException($"{renderOrder} is not supported.");
+ }
+
+ return tiles.ToArray();
+ }
+
+ private static IEnumerable CreateTilesInLeftDownOrder(List tileLayerData, int mapWidth, int mapHeight)
+ {
+ for (var y = 0; y < mapHeight; y++)
+ {
+ for (var x = mapWidth - 1; x >= 0; x--)
+ {
+ var dataIndex = x + y * mapWidth;
+ var globalIdentifier = tileLayerData[dataIndex].GlobalIdentifier;
+ if (globalIdentifier == 0)
+ continue;
+ var tile = new TiledMapTile(globalIdentifier, (ushort)x, (ushort)y);
+ yield return tile;
+ }
+ }
+ }
+
+ private static IEnumerable CreateTilesInLeftUpOrder(List tileLayerData, int mapWidth, int mapHeight)
+ {
+ for (var y = mapHeight - 1; y >= 0; y--)
+ {
+ for (var x = mapWidth - 1; x >= 0; x--)
+ {
+ var dataIndex = x + y * mapWidth;
+ var globalIdentifier = tileLayerData[dataIndex].GlobalIdentifier;
+ if (globalIdentifier == 0)
+ continue;
+ var tile = new TiledMapTile(globalIdentifier, (ushort)x, (ushort)y);
+ yield return tile;
+ }
+ }
+ }
+
+ private static IEnumerable CreateTilesInRightDownOrder(List tileLayerData, int mapWidth, int mapHeight)
+ {
+ for (var y = 0; y < mapHeight; y++)
+ {
+ for (var x = 0; x < mapWidth; x++)
+ {
+ var dataIndex = x + y * mapWidth;
+ var globalIdentifier = tileLayerData[dataIndex].GlobalIdentifier;
+ if (globalIdentifier == 0)
+ continue;
+ var tile = new TiledMapTile(globalIdentifier, (ushort)x, (ushort)y);
+ yield return tile;
+ }
+ }
+ }
+
+ private static IEnumerable CreateTilesInRightUpOrder(List tileLayerData, int mapWidth, int mapHeight)
+ {
+ for (var y = mapHeight - 1; y >= 0; y--)
+ {
+ for (var x = mapWidth - 1; x >= 0; x--)
+ {
+ var dataIndex = x + y * mapWidth;
+ var globalIdentifier = tileLayerData[dataIndex].GlobalIdentifier;
+ if (globalIdentifier == 0)
+ continue;
+ var tile = new TiledMapTile(globalIdentifier, (ushort)x, (ushort)y);
+ yield return tile;
+ }
+ }
+ }
+
+ private static List DecodeBase64Data(TiledMapTileLayerDataContent data, int width, int height)
+ {
+ var tileList = new List();
+ var encodedData = data.Value.Trim();
+ var decodedData = Convert.FromBase64String(encodedData);
+
+ using (var stream = OpenStream(decodedData, data.Compression))
+ {
+ using (var reader = new BinaryReader(stream))
+ {
+ data.Tiles = new List();
+
+ for (var y = 0; y < width; y++)
+ {
+ for (var x = 0; x < height; x++)
+ {
+ var gid = reader.ReadUInt32();
+ tileList.Add(new TiledMapTileContent
+ {
+ GlobalIdentifier = gid
+ });
+ }
+ }
+ }
+ }
+
+ return tileList;
+ }
+
+ private static List DecodeCommaSeperatedValuesData(TiledMapTileLayerDataContent data)
+ {
+ return data.Value
+ .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(uint.Parse)
+ .Select(x => new TiledMapTileContent { GlobalIdentifier = x })
+ .ToList();
+ }
+
+ private static Stream OpenStream(byte[] decodedData, string compressionMode)
+ {
+ var memoryStream = new MemoryStream(decodedData, false);
+
+ return compressionMode switch
+ {
+ "gzip" => new GZipStream(memoryStream, CompressionMode.Decompress),
+ "zlib" => new ZlibStream(memoryStream, Framework.Utilities.Deflate.CompressionMode.Decompress),
+ _ => memoryStream
+ };
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetContentItem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetContentItem.cs
new file mode 100644
index 0000000..d4b2221
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetContentItem.cs
@@ -0,0 +1,14 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ public class TiledMapTilesetContentItem : TiledContentItem
+ {
+ public TiledMapTilesetContentItem(TiledMapTilesetContent data)
+ : base(data)
+ {
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetImporter.cs
new file mode 100644
index 0000000..c848bde
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetImporter.cs
@@ -0,0 +1,60 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using System;
+using System.IO;
+using System.Xml.Serialization;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentImporter(".tsx", DefaultProcessor = "TiledMapTilesetProcessor", DisplayName = "Tiled Map Tileset Importer - MonoGame.Extended")]
+ public class TiledMapTilesetImporter : ContentImporter
+ {
+ public override TiledMapTilesetContentItem Import(string filePath, ContentImporterContext context)
+ {
+ try
+ {
+ if (filePath == null)
+ throw new ArgumentNullException(nameof(filePath));
+
+ ContentLogger.Logger = context.Logger;
+ ContentLogger.Log($"Importing '{filePath}'");
+
+ var tileset = DeserializeTiledMapTilesetContent(filePath, context);
+
+ ContentLogger.Log($"Imported '{filePath}'");
+
+ return new TiledMapTilesetContentItem(tileset);
+ }
+ catch (Exception e)
+ {
+ context.Logger.LogImportantMessage(e.StackTrace);
+ throw;
+ }
+ }
+
+ private TiledMapTilesetContent DeserializeTiledMapTilesetContent(string filePath, ContentImporterContext context)
+ {
+ using (var reader = new StreamReader(filePath))
+ {
+ var tilesetSerializer = new XmlSerializer(typeof(TiledMapTilesetContent));
+ var tileset = (TiledMapTilesetContent)tilesetSerializer.Deserialize(reader);
+
+ if (tileset.Image is not null)
+ tileset.Image.Source = context.AddDependencyWithLogging(filePath, tileset.Image.Source);
+
+ foreach (var tile in tileset.Tiles)
+ {
+ foreach (var obj in tile.Objects)
+ {
+ if (!string.IsNullOrWhiteSpace(obj.TemplateSource))
+ obj.TemplateSource = context.AddDependencyWithLogging(filePath, obj.TemplateSource);
+ }
+ if (tile.Image is not null)
+ tile.Image.Source = context.AddDependencyWithLogging(filePath, tile.Image.Source);
+ }
+
+ return tileset;
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetProcessor.cs
new file mode 100644
index 0000000..5682602
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetProcessor.cs
@@ -0,0 +1,44 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using System;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentProcessor(DisplayName = "Tiled Map Tileset Processor - MonoGame.Extended")]
+ public class TiledMapTilesetProcessor : ContentProcessor
+ {
+ public override TiledMapTilesetContentItem Process(TiledMapTilesetContentItem contentItem, ContentProcessorContext context)
+ {
+ try
+ {
+ var tileset = contentItem.Data;
+
+ ContentLogger.Logger = context.Logger;
+ ContentLogger.Log($"Processing tileset '{tileset.Name}'");
+
+ // Build the Texture2D asset and load it as it will be saved as part of this tileset file.
+ if (tileset.Image is not null)
+ contentItem.BuildExternalReference(context, tileset.Image);
+
+ foreach (var tile in tileset.Tiles)
+ {
+ foreach (var obj in tile.Objects)
+ {
+ TiledMapContentHelper.Process(obj, context);
+ }
+ if (tile.Image is not null)
+ contentItem.BuildExternalReference(context, tile.Image);
+ }
+
+ ContentLogger.Log($"Processed tileset '{tileset.Name}'");
+
+ return contentItem;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogImportantMessage(ex.Message);
+ throw ex;
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetWriter.cs
new file mode 100644
index 0000000..48690ad
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetWriter.cs
@@ -0,0 +1,145 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+using MonoGame.Extended.Tiled;
+using System;
+using System.Globalization;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentTypeWriter]
+ public class TiledMapTilesetWriter : ContentTypeWriter
+ {
+ public override string GetRuntimeReader(TargetPlatform targetPlatform) => "MonoGame.Extended.Tiled.TiledMapTilesetReader, MonoGame.Extended.Tiled";
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform) => "MonoGame.Extended.Tiled.TiledMapTileset, MonoGame.Extended.Tiled";
+
+ protected override void Write(ContentWriter writer, TiledMapTilesetContentItem contentItem)
+ {
+ try
+ {
+ WriteTileset(writer, contentItem.Data, contentItem);
+ }
+ catch (Exception ex)
+ {
+ ContentLogger.Logger.LogImportantMessage(ex.StackTrace);
+ throw;
+ }
+ }
+
+ public static void WriteTileset(ContentWriter writer, TiledMapTilesetContent tileset, IExternalReferenceRepository externalReferenceRepository)
+ {
+ var externalReference = externalReferenceRepository.GetExternalReference(tileset.Image?.Source);
+ writer.WriteExternalReference(externalReference);
+ writer.Write(tileset.Class ?? tileset.Type ?? string.Empty);
+ writer.Write(tileset.TileWidth);
+ writer.Write(tileset.TileHeight);
+ writer.Write(tileset.TileCount);
+ writer.Write(tileset.Spacing);
+ writer.Write(tileset.Margin);
+ writer.Write(tileset.Columns);
+ writer.Write(tileset.Tiles.Count);
+
+ foreach (var tilesetTile in tileset.Tiles)
+ WriteTilesetTile(writer, tilesetTile, externalReferenceRepository);
+
+ writer.WriteTiledMapProperties(tileset.Properties);
+ }
+
+ private static void WriteTilesetTile(ContentWriter writer, TiledMapTilesetTileContent tilesetTile,
+ IExternalReferenceRepository externalReferenceRepository)
+ {
+ var externalReference = externalReferenceRepository.GetExternalReference(tilesetTile.Image?.Source);
+ writer.WriteExternalReference(externalReference);
+
+ writer.Write(tilesetTile.LocalIdentifier);
+ writer.Write(tilesetTile.Type);
+ writer.Write(tilesetTile.Frames.Count);
+ writer.Write(tilesetTile.Objects.Count);
+
+ foreach (var @object in tilesetTile.Objects)
+ WriteObject(writer, @object);
+
+ foreach (var frame in tilesetTile.Frames)
+ {
+ writer.Write(frame.TileIdentifier);
+ writer.Write(frame.Duration);
+ }
+
+ writer.WriteTiledMapProperties(tilesetTile.Properties);
+ }
+
+ private static void WriteObject(ContentWriter writer, TiledMapObjectContent @object)
+ {
+ var type = GetObjectType(@object);
+
+ writer.Write((byte)type);
+
+ writer.Write(@object.Identifier);
+ writer.Write(@object.Name ?? string.Empty);
+ writer.Write(@object.Class ?? @object.Type ?? string.Empty);
+ writer.Write(@object.X);
+ writer.Write(@object.Y);
+ writer.Write(@object.Width);
+ writer.Write(@object.Height);
+ writer.Write(@object.Rotation);
+ writer.Write(@object.Visible);
+
+ writer.WriteTiledMapProperties(@object.Properties);
+
+ switch (type)
+ {
+ case TiledMapObjectType.Rectangle:
+ case TiledMapObjectType.Ellipse:
+ break;
+ case TiledMapObjectType.Tile:
+ writer.Write(@object.GlobalIdentifier);
+ break;
+ case TiledMapObjectType.Polygon:
+ WritePolyPoints(writer, @object.Polygon.Points);
+ break;
+ case TiledMapObjectType.Polyline:
+ WritePolyPoints(writer, @object.Polyline.Points);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ // ReSharper disable once SuggestBaseTypeForParameter
+ private static void WritePolyPoints(ContentWriter writer, string @string)
+ {
+ var stringPoints = @string.Split(' ');
+
+ writer.Write(stringPoints.Length);
+
+ foreach (var stringPoint in stringPoints)
+ {
+ var xy = stringPoint.Split(',');
+ var x = float.Parse(xy[0], CultureInfo.InvariantCulture.NumberFormat);
+ writer.Write(x);
+ var y = float.Parse(xy[1], CultureInfo.InvariantCulture.NumberFormat);
+ writer.Write(y);
+ }
+ }
+
+ public static TiledMapObjectType GetObjectType(TiledMapObjectContent content)
+ {
+ if (content.GlobalIdentifier > 0)
+ return TiledMapObjectType.Tile;
+
+ if (content.Ellipse != null)
+ return TiledMapObjectType.Ellipse;
+
+ if (content.Polygon != null)
+ return TiledMapObjectType.Polygon;
+
+ // ReSharper disable once ConvertIfStatementToReturnStatement
+ if (content.Polyline != null)
+ return TiledMapObjectType.Polyline;
+
+ return TiledMapObjectType.Rectangle;
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapWriter.cs
new file mode 100644
index 0000000..126debb
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapWriter.cs
@@ -0,0 +1,227 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+using MonoGame.Extended.Tiled;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentTypeWriter]
+ public class TiledMapWriter : ContentTypeWriter
+ {
+ private TiledMapContentItem _contentItem;
+
+ protected override void Write(ContentWriter writer, TiledMapContentItem contentItem)
+ {
+ _contentItem = contentItem;
+
+ var map = contentItem.Data;
+
+ try
+ {
+ WriteMetaData(writer, map);
+ WriteTilesets(writer, map.Tilesets);
+ WriteLayers(writer, map.Layers);
+ }
+ catch (Exception ex)
+ {
+ ContentLogger.Logger.LogImportantMessage(ex.StackTrace);
+ throw;
+ }
+ }
+
+ private static void WriteMetaData(ContentWriter writer, TiledMapContent map)
+ {
+ writer.Write(map.Class ?? map.Type ?? string.Empty);
+ writer.Write(map.Width);
+ writer.Write(map.Height);
+ writer.Write(map.TileWidth);
+ writer.Write(map.TileHeight);
+ writer.Write(ColorHelper.FromHex(map.BackgroundColor));
+ writer.Write((byte)map.RenderOrder);
+ writer.Write((byte)map.Orientation);
+ writer.WriteTiledMapProperties(map.Properties);
+ }
+
+ private void WriteTilesets(ContentWriter writer, IReadOnlyCollection tilesets)
+ {
+ writer.Write(tilesets.Count);
+
+ foreach (var tileset in tilesets)
+ WriteTileset(writer, tileset);
+ }
+
+ private void WriteTileset(ContentWriter writer, TiledMapTilesetContent tileset)
+ {
+ writer.Write(tileset.FirstGlobalIdentifier);
+
+ if (!string.IsNullOrWhiteSpace(tileset.Source))
+ {
+ writer.Write(true);
+ writer.WriteExternalReference(_contentItem.GetExternalReference(tileset.Source));
+ }
+ else
+ {
+ writer.Write(false);
+ TiledMapTilesetWriter.WriteTileset(writer, tileset, _contentItem);
+ }
+ }
+
+ private void WriteLayers(ContentWriter writer, IReadOnlyCollection layers)
+ {
+ writer.Write(layers.Count);
+
+ foreach (var layer in layers)
+ WriteLayer(writer, layer);
+ }
+
+ private void WriteLayer(ContentWriter writer, TiledMapLayerContent layer)
+ {
+ writer.Write((byte)layer.LayerType);
+
+ writer.Write(layer.Name ?? string.Empty);
+ writer.Write(layer.Class ?? layer.Type ?? string.Empty);
+ writer.Write(layer.Visible);
+ writer.Write(layer.Opacity);
+ writer.Write(layer.OffsetX);
+ writer.Write(layer.OffsetY);
+ writer.Write(layer.ParallaxX);
+ writer.Write(layer.ParallaxY);
+
+ writer.WriteTiledMapProperties(layer.Properties);
+
+ switch (layer.LayerType)
+ {
+ case TiledMapLayerType.ImageLayer:
+ WriteImageLayer(writer, (TiledMapImageLayerContent)layer);
+ break;
+ case TiledMapLayerType.TileLayer:
+ WriteTileLayer(writer, (TiledMapTileLayerContent)layer);
+ break;
+ case TiledMapLayerType.ObjectLayer:
+ WriteObjectLayer(writer, (TiledMapObjectLayerContent)layer);
+ break;
+ case TiledMapLayerType.GroupLayer:
+ WriteLayers(writer, ((TiledMapGroupLayerContent)layer).Layers);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(layer.LayerType));
+ }
+ }
+
+ private void WriteImageLayer(ContentWriter writer, TiledMapImageLayerContent imageLayer)
+ {
+ var externalReference = _contentItem.GetExternalReference(imageLayer.Image.Source);
+ writer.WriteExternalReference(externalReference);
+ writer.Write(new Vector2(imageLayer.X, imageLayer.Y));
+ }
+
+ // ReSharper disable once SuggestBaseTypeForParameter
+ private static void WriteTileLayer(ContentWriter writer, TiledMapTileLayerContent tileLayer)
+ {
+ writer.Write(tileLayer.Width);
+ writer.Write(tileLayer.Height);
+
+ writer.Write(tileLayer.Tiles.Length);
+
+ foreach (var tile in tileLayer.Tiles)
+ {
+ writer.Write(tile.GlobalTileIdentifierWithFlags);
+ writer.Write(tile.X);
+ writer.Write(tile.Y);
+ }
+ }
+
+ private static void WriteObjectLayer(ContentWriter writer, TiledMapObjectLayerContent layer)
+ {
+ writer.Write(ColorHelper.FromHex(layer.Color));
+ writer.Write((byte)layer.DrawOrder);
+
+ writer.Write(layer.Objects.Count);
+
+ foreach (var @object in layer.Objects)
+ WriteObject(writer, @object);
+ }
+
+
+ private static void WriteObject(ContentWriter writer, TiledMapObjectContent @object)
+ {
+ var type = GetObjectType(@object);
+
+ writer.Write((byte)type);
+
+ writer.Write(@object.Identifier);
+ writer.Write(@object.Name ?? string.Empty);
+ writer.Write(@object.Class ?? @object.Type ?? string.Empty);
+ writer.Write(@object.X);
+ writer.Write(@object.Y);
+ writer.Write(@object.Width);
+ writer.Write(@object.Height);
+ writer.Write(@object.Rotation);
+ writer.Write(@object.Visible);
+
+ writer.WriteTiledMapProperties(@object.Properties);
+
+ switch (type)
+ {
+ case TiledMapObjectType.Rectangle:
+ case TiledMapObjectType.Ellipse:
+ break;
+ case TiledMapObjectType.Tile:
+ writer.Write(@object.GlobalIdentifier);
+ break;
+ case TiledMapObjectType.Polygon:
+ WritePolyPoints(writer, @object.Polygon.Points);
+ break;
+ case TiledMapObjectType.Polyline:
+ WritePolyPoints(writer, @object.Polyline.Points);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ // ReSharper disable once SuggestBaseTypeForParameter
+ private static void WritePolyPoints(ContentWriter writer, string @string)
+ {
+ var stringPoints = @string.Split(' ');
+
+ writer.Write(stringPoints.Length);
+
+ foreach (var stringPoint in stringPoints)
+ {
+ var xy = stringPoint.Split(',');
+ var x = float.Parse(xy[0], CultureInfo.InvariantCulture.NumberFormat);
+ writer.Write(x);
+ var y = float.Parse(xy[1], CultureInfo.InvariantCulture.NumberFormat);
+ writer.Write(y);
+ }
+ }
+
+ public static TiledMapObjectType GetObjectType(TiledMapObjectContent content)
+ {
+ if (content.GlobalIdentifier > 0)
+ return TiledMapObjectType.Tile;
+
+ if (content.Ellipse != null)
+ return TiledMapObjectType.Ellipse;
+
+ if (content.Polygon != null)
+ return TiledMapObjectType.Polygon;
+
+ // ReSharper disable once ConvertIfStatementToReturnStatement
+ if (content.Polyline != null)
+ return TiledMapObjectType.Polyline;
+
+ return TiledMapObjectType.Rectangle;
+ }
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform) => "MonoGame.Extended.Tiled.TiledMap, MonoGame.Extended.Tiled";
+
+ public override string GetRuntimeReader(TargetPlatform targetPlatform) => "MonoGame.Extended.Tiled.TiledMapReader, MonoGame.Extended.Tiled";
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/readme.txt b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/readme.txt
new file mode 100644
index 0000000..54f1cda
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/readme.txt
@@ -0,0 +1,15 @@
+# MonoGame.Extended.Content.Pipeline
+
+This NuGet package is intended to be used with the MonoGame Content Pipeline tool. You'll need to
+make some changes to your Content Pipline file (usually Content.mgcb) for everything to work
+properly.
+
+Add a reference to the `MonoGame.Extended.Content.Pipeline.dll` now installed in your `packages` folder
+to the [MonoGame Content Pipeline tool](http://www.monogame.net/documentation/?page=Pipeline).
+
+You can do this either with the Reference Editor in the GUI or by manually adding a reference line to
+your `Content.mgcb` file using a text editor.
+
+**Remember**: the versions need to match exactly for everything to work.
+
+For more information, take a look at the [installation guide](http://craftworkgames.github.io/MonoGame.Extended/installation/).
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Aspect.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Aspect.cs
new file mode 100644
index 0000000..e6fb606
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Aspect.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Specialized;
+
+namespace MonoGame.Extended.Entities
+{
+ public class Aspect
+ {
+ internal Aspect()
+ {
+ AllSet = new BitVector32();
+ ExclusionSet = new BitVector32();
+ OneSet = new BitVector32();
+ }
+
+ public BitVector32 AllSet;
+ public BitVector32 ExclusionSet;
+ public BitVector32 OneSet;
+
+ public static AspectBuilder All(params Type[] types)
+ {
+ return new AspectBuilder().All(types);
+ }
+
+ public static AspectBuilder One(params Type[] types)
+ {
+ return new AspectBuilder().One(types);
+ }
+
+ public static AspectBuilder Exclude(params Type[] types)
+ {
+ return new AspectBuilder().Exclude(types);
+ }
+
+ public bool IsInterested(BitVector32 componentBits)
+ {
+ if (AllSet.Data != 0 && (componentBits.Data & AllSet.Data) != AllSet.Data)
+ return false;
+
+ if (ExclusionSet.Data != 0 && (componentBits.Data & ExclusionSet.Data) != 0)
+ return false;
+
+ if (OneSet.Data != 0 && (componentBits.Data & OneSet.Data) == 0)
+ return false;
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/AspectBuilder.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/AspectBuilder.cs
new file mode 100644
index 0000000..d749795
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/AspectBuilder.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Specialized;
+using MonoGame.Extended.Collections;
+
+namespace MonoGame.Extended.Entities
+{
+ public class AspectBuilder
+ {
+ public AspectBuilder()
+ {
+ AllTypes = new Bag();
+ ExclusionTypes = new Bag();
+ OneTypes = new Bag();
+ }
+
+ public Bag AllTypes { get; }
+ public Bag ExclusionTypes { get; }
+ public Bag OneTypes { get; }
+
+ public AspectBuilder All(params Type[] types)
+ {
+ foreach (var type in types)
+ AllTypes.Add(type);
+
+ return this;
+ }
+
+ public AspectBuilder One(params Type[] types)
+ {
+ foreach (var type in types)
+ OneTypes.Add(type);
+
+ return this;
+ }
+
+ public AspectBuilder Exclude(params Type[] types)
+ {
+ foreach (var type in types)
+ ExclusionTypes.Add(type);
+
+ return this;
+ }
+
+ public Aspect Build(ComponentManager componentManager)
+ {
+ var aspect = new Aspect();
+ Associate(componentManager, AllTypes, ref aspect.AllSet);
+ Associate(componentManager, OneTypes, ref aspect.OneSet);
+ Associate(componentManager, ExclusionTypes, ref aspect.ExclusionSet);
+ return aspect;
+ }
+
+ // ReSharper disable once ParameterTypeCanBeEnumerable.Local
+ private static void Associate(ComponentManager componentManager, Bag types, ref BitVector32 bits)
+ {
+ foreach (var type in types)
+ {
+ var id = componentManager.GetComponentTypeId(type);
+ bits[1 << id] = true;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/BitArrayExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/BitArrayExtensions.cs
new file mode 100644
index 0000000..2ca0737
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/BitArrayExtensions.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections;
+
+namespace MonoGame.Extended.Entities
+{
+ public static class BitArrayExtensions
+ {
+ public static bool IsEmpty(this BitArray bitArray)
+ {
+ for (var i = 0; i < bitArray.Length; i++)
+ {
+ if (bitArray[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ public static bool ContainsAll(this BitArray bitArray, BitArray other)
+ {
+ var otherBitsLength = other.Length;
+ var bitsLength = bitArray.Length;
+
+ for (var i = bitsLength; i < otherBitsLength; i++)
+ {
+ if (other[i])
+ return false;
+ }
+
+ var s = Math.Min(bitsLength, otherBitsLength);
+
+ for (var i = 0; s > i; i++)
+ {
+ if ((bitArray[i] & other[i]) != other[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ public static bool Intersects(this BitArray bitArray, BitArray other)
+ {
+ var s = Math.Min(bitArray.Length, other.Length);
+
+ for (var i = 0; s > i; i++)
+ {
+ if (bitArray[i] & other[i])
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentManager.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentManager.cs
new file mode 100644
index 0000000..a59c87c
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentManager.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Collections;
+using MonoGame.Extended.Entities.Systems;
+
+namespace MonoGame.Extended.Entities
+{
+ public interface IComponentMapperService
+ {
+ ComponentMapper GetMapper() where T : class;
+ }
+
+ public class ComponentManager : UpdateSystem, IComponentMapperService
+ {
+ public ComponentManager()
+ {
+ _componentMappers = new Bag();
+ _componentTypes = new Dictionary();
+ }
+
+ private readonly Bag _componentMappers;
+ private readonly Dictionary _componentTypes;
+
+ public Action ComponentsChanged;
+
+ private ComponentMapper CreateMapperForType(int componentTypeId)
+ where T : class
+ {
+ // TODO: We can probably do better than this without a huge performance penalty by creating our own bit vector that grows after the first 32 bits.
+ if (componentTypeId >= 32)
+ throw new InvalidOperationException("Component type limit exceeded. We currently only allow 32 component types for performance reasons.");
+
+ var mapper = new ComponentMapper(componentTypeId, ComponentsChanged);
+ _componentMappers[componentTypeId] = mapper;
+ return mapper;
+ }
+
+ public ComponentMapper GetMapper(int componentTypeId)
+ {
+ return _componentMappers[componentTypeId];
+ }
+
+ public ComponentMapper GetMapper()
+ where T : class
+ {
+ var componentTypeId = GetComponentTypeId(typeof(T));
+
+ if (_componentMappers[componentTypeId] != null)
+ return _componentMappers[componentTypeId] as ComponentMapper;
+
+ return CreateMapperForType(componentTypeId);
+ }
+
+ public int GetComponentTypeId(Type type)
+ {
+ if (_componentTypes.TryGetValue(type, out var id))
+ return id;
+
+ id = _componentTypes.Count;
+ _componentTypes.Add(type, id);
+ return id;
+ }
+
+ public BitVector32 CreateComponentBits(int entityId)
+ {
+ var componentBits = new BitVector32();
+ var mask = BitVector32.CreateMask();
+
+ for (var componentId = 0; componentId < _componentMappers.Count; componentId++)
+ {
+ componentBits[mask] = _componentMappers[componentId]?.Has(entityId) ?? false;
+ mask = BitVector32.CreateMask(mask);
+ }
+
+ return componentBits;
+ }
+
+ public void Destroy(int entityId)
+ {
+ foreach (var componentMapper in _componentMappers)
+ componentMapper?.Delete(entityId);
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentMapper.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentMapper.cs
new file mode 100644
index 0000000..35b196c
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentMapper.cs
@@ -0,0 +1,69 @@
+using System;
+using MonoGame.Extended.Collections;
+
+namespace MonoGame.Extended.Entities
+{
+ public abstract class ComponentMapper
+ {
+ protected ComponentMapper(int id, Type componentType)
+ {
+ Id = id;
+ ComponentType = componentType;
+ }
+
+ public int Id { get; }
+ public Type ComponentType { get; }
+ public abstract bool Has(int entityId);
+ public abstract void Delete(int entityId);
+ }
+
+ public class ComponentMapper : ComponentMapper
+ where T : class
+ {
+ public event Action OnPut;
+ public event Action OnDelete;
+
+ private readonly Action _onCompositionChanged;
+
+ public ComponentMapper(int id, Action onCompositionChanged)
+ : base(id, typeof(T))
+ {
+ _onCompositionChanged = onCompositionChanged;
+ Components = new Bag();
+ }
+
+ public Bag Components { get; }
+
+ public void Put(int entityId, T component)
+ {
+ Components[entityId] = component;
+ _onCompositionChanged(entityId);
+ OnPut?.Invoke(entityId);
+ }
+
+ public T Get(Entity entity)
+ {
+ return Get(entity.Id);
+ }
+
+ public T Get(int entityId)
+ {
+ return Components[entityId];
+ }
+
+ public override bool Has(int entityId)
+ {
+ if (entityId >= Components.Count)
+ return false;
+
+ return Components[entityId] != null;
+ }
+
+ public override void Delete(int entityId)
+ {
+ Components[entityId] = null;
+ _onCompositionChanged(entityId);
+ OnDelete?.Invoke(entityId);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentType.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentType.cs
new file mode 100644
index 0000000..ebef996
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/ComponentType.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace MonoGame.Extended.Entities
+{
+ //public class ComponentType : IEquatable
+ //{
+ // public ComponentType(Type type, int id)
+ // {
+ // Type = type;
+ // Id = id;
+ // }
+
+ // public Type Type { get; }
+ // public int Id { get; }
+
+ // public bool Equals(ComponentType other)
+ // {
+ // if (ReferenceEquals(null, other)) return false;
+ // if (ReferenceEquals(this, other)) return true;
+ // return Id == other.Id;
+ // }
+
+ // public override bool Equals(object obj)
+ // {
+ // if (ReferenceEquals(null, obj)) return false;
+ // if (ReferenceEquals(this, obj)) return true;
+ // if (obj.GetType() != GetType()) return false;
+ // return Equals((ComponentType) obj);
+ // }
+
+ // public override int GetHashCode()
+ // {
+ // return Id;
+ // }
+
+ // public static bool operator ==(ComponentType left, ComponentType right)
+ // {
+ // return Equals(left, right);
+ // }
+
+ // public static bool operator !=(ComponentType left, ComponentType right)
+ // {
+ // return !Equals(left, right);
+ // }
+ //}
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Entity.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Entity.cs
new file mode 100644
index 0000000..a56ccff
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Entity.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Specialized;
+
+namespace MonoGame.Extended.Entities
+{
+ public class Entity : IEquatable
+ {
+ private readonly EntityManager _entityManager;
+ private readonly ComponentManager _componentManager;
+
+ internal Entity(int id, EntityManager entityManager, ComponentManager componentManager)
+ {
+ Id = id;
+
+ _entityManager = entityManager;
+ _componentManager = componentManager;
+ }
+
+ public int Id { get; }
+
+ public BitVector32 ComponentBits => _entityManager.GetComponentBits(Id);
+
+ public void Attach(T component)
+ where T : class
+ {
+ var mapper = _componentManager.GetMapper();
+ mapper.Put(Id, component);
+ }
+
+ public void Detach()
+ where T : class
+ {
+ var mapper = _componentManager.GetMapper();
+ mapper.Delete(Id);
+ }
+
+ public T Get()
+ where T : class
+ {
+ var mapper = _componentManager.GetMapper();
+ return mapper.Get(Id);
+ }
+
+
+ public bool Has()
+ where T : class
+ {
+ return _componentManager.GetMapper().Has(Id);
+ }
+
+ public void Destroy()
+ {
+ _entityManager.Destroy(Id);
+ }
+
+ public bool Equals(Entity other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Id == other.Id;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((Entity) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ // ReSharper disable once NonReadonlyMemberInGetHashCode
+ return Id;
+ }
+
+ public static bool operator ==(Entity left, Entity right)
+ {
+ return Equals(left, right);
+ }
+
+ public static bool operator !=(Entity left, Entity right)
+ {
+ return !Equals(left, right);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/EntityManager.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/EntityManager.cs
new file mode 100644
index 0000000..5e1d28a
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/EntityManager.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Linq;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Collections;
+using MonoGame.Extended.Entities.Systems;
+
+namespace MonoGame.Extended.Entities
+{
+ public class EntityManager : UpdateSystem
+ {
+ private const int _defaultBagSize = 128;
+
+ public EntityManager(ComponentManager componentManager)
+ {
+ _componentManager = componentManager;
+ _addedEntities = new Bag(_defaultBagSize);
+ _removedEntities = new Bag(_defaultBagSize);
+ _changedEntities = new Bag(_defaultBagSize);
+ _entityToComponentBits = new Bag(_defaultBagSize);
+ _componentManager.ComponentsChanged += OnComponentsChanged;
+
+ _entityBag = new Bag(_defaultBagSize);
+ _entityPool = new Pool(() => new Entity(_nextId++, this, _componentManager), _defaultBagSize);
+ }
+
+ private readonly ComponentManager _componentManager;
+ private int _nextId;
+
+ public int Capacity => _entityBag.Capacity;
+ public IEnumerable Entities => _entityBag.Where(e => e != null).Select(e => e.Id);
+ public int ActiveCount { get; private set; }
+
+ private readonly Bag _entityBag;
+ private readonly Pool _entityPool;
+ private readonly Bag _addedEntities;
+ private readonly Bag _removedEntities;
+ private readonly Bag _changedEntities;
+ private readonly Bag _entityToComponentBits;
+
+ public event Action EntityAdded;
+ public event Action EntityRemoved;
+ public event Action EntityChanged;
+
+ public Entity Create()
+ {
+ var entity = _entityPool.Obtain();
+ var id = entity.Id;
+ Debug.Assert(_entityBag[id] == null);
+ _entityBag[id] = entity;
+ _addedEntities.Add(id);
+ _entityToComponentBits[id] = new BitVector32(0);
+ return entity;
+ }
+
+ public void Destroy(int entityId)
+ {
+ if (!_removedEntities.Contains(entityId))
+ _removedEntities.Add(entityId);
+ }
+
+ public void Destroy(Entity entity)
+ {
+ Destroy(entity.Id);
+ }
+
+ public Entity Get(int entityId)
+ {
+ return _entityBag[entityId];
+ }
+
+ public BitVector32 GetComponentBits(int entityId)
+ {
+ return _entityToComponentBits[entityId];
+ }
+
+ private void OnComponentsChanged(int entityId)
+ {
+ _changedEntities.Add(entityId);
+ _entityToComponentBits[entityId] = _componentManager.CreateComponentBits(entityId);
+ EntityChanged?.Invoke(entityId);
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ foreach (var entityId in _addedEntities)
+ {
+ _entityToComponentBits[entityId] = _componentManager.CreateComponentBits(entityId);
+ ActiveCount++;
+ EntityAdded?.Invoke(entityId);
+ }
+
+ foreach (var entityId in _changedEntities)
+ {
+ _entityToComponentBits[entityId] = _componentManager.CreateComponentBits(entityId);
+ EntityChanged?.Invoke(entityId);
+ }
+
+ foreach (var entityId in _removedEntities)
+ {
+ // we must notify subscribers before removing it from the pool
+ // otherwise an entity system could still be using the entity when the same id is obtained.
+ EntityRemoved?.Invoke(entityId);
+
+ var entity = _entityBag[entityId];
+ _entityBag[entityId] = null;
+ _componentManager.Destroy(entityId);
+ _entityToComponentBits[entityId] = default(BitVector32);
+ ActiveCount--;
+ _entityPool.Free(entity);
+ }
+
+ _addedEntities.Clear();
+ _removedEntities.Clear();
+ _changedEntities.Clear();
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/EntitySubscription.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/EntitySubscription.cs
new file mode 100644
index 0000000..6766b0f
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/EntitySubscription.cs
@@ -0,0 +1,61 @@
+using System;
+using MonoGame.Extended.Collections;
+
+namespace MonoGame.Extended.Entities
+{
+ internal class EntitySubscription : IDisposable
+ {
+ private readonly Bag _activeEntities;
+ private readonly EntityManager _entityManager;
+ private readonly Aspect _aspect;
+ private bool _rebuildActives;
+
+ internal EntitySubscription(EntityManager entityManager, Aspect aspect)
+ {
+ _entityManager = entityManager;
+ _aspect = aspect;
+ _activeEntities = new Bag(entityManager.Capacity);
+ _rebuildActives = true;
+
+ _entityManager.EntityAdded += OnEntityAdded;
+ _entityManager.EntityRemoved += OnEntityRemoved;
+ _entityManager.EntityChanged += OnEntityChanged;
+ }
+
+ private void OnEntityAdded(int entityId)
+ {
+ if (_aspect.IsInterested(_entityManager.GetComponentBits(entityId)))
+ _activeEntities.Add(entityId);
+ }
+
+ private void OnEntityRemoved(int entityId) => _rebuildActives = true;
+ private void OnEntityChanged(int entityId) => _rebuildActives = true;
+
+ public void Dispose()
+ {
+ _entityManager.EntityAdded -= OnEntityAdded;
+ _entityManager.EntityRemoved -= OnEntityRemoved;
+ }
+
+ public Bag ActiveEntities
+ {
+ get
+ {
+ if (_rebuildActives)
+ RebuildActives();
+
+ return _activeEntities;
+ }
+ }
+
+ private void RebuildActives()
+ {
+ _activeEntities.Clear();
+
+ foreach (var entity in _entityManager.Entities)
+ OnEntityAdded(entity);
+
+ _rebuildActives = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/MonoGame.Extended.Entities.csproj b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/MonoGame.Extended.Entities.csproj
new file mode 100644
index 0000000..21ca693
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/MonoGame.Extended.Entities.csproj
@@ -0,0 +1,12 @@
+
+
+
+ An Entity Component System to make MonoGame more awesome.
+ monogame ecs entity component system
+
+
+
+
+
+
+
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/DrawSystem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/DrawSystem.cs
new file mode 100644
index 0000000..b9e63eb
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/DrawSystem.cs
@@ -0,0 +1,16 @@
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended.Entities.Systems
+{
+ public interface IDrawSystem : ISystem
+ {
+ void Draw(GameTime gameTime);
+ }
+
+ public abstract class DrawSystem : IDrawSystem
+ {
+ public virtual void Dispose() { }
+ public virtual void Initialize(World world) { }
+ public abstract void Draw(GameTime gameTime);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityDrawSystem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityDrawSystem.cs
new file mode 100644
index 0000000..5a0d6b9
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityDrawSystem.cs
@@ -0,0 +1,14 @@
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended.Entities.Systems
+{
+ public abstract class EntityDrawSystem : EntitySystem, IDrawSystem
+ {
+ protected EntityDrawSystem(AspectBuilder aspect)
+ : base(aspect)
+ {
+ }
+
+ public abstract void Draw(GameTime gameTime);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityProcessingSystem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityProcessingSystem.cs
new file mode 100644
index 0000000..c4d9339
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityProcessingSystem.cs
@@ -0,0 +1,26 @@
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended.Entities.Systems
+{
+ public abstract class EntityProcessingSystem : EntityUpdateSystem
+ {
+ protected EntityProcessingSystem(AspectBuilder aspectBuilder)
+ : base(aspectBuilder)
+ {
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ Begin();
+
+ foreach (var entityId in ActiveEntities)
+ Process(gameTime, entityId);
+
+ End();
+ }
+
+ public virtual void Begin() { }
+ public abstract void Process(GameTime gameTime, int entityId);
+ public virtual void End() { }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntitySystem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntitySystem.cs
new file mode 100644
index 0000000..2c95107
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntitySystem.cs
@@ -0,0 +1,51 @@
+using MonoGame.Extended.Collections;
+
+namespace MonoGame.Extended.Entities.Systems
+{
+ public abstract class EntitySystem : ISystem
+ {
+ protected EntitySystem(AspectBuilder aspectBuilder)
+ {
+ _aspectBuilder = aspectBuilder;
+ }
+
+ public void Dispose()
+ {
+ if (_world != null)
+ {
+ _world.EntityManager.EntityAdded -= OnEntityAdded;
+ _world.EntityManager.EntityRemoved -= OnEntityRemoved;
+ }
+ }
+
+ private readonly AspectBuilder _aspectBuilder;
+ private EntitySubscription _subscription;
+
+ private World _world;
+
+ protected virtual void OnEntityChanged(int entityId) { }
+ protected virtual void OnEntityAdded(int entityId) { }
+ protected virtual void OnEntityRemoved(int entityId) { }
+
+ public Bag ActiveEntities => _subscription.ActiveEntities;
+
+ public virtual void Initialize(World world)
+ {
+ _world = world;
+
+ var aspect = _aspectBuilder.Build(_world.ComponentManager);
+ _subscription = new EntitySubscription(_world.EntityManager, aspect);
+ _world.EntityManager.EntityAdded += OnEntityAdded;
+ _world.EntityManager.EntityRemoved += OnEntityRemoved;
+ _world.EntityManager.EntityChanged += OnEntityChanged;
+
+ Initialize(world.ComponentManager);
+ }
+
+ public abstract void Initialize(IComponentMapperService mapperService);
+
+ protected void DestroyEntity(int entityId) => _world.DestroyEntity(entityId);
+ protected Entity CreateEntity() => _world.CreateEntity();
+ protected Entity GetEntity(int entityId) => _world.GetEntity(entityId);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityUpdateSystem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityUpdateSystem.cs
new file mode 100644
index 0000000..97a61d5
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/EntityUpdateSystem.cs
@@ -0,0 +1,14 @@
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended.Entities.Systems
+{
+ public abstract class EntityUpdateSystem : EntitySystem, IUpdateSystem
+ {
+ protected EntityUpdateSystem(AspectBuilder aspectBuilder)
+ : base(aspectBuilder)
+ {
+ }
+
+ public abstract void Update(GameTime gameTime);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/ISystem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/ISystem.cs
new file mode 100644
index 0000000..d4511fc
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/ISystem.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace MonoGame.Extended.Entities.Systems
+{
+ public interface ISystem : IDisposable
+ {
+ void Initialize(World world);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/UpdateSystem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/UpdateSystem.cs
new file mode 100644
index 0000000..e85c964
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/Systems/UpdateSystem.cs
@@ -0,0 +1,16 @@
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended.Entities.Systems
+{
+ public interface IUpdateSystem : ISystem
+ {
+ void Update(GameTime gameTime);
+ }
+
+ public abstract class UpdateSystem : IUpdateSystem
+ {
+ public virtual void Dispose() { }
+ public virtual void Initialize(World world) { }
+ public abstract void Update(GameTime gameTime);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/World.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/World.cs
new file mode 100644
index 0000000..022d4b8
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/World.cs
@@ -0,0 +1,84 @@
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Collections;
+using MonoGame.Extended.Entities.Systems;
+
+namespace MonoGame.Extended.Entities
+{
+ public class World : SimpleDrawableGameComponent
+ {
+ private readonly Bag _updateSystems;
+ private readonly Bag _drawSystems;
+
+ internal World()
+ {
+ _updateSystems = new Bag();
+ _drawSystems = new Bag();
+
+ RegisterSystem(ComponentManager = new ComponentManager());
+ RegisterSystem(EntityManager = new EntityManager(ComponentManager));
+ }
+
+ public override void Dispose()
+ {
+ foreach (var updateSystem in _updateSystems)
+ updateSystem.Dispose();
+
+ foreach (var drawSystem in _drawSystems)
+ drawSystem.Dispose();
+
+ _updateSystems.Clear();
+ _drawSystems.Clear();
+
+ base.Dispose();
+ }
+
+ internal EntityManager EntityManager { get; }
+ internal ComponentManager ComponentManager { get; }
+
+ public int EntityCount => EntityManager.ActiveCount;
+
+ internal void RegisterSystem(ISystem system)
+ {
+ // ReSharper disable once ConvertIfStatementToSwitchStatement
+ if (system is IUpdateSystem updateSystem)
+ _updateSystems.Add(updateSystem);
+
+ if (system is IDrawSystem drawSystem)
+ _drawSystems.Add(drawSystem);
+
+ system.Initialize(this);
+ }
+
+ public Entity GetEntity(int entityId)
+ {
+ return EntityManager.Get(entityId);
+ }
+
+ public Entity CreateEntity()
+ {
+ return EntityManager.Create();
+ }
+
+ public void DestroyEntity(int entityId)
+ {
+ EntityManager.Destroy(entityId);
+ }
+
+ public void DestroyEntity(Entity entity)
+ {
+ EntityManager.Destroy(entity);
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ foreach (var system in _updateSystems)
+ system.Update(gameTime);
+ }
+
+ public override void Draw(GameTime gameTime)
+ {
+ foreach (var system in _drawSystems)
+ system.Draw(gameTime);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/WorldBuilder.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/WorldBuilder.cs
new file mode 100644
index 0000000..7f03323
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Entities/WorldBuilder.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using MonoGame.Extended.Entities.Systems;
+
+namespace MonoGame.Extended.Entities
+{
+ public class WorldBuilder
+ {
+ private readonly List _systems = new List();
+
+ public WorldBuilder AddSystem(ISystem system)
+ {
+ _systems.Add(system);
+ return this;
+ }
+
+ public World Build()
+ {
+ var world = new World();
+
+ foreach (var system in _systems)
+ world.RegisterSystem(system);
+
+ return world;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Batcher.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Batcher.cs
new file mode 100644
index 0000000..3cb5704
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Batcher.cs
@@ -0,0 +1,387 @@
+using System;
+using System.Runtime.CompilerServices;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics
+{
+ ///
+ /// Minimizes draw calls to a by sorting them and attempting to merge them together
+ /// before submitting them.
+ ///
+ /// The type of the information for a draw call.
+ ///
+ public abstract class Batcher : IDisposable
+ where TDrawCallInfo : struct, IBatchDrawCallInfo, IComparable
+ {
+ internal const int DefaultBatchMaximumDrawCallsCount = 2048;
+ private BlendState _blendState;
+ private SamplerState _samplerState;
+ private DepthStencilState _depthStencilState;
+ private RasterizerState _rasterizerState;
+ private readonly Effect _defaultEffect;
+ private Effect _currentEffect;
+ private Matrix? _viewMatrix;
+ private Matrix? _projectionMatrix;
+
+ ///
+ /// The array of structs currently enqueued.
+ ///
+ protected TDrawCallInfo[] DrawCalls;
+
+ ///
+ /// The number of structs currently enqueued.
+ ///
+ protected int EnqueuedDrawCallCount;
+
+ ///
+ /// Gets the associated with this .
+ ///
+ ///
+ /// The associated with this .
+ ///
+ public GraphicsDevice GraphicsDevice { get; }
+
+ ///
+ /// Gets a value indicating whether batching is currently in progress by being within a and
+ /// pair block of code.
+ ///
+ ///
+ /// true if batching has begun; otherwise, false.
+ ///
+ public bool HasBegun { get; internal set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ /// The default effect.
+ ///
+ /// The maximum number of structs that can be enqueued before a
+ ///
+ /// is required. The default value is 2048
.
+ ///
+ ///
+ /// is
+ /// null.
+ ///
+ ///
+ /// is less than or equal
+ /// 0
.
+ ///
+ protected Batcher(GraphicsDevice graphicsDevice, Effect defaultEffect,
+ int maximumDrawCallsCount = DefaultBatchMaximumDrawCallsCount)
+ {
+ if (graphicsDevice == null)
+ throw new ArgumentNullException(nameof(graphicsDevice));
+
+ if (maximumDrawCallsCount <= 0)
+ throw new ArgumentOutOfRangeException(nameof(maximumDrawCallsCount));
+
+ GraphicsDevice = graphicsDevice;
+ _defaultEffect = defaultEffect;
+ DrawCalls = new TDrawCallInfo[maximumDrawCallsCount];
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources.
+ ///
+ ///
+ /// true to release both managed and unmanaged resources; false to release only
+ /// unmanaged resources.
+ ///
+ protected virtual void Dispose(bool diposing)
+ {
+ if (!diposing)
+ return;
+ _defaultEffect.Dispose();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected void EnsureHasBegun([CallerMemberName] string callerMemberName = null)
+ {
+ if (!HasBegun)
+ throw new InvalidOperationException(
+ $"The {nameof(Begin)} method must be called before the {callerMemberName} method can be called.");
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected void EnsureHasNotBegun([CallerMemberName] string callerMemberName = null)
+ {
+ if (HasBegun)
+ throw new InvalidOperationException(
+ $"The {nameof(End)} method must be called before the {callerMemberName} method can be called.");
+ }
+
+ ///
+ /// Begins the batch operation using an optional , ,
+ /// , , , world-to-view
+ /// , or view-to-projection .
+ ///
+ ///
+ ///
+ /// The default objects for , ,
+ /// , and are
+ /// , ,
+ /// and respectively.
+ /// Passing
+ /// null
for any of the previously mentioned parameters result in using their default object.
+ ///
+ ///
+ /// The to use for the , pair.
+ ///
+ /// The texture to use for the and
+ /// pair.
+ ///
+ ///
+ /// The to use for the and
+ /// pair.
+ ///
+ ///
+ /// The to use for the and
+ /// pair.
+ ///
+ /// The to use for the and pair.
+ ///
+ /// The world-to-view transformation matrix to use for the and
+ /// pair.
+ ///
+ ///
+ /// The view-to-projection transformation matrix to use for the and
+ /// pair.
+ ///
+ ///
+ /// cannot be invoked again until has been invoked.
+ ///
+ ///
+ ///
+ /// This method must be called before any enqueuing of draw calls. When all the geometry have been enqueued for
+ /// drawing, call .
+ ///
+ ///
+ public virtual void Begin(Matrix? viewMatrix = null, Matrix? projectionMatrix = null, BlendState blendState = null, SamplerState samplerState = null,
+ DepthStencilState depthStencilState = null, RasterizerState rasterizerState = null, Effect effect = null)
+ {
+ var viewMatrix1 = viewMatrix ?? Matrix.Identity;
+ var projectionMatrix1 = projectionMatrix ?? Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, -1);
+ Begin(ref viewMatrix1, ref projectionMatrix1, blendState, samplerState, depthStencilState, rasterizerState, effect);
+ }
+
+ ///
+ /// Begins the batch operation using an optional , ,
+ /// , , , world-to-view
+ /// , or view-to-projection .
+ ///
+ ///
+ ///
+ /// The default objects for , ,
+ /// , and are
+ /// , ,
+ /// and respectively.
+ /// Passing
+ /// null
for any of the previously mentioned parameters result in using their default object.
+ ///
+ ///
+ /// The to use for the , pair.
+ ///
+ /// The texture to use for the and
+ /// pair.
+ ///
+ ///
+ /// The to use for the and
+ /// pair.
+ ///
+ ///
+ /// The to use for the and
+ /// pair.
+ ///
+ /// The to use for the and pair.
+ ///
+ /// The world-to-view transformation matrix to use for the and
+ /// pair.
+ ///
+ ///
+ /// The view-to-projection transformation matrix to use for the and
+ /// pair.
+ ///
+ ///
+ /// cannot be invoked again until has been invoked.
+ ///
+ ///
+ ///
+ /// This method must be called before any enqueuing of draw calls. When all the geometry have been enqueued for
+ /// drawing, call .
+ ///
+ ///
+ public virtual void Begin(ref Matrix viewMatrix, ref Matrix projectionMatrix, BlendState blendState = null, SamplerState samplerState = null,
+ DepthStencilState depthStencilState = null, RasterizerState rasterizerState = null, Effect effect = null)
+ {
+ EnsureHasNotBegun();
+ HasBegun = true;
+
+ // Store the states to be applied on End()
+ // This ensures that two or more batchers will not affect each other
+ _blendState = blendState ?? BlendState.AlphaBlend;
+ _samplerState = samplerState ?? SamplerState.PointClamp;
+ _depthStencilState = depthStencilState ?? DepthStencilState.None;
+ _rasterizerState = rasterizerState ?? RasterizerState.CullCounterClockwise;
+ _currentEffect = effect ?? _defaultEffect;
+ _projectionMatrix = projectionMatrix;
+ _viewMatrix = viewMatrix;
+ }
+
+ ///
+ /// Flushes the batched geometry to the and restores it's state to how it was before
+ /// was called.
+ ///
+ ///
+ /// cannot be invoked until has been invoked.
+ ///
+ ///
+ ///
+ /// This method must be called after all enqueuing of draw calls.
+ ///
+ ///
+ public void End()
+ {
+ EnsureHasBegun();
+ Flush();
+ HasBegun = false;
+ }
+
+ ///
+ /// Sorts then submits the (sorted) enqueued draw calls to the for
+ /// rendering without ending the and pair.
+ ///
+ protected void Flush()
+ {
+ if (EnqueuedDrawCallCount == 0)
+ return;
+ SortDrawCallsAndBindBuffers();
+ ApplyStates();
+ SubmitDrawCalls();
+ RestoreStates();
+ }
+
+ ///
+ /// Sorts the enqueued draw calls and binds any used or to the .
+ ///
+ protected abstract void SortDrawCallsAndBindBuffers();
+
+ private void ApplyStates()
+ {
+ var oldBlendState = GraphicsDevice.BlendState;
+ var oldSamplerState = GraphicsDevice.SamplerStates[0];
+ var oldDepthStencilState = GraphicsDevice.DepthStencilState;
+ var oldRasterizerState = GraphicsDevice.RasterizerState;
+
+ GraphicsDevice.BlendState = _blendState;
+
+ GraphicsDevice.SamplerStates[0] = _samplerState;
+ GraphicsDevice.DepthStencilState = _depthStencilState;
+ GraphicsDevice.RasterizerState = _rasterizerState;
+
+ _blendState = oldBlendState;
+ _samplerState = oldSamplerState;
+ _depthStencilState = oldDepthStencilState;
+ _rasterizerState = oldRasterizerState;
+
+ var viewMatrix = _viewMatrix ?? Matrix.Identity;
+ var projectionMatrix = _projectionMatrix ??
+ Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width,
+ GraphicsDevice.Viewport.Height, 0, 0f, -1f);
+
+ var matrixChainEffect = _currentEffect as IMatrixChainEffect;
+ if (matrixChainEffect != null)
+ {
+ matrixChainEffect.World = Matrix.Identity;
+ matrixChainEffect.SetView(ref viewMatrix);
+ matrixChainEffect.SetProjection(ref projectionMatrix);
+ }
+ else
+ {
+ var effectMatrices = _currentEffect as IEffectMatrices;
+ if (effectMatrices == null)
+ return;
+ effectMatrices.World = Matrix.Identity;
+ effectMatrices.View = viewMatrix;
+ effectMatrices.Projection = projectionMatrix;
+ }
+ }
+
+ private void RestoreStates()
+ {
+ GraphicsDevice.BlendState = _blendState;
+ GraphicsDevice.SamplerStates[0] = _samplerState;
+ GraphicsDevice.DepthStencilState = _depthStencilState;
+ GraphicsDevice.RasterizerState = _rasterizerState;
+ }
+
+ ///
+ /// Enqueues draw call information.
+ ///
+ /// The draw call information.
+ ///
+ ///
+ /// If possible, the is merged with the last enqueued draw call information instead of
+ /// being
+ /// enqueued.
+ ///
+ ///
+ /// If the enqueue buffer is full, a is invoked and then afterwards
+ /// is enqueued.
+ ///
+ ///
+ protected void Enqueue(ref TDrawCallInfo drawCall)
+ {
+ if (EnqueuedDrawCallCount > 0 && drawCall.TryMerge(ref DrawCalls[EnqueuedDrawCallCount - 1]))
+ return;
+ if (EnqueuedDrawCallCount >= DrawCalls.Length)
+ Flush();
+ DrawCalls[EnqueuedDrawCallCount++] = drawCall;
+ }
+
+ /* It might be better to have derived classes just implement the for loop instead of having this virtual method call...
+ * However, if the derived class is only going to override this method once and the code is short, which should both be
+ * true, then maybe we can get away with this virtual method call by having it inlined. So tell the JIT or AOT compiler
+ * we would like it be so. This does NOT guarantee the compiler will respect our wishes.
+ */
+
+ ///
+ /// Submits a draw operation to the using the specified .
+ ///
+ /// The draw call information.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected abstract void InvokeDrawCall(ref TDrawCallInfo drawCall);
+
+ private void SubmitDrawCalls()
+ {
+ if (EnqueuedDrawCallCount == 0)
+ return;
+
+ for (var i = 0; i < EnqueuedDrawCallCount; i++)
+ {
+ DrawCalls[i].SetState(_currentEffect);
+
+ foreach (var pass in _currentEffect.CurrentTechnique.Passes)
+ {
+ pass.Apply();
+ InvokeDrawCall(ref DrawCalls[i]);
+ }
+ }
+
+ Array.Clear(DrawCalls, 0, EnqueuedDrawCallCount);
+ EnqueuedDrawCallCount = 0;
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Batcher2D.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Batcher2D.cs
new file mode 100644
index 0000000..e7ec533
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Batcher2D.cs
@@ -0,0 +1,450 @@
+using System;
+using System.Text;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.BitmapFonts;
+using MonoGame.Extended.Graphics.Effects;
+using MonoGame.Extended.Graphics.Geometry;
+
+namespace MonoGame.Extended.Graphics
+{
+ ///
+ /// A general purpose for two-dimensional geometry that change
+ /// frequently between frames such as sprites and shapes.
+ ///
+ ///
+ ///
+ /// For drawing user interfaces, consider using instead because it supports scissor rectangles.
+ ///
+ public sealed class Batcher2D : Batcher
+ {
+
+ internal const int DefaultMaximumVerticesCount = 8192;
+ internal const int DefaultMaximumIndicesCount = 12288;
+
+ private readonly VertexBuffer _vertexBuffer;
+ private readonly IndexBuffer _indexBuffer;
+ private readonly VertexPositionColorTexture[] _vertices;
+ private int _vertexCount;
+ private readonly ushort[] _indices;
+ private int _indexCount;
+ private readonly ushort[] _sortedIndices;
+ private readonly GeometryBuilder2D _geometryBuilder;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ ///
+ /// The maximum number of vertices that can be enqueued before a
+ /// is required. The default value is 8192
.
+ ///
+ ///
+ /// The maximum number of indices that can be enqueued before a
+ /// is required. The default value is 12288
.
+ ///
+ ///
+ /// The maximum number of structs that can be enqueued before a
+ /// is required. The default value is 2048
.
+ ///
+ /// .
+ ///
+ /// is less than or equal
+ /// 0
, or is less than or equal to 0
, or,
+ /// is less than or equal to 0
.
+ ///
+ public Batcher2D(GraphicsDevice graphicsDevice,
+ ushort maximumVerticesCount = DefaultMaximumVerticesCount,
+ ushort maximumIndicesCount = DefaultMaximumIndicesCount,
+ int maximumDrawCallsCount = DefaultBatchMaximumDrawCallsCount)
+ : base(
+ graphicsDevice,
+ new DefaultEffect(graphicsDevice)
+ {
+ TextureEnabled = true,
+ VertexColorEnabled = true
+ }, maximumDrawCallsCount)
+
+ {
+ _vertices = new VertexPositionColorTexture[maximumVerticesCount];
+ _vertexBuffer = new DynamicVertexBuffer(graphicsDevice, VertexPositionColorTexture.VertexDeclaration, maximumVerticesCount, BufferUsage.WriteOnly);
+
+ _indices = new ushort[maximumIndicesCount];
+ _sortedIndices = new ushort[maximumIndicesCount];
+ _indexBuffer = new DynamicIndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, maximumIndicesCount, BufferUsage.WriteOnly);
+ _geometryBuilder = new GeometryBuilder2D(4, 6);
+ }
+
+ protected override void SortDrawCallsAndBindBuffers()
+ {
+ // Upload the vertices to the GPU and then select that vertex stream for drawing
+ _vertexBuffer.SetData(_vertices, 0, _vertexCount);
+ GraphicsDevice.SetVertexBuffer(_vertexBuffer);
+
+ Array.Sort(DrawCalls, 0, EnqueuedDrawCallCount);
+ BuildSortedIndices();
+
+ // Upload the indices to the GPU and then select that index stream for drawing
+ _indexBuffer.SetData(_sortedIndices, 0, _indexCount);
+ GraphicsDevice.Indices = _indexBuffer;
+
+ _indexCount = 0;
+ _vertexCount = 0;
+ }
+
+ private void BuildSortedIndices()
+ {
+ var newDrawCallsCount = 0;
+ DrawCalls[0].StartIndex = 0;
+ var currentDrawCall = DrawCalls[0];
+ DrawCalls[newDrawCallsCount++] = DrawCalls[0];
+
+ var drawCallIndexCount = currentDrawCall.PrimitiveCount * 3;
+ Array.Copy(_indices, currentDrawCall.StartIndex, _sortedIndices, 0, drawCallIndexCount);
+ var sortedIndexCount = drawCallIndexCount;
+
+ // iterate through sorted draw calls checking if any can now be merged to reduce expensive draw calls to the graphics API
+ // this might need to be changed for next-gen graphics API (Vulkan, Metal, DirectX 12) where the draw calls are not so expensive
+ for (var i = 1; i < EnqueuedDrawCallCount; i++)
+ {
+ currentDrawCall = DrawCalls[i];
+ drawCallIndexCount = currentDrawCall.PrimitiveCount * 3;
+ Array.Copy(_indices, currentDrawCall.StartIndex, _sortedIndices, sortedIndexCount, drawCallIndexCount);
+ sortedIndexCount += drawCallIndexCount;
+
+ if (currentDrawCall.TryMerge(ref DrawCalls[newDrawCallsCount - 1]))
+ continue;
+
+ currentDrawCall.StartIndex = sortedIndexCount;
+ DrawCalls[newDrawCallsCount++] = currentDrawCall;
+ }
+
+ EnqueuedDrawCallCount = newDrawCallsCount;
+ }
+
+ ///
+ /// Submits a draw operation to the using the specified .
+ ///
+ /// The draw call information.
+ protected override void InvokeDrawCall(ref DrawCallInfo drawCall)
+ {
+ GraphicsDevice.DrawIndexedPrimitives(drawCall.PrimitiveType, 0, drawCall.StartIndex, drawCall.PrimitiveCount);
+ }
+
+ ///
+ /// Draws a sprite using a specified , transform , source
+ /// , and an optional
+ /// , origin , , and depth .
+ ///
+ /// The .
+ /// The transform .
+ ///
+ /// The texture region of the . Use
+ /// null
to use the entire .
+ ///
+ /// The . Use null
to use the default .
+ /// The . The default value is .
+ /// The depth . The default value is 0
.
+ /// The method has not been called.
+ /// is null.
+ public void DrawSprite(Texture2D texture, ref Matrix2 transformMatrix, ref Rectangle sourceRectangle,
+ Color? color = null, FlipFlags flags = FlipFlags.None, float depth = 0)
+ {
+ _geometryBuilder.BuildSprite(_vertexCount, ref transformMatrix, texture, ref sourceRectangle, color, flags, depth);
+ EnqueueBuiltGeometry(texture, depth);
+ }
+
+ ///
+ /// Draws a using the specified transform and an optional
+ /// , origin , , and depth .
+ ///
+ /// The .
+ /// The transform .
+ /// The . Use null
to use the default .
+ /// The . The default value is .
+ /// The depth . The default value is 0
.
+ /// The method has not been called.
+ /// is null.
+ public void DrawTexture(Texture2D texture, ref Matrix2 transformMatrix, Color? color = null,
+ FlipFlags flags = FlipFlags.None, float depth = 0)
+ {
+ var rectangle = default(Rectangle);
+ _geometryBuilder.BuildSprite(_vertexCount, ref transformMatrix, texture, ref rectangle, color, flags, depth);
+ EnqueueBuiltGeometry(texture, depth);
+ }
+
+ private void EnqueueBuiltGeometry(Texture2D texture, float depth)
+ {
+ if ((_vertexCount + _geometryBuilder.VertexCount > _vertices.Length) ||
+ (_indexCount + _geometryBuilder.IndexCount > _indices.Length))
+ Flush();
+ var drawCall = new DrawCallInfo(texture, _geometryBuilder.PrimitiveType, _indexCount,
+ _geometryBuilder.PrimitivesCount, depth);
+ Array.Copy(_geometryBuilder.Vertices, 0, _vertices, _vertexCount, _geometryBuilder.VertexCount);
+ _vertexCount += _geometryBuilder.VertexCount;
+ Array.Copy(_geometryBuilder.Indices, 0, _indices, _indexCount, _geometryBuilder.IndexCount);
+ _indexCount += _geometryBuilder.IndexCount;
+ Enqueue(ref drawCall);
+ }
+
+ ///
+ /// Draws unicode (UTF-16) characters as sprites using the specified , text
+ /// , transform and optional , origin
+ /// , , and depth .
+ ///
+ /// The .
+ /// The text .
+ /// The transform .
+ ///
+ /// The . Use null
to use the default
+ /// .
+ ///
+ /// The . The default value is .
+ /// The depth . The default value is 0f
.
+ /// The method has not been called.
+ /// is null or is null.
+ public void DrawString(BitmapFont bitmapFont, StringBuilder text, ref Matrix2 transformMatrix,
+ Color? color = null, FlipFlags flags = FlipFlags.None, float depth = 0f)
+ {
+ EnsureHasBegun();
+
+ if (bitmapFont == null)
+ throw new ArgumentNullException(nameof(bitmapFont));
+
+ if (text == null)
+ throw new ArgumentNullException(nameof(text));
+
+ var lineSpacing = bitmapFont.LineHeight;
+ var offset = new Vector2(0, 0);
+
+ BitmapFontRegion lastGlyph = null;
+ for (var i = 0; i < text.Length;)
+ {
+ int character;
+ if (char.IsLowSurrogate(text[i]))
+ {
+ character = char.ConvertToUtf32(text[i - 1], text[i]);
+ i += 2;
+ }
+ else if (char.IsHighSurrogate(text[i]))
+ {
+ character = char.ConvertToUtf32(text[i], text[i - 1]);
+ i += 2;
+ }
+ else
+ {
+ character = text[i];
+ i += 1;
+ }
+
+ // ReSharper disable once SwitchStatementMissingSomeCases
+ switch (character)
+ {
+ case '\r':
+ continue;
+ case '\n':
+ offset.X = 0;
+ offset.Y += lineSpacing;
+ lastGlyph = null;
+ continue;
+ }
+
+ var fontRegion = bitmapFont.GetCharacterRegion(character);
+ if (fontRegion == null)
+ continue;
+
+ var transform1Matrix = transformMatrix;
+ transform1Matrix.M31 += offset.X + fontRegion.XOffset;
+ transform1Matrix.M32 += offset.Y + fontRegion.YOffset;
+
+ var textureRegion = fontRegion.TextureRegion;
+ var bounds = textureRegion.Bounds;
+ DrawSprite(textureRegion.Texture, ref transform1Matrix, ref bounds, color, flags, depth);
+
+ var advance = fontRegion.XAdvance + bitmapFont.LetterSpacing;
+ if (BitmapFont.UseKernings && lastGlyph != null)
+ {
+ int amount;
+ if (lastGlyph.Kernings.TryGetValue(character, out amount))
+ {
+ advance += amount;
+ }
+ }
+
+ offset.X += i != text.Length - 1
+ ? advance
+ : fontRegion.XOffset + fontRegion.Width;
+
+ lastGlyph = fontRegion;
+ }
+ }
+
+ ///
+ /// Draws unicode (UTF-16) characters as sprites using the specified , text
+ /// , position and optional , rotation
+ /// , origin , scale , and
+ /// depth .
+ ///
+ /// The .
+ /// The text .
+ /// The position .
+ ///
+ /// The . Use null
to use the default
+ /// .
+ ///
+ ///
+ /// The angle (in radians) to rotate each sprite about its . The default
+ /// value is 0f
.
+ ///
+ ///
+ /// The origin . Use null
to use the default
+ /// .
+ ///
+ ///
+ /// The scale . Use null
to use the default
+ /// .
+ ///
+ /// The . The default value is .
+ /// The depth . The default value is 0f
+ /// The method has not been called.
+ /// is null or is null.
+ public void DrawString(BitmapFont bitmapFont, StringBuilder text, Vector2 position, Color? color = null,
+ float rotation = 0f, Vector2? origin = null, Vector2? scale = null,
+ FlipFlags flags = FlipFlags.None, float depth = 0f)
+ {
+ Matrix2 transformMatrix;
+ Matrix2.CreateFrom(position, rotation, scale, origin, out transformMatrix);
+ DrawString(bitmapFont, text, ref transformMatrix, color, flags, depth);
+ }
+
+ ///
+ /// Draws unicode (UTF-16) characters as sprites using the specified , text
+ /// , transform and optional , origin
+ /// , , and depth .
+ ///
+ /// The .
+ /// The text .
+ /// The transform .
+ ///
+ /// The . Use null
to use the default
+ /// .
+ ///
+ /// The . The default value is .
+ /// The depth . The default value is 0f
+ /// The method has not been called.
+ /// is null or is null.
+ public void DrawString(BitmapFont bitmapFont, string text, ref Matrix2 transformMatrix, Color? color = null,
+ FlipFlags flags = FlipFlags.None, float depth = 0f)
+ {
+ EnsureHasBegun();
+
+ if (bitmapFont == null)
+ throw new ArgumentNullException(nameof(bitmapFont));
+
+ if (text == null)
+ throw new ArgumentNullException(nameof(text));
+
+ var glyphs = bitmapFont.GetGlyphs(text);
+ foreach (var glyph in glyphs)
+ {
+ var transform1Matrix = transformMatrix;
+ transform1Matrix.M31 += glyph.Position.X;
+ transform1Matrix.M32 += glyph.Position.Y;
+
+ var texture = glyph.FontRegion.TextureRegion.Texture;
+ var bounds = texture.Bounds;
+ DrawSprite(texture, ref transform1Matrix, ref bounds, color, flags, depth);
+ }
+ }
+
+ ///
+ /// Draws unicode (UTF-16) characters as sprites using the specified , text
+ /// , position and optional , rotation
+ /// , origin , scale , and
+ /// depth .
+ ///
+ /// The .
+ /// The text .
+ /// The position .
+ ///
+ /// The . Use null
to use the default
+ /// .
+ ///
+ ///
+ /// The angle (in radians) to rotate each sprite about its . The default
+ /// value is 0f
.
+ ///
+ ///
+ /// The origin . Use null
to use the default
+ /// .
+ ///
+ ///
+ /// The scale . Use null
to use the default
+ /// .
+ ///
+ /// The . The default value is .
+ /// The depth . The default value is 0f
+ /// The method has not been called.
+ /// is null or is null.
+ public void DrawString(BitmapFont bitmapFont, string text, Vector2 position, Color? color = null,
+ float rotation = 0f, Vector2? origin = null, Vector2? scale = null,
+ FlipFlags flags = FlipFlags.None, float depth = 0f)
+ {
+ Matrix2 matrix;
+ Matrix2.CreateFrom(position, rotation, scale, origin, out matrix);
+ DrawString(bitmapFont, text, ref matrix, color, flags, depth);
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public struct DrawCallInfo : IBatchDrawCallInfo, IComparable
+ {
+ internal readonly PrimitiveType PrimitiveType;
+ internal int StartIndex;
+ internal int PrimitiveCount;
+ internal readonly Texture2D Texture;
+ internal readonly uint TextureKey;
+ internal readonly uint DepthKey;
+
+ internal unsafe DrawCallInfo(Texture2D texture, PrimitiveType primitiveType, int startIndex, int primitiveCount, float depth)
+ {
+ PrimitiveType = primitiveType;
+ StartIndex = startIndex;
+ PrimitiveCount = primitiveCount;
+ Texture = texture;
+ TextureKey = (uint)RuntimeHelpers.GetHashCode(texture);
+ DepthKey = *(uint*)&depth;
+ }
+
+ public void SetState(Effect effect)
+ {
+ var textureEffect = effect as ITextureEffect;
+ if (textureEffect != null)
+ textureEffect.Texture = Texture;
+ }
+
+ public bool TryMerge(ref DrawCallInfo drawCall)
+ {
+ if (PrimitiveType != drawCall.PrimitiveType || TextureKey != drawCall.TextureKey ||
+ DepthKey != drawCall.DepthKey)
+ return false;
+ drawCall.PrimitiveCount += PrimitiveCount;
+ return true;
+ }
+
+ [SuppressMessage("ReSharper", "ImpureMethodCallOnReadonlyValueField")]
+ public int CompareTo(DrawCallInfo other)
+ {
+ var result = TextureKey.CompareTo(other.TextureKey);;
+ if (result != 0)
+ return result;
+ result = DepthKey.CompareTo(other.DepthKey);
+ return result != 0 ? result : ((byte)PrimitiveType).CompareTo((byte)other.PrimitiveType);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/DefaultEffect.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/DefaultEffect.cs
new file mode 100644
index 0000000..df71e47
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/DefaultEffect.cs
@@ -0,0 +1,203 @@
+using System.Collections.Specialized;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics.Effects
+{
+ ///
+ /// An that allows objects, within a 3D context, to be represented on a 2D monitor.
+ ///
+ ///
+ ///
+ public class DefaultEffect : MatrixChainEffect, ITextureEffect
+ {
+ ///
+ /// The bitmask for use with indicating wether has
+ /// changed in the last frame.
+ ///
+ protected static int DirtyTextureBitMask = BitVector32.CreateMask(UseDefaultProjectionBitMask);
+
+ ///
+ /// The bitmask for use with indicating wether the underlying vertex shader and
+ /// fragment (pixel) shaders have changed to one of the pre-defined shaders in the last frame.
+ ///
+ protected static int DirtyShaderIndexBitMask = BitVector32.CreateMask(DirtyTextureBitMask);
+
+ ///
+ /// The bitmask for use with indicating wether the material color has changed in
+ /// the last frame.
+ ///
+ public static int DirtyMaterialColorBitMask = BitVector32.CreateMask(DirtyShaderIndexBitMask);
+
+ private Texture2D _texture;
+ private EffectParameter _textureParameter;
+
+ private float _alpha = 1;
+ private Color _diffuseColor = Color.White;
+ private EffectParameter _diffuseColorParameter;
+
+ private bool _textureEnabled;
+ private bool _vertexColorEnabled;
+
+ ///
+ /// Gets or sets the material .
+ ///
+ ///
+ /// The material .
+ ///
+ public Texture2D Texture
+ {
+ get { return _texture; }
+ set
+ {
+ _texture = value;
+ Flags[DirtyTextureBitMask] = true;
+ }
+ }
+
+ ///
+ /// Gets or sets the material color alpha.
+ ///
+ ///
+ ///
+ /// The alpha channel uses the premultiplied (associated) representation. This means that the RGB components of a
+ /// color represent
+ /// the color of the object of pixel, adjusted for its opacity by multiplication of .
+ ///
+ ///
+ public float Alpha
+ {
+ get { return _alpha; }
+
+ set
+ {
+ _alpha = value;
+ Flags[DirtyMaterialColorBitMask] = true;
+ }
+ }
+
+ ///
+ /// Gets or sets whether texturing is enabled.
+ ///
+ public bool TextureEnabled
+ {
+ get { return _textureEnabled; }
+
+ set
+ {
+ if (_textureEnabled == value)
+ return;
+ _textureEnabled = value;
+ Flags[DirtyShaderIndexBitMask] = true;
+ }
+ }
+
+ ///
+ /// Gets or sets whether vertex color is enabled.
+ ///
+ public bool VertexColorEnabled
+ {
+ get { return _vertexColorEnabled; }
+
+ set
+ {
+ if (_vertexColorEnabled == value)
+ return;
+ _vertexColorEnabled = value;
+ Flags[DirtyShaderIndexBitMask] = true;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ public DefaultEffect(GraphicsDevice graphicsDevice)
+ : base(graphicsDevice, EffectResource.DefaultEffect.Bytecode)
+ {
+ Initialize();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ /// The byte code of the shader program.
+ public DefaultEffect(GraphicsDevice graphicsDevice, byte[] byteCode)
+ : base(graphicsDevice, byteCode)
+ {
+ Initialize();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The clone source.
+ public DefaultEffect(Effect cloneSource)
+ : base(cloneSource)
+ {
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ Flags[DirtyMaterialColorBitMask] = true;
+ _textureParameter = Parameters["Texture"];
+ _diffuseColorParameter = Parameters["DiffuseColor"];
+ }
+
+ ///
+ /// Computes derived parameter values immediately before applying the effect.
+ ///
+ protected override void OnApply()
+ {
+ base.OnApply();
+
+ if (Flags[DirtyTextureBitMask])
+ {
+ _textureParameter.SetValue(_texture);
+ Flags[DirtyTextureBitMask] = false;
+ }
+
+ // ReSharper disable once InvertIf
+ if (Flags[DirtyMaterialColorBitMask])
+ {
+ UpdateMaterialColor();
+ Flags[DirtyMaterialColorBitMask] = false;
+ }
+
+ // ReSharper disable once InvertIf
+ if (Flags[DirtyShaderIndexBitMask])
+ {
+ var shaderIndex = 0;
+
+ if (_textureEnabled)
+ shaderIndex += 1;
+
+ if (_vertexColorEnabled)
+ shaderIndex += 2;
+
+ Flags[DirtyShaderIndexBitMask] = false;
+ CurrentTechnique = Techniques[shaderIndex];
+ }
+ }
+
+ ///
+ /// Updates the material color parameters associated with this .
+ ///
+ protected virtual void UpdateMaterialColor()
+ {
+ var diffuseColorVector3 = _diffuseColor.ToVector3();
+
+ var diffuseColorVector4 = new Vector4()
+ {
+ X = diffuseColorVector3.X * Alpha,
+ Y = diffuseColorVector3.Y * Alpha,
+ Z = diffuseColorVector3.Z * Alpha,
+ W = Alpha,
+ };
+
+ _diffuseColorParameter.SetValue(diffuseColorVector4);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/EffectResource.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/EffectResource.cs
new file mode 100644
index 0000000..43bd535
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/EffectResource.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics.Effects
+{
+ ///
+ /// Reperesents the bytecode of an that is encapsulated inside a compiled assembly.
+ ///
+ ///
+ ///
+ /// Files that are encapsulated inside a compiled assembly are commonly known as Manifiest or embedded resources.
+ /// Since embedded resources are added to the assembly at compiled time, they can not be accidentally deleted or
+ /// misplaced. However, if the file needs to be changed, the assembly will need to be re-compiled with the changed
+ /// file.
+ ///
+ ///
+ /// To add an embedded resource file to an assembly, first add it to the project and then change the Build Action
+ /// in the Properties of the file to Embedded Resource
. The next time the project is compiled, the
+ /// compiler will add the file to the assembly as an embedded resource. The compiler adds namespace(s) to the
+ /// embedded resource so it matches with the path of where the file was added to the project.
+ ///
+ ///
+ public class EffectResource
+ {
+ private static EffectResource _defaultEffect;
+ private static string _shaderExtension;
+
+ ///
+ /// Gets the embedded into the MonoGame.Extended.Graphics library.
+ ///
+ public static EffectResource DefaultEffect => _defaultEffect ?? (_defaultEffect = new EffectResource($"MonoGame.Extended.Graphics.Effects.Resources.DefaultEffect.{_shaderExtension}.mgfxo"));
+
+ static EffectResource()
+ {
+ DetermineShaderExtension();
+ }
+
+ private static void DetermineShaderExtension()
+ {
+ // use reflection to figure out if Shader.Profile is OpenGL (0) or DirectX (1),
+ // may need to be changed / fixed for future shader profiles
+
+ var assembly = typeof(Game).GetTypeInfo().Assembly;
+ Debug.Assert(assembly != null);
+
+ var shaderType = assembly.GetType("Microsoft.Xna.Framework.Graphics.Shader");
+ Debug.Assert(shaderType != null);
+ var shaderTypeInfo = shaderType.GetTypeInfo();
+ Debug.Assert(shaderTypeInfo != null);
+
+ // https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/Graphics/Shader/Shader.cs#L47
+ var profileProperty = shaderTypeInfo.GetDeclaredProperty("Profile");
+ var value = (int)profileProperty.GetValue(null);
+
+ switch (value)
+ {
+ case 0:
+ // OpenGL
+ _shaderExtension = "ogl";
+ break;
+ case 1:
+ // DirectX
+ _shaderExtension = "dx11";
+ break;
+ default:
+ throw new InvalidOperationException("Unknown shader profile.");
+ }
+ }
+
+ private readonly string _resourceName;
+ private volatile byte[] _bytecode;
+ private readonly Assembly _assembly;
+
+ ///
+ /// Gets the bytecode of the file.
+ ///
+ ///
+ /// The bytecode of the file.
+ ///
+ public byte[] Bytecode
+ {
+ get
+ {
+ if (_bytecode != null)
+ return _bytecode;
+
+ lock (this)
+ {
+ if (_bytecode != null)
+ return _bytecode;
+
+ var stream = _assembly.GetManifestResourceStream(_resourceName);
+ using (var memoryStream = new MemoryStream())
+ {
+ stream.CopyTo(memoryStream);
+ _bytecode = memoryStream.ToArray();
+ }
+ }
+
+ return _bytecode;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the embedded resource. This must include the namespace(s).
+ /// The assembly which the embedded resource is apart of.
+ public EffectResource(string resourceName, Assembly assembly = null)
+ {
+ _resourceName = resourceName;
+ _assembly = assembly ?? typeof(EffectResource).GetTypeInfo().Assembly;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/ITextureEffect.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/ITextureEffect.cs
new file mode 100644
index 0000000..ea2ef0b
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/ITextureEffect.cs
@@ -0,0 +1,18 @@
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics.Effects
+{
+ ///
+ /// Defines an that uses a .
+ ///
+ public interface ITextureEffect
+ {
+ ///
+ /// Gets or sets the .
+ ///
+ ///
+ /// The .
+ ///
+ Texture2D Texture { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/MatrixChainEffect.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/MatrixChainEffect.cs
new file mode 100644
index 0000000..046479f
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/MatrixChainEffect.cs
@@ -0,0 +1,155 @@
+using System.Collections.Specialized;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics.Effects
+{
+ ///
+ /// An that uses the standard chain of matrix transformations to represent a 3D object on a 2D
+ /// monitor.
+ ///
+ ///
+ ///
+ public abstract class MatrixChainEffect : Effect, IMatrixChainEffect
+ {
+ ///
+ /// The bitmask for use with indicating wether , , or has changed in the last frame.
+ ///
+ protected static int DirtyWorldViewProjectionBitMask = BitVector32.CreateMask();
+
+ ///
+ /// The bitmask for use with indicating wether to use a default projection matrix or a custom projection matrix.
+ ///
+ protected static int UseDefaultProjectionBitMask = BitVector32.CreateMask(DirtyWorldViewProjectionBitMask);
+
+ ///
+ /// The dirty flags associated with this .
+ ///
+ protected BitVector32 Flags;
+
+ private Matrix _projection = Matrix.Identity;
+ private Matrix _view = Matrix.Identity;
+ private Matrix _world = Matrix.Identity;
+ private EffectParameter _matrixParameter;
+
+ ///
+ /// Gets or sets the model-to-world .
+ ///
+ ///
+ /// The model-to-world .
+ ///
+ public Matrix World
+ {
+ get { return _world; }
+ set { SetWorld(ref value); }
+ }
+
+ ///
+ /// Gets or sets the world-to-view .
+ ///
+ ///
+ /// The world-to-view .
+ ///
+ public Matrix View
+ {
+ get { return _view; }
+ set { SetView(ref value); }
+ }
+
+ ///
+ /// Gets or sets the view-to-projection .
+ ///
+ ///
+ /// The view-to-projection .
+ ///
+ public Matrix Projection
+ {
+ get { return _projection; }
+ set { SetProjection(ref value); }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ /// The effect code.
+ protected MatrixChainEffect(GraphicsDevice graphicsDevice, byte[] byteCode)
+ : base(graphicsDevice, byteCode)
+ {
+ Initialize();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The clone source.
+ protected MatrixChainEffect(Effect cloneSource)
+ : base(cloneSource)
+ {
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ Flags[UseDefaultProjectionBitMask] = true;
+
+ _matrixParameter = Parameters["WorldViewProjection"];
+ }
+
+ ///
+ /// Sets the model-to-world .
+ ///
+ /// The model-to-world .
+ public void SetWorld(ref Matrix world)
+ {
+ _world = world;
+ Flags[DirtyWorldViewProjectionBitMask] = true;
+ }
+
+ ///
+ /// Sets the world-to-view .
+ ///
+ /// The world-to-view .
+ public void SetView(ref Matrix view)
+ {
+ _view = view;
+ Flags[DirtyWorldViewProjectionBitMask] = true;
+ }
+
+ ///
+ /// Sets the view-to-projection .
+ ///
+ /// The view-to-projection .
+ public void SetProjection(ref Matrix projection)
+ {
+ _projection = projection;
+ Flags[DirtyWorldViewProjectionBitMask] = true;
+ Flags[UseDefaultProjectionBitMask] = false;
+ }
+
+ ///
+ /// Computes derived parameter values immediately before applying the effect.
+ ///
+ protected override void OnApply()
+ {
+ base.OnApply();
+
+ // ReSharper disable once InvertIf
+ if (Flags[DirtyWorldViewProjectionBitMask] || Flags[UseDefaultProjectionBitMask])
+ {
+ if (Flags[UseDefaultProjectionBitMask])
+ {
+ var viewport = GraphicsDevice.Viewport;
+ _projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, -1);
+ }
+
+ Matrix worldViewProjection;
+ Matrix.Multiply(ref _world, ref _view, out worldViewProjection);
+ Matrix.Multiply(ref worldViewProjection, ref _projection, out worldViewProjection);
+ _matrixParameter.SetValue(worldViewProjection);
+
+ Flags[DirtyWorldViewProjectionBitMask] = false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.dx11.mgfxo b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.dx11.mgfxo
new file mode 100644
index 0000000..b83b6ed
Binary files /dev/null and b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.dx11.mgfxo differ
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.fx b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.fx
new file mode 100644
index 0000000..30a772d
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.fx
@@ -0,0 +1,72 @@
+#include "Macros.fxh"
+#include "Structures.fxh"
+
+DECLARE_TEXTURE(Texture, 0);
+
+BEGIN_CONSTANTS
+
+float4 DiffuseColor = float4(1, 1, 1, 1);
+
+MATRIX_CONSTANTS
+
+float4x4 WorldViewProjection _vs(c0) _cb(c0);
+
+END_CONSTANTS
+
+VertexShaderOutputPosition VertexShaderFunctionPosition(VertexShaderInputPosition input)
+{
+ VertexShaderOutputPosition output;
+ output.Position = mul(input.Position, WorldViewProjection);
+ return output;
+}
+
+float4 PixelShaderFunctionPosition(VertexShaderOutputPosition input) : SV_Target0
+{
+ return DiffuseColor;
+}
+
+VertexShaderOutputPositionTexture VertexShaderFunctionPositionTexture(VertexShaderInputPositionTexture input)
+{
+ VertexShaderOutputPositionTexture output;
+ output.Position = mul(input.Position, WorldViewProjection);
+ output.TextureCoordinate = input.TextureCoordinate;
+ return output;
+}
+
+float4 PixelShaderFunctionPositionTexture(VertexShaderOutputPositionTexture input) : SV_Target0
+{
+ return SAMPLE_TEXTURE(Texture, input.TextureCoordinate) * DiffuseColor;
+}
+
+VertexShaderOutputPositionColor VertexShaderFunctionPositionColor(VertexShaderInputPositionColor input)
+{
+ VertexShaderOutputPositionColor output;
+ output.Position = mul(input.Position, WorldViewProjection);
+ output.Color = input.Color;
+ return output;
+}
+
+float4 PixelShaderFunctionPositionColor(VertexShaderOutputPositionColor input) : SV_Target0
+{
+ return input.Color * DiffuseColor;
+}
+
+VertexShaderOutputPositionColorTexture VertexShaderFunctionPositionColorTexture(VertexShaderInputPositionColorTexture input)
+{
+ VertexShaderOutputPositionColorTexture output;
+ output.Position = mul(input.Position, WorldViewProjection);
+ output.Color = input.Color;
+ output.TextureCoordinate = input.TextureCoordinate;
+ return output;
+}
+
+float4 PixelShaderFunctionPositionColorTexture(VertexShaderOutputPositionColorTexture input) : SV_Target0
+{
+ float4 textureColor = SAMPLE_TEXTURE(Texture, input.TextureCoordinate);
+ return textureColor * input.Color * DiffuseColor;
+}
+
+TECHNIQUE(Position, VertexShaderFunctionPosition, PixelShaderFunctionPosition);
+TECHNIQUE(PositionTexture, VertexShaderFunctionPositionTexture, PixelShaderFunctionPositionTexture);
+TECHNIQUE(PositionColor, VertexShaderFunctionPositionColor, PixelShaderFunctionPositionColor);
+TECHNIQUE(PositionColorTexture, VertexShaderFunctionPositionColorTexture, PixelShaderFunctionPositionColorTexture);
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.ogl.mgfxo b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.ogl.mgfxo
new file mode 100644
index 0000000..4f51d2a
Binary files /dev/null and b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/DefaultEffect.ogl.mgfxo differ
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/Macros.fxh b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/Macros.fxh
new file mode 100644
index 0000000..c253efe
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/Macros.fxh
@@ -0,0 +1,60 @@
+//-----------------------------------------------------------------------------
+// Macros.fxh
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+#if SM4
+
+// Macros for targetting shader model 4.0 (DX11)
+
+#define TECHNIQUE(name, vsname, psname ) \
+ technique name { pass { VertexShader = compile vs_4_0_level_9_1 vsname (); PixelShader = compile ps_4_0_level_9_1 psname(); } }
+
+#define BEGIN_CONSTANTS cbuffer Parameters : register(b0) {
+#define MATRIX_CONSTANTS
+#define END_CONSTANTS };
+
+#define _vs(r)
+#define _ps(r)
+#define _cb(r)
+
+#define DECLARE_TEXTURE(Name, index) \
+ Texture2D Name : register(t##index); \
+ sampler Name##Sampler : register(s##index)
+
+#define DECLARE_CUBEMAP(Name, index) \
+ TextureCube Name : register(t##index); \
+ sampler Name##Sampler : register(s##index)
+
+#define SAMPLE_TEXTURE(Name, texCoord) Name.Sample(Name##Sampler, texCoord)
+#define SAMPLE_CUBEMAP(Name, texCoord) Name.Sample(Name##Sampler, texCoord)
+
+
+#else
+
+// Macros for targetting shader model 2.0 (DX9)
+
+#define TECHNIQUE(name, vsname, psname ) \
+ technique name { pass { VertexShader = compile vs_2_0 vsname (); PixelShader = compile ps_2_0 psname(); } }
+
+#define BEGIN_CONSTANTS
+#define MATRIX_CONSTANTS
+#define END_CONSTANTS
+
+#define _vs(r) : register(vs, r)
+#define _ps(r) : register(ps, r)
+#define _cb(r)
+
+#define DECLARE_TEXTURE(Name, index) \
+ sampler2D Name : register(s##index);
+
+#define DECLARE_CUBEMAP(Name, index) \
+ samplerCUBE Name : register(s##index);
+
+#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name, texCoord)
+#define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name, texCoord)
+
+
+#endif
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/RebuildEffects.bat b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/RebuildEffects.bat
new file mode 100644
index 0000000..4fc7f21
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/RebuildEffects.bat
@@ -0,0 +1,15 @@
+setlocal
+
+SET TWOMGFX="mgfxc"
+
+@for /f %%f IN ('dir /b *.fx') do (
+
+ call %TWOMGFX% %%~nf.fx %%~nf.ogl.mgfxo /Profile:OpenGL
+
+ call %TWOMGFX% %%~nf.fx %%~nf.dx11.mgfxo /Profile:DirectX_11
+
+)
+
+endlocal
+
+pause
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/Structures.fxh b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/Structures.fxh
new file mode 100644
index 0000000..d3af6a0
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Effects/Resources/Structures.fxh
@@ -0,0 +1,51 @@
+// Vertex shader input structures.
+
+struct VertexShaderInputPosition
+{
+ float4 Position : SV_Position;
+};
+
+struct VertexShaderInputPositionColor
+{
+ float4 Position : SV_Position;
+ float4 Color : COLOR;
+};
+
+struct VertexShaderInputPositionTexture
+{
+ float4 Position : SV_Position;
+ float2 TextureCoordinate : TEXCOORD0;
+};
+
+struct VertexShaderInputPositionColorTexture
+{
+ float4 Position : SV_Position;
+ float4 Color : COLOR;
+ float2 TextureCoordinate : TEXCOORD0;
+};
+
+// Vertex shader output structures.
+
+struct VertexShaderOutputPosition
+{
+ float4 Position : SV_Position;
+};
+
+struct VertexShaderOutputPositionColor
+{
+ float4 Position : SV_Position;
+ float4 Color : COLOR0;
+};
+
+struct VertexShaderOutputPositionTexture
+{
+ float4 Position : SV_Position;
+ float2 TextureCoordinate : TEXCOORD0;
+};
+
+struct VertexShaderOutputPositionColorTexture
+{
+ float4 Position : SV_Position;
+ float4 Color : COLOR0;
+ float2 TextureCoordinate : TEXCOORD0;
+};
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/FlipFlags.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/FlipFlags.cs
new file mode 100644
index 0000000..6c19887
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/FlipFlags.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace MonoGame.Extended.Graphics
+{
+ [Flags]
+ public enum FlipFlags : byte
+ {
+ None = 0,
+ FlipDiagonally = 1 << 0,
+ FlipVertically = 1 << 1,
+ FlipHorizontally = 1 << 2
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder.cs
new file mode 100644
index 0000000..dad4f15
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder.cs
@@ -0,0 +1,24 @@
+using System;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics.Geometry
+{
+ public abstract class GeometryBuilder
+ where TVertexType : struct, IVertexType
+ where TIndexType : struct
+ {
+ public PrimitiveType PrimitiveType { get; protected set; }
+ public int VertexCount { get; protected set; }
+ public int IndexCount { get; protected set; }
+ public int PrimitivesCount { get; protected set; }
+
+ public TVertexType[] Vertices { get; }
+ public TIndexType[] Indices { get; }
+
+ protected GeometryBuilder(int maximumVerticesCount, int maximumIndicesCount)
+ {
+ Vertices = new TVertexType[maximumVerticesCount];
+ Indices = new TIndexType[maximumIndicesCount];
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder2D.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder2D.cs
new file mode 100644
index 0000000..c113fbe
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder2D.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Runtime.CompilerServices;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics.Geometry
+{
+ public class GeometryBuilder2D : GeometryBuilder
+ {
+ public GeometryBuilder2D(int maximumVerticesCount, int maximumIndicesCount)
+ : base(maximumVerticesCount, maximumIndicesCount)
+ {
+ }
+
+ public void BuildSprite(int indexOffset, ref Matrix2 transformMatrix, Texture2D texture,
+ ref Rectangle sourceRectangle,
+ Color? color = null, FlipFlags flags = FlipFlags.None, float depth = 0)
+ {
+ if (texture == null)
+ throw new ArgumentNullException(nameof(texture));
+
+ var texelLeft = 0f;
+ var texelTop = 0f;
+ var texelRight = 1f;
+ var texelBottom = 1f;
+
+ if (sourceRectangle.Width > 0)
+ {
+ texelLeft = (float)sourceRectangle.X / texture.Width;
+ texelTop = (float)sourceRectangle.Y / texture.Height;
+ texelRight = (sourceRectangle.X + sourceRectangle.Width) / (float)texture.Width;
+ texelBottom = (sourceRectangle.Y + sourceRectangle.Height) / (float)texture.Height;
+ }
+ else
+ {
+ sourceRectangle.Width = texture.Width;
+ sourceRectangle.Height = texture.Height;
+ }
+
+ var color1 = color ?? Color.White;
+
+ var vertices = Vertices;
+
+ transformMatrix.Transform(0, 0, ref vertices[0].Position);
+ vertices[0].Position.Z = depth;
+ vertices[0].Color = color1;
+ vertices[0].TextureCoordinate.X = texelLeft;
+ vertices[0].TextureCoordinate.Y = texelTop;
+
+ transformMatrix.Transform(sourceRectangle.Width, 0, ref vertices[1].Position);
+ vertices[1].Position.Z = depth;
+ vertices[1].Color = color1;
+ vertices[1].TextureCoordinate.X = texelRight;
+ vertices[1].TextureCoordinate.Y = texelTop;
+
+ transformMatrix.Transform(0, sourceRectangle.Height, ref vertices[2].Position);
+ vertices[2].Position.Z = depth;
+ vertices[2].Color = color1;
+ vertices[2].TextureCoordinate.X = texelLeft;
+ vertices[2].TextureCoordinate.Y = texelBottom;
+
+ transformMatrix.Transform(sourceRectangle.Width, sourceRectangle.Height, ref vertices[3].Position);
+ vertices[3].Position.Z = depth;
+ vertices[3].Color = color1;
+ vertices[3].TextureCoordinate.X = texelRight;
+ vertices[3].TextureCoordinate.Y = texelBottom;
+
+ var flipDiagonally = (flags & FlipFlags.FlipDiagonally) != 0;
+ var flipHorizontally = (flags & FlipFlags.FlipHorizontally) != 0;
+ var flipVertically = (flags & FlipFlags.FlipVertically) != 0;
+
+ if (flipDiagonally)
+ {
+ FloatHelper.Swap(ref vertices[1].TextureCoordinate.X, ref vertices[2].TextureCoordinate.X);
+ FloatHelper.Swap(ref vertices[1].TextureCoordinate.Y, ref vertices[2].TextureCoordinate.Y);
+ }
+
+ if (flipHorizontally)
+ if (flipDiagonally)
+ {
+ FloatHelper.Swap(ref vertices[0].TextureCoordinate.Y, ref vertices[1].TextureCoordinate.Y);
+ FloatHelper.Swap(ref vertices[2].TextureCoordinate.Y, ref vertices[3].TextureCoordinate.Y);
+ }
+ else
+ {
+ FloatHelper.Swap(ref vertices[0].TextureCoordinate.X, ref vertices[1].TextureCoordinate.X);
+ FloatHelper.Swap(ref vertices[2].TextureCoordinate.X, ref vertices[3].TextureCoordinate.X);
+ }
+
+ if (flipVertically)
+ if (flipDiagonally)
+ {
+ FloatHelper.Swap(ref vertices[0].TextureCoordinate.X, ref vertices[2].TextureCoordinate.X);
+ FloatHelper.Swap(ref vertices[1].TextureCoordinate.X, ref vertices[3].TextureCoordinate.X);
+ }
+ else
+ {
+ FloatHelper.Swap(ref vertices[0].TextureCoordinate.Y, ref vertices[2].TextureCoordinate.Y);
+ FloatHelper.Swap(ref vertices[1].TextureCoordinate.Y, ref vertices[3].TextureCoordinate.Y);
+ }
+
+ VertexCount = 4;
+ AddQuadrilateralIndices(indexOffset);
+ IndexCount = 6;
+ PrimitivesCount = 2;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void AddQuadrilateralIndices(int indexOffset)
+ {
+ Indices[0] = (ushort)(0 + indexOffset);
+ Indices[1] = (ushort)(1 + indexOffset);
+ Indices[2] = (ushort)(2 + indexOffset);
+ Indices[3] = (ushort)(1 + indexOffset);
+ Indices[4] = (ushort)(3 + indexOffset);
+ Indices[5] = (ushort)(2 + indexOffset);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/IBatchDrawCallInfo.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/IBatchDrawCallInfo.cs
new file mode 100644
index 0000000..67c4755
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/IBatchDrawCallInfo.cs
@@ -0,0 +1,19 @@
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics
+{
+ ///
+ /// Defines the for a deferred draw call when batching.
+ ///
+ public interface IBatchDrawCallInfo where TDrawCallInfo : IBatchDrawCallInfo
+ {
+ ///
+ /// Applies any state from the to the
+ /// or .
+ ///
+ /// The effect.
+ void SetState(Effect effect);
+
+ bool TryMerge(ref TDrawCallInfo drawCall);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/IMatrixChainEffect.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/IMatrixChainEffect.cs
new file mode 100644
index 0000000..da8ccb9
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/IMatrixChainEffect.cs
@@ -0,0 +1,30 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics
+{
+ ///
+ /// Defines an that uses the standard chain of matrix transformations to represent a 3D object on
+ /// a 2D monitor.
+ ///
+ public interface IMatrixChainEffect : IEffectMatrices
+ {
+ ///
+ /// Sets the model-to-world .
+ ///
+ /// The model-to-world .
+ void SetWorld(ref Matrix world);
+
+ ///
+ /// Sets the world-to-view .
+ ///
+ /// The world-to-view .
+ void SetView(ref Matrix view);
+
+ ///
+ /// Sets the view-to-projection .
+ ///
+ /// The view-to-projection .
+ void SetProjection(ref Matrix projection);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/MonoGame.Extended.Graphics.csproj b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/MonoGame.Extended.Graphics.csproj
new file mode 100644
index 0000000..fd25850
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/MonoGame.Extended.Graphics.csproj
@@ -0,0 +1,28 @@
+
+
+
+ Graphics makes MonoGame more awesome.
+ monogame graphics batcher effects
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/PrimitiveTypeExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/PrimitiveTypeExtensions.cs
new file mode 100644
index 0000000..68a39ef
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/PrimitiveTypeExtensions.cs
@@ -0,0 +1,42 @@
+using System;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics
+{
+ public static class PrimitiveTypeExtensions
+ {
+ internal static int GetPrimitivesCount(this PrimitiveType primitiveType, int verticesCount)
+ {
+ switch (primitiveType)
+ {
+ case PrimitiveType.LineStrip:
+ return verticesCount - 1;
+ case PrimitiveType.LineList:
+ return verticesCount/2;
+ case PrimitiveType.TriangleStrip:
+ return verticesCount - 2;
+ case PrimitiveType.TriangleList:
+ return verticesCount/3;
+ default:
+ throw new ArgumentException("Invalid primitive type.");
+ }
+ }
+
+ internal static int GetVerticesCount(this PrimitiveType primitiveType, int primitivesCount)
+ {
+ switch (primitiveType)
+ {
+ case PrimitiveType.LineStrip:
+ return primitivesCount + 1;
+ case PrimitiveType.LineList:
+ return primitivesCount*2;
+ case PrimitiveType.TriangleStrip:
+ return primitivesCount + 2;
+ case PrimitiveType.TriangleList:
+ return primitivesCount*3;
+ default:
+ throw new ArgumentException("Invalid primitive type.");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/RenderTarget2DExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/RenderTarget2DExtensions.cs
new file mode 100644
index 0000000..f090603
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Graphics/RenderTarget2DExtensions.cs
@@ -0,0 +1,41 @@
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MonoGame.Extended.Graphics
+{
+ public static class RenderTarget2DExtensions
+ {
+ public static IDisposable BeginDraw(this RenderTarget2D renderTarget, GraphicsDevice graphicsDevice,
+ Color backgroundColor)
+ {
+ return new RenderTargetOperation(renderTarget, graphicsDevice, backgroundColor);
+ }
+
+ private class RenderTargetOperation : IDisposable
+ {
+ private readonly GraphicsDevice _graphicsDevice;
+ private readonly RenderTargetUsage _previousRenderTargetUsage;
+ private readonly Viewport _viewport;
+
+ public RenderTargetOperation(RenderTarget2D renderTarget, GraphicsDevice graphicsDevice,
+ Color backgroundColor)
+ {
+ _graphicsDevice = graphicsDevice;
+ _viewport = _graphicsDevice.Viewport;
+ _previousRenderTargetUsage = _graphicsDevice.PresentationParameters.RenderTargetUsage;
+
+ _graphicsDevice.PresentationParameters.RenderTargetUsage = RenderTargetUsage.PreserveContents;
+ _graphicsDevice.SetRenderTarget(renderTarget);
+ _graphicsDevice.Clear(backgroundColor);
+ }
+
+ public void Dispose()
+ {
+ _graphicsDevice.SetRenderTarget(null);
+ _graphicsDevice.PresentationParameters.RenderTargetUsage = _previousRenderTargetUsage;
+ _graphicsDevice.Viewport = _viewport;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/ControlStyle.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/ControlStyle.cs
new file mode 100644
index 0000000..1593da3
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/ControlStyle.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using MonoGame.Extended.Gui.Controls;
+
+namespace MonoGame.Extended.Gui
+{
+ public class ControlStyle : IDictionary
+ {
+ private readonly Dictionary> _previousStates = new Dictionary>();
+
+ public ControlStyle()
+ : this(typeof(Element))
+ {
+ }
+
+ public ControlStyle(Type targetType)
+ : this(targetType.FullName, targetType)
+ {
+ }
+
+ public ControlStyle(string name, Type targetType)
+ {
+ Name = name;
+ TargetType = targetType;
+ _setters = new Dictionary();
+ }
+
+ public string Name { get; }
+ public Type TargetType { get; set; }
+
+ private readonly Dictionary _setters;
+
+ public void ApplyIf(Control control, bool predicate)
+ {
+ if (predicate)
+ Apply(control);
+ else
+ Revert(control);
+ }
+
+ public void Apply(Control control)
+ {
+ _previousStates[control.Id] = _setters
+ .ToDictionary(i => i.Key, i => TargetType.GetRuntimeProperty(i.Key)?.GetValue(control));
+
+ ChangePropertyValues(control, _setters);
+ }
+
+ public void Revert(Control control)
+ {
+ if (_previousStates.ContainsKey(control.Id) && _previousStates[control.Id] != null)
+ ChangePropertyValues(control, _previousStates[control.Id]);
+
+ _previousStates[control.Id] = null;
+ }
+
+ private static void ChangePropertyValues(Control control, Dictionary setters)
+ {
+ var targetType = control.GetType();
+
+ foreach (var propertyName in setters.Keys)
+ {
+ var propertyInfo = targetType.GetRuntimeProperty(propertyName);
+ var value = setters[propertyName];
+
+ if (propertyInfo != null)
+ {
+ if(propertyInfo.CanWrite)
+ propertyInfo.SetValue(control, value);
+
+ // special case when we have a list of items as objects (like on a list box)
+ if (propertyInfo.PropertyType == typeof(List