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
---
.../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 +
423 files changed, 31527 insertions(+)
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
(limited to 'Plugins/MonoGame.Extended/source')
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