diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ddb8b56
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+bin/
+obj/
+*.pidb
+*.userprefs
+*.suo
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..8ef8fe6
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,15 @@
+[submodule "lib/SDL2-CS"]
+ path = lib/SDL2-CS
+ url = git://github.com/flibitijibibo/SDL2-CS.git
+[submodule "lib/OpenAL-CS"]
+ path = lib/OpenAL-CS
+ url = git://github.com/flibitijibibo/OpenAL-CS.git
+[submodule "lib/MojoShader-CS"]
+ path = lib/MojoShader-CS
+ url = git://github.com/flibitijibibo/MojoShader-CS.git
+[submodule "lib/Vorbisfile-CS"]
+ path = lib/Vorbisfile-CS
+ url = git://github.com/flibitijibibo/Vorbisfile-CS.git
+[submodule "lib/TheoraPlay-CS"]
+ path = lib/TheoraPlay-CS
+ url = git://github.com/flibitijibibo/TheoraPlay-CS.git
diff --git a/FNA.csproj b/FNA.csproj
new file mode 100644
index 0000000..4439365
--- /dev/null
+++ b/FNA.csproj
@@ -0,0 +1,391 @@
+
+
+
+ Debug
+ x86
+ 9.0.21022
+ 2.0
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}
+ Library
+ Microsoft.Xna.Framework
+ FNA
+
+
+ True
+ full
+ False
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ x86
+ False
+ True
+
+
+ none
+ True
+ bin\Release
+ prompt
+ 4
+ x86
+ False
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
+ Microsoft.Xna.Framework.Graphics.Effect.Resources.AlphaTestEffect.fxb
+
+
+ Microsoft.Xna.Framework.Graphics.Effect.Resources.BasicEffect.fxb
+
+
+ Microsoft.Xna.Framework.Graphics.Effect.Resources.DualTextureEffect.fxb
+
+
+ Microsoft.Xna.Framework.Graphics.Effect.Resources.EnvironmentMapEffect.fxb
+
+
+ Microsoft.Xna.Framework.Graphics.Effect.Resources.SkinnedEffect.fxb
+
+
+ Microsoft.Xna.Framework.Graphics.Effect.Resources.SpriteEffect.fxb
+
+
+ Microsoft.Xna.Framework.Graphics.Effect.Resources.YUVToRGBAEffect.fxb
+
+
+
diff --git a/FNA.dll.config b/FNA.dll.config
new file mode 100644
index 0000000..730894d
--- /dev/null
+++ b/FNA.dll.config
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FNA.sln b/FNA.sln
new file mode 100644
index 0000000..81084c0
--- /dev/null
+++ b/FNA.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNA", "FNA.csproj", "{35253CE1-C864-4CD3-8249-4D1319748E8F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|x86.ActiveCfg = Debug|x86
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|x86.Build.0 = Debug|x86
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|x86.ActiveCfg = Release|x86
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = FNA.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a3f8632
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,350 @@
+# Makefile for FNA
+# Written by Ethan "flibitijibibo" Lee
+
+# Source Lists
+SRC = \
+ src/Audio/AudioCategory.cs \
+ src/Audio/AudioChannels.cs \
+ src/Audio/AudioDevice.cs \
+ src/Audio/AudioEmitter.cs \
+ src/Audio/AudioEngine.cs \
+ src/Audio/AudioListener.cs \
+ src/Audio/AudioStopOptions.cs \
+ src/Audio/Cue.cs \
+ src/Audio/CueData.cs \
+ src/Audio/DynamicSoundEffectInstance.cs \
+ src/Audio/IALDevice.cs \
+ src/Audio/InstancePlayLimitException.cs \
+ src/Audio/Microphone.cs \
+ src/Audio/MicrophoneState.cs \
+ src/Audio/NoAudioHardwareException.cs \
+ src/Audio/NoMicrophoneConnectedException.cs \
+ src/Audio/NullDevice.cs \
+ src/Audio/OpenALDevice.cs \
+ src/Audio/RendererDetail.cs \
+ src/Audio/SoundBank.cs \
+ src/Audio/SoundEffect.cs \
+ src/Audio/SoundEffectInstance.cs \
+ src/Audio/SoundState.cs \
+ src/Audio/WaveBank.cs \
+ src/Audio/XACTInternal.cs \
+ src/BoundingBox.cs \
+ src/BoundingFrustum.cs \
+ src/BoundingSphere.cs \
+ src/Color.cs \
+ src/ContainmentType.cs \
+ src/Content/ContentExtensions.cs \
+ src/Content/ContentLoadException.cs \
+ src/Content/ContentManager.cs \
+ src/Content/ContentReader.cs \
+ src/Content/ContentReaders/AlphaTestEffectReader.cs \
+ src/Content/ContentReaders/ArrayReader.cs \
+ src/Content/ContentReaders/BasicEffectReader.cs \
+ src/Content/ContentReaders/BooleanReader.cs \
+ src/Content/ContentReaders/BoundingBoxReader.cs \
+ src/Content/ContentReaders/BoundingFrustumReader.cs \
+ src/Content/ContentReaders/BoundingSphereReader.cs \
+ src/Content/ContentReaders/ByteReader.cs \
+ src/Content/ContentReaders/CharReader.cs \
+ src/Content/ContentReaders/ColorReader.cs \
+ src/Content/ContentReaders/CurveReader.cs \
+ src/Content/ContentReaders/DateTimeReader.cs \
+ src/Content/ContentReaders/DecimalReader.cs \
+ src/Content/ContentReaders/DictionaryReader.cs \
+ src/Content/ContentReaders/DoubleReader.cs \
+ src/Content/ContentReaders/DualTextureEffectReader.cs \
+ src/Content/ContentReaders/EffectMaterialReader.cs \
+ src/Content/ContentReaders/EffectReader.cs \
+ src/Content/ContentReaders/EnumReader.cs \
+ src/Content/ContentReaders/EnvironmentMapEffectReader.cs \
+ src/Content/ContentReaders/ExternalReferenceReader.cs \
+ src/Content/ContentReaders/IndexBufferReader.cs \
+ src/Content/ContentReaders/Int16Reader.cs \
+ src/Content/ContentReaders/Int32Reader.cs \
+ src/Content/ContentReaders/Int64Reader.cs \
+ src/Content/ContentReaders/ListReader.cs \
+ src/Content/ContentReaders/MatrixReader.cs \
+ src/Content/ContentReaders/ModelReader.cs \
+ src/Content/ContentReaders/NullableReader.cs \
+ src/Content/ContentReaders/PlaneReader.cs \
+ src/Content/ContentReaders/PointReader.cs \
+ src/Content/ContentReaders/QuaternionReader.cs \
+ src/Content/ContentReaders/RayReader.cs \
+ src/Content/ContentReaders/RectangleReader.cs \
+ src/Content/ContentReaders/ReflectiveReader.cs \
+ src/Content/ContentReaders/SByteReader.cs \
+ src/Content/ContentReaders/SingleReader.cs \
+ src/Content/ContentReaders/SkinnedEffectReader.cs \
+ src/Content/ContentReaders/SongReader.cs \
+ src/Content/ContentReaders/SoundEffectReader.cs \
+ src/Content/ContentReaders/SpriteFontReader.cs \
+ src/Content/ContentReaders/StringReader.cs \
+ src/Content/ContentReaders/Texture2DReader.cs \
+ src/Content/ContentReaders/Texture3DReader.cs \
+ src/Content/ContentReaders/TextureCubeReader.cs \
+ src/Content/ContentReaders/TextureReader.cs \
+ src/Content/ContentReaders/TimeSpanReader.cs \
+ src/Content/ContentReaders/UInt16Reader.cs \
+ src/Content/ContentReaders/UInt32Reader.cs \
+ src/Content/ContentReaders/UInt64Reader.cs \
+ src/Content/ContentReaders/Vector2Reader.cs \
+ src/Content/ContentReaders/Vector3Reader.cs \
+ src/Content/ContentReaders/Vector4Reader.cs \
+ src/Content/ContentReaders/VertexBufferReader.cs \
+ src/Content/ContentReaders/VertexDeclarationReader.cs \
+ src/Content/ContentReaders/VideoReader.cs \
+ src/Content/ContentSerializerAttribute.cs \
+ src/Content/ContentSerializerCollectionItemNameAttribute.cs \
+ src/Content/ContentSerializerIgnoreAttribute.cs \
+ src/Content/ContentSerializerRuntimeTypeAttribute.cs \
+ src/Content/ContentSerializerTypeVersionAttribute.cs \
+ src/Content/ContentTypeReader.cs \
+ src/Content/ContentTypeReaderManager.cs \
+ src/Content/LzxDecoder.cs \
+ src/Content/ResourceContentManager.cs \
+ src/Curve.cs \
+ src/CurveContinuity.cs \
+ src/CurveKey.cs \
+ src/CurveKeyCollection.cs \
+ src/CurveLoopType.cs \
+ src/CurveTangent.cs \
+ src/Design/BoundingBoxConverter.cs \
+ src/Design/BoundingSphereConverter.cs \
+ src/Design/ColorConverter.cs \
+ src/Design/MathTypeConverter.cs \
+ src/Design/MatrixConverter.cs \
+ src/Design/PlaneConverter.cs \
+ src/Design/PointConverter.cs \
+ src/Design/QuaternionConverter.cs \
+ src/Design/RayConverter.cs \
+ src/Design/RectangleConverter.cs \
+ src/Design/Vector2Converter.cs \
+ src/Design/Vector3Converter.cs \
+ src/Design/Vector4Converter.cs \
+ src/DisplayOrientation.cs \
+ src/DrawableGameComponent.cs \
+ src/FrameworkDispatcher.cs \
+ src/Game.cs \
+ src/GameComponent.cs \
+ src/GameComponentCollection.cs \
+ src/GameComponentCollectionEventArgs.cs \
+ src/GamePlatform.cs \
+ src/GameServiceContainer.cs \
+ src/GameTime.cs \
+ src/GameWindow.cs \
+ src/Graphics/ClearOptions.cs \
+ src/Graphics/ColorWriteChannels.cs \
+ src/Graphics/CubeMapFace.cs \
+ src/Graphics/DepthFormat.cs \
+ src/Graphics/DeviceLostException.cs \
+ src/Graphics/DeviceNotResetException.cs \
+ src/Graphics/DirectionalLight.cs \
+ src/Graphics/DisplayMode.cs \
+ src/Graphics/DisplayModeCollection.cs \
+ src/Graphics/DxtUtil.cs \
+ src/Graphics/Effect/Effect.cs \
+ src/Graphics/Effect/EffectAnnotation.cs \
+ src/Graphics/Effect/EffectAnnotationCollection.cs \
+ src/Graphics/Effect/EffectMaterial.cs \
+ src/Graphics/Effect/EffectParameter.cs \
+ src/Graphics/Effect/EffectParameterClass.cs \
+ src/Graphics/Effect/EffectParameterCollection.cs \
+ src/Graphics/Effect/EffectParameterType.cs \
+ src/Graphics/Effect/EffectPass.cs \
+ src/Graphics/Effect/EffectPassCollection.cs \
+ src/Graphics/Effect/EffectTechnique.cs \
+ src/Graphics/Effect/EffectTechniqueCollection.cs \
+ src/Graphics/Effect/IEffectFog.cs \
+ src/Graphics/Effect/IEffectLights.cs \
+ src/Graphics/Effect/IEffectMatrices.cs \
+ src/Graphics/Effect/Resources.cs \
+ src/Graphics/Effect/StockEffects/AlphaTestEffect.cs \
+ src/Graphics/Effect/StockEffects/BasicEffect.cs \
+ src/Graphics/Effect/StockEffects/DualTextureEffect.cs \
+ src/Graphics/Effect/StockEffects/EffectHelpers.cs \
+ src/Graphics/Effect/StockEffects/EnvironmentMapEffect.cs \
+ src/Graphics/Effect/StockEffects/SkinnedEffect.cs \
+ src/Graphics/Effect/StockEffects/SpriteEffect.cs \
+ src/Graphics/GraphicsAdapter.cs \
+ src/Graphics/GraphicsDevice.cs \
+ src/Graphics/GraphicsDeviceStatus.cs \
+ src/Graphics/GraphicsProfile.cs \
+ src/Graphics/GraphicsResource.cs \
+ src/Graphics/IGLDevice.cs \
+ src/Graphics/IGraphicsDeviceService.cs \
+ src/Graphics/IRenderTarget.cs \
+ src/Graphics/Model.cs \
+ src/Graphics/ModelBone.cs \
+ src/Graphics/ModelBoneCollection.cs \
+ src/Graphics/ModelEffectCollection.cs \
+ src/Graphics/ModelMesh.cs \
+ src/Graphics/ModelMeshCollection.cs \
+ src/Graphics/ModelMeshPart.cs \
+ src/Graphics/ModelMeshPartCollection.cs \
+ src/Graphics/NoSuitableGraphicsDeviceException.cs \
+ src/Graphics/OcclusionQuery.cs \
+ src/Graphics/OpenGLDevice.cs \
+ src/Graphics/OpenGLDevice_GL.cs \
+ src/Graphics/PackedVector/Alpha8.cs \
+ src/Graphics/PackedVector/Bgr565.cs \
+ src/Graphics/PackedVector/Bgra4444.cs \
+ src/Graphics/PackedVector/Bgra5551.cs \
+ src/Graphics/PackedVector/Byte4.cs \
+ src/Graphics/PackedVector/HalfSingle.cs \
+ src/Graphics/PackedVector/HalfTypeHelper.cs \
+ src/Graphics/PackedVector/HalfVector2.cs \
+ src/Graphics/PackedVector/HalfVector4.cs \
+ src/Graphics/PackedVector/IPackedVector.cs \
+ src/Graphics/PackedVector/NormalizedByte2.cs \
+ src/Graphics/PackedVector/NormalizedByte4.cs \
+ src/Graphics/PackedVector/NormalizedShort2.cs \
+ src/Graphics/PackedVector/NormalizedShort4.cs \
+ src/Graphics/PackedVector/Rg32.cs \
+ src/Graphics/PackedVector/Rgba64.cs \
+ src/Graphics/PackedVector/Rgba1010102.cs \
+ src/Graphics/PackedVector/Short2.cs \
+ src/Graphics/PackedVector/Short4.cs \
+ src/Graphics/PresentationParameters.cs \
+ src/Graphics/PresentInterval.cs \
+ src/Graphics/PrimitiveType.cs \
+ src/Graphics/RenderTarget2D.cs \
+ src/Graphics/RenderTargetBinding.cs \
+ src/Graphics/RenderTargetCube.cs \
+ src/Graphics/RenderTargetUsage.cs \
+ src/Graphics/ResourceCreatedEventArgs.cs \
+ src/Graphics/ResourceDestroyedEventArgs.cs \
+ src/Graphics/SamplerStateCollection.cs \
+ src/Graphics/SetDataOptions.cs \
+ src/Graphics/SpriteBatch.cs \
+ src/Graphics/SpriteEffects.cs \
+ src/Graphics/SpriteFont.cs \
+ src/Graphics/SpriteSortMode.cs \
+ src/Graphics/States/Blend.cs \
+ src/Graphics/States/BlendFunction.cs \
+ src/Graphics/States/BlendState.cs \
+ src/Graphics/States/CompareFunction.cs \
+ src/Graphics/States/CullMode.cs \
+ src/Graphics/States/DepthStencilState.cs \
+ src/Graphics/States/FillMode.cs \
+ src/Graphics/States/RasterizerState.cs \
+ src/Graphics/States/SamplerState.cs \
+ src/Graphics/States/StencilOperation.cs \
+ src/Graphics/States/TextureAddressMode.cs \
+ src/Graphics/States/TextureFilter.cs \
+ src/Graphics/SurfaceFormat.cs \
+ src/Graphics/Texture.cs \
+ src/Graphics/Texture2D.cs \
+ src/Graphics/Texture3D.cs \
+ src/Graphics/TextureCollection.cs \
+ src/Graphics/TextureCube.cs \
+ src/Graphics/Vertices/BufferUsage.cs \
+ src/Graphics/Vertices/DynamicIndexBuffer.cs \
+ src/Graphics/Vertices/DynamicVertexBuffer.cs \
+ src/Graphics/Vertices/IndexBuffer.cs \
+ src/Graphics/Vertices/IndexElementSize.cs \
+ src/Graphics/Vertices/IVertexType.cs \
+ src/Graphics/Vertices/VertexBuffer.cs \
+ src/Graphics/Vertices/VertexBufferBinding.cs \
+ src/Graphics/Vertices/VertexDeclaration.cs \
+ src/Graphics/Vertices/VertexDeclarationCache.cs \
+ src/Graphics/Vertices/VertexElement.cs \
+ src/Graphics/Vertices/VertexElementFormat.cs \
+ src/Graphics/Vertices/VertexElementUsage.cs \
+ src/Graphics/Vertices/VertexPositionColor.cs \
+ src/Graphics/Vertices/VertexPositionColorTexture.cs \
+ src/Graphics/Vertices/VertexPositionNormalTexture.cs \
+ src/Graphics/Vertices/VertexPositionTexture.cs \
+ src/Graphics/Viewport.cs \
+ src/GraphicsDeviceInformation.cs \
+ src/GraphicsDeviceManager.cs \
+ src/IDrawable.cs \
+ src/IGameComponent.cs \
+ src/IGraphicsDeviceManager.cs \
+ src/Input/Buttons.cs \
+ src/Input/ButtonState.cs \
+ src/Input/GamePadButtons.cs \
+ src/Input/GamePadCapabilities.cs \
+ src/Input/GamePadDeadZone.cs \
+ src/Input/GamePadDPad.cs \
+ src/Input/GamePadState.cs \
+ src/Input/GamePadThumbSticks.cs \
+ src/Input/GamePadTriggers.cs \
+ src/Input/GamePadType.cs \
+ src/Input/Keyboard.cs \
+ src/Input/KeyboardState.cs \
+ src/Input/Keys.cs \
+ src/Input/KeyState.cs \
+ src/Input/MouseState.cs \
+ src/Input/TextInputEXT.cs \
+ src/IUpdateable.cs \
+ src/LaunchParameters.cs \
+ src/MathHelper.cs \
+ src/Matrix.cs \
+ src/Media/MediaPlayer.cs \
+ src/Media/MediaQueue.cs \
+ src/Media/MediaState.cs \
+ src/Media/SongCollection.cs \
+ src/Media/VideoSoundtrackType.cs \
+ src/Media/VisualizationData.cs \
+ src/Media/Xiph/Song.cs \
+ src/Media/Xiph/Video.cs \
+ src/Media/Xiph/VideoPlayer.cs \
+ src/NamespaceDocs.cs \
+ src/Plane.cs \
+ src/PlaneIntersectionType.cs \
+ src/PlayerIndex.cs \
+ src/Point.cs \
+ src/PreparingDeviceSettingsEventArgs.cs \
+ src/Properties/AssemblyInfo.cs \
+ src/Quaternion.cs \
+ src/Ray.cs \
+ src/Rectangle.cs \
+ src/SDL2/Input/SDL2_GamePad.cs \
+ src/SDL2/Input/SDL2_KeyboardUtil.cs \
+ src/SDL2/Input/SDL2_Mouse.cs \
+ src/SDL2/SDL2_GamePlatform.cs \
+ src/SDL2/SDL2_GameWindow.cs \
+ src/Storage/StorageContainer.cs \
+ src/Storage/StorageDevice.cs \
+ src/Storage/StorageDeviceNotConnectedException.cs \
+ src/TitleContainer.cs \
+ src/Utilities/AssemblyHelper.cs \
+ src/Utilities/FileHelpers.cs \
+ src/Vector2.cs \
+ src/Vector3.cs \
+ src/Vector4.cs \
+ lib/SDL2-CS/src/SDL2.cs \
+ lib/SDL2-CS/src/SDL2_image.cs \
+ lib/SDL2-CS/src/LPUtf8StrMarshaler.cs \
+ lib/OpenAL-CS/src/ALC10.cs \
+ lib/OpenAL-CS/src/ALC11.cs \
+ lib/OpenAL-CS/src/AL10.cs \
+ lib/OpenAL-CS/src/AL11.cs \
+ lib/OpenAL-CS/src/ALEXT.cs \
+ lib/OpenAL-CS/src/EFX.cs \
+ lib/MojoShader-CS/MojoShader.cs \
+ lib/Vorbisfile-CS/Vorbisfile.cs \
+ lib/TheoraPlay-CS/TheoraPlay.cs
+
+# Targets
+
+debug: clean-debug
+ mkdir -p bin/Debug
+ cp FNA.dll.config bin/Debug
+ dmcs /unsafe -debug -out:bin/Debug/FNA.dll -target:library $(SRC)
+
+clean-debug:
+ rm -rf bin/Debug
+
+release: clean-release
+ mkdir -p bin/Release
+ cp FNA.dll.config bin/Release
+ dmcs /unsafe -optimize -out:bin/Release/FNA.dll -target:library $(SRC)
+
+clean-release:
+ rm -rf bin/Release
+
+clean: clean-debug clean-release
+ rm -rf bin
+
+all: debug release
diff --git a/README b/README
new file mode 100644
index 0000000..108403c
--- /dev/null
+++ b/README
@@ -0,0 +1,29 @@
+This is FNA, an XNA4 reimplementation that focuses solely on developing a fully
+accurate XNA4 runtime for the desktop.
+
+Project Website: http://fna-xna.github.io/
+
+License
+-------
+FNA is released under the Microsoft Public License. See LICENSE for details.
+
+FNA uses LzxDecoder.cs, released under a dual MSPL/LGPL license.
+See lzxdecoder.LICENSE for details.
+
+FNA uses code from the unxwb project, specially released under the MonoGame
+project license. See unxwb.LICENSE for details.
+
+FNA uses code from the Mono.Xna project, released under the MIT license.
+See monoxna.LICENSE for details.
+
+Documentation
+-------------
+Documentation for FNA can be found on the FNA wiki:
+
+https://github.com/FNA-XNA/FNA/wiki
+
+Found an issue?
+---------------
+Issues and patches can be reported via GitHub:
+
+https://github.com/FNA-XNA/FNA/issues
diff --git a/gendarme/fna.ignore b/gendarme/fna.ignore
new file mode 100644
index 0000000..7d420d7
--- /dev/null
+++ b/gendarme/fna.ignore
@@ -0,0 +1,12 @@
+R: Gendarme.Rules.Design.AvoidRefAndOutParametersRule
+A: FNA
+
+R: Gendarme.Rules.Naming.AvoidDeepNamespaceHierarchyRule
+A: FNA
+
+# Ignore everything from the lib folder
+@ sdl2.ignore
+@ openal.ignore
+@ mojoshader.ignore
+@ vorbisfile.ignore
+@ theoraplay.ignore
diff --git a/gendarme/mojoshader.ignore b/gendarme/mojoshader.ignore
new file mode 100644
index 0000000..894c34f
--- /dev/null
+++ b/gendarme/mojoshader.ignore
@@ -0,0 +1,339 @@
+R: Gendarme.Rules.Design.Generic.AvoidDeclaringCustomDelegatesRule
+T: MojoShader/MOJOSHADER_malloc
+T: MojoShader/MOJOSHADER_free
+T: MojoShader/MOJOSHADER_glGetProcAddress
+
+R: Gendarme.Rules.Performance.AvoidLargeStructureRule
+T: MojoShader/MOJOSHADER_symbol
+T: MojoShader/MOJOSHADER_preshaderInstruction
+T: MojoShader/MOJOSHADER_parseData
+T: MojoShader/MOJOSHADER_effectValue
+T: MojoShader/MOJOSHADER_effectState
+T: MojoShader/MOJOSHADER_effectSamplerState
+T: MojoShader/MOJOSHADER_effectAnnotation
+T: MojoShader/MOJOSHADER_effectParam
+T: MojoShader/MOJOSHADER_effectShader
+T: MojoShader/MOJOSHADER_effectObject
+T: MojoShader/MOJOSHADER_effect
+
+R: Gendarme.Rules.Naming.AvoidNonAlphanumericIdentifierRule
+T: MojoShader
+M: System.Int32 MojoShader::MOJOSHADER_version()
+M: System.IntPtr MojoShader::MOJOSHADER_changeset()
+M: System.Int32 MojoShader::MOJOSHADER_maxShaderModel(System.String)
+M: System.IntPtr MojoShader::MOJOSHADER_parse(System.String,System.Byte[],System.UInt32,MojoShader/MOJOSHADER_swizzle[],System.UInt32,MojoShader/MOJOSHADER_samplerMap[],System.UInt32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_freeParseData(System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_parsePreshader(System.Byte[],System.UInt32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_freePreshader(System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_parseEffect(System.String,System.Byte[],System.UInt32,MojoShader/MOJOSHADER_swizzle[],System.UInt32,MojoShader/MOJOSHADER_samplerMap[],System.UInt32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_freeEffect(System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_cloneEffect(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_effectSetRawValueHandle(System.IntPtr,System.IntPtr,System.UInt32,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_effectSetRawValueName(System.IntPtr,System.String,System.IntPtr,System.UInt32,System.UInt32)
+M: System.IntPtr MojoShader::MOJOSHADER_effectGetCurrentTechnique(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_effectSetTechnique(System.IntPtr,System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_effectFindNextValidTechnique(System.IntPtr,System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_glCompileEffect(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glDeleteEffect(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glEffectBegin(System.IntPtr,System.UInt32&,System.Int32,MojoShader/MOJOSHADER_effectStateChanges&)
+M: System.Void MojoShader::MOJOSHADER_glEffectBeginPass(System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glEffectCommitChanges(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glEffectEndPass(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glEffectEnd(System.IntPtr)
+M: System.Int32 MojoShader::MOJOSHADER_glAvailableProfiles(MojoShader/MOJOSHADER_glGetProcAddress,System.IntPtr,System.IntPtr,System.Int32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.String MojoShader::MOJOSHADER_glBestProfile(MojoShader/MOJOSHADER_glGetProcAddress,System.IntPtr,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_glCreateContext(System.String,MojoShader/MOJOSHADER_glGetProcAddress,System.IntPtr,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glMakeContextCurrent(System.IntPtr)
+M: System.String MojoShader::MOJOSHADER_glGetError()
+M: System.Int32 MojoShader::MOJOSHADER_glMaxUniforms(MojoShader/MOJOSHADER_shaderType)
+M: System.IntPtr MojoShader::MOJOSHADER_glCompileShader(System.Byte[],System.UInt32,MojoShader/MOJOSHADER_swizzle[],System.UInt32,MojoShader/MOJOSHADER_samplerMap[],System.UInt32)
+M: System.IntPtr MojoShader::MOJOSHADER_glGetShaderParseData(System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_glLinkProgram(System.IntPtr,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glBindProgram(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glBindShaders(System.IntPtr,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexShaderUniformF(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetVertexShaderUniformF(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexShaderUniformI(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetVertexShaderUniformI(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexShaderUniformB(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetVertexShaderUniformB(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetPixelShaderUniformF(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetPixelShaderUniformF(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetPixelShaderUniformI(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetPixelShaderUniformI(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetPixelShaderUniformB(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetPixelShaderUniformB(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetLegacyBumpMapEnv(System.UInt32,System.Single,System.Single,System.Single,System.Single,System.Single,System.Single)
+M: System.Int32 MojoShader::MOJOSHADER_glGetVertexAttribLocation(MojoShader/MOJOSHADER_usage,System.Int32)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexAttribute(MojoShader/MOJOSHADER_usage,System.Int32,System.UInt32,MojoShader/MOJOSHADER_attributeType,System.Int32,System.UInt32,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexAttribDivisor(MojoShader/MOJOSHADER_usage,System.Int32,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glProgramReady()
+M: System.Void MojoShader::MOJOSHADER_glProgramViewportFlip(System.Int32)
+M: System.Void MojoShader::MOJOSHADER_glDeleteProgram(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glDeleteShader(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glDestroyContext(System.IntPtr)
+T: MojoShader/MOJOSHADER_malloc
+T: MojoShader/MOJOSHADER_free
+T: MojoShader/MOJOSHADER_shaderType
+T: MojoShader/MOJOSHADER_attributeType
+T: MojoShader/MOJOSHADER_uniformType
+T: MojoShader/MOJOSHADER_uniform
+T: MojoShader/MOJOSHADER_constant
+T: MojoShader/MOJOSHADER_samplerType
+T: MojoShader/MOJOSHADER_sampler
+T: MojoShader/MOJOSHADER_samplerMap
+T: MojoShader/MOJOSHADER_usage
+T: MojoShader/MOJOSHADER_attribute
+T: MojoShader/MOJOSHADER_swizzle
+T: MojoShader/MOJOSHADER_symbolRegisterSet
+T: MojoShader/MOJOSHADER_symbolClass
+T: MojoShader/MOJOSHADER_symbolType
+T: MojoShader/MOJOSHADER_symbolTypeInfo
+T: MojoShader/MOJOSHADER_symbolStructMember
+T: MojoShader/MOJOSHADER_symbol
+T: MojoShader/MOJOSHADER_error
+T: MojoShader/MOJOSHADER_preshaderOpcode
+T: MojoShader/MOJOSHADER_preshaderOperandType
+T: MojoShader/MOJOSHADER_preshaderOperand
+T: MojoShader/MOJOSHADER_preshaderInstruction
+T: MojoShader/MOJOSHADER_preshader
+T: MojoShader/MOJOSHADER_parseData
+T: MojoShader/MOJOSHADER_renderStateType
+T: MojoShader/MOJOSHADER_zBufferType
+T: MojoShader/MOJOSHADER_fillMode
+T: MojoShader/MOJOSHADER_shadeMode
+T: MojoShader/MOJOSHADER_blendMode
+T: MojoShader/MOJOSHADER_cullMode
+T: MojoShader/MOJOSHADER_compareFunc
+T: MojoShader/MOJOSHADER_fogMode
+T: MojoShader/MOJOSHADER_stencilOp
+T: MojoShader/MOJOSHADER_materialColorSource
+T: MojoShader/MOJOSHADER_vertexBlendFlags
+T: MojoShader/MOJOSHADER_patchedEdgeStyle
+T: MojoShader/MOJOSHADER_debugMonitorTokens
+T: MojoShader/MOJOSHADER_blendOp
+T: MojoShader/MOJOSHADER_degreeType
+T: MojoShader/MOJOSHADER_samplerStateType
+T: MojoShader/MOJOSHADER_textureAddress
+T: MojoShader/MOJOSHADER_textureFilterType
+T: MojoShader/MOJOSHADER_effectValue
+T: MojoShader/MOJOSHADER_effectState
+T: MojoShader/MOJOSHADER_effectSamplerState
+T: MojoShader/MOJOSHADER_effectAnnotation
+T: MojoShader/MOJOSHADER_effectParam
+T: MojoShader/MOJOSHADER_effectPass
+T: MojoShader/MOJOSHADER_effectTechnique
+T: MojoShader/MOJOSHADER_effectShader
+T: MojoShader/MOJOSHADER_effectSamplerMap
+T: MojoShader/MOJOSHADER_effectString
+T: MojoShader/MOJOSHADER_effectTexture
+T: MojoShader/MOJOSHADER_effectObject
+T: MojoShader/MOJOSHADER_samplerStateRegister
+T: MojoShader/MOJOSHADER_effectStateChanges
+T: MojoShader/MOJOSHADER_effect
+T: MojoShader/MOJOSHADER_glGetProcAddress
+
+R: Gendarme.Rules.BadPractice.AvoidVisibleConstantFieldRule
+T: MojoShader
+
+R: Gendarme.Rules.Design.AvoidVisibleFieldsRule
+T: MojoShader/MOJOSHADER_uniform
+T: MojoShader/MOJOSHADER_constant
+T: MojoShader/MOJOSHADER_sampler
+T: MojoShader/MOJOSHADER_samplerMap
+T: MojoShader/MOJOSHADER_attribute
+T: MojoShader/MOJOSHADER_swizzle
+T: MojoShader/MOJOSHADER_symbolTypeInfo
+T: MojoShader/MOJOSHADER_symbolStructMember
+T: MojoShader/MOJOSHADER_symbol
+T: MojoShader/MOJOSHADER_error
+T: MojoShader/MOJOSHADER_preshaderOperand
+T: MojoShader/MOJOSHADER_preshaderInstruction
+T: MojoShader/MOJOSHADER_preshader
+T: MojoShader/MOJOSHADER_parseData
+T: MojoShader/MOJOSHADER_effectValue
+T: MojoShader/MOJOSHADER_effectState
+T: MojoShader/MOJOSHADER_effectSamplerState
+T: MojoShader/MOJOSHADER_effectAnnotation
+T: MojoShader/MOJOSHADER_effectParam
+T: MojoShader/MOJOSHADER_effectPass
+T: MojoShader/MOJOSHADER_effectTechnique
+T: MojoShader/MOJOSHADER_effectShader
+T: MojoShader/MOJOSHADER_effectSamplerMap
+T: MojoShader/MOJOSHADER_effectString
+T: MojoShader/MOJOSHADER_effectTexture
+T: MojoShader/MOJOSHADER_effectObject
+T: MojoShader/MOJOSHADER_samplerStateRegister
+T: MojoShader/MOJOSHADER_effectStateChanges
+T: MojoShader/MOJOSHADER_effect
+
+R: Gendarme.Rules.Design.AvoidVisibleNestedTypesRule
+T: MojoShader/MOJOSHADER_malloc
+T: MojoShader/MOJOSHADER_free
+T: MojoShader/MOJOSHADER_shaderType
+T: MojoShader/MOJOSHADER_attributeType
+T: MojoShader/MOJOSHADER_uniformType
+T: MojoShader/MOJOSHADER_uniform
+T: MojoShader/MOJOSHADER_constant
+T: MojoShader/MOJOSHADER_constant/__FixedBuffer0
+T: MojoShader/MOJOSHADER_constant/__FixedBuffer1
+T: MojoShader/MOJOSHADER_samplerType
+T: MojoShader/MOJOSHADER_sampler
+T: MojoShader/MOJOSHADER_samplerMap
+T: MojoShader/MOJOSHADER_usage
+T: MojoShader/MOJOSHADER_attribute
+T: MojoShader/MOJOSHADER_swizzle
+T: MojoShader/MOJOSHADER_swizzle/__FixedBuffer2
+T: MojoShader/MOJOSHADER_symbolRegisterSet
+T: MojoShader/MOJOSHADER_symbolClass
+T: MojoShader/MOJOSHADER_symbolType
+T: MojoShader/MOJOSHADER_symbolTypeInfo
+T: MojoShader/MOJOSHADER_symbolStructMember
+T: MojoShader/MOJOSHADER_symbol
+T: MojoShader/MOJOSHADER_error
+T: MojoShader/MOJOSHADER_preshaderOpcode
+T: MojoShader/MOJOSHADER_preshaderOperandType
+T: MojoShader/MOJOSHADER_preshaderOperand
+T: MojoShader/MOJOSHADER_preshaderInstruction
+T: MojoShader/MOJOSHADER_preshader
+T: MojoShader/MOJOSHADER_parseData
+T: MojoShader/MOJOSHADER_renderStateType
+T: MojoShader/MOJOSHADER_zBufferType
+T: MojoShader/MOJOSHADER_fillMode
+T: MojoShader/MOJOSHADER_shadeMode
+T: MojoShader/MOJOSHADER_blendMode
+T: MojoShader/MOJOSHADER_cullMode
+T: MojoShader/MOJOSHADER_compareFunc
+T: MojoShader/MOJOSHADER_fogMode
+T: MojoShader/MOJOSHADER_stencilOp
+T: MojoShader/MOJOSHADER_materialColorSource
+T: MojoShader/MOJOSHADER_vertexBlendFlags
+T: MojoShader/MOJOSHADER_patchedEdgeStyle
+T: MojoShader/MOJOSHADER_debugMonitorTokens
+T: MojoShader/MOJOSHADER_blendOp
+T: MojoShader/MOJOSHADER_degreeType
+T: MojoShader/MOJOSHADER_samplerStateType
+T: MojoShader/MOJOSHADER_textureAddress
+T: MojoShader/MOJOSHADER_textureFilterType
+T: MojoShader/MOJOSHADER_effectValue
+T: MojoShader/MOJOSHADER_effectState
+T: MojoShader/MOJOSHADER_effectSamplerState
+T: MojoShader/MOJOSHADER_effectAnnotation
+T: MojoShader/MOJOSHADER_effectParam
+T: MojoShader/MOJOSHADER_effectPass
+T: MojoShader/MOJOSHADER_effectTechnique
+T: MojoShader/MOJOSHADER_effectShader
+T: MojoShader/MOJOSHADER_effectSamplerMap
+T: MojoShader/MOJOSHADER_effectString
+T: MojoShader/MOJOSHADER_effectTexture
+T: MojoShader/MOJOSHADER_effectObject
+T: MojoShader/MOJOSHADER_samplerStateRegister
+T: MojoShader/MOJOSHADER_effectStateChanges
+T: MojoShader/MOJOSHADER_effect
+T: MojoShader/MOJOSHADER_glGetProcAddress
+
+R: Gendarme.Rules.Interoperability.CentralizePInvokesIntoNativeMethodsTypeRule
+M: System.Int32 MojoShader::MOJOSHADER_version()
+M: System.IntPtr MojoShader::MOJOSHADER_changeset()
+M: System.Int32 MojoShader::MOJOSHADER_maxShaderModel(System.String)
+M: System.IntPtr MojoShader::MOJOSHADER_parse(System.String,System.Byte[],System.UInt32,MojoShader/MOJOSHADER_swizzle[],System.UInt32,MojoShader/MOJOSHADER_samplerMap[],System.UInt32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_freeParseData(System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_parsePreshader(System.Byte[],System.UInt32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_freePreshader(System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_parseEffect(System.String,System.Byte[],System.UInt32,MojoShader/MOJOSHADER_swizzle[],System.UInt32,MojoShader/MOJOSHADER_samplerMap[],System.UInt32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_freeEffect(System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_cloneEffect(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_effectSetRawValueHandle(System.IntPtr,System.IntPtr,System.UInt32,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_effectSetRawValueName(System.IntPtr,System.String,System.IntPtr,System.UInt32,System.UInt32)
+M: System.IntPtr MojoShader::MOJOSHADER_effectGetCurrentTechnique(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_effectSetTechnique(System.IntPtr,System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_effectFindNextValidTechnique(System.IntPtr,System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_glCompileEffect(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glDeleteEffect(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glEffectBegin(System.IntPtr,System.UInt32&,System.Int32,MojoShader/MOJOSHADER_effectStateChanges&)
+M: System.Void MojoShader::MOJOSHADER_glEffectBeginPass(System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glEffectCommitChanges(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glEffectEndPass(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glEffectEnd(System.IntPtr)
+M: System.Int32 MojoShader::MOJOSHADER_glAvailableProfiles(MojoShader/MOJOSHADER_glGetProcAddress,System.IntPtr,System.IntPtr,System.Int32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.IntPtr MojoShader::INTERNAL_glBestProfile(MojoShader/MOJOSHADER_glGetProcAddress,System.IntPtr,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_glCreateContext(System.String,MojoShader/MOJOSHADER_glGetProcAddress,System.IntPtr,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glMakeContextCurrent(System.IntPtr)
+M: System.IntPtr MojoShader::INTERNAL_glGetError()
+M: System.Int32 MojoShader::MOJOSHADER_glMaxUniforms(MojoShader/MOJOSHADER_shaderType)
+M: System.IntPtr MojoShader::MOJOSHADER_glCompileShader(System.Byte[],System.UInt32,MojoShader/MOJOSHADER_swizzle[],System.UInt32,MojoShader/MOJOSHADER_samplerMap[],System.UInt32)
+M: System.IntPtr MojoShader::MOJOSHADER_glGetShaderParseData(System.IntPtr)
+M: System.IntPtr MojoShader::MOJOSHADER_glLinkProgram(System.IntPtr,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glBindProgram(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glBindShaders(System.IntPtr,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexShaderUniformF(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetVertexShaderUniformF(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexShaderUniformI(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetVertexShaderUniformI(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexShaderUniformB(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetVertexShaderUniformB(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetPixelShaderUniformF(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetPixelShaderUniformF(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetPixelShaderUniformI(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetPixelShaderUniformI(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetPixelShaderUniformB(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glGetPixelShaderUniformB(System.UInt32,System.IntPtr,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glSetLegacyBumpMapEnv(System.UInt32,System.Single,System.Single,System.Single,System.Single,System.Single,System.Single)
+M: System.Int32 MojoShader::MOJOSHADER_glGetVertexAttribLocation(MojoShader/MOJOSHADER_usage,System.Int32)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexAttribute(MojoShader/MOJOSHADER_usage,System.Int32,System.UInt32,MojoShader/MOJOSHADER_attributeType,System.Int32,System.UInt32,System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glSetVertexAttribDivisor(MojoShader/MOJOSHADER_usage,System.Int32,System.UInt32)
+M: System.Void MojoShader::MOJOSHADER_glProgramReady()
+M: System.Void MojoShader::MOJOSHADER_glProgramViewportFlip(System.Int32)
+M: System.Void MojoShader::MOJOSHADER_glDeleteProgram(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glDeleteShader(System.IntPtr)
+M: System.Void MojoShader::MOJOSHADER_glDestroyContext(System.IntPtr)
+
+R: Gendarme.Rules.Naming.DoNotPrefixValuesWithEnumNameRule
+T: MojoShader/MOJOSHADER_usage
+T: MojoShader/MOJOSHADER_stencilOp
+T: MojoShader/MOJOSHADER_blendOp
+
+R: Gendarme.Rules.Design.MarkAssemblyWithAssemblyVersionRule
+A: MojoShader-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithCLSCompliantRule
+A: MojoShader-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithComVisibleRule
+A: MojoShader-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Security.NativeFieldsShouldNotBeVisibleRule
+T: MojoShader/MOJOSHADER_uniform
+T: MojoShader/MOJOSHADER_sampler
+T: MojoShader/MOJOSHADER_attribute
+T: MojoShader/MOJOSHADER_symbolTypeInfo
+T: MojoShader/MOJOSHADER_symbolStructMember
+T: MojoShader/MOJOSHADER_symbol
+T: MojoShader/MOJOSHADER_error
+T: MojoShader/MOJOSHADER_preshader
+T: MojoShader/MOJOSHADER_parseData
+T: MojoShader/MOJOSHADER_effectValue
+T: MojoShader/MOJOSHADER_effectAnnotation
+T: MojoShader/MOJOSHADER_effectParam
+T: MojoShader/MOJOSHADER_effectPass
+T: MojoShader/MOJOSHADER_effectTechnique
+T: MojoShader/MOJOSHADER_effectShader
+T: MojoShader/MOJOSHADER_effectSamplerMap
+T: MojoShader/MOJOSHADER_effectString
+T: MojoShader/MOJOSHADER_samplerStateRegister
+T: MojoShader/MOJOSHADER_effectStateChanges
+T: MojoShader/MOJOSHADER_effect
+
+R: Gendarme.Rules.Naming.UseCorrectCasingRule
+M: System.IntPtr MojoShader::MOJOSHADER_parseEffect(System.String,System.Byte[],System.UInt32,MojoShader/MOJOSHADER_swizzle[],System.UInt32,MojoShader/MOJOSHADER_samplerMap[],System.UInt32,MojoShader/MOJOSHADER_malloc,MojoShader/MOJOSHADER_free,System.IntPtr)
+
+R: Gendarme.Rules.Naming.UseCorrectSuffixRule
+T: MojoShader/MOJOSHADER_attribute
+T: MojoShader/MOJOSHADER_vertexBlendFlags
+
+R: Gendarme.Rules.Naming.UseSingularNameInEnumsUnlessAreFlagsRule
+T: MojoShader/MOJOSHADER_symbolClass
+T: MojoShader/MOJOSHADER_vertexBlendFlags
+T: MojoShader/MOJOSHADER_debugMonitorTokens
+T: MojoShader/MOJOSHADER_textureAddress
+
diff --git a/gendarme/openal.ignore b/gendarme/openal.ignore
new file mode 100644
index 0000000..8e6b289
--- /dev/null
+++ b/gendarme/openal.ignore
@@ -0,0 +1,320 @@
+R: Gendarme.Rules.Naming.AvoidNonAlphanumericIdentifierRule
+T: OpenAL.ALC10
+T: OpenAL.ALC11
+T: OpenAL.AL10
+T: OpenAL.AL11
+T: OpenAL.ALEXT
+T: OpenAL.EFX
+
+R: Gendarme.Rules.BadPractice.AvoidVisibleConstantFieldRule
+T: OpenAL.ALC10
+T: OpenAL.ALC11
+T: OpenAL.AL10
+T: OpenAL.AL11
+T: OpenAL.ALEXT
+T: OpenAL.EFX
+
+R: Gendarme.Rules.Interoperability.CentralizePInvokesIntoNativeMethodsTypeRule
+M: System.IntPtr OpenAL.ALC10::alcCreateContext(System.IntPtr,System.Int32[])
+M: System.Boolean OpenAL.ALC10::alcMakeContextCurrent(System.IntPtr)
+M: System.Void OpenAL.ALC10::alcDestroyContext(System.IntPtr)
+M: System.IntPtr OpenAL.ALC10::alcGetCurrentContext()
+M: System.IntPtr OpenAL.ALC10::alcGetContextsDevice(System.IntPtr)
+M: System.IntPtr OpenAL.ALC10::alcOpenDevice(System.String)
+M: System.Boolean OpenAL.ALC10::alcCloseDevice(System.IntPtr)
+M: System.Int32 OpenAL.ALC10::alcGetError(System.IntPtr)
+M: System.IntPtr OpenAL.ALC10::alcGetProcAddress(System.IntPtr,System.String)
+M: System.Int32 OpenAL.ALC10::alcGetEnumValue(System.IntPtr,System.String)
+M: System.IntPtr OpenAL.ALC10::alcGetString(System.IntPtr,System.Int32)
+M: System.Void OpenAL.ALC10::alcGetIntegerv(System.IntPtr,System.Int32,System.IntPtr,System.Int32[])
+M: System.Void OpenAL.ALC11::alcProcessContext(System.IntPtr)
+M: System.Void OpenAL.ALC11::alcSuspendContext(System.IntPtr)
+M: System.Boolean OpenAL.ALC11::alcIsExtensionPresent(System.IntPtr,System.String)
+M: System.IntPtr OpenAL.ALC11::alcCaptureOpenDevice(System.String,System.UInt32,System.Int32,System.IntPtr)
+M: System.Boolean OpenAL.ALC11::alcCaptureCloseDevice(System.IntPtr)
+M: System.Void OpenAL.ALC11::alcCaptureStart(System.IntPtr)
+M: System.Void OpenAL.ALC11::alcCaptureStop(System.IntPtr)
+M: System.Void OpenAL.ALC11::alcCaptureSamples(System.IntPtr,System.IntPtr,System.IntPtr)
+M: System.Void OpenAL.AL10::alDistanceModel(System.Int32)
+M: System.Void OpenAL.AL10::alEnable(System.Int32)
+M: System.Void OpenAL.AL10::alDisable(System.Int32)
+M: System.Boolean OpenAL.AL10::alIsEnabled(System.Int32)
+M: System.IntPtr OpenAL.AL10::INTERNAL_alGetString(System.Int32)
+M: System.Void OpenAL.AL10::alGetBooleanv(System.Int32,System.Boolean[])
+M: System.Void OpenAL.AL10::alGetIntegerv(System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGetFloatv(System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alGetDoublev(System.Int32,System.Double[])
+M: System.Boolean OpenAL.AL10::alGetBoolean(System.Int32)
+M: System.Int32 OpenAL.AL10::alGetInteger(System.Int32)
+M: System.Single OpenAL.AL10::alGetFloat(System.Int32)
+M: System.Double OpenAL.AL10::alGetDouble(System.Int32)
+M: System.Int32 OpenAL.AL10::alGetError()
+M: System.Boolean OpenAL.AL10::alIsExtensionPresent(System.String)
+M: System.IntPtr OpenAL.AL10::alGetProcAddress(System.String)
+M: System.Int32 OpenAL.AL10::alGetEnumValue(System.String)
+M: System.Void OpenAL.AL10::alListenerf(System.Int32,System.Single)
+M: System.Void OpenAL.AL10::alListener3f(System.Int32,System.Single,System.Single,System.Single)
+M: System.Void OpenAL.AL10::alListenerfv(System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alListeneri(System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alListener3i(System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alListeneriv(System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGetListenerf(System.Int32,System.Single&)
+M: System.Void OpenAL.AL10::alGetListener3f(System.Int32,System.Single&,System.Single&,System.Single&)
+M: System.Void OpenAL.AL10::alGetListenerfv(System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alGetListeneri(System.Int32,System.Int32&)
+M: System.Void OpenAL.AL10::alGetListener3i(System.Int32,System.Int32&,System.Int32&,System.Int32&)
+M: System.Void OpenAL.AL10::alGetListeneriv(System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGenSources(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alGenSources(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.AL10::alDeleteSources(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alDeleteSources(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.AL10::alIsSource(System.UInt32)
+M: System.Void OpenAL.AL10::alSourcef(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.AL10::alSource3f(System.UInt32,System.Int32,System.Single,System.Single,System.Single)
+M: System.Void OpenAL.AL10::alSourcefv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alSourcei(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alSource3i(System.UInt32,System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alSourceiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGetSourcef(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.AL10::alGetSource3f(System.UInt32,System.Int32,System.Single&,System.Single&,System.Single&)
+M: System.Void OpenAL.AL10::alGetSourcefv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alGetSourcei(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.AL10::alGetSource3i(System.UInt32,System.Int32,System.Int32&,System.Int32&,System.Int32&)
+M: System.Void OpenAL.AL10::alGetSourceiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alSourcePlayv(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourceStopv(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourceRewindv(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourcePausev(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourcePlay(System.UInt32)
+M: System.Void OpenAL.AL10::alSourceStop(System.UInt32)
+M: System.Void OpenAL.AL10::alSourceRewind(System.UInt32)
+M: System.Void OpenAL.AL10::alSourcePause(System.UInt32)
+M: System.Void OpenAL.AL10::alSourceQueueBuffers(System.UInt32,System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourceQueueBuffers(System.UInt32,System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.AL10::alSourceUnqueueBuffers(System.UInt32,System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourceUnqueueBuffers(System.UInt32,System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.AL10::alGenBuffers(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alGenBuffers(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.AL10::alDeleteBuffers(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alDeleteBuffers(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.AL10::alIsBuffer(System.UInt32)
+M: System.Void OpenAL.AL10::alBufferData(System.UInt32,System.Int32,System.Byte[],System.IntPtr,System.IntPtr)
+M: System.Void OpenAL.AL10::alBufferData(System.UInt32,System.Int32,System.Int16[],System.IntPtr,System.IntPtr)
+M: System.Void OpenAL.AL10::alBufferData(System.UInt32,System.Int32,System.Single[],System.IntPtr,System.IntPtr)
+M: System.Void OpenAL.AL10::alBufferf(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.AL10::alBuffer3f(System.UInt32,System.Int32,System.Single,System.Single,System.Single)
+M: System.Void OpenAL.AL10::alBufferfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alBufferi(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alBuffer3i(System.UInt32,System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alBufferiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGetBufferf(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.AL10::alGetBuffer3f(System.UInt32,System.Int32,System.Single&,System.Single&,System.Single&)
+M: System.Void OpenAL.AL10::alGetBufferfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alGetBufferi(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.AL10::alGetBuffer3i(System.UInt32,System.Int32,System.Int32&,System.Int32&,System.Int32&)
+M: System.Void OpenAL.AL10::alGetBufferiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.ALEXT::alGetBufferSamplesSOFT(System.UInt32,System.Int32,System.Int32,System.Int32,System.Int32,System.IntPtr)
+M: System.Void OpenAL.EFX::alGenEffects(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alGenEffects(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.EFX::alDeleteEffects(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alDeleteEffects(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.EFX::alIsEffect(System.UInt32)
+M: System.Void OpenAL.EFX::alEffecti(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.EFX::alEffectiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alEffectf(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.EFX::alEffectfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGetEffecti(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.EFX::alGetEffectiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alGetEffectf(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.EFX::alGetEffectfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGenFilters(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alGenFilters(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.EFX::alDeleteFilters(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alDeleteFilters(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.EFX::alIsFilter(System.UInt32)
+M: System.Void OpenAL.EFX::alFilteri(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.EFX::alFilteriv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alFilterf(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.EFX::alFilterfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGetFilteri(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.EFX::alGetFilteriv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alGetFilterf(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.EFX::alGetFilterfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGenAuxiliaryEffectSlots(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alGenAuxiliaryEffectSlots(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.EFX::alDeleteAuxiliaryEffectSlots(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alDeleteAuxiliaryEffectSlots(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.EFX::alIsAuxiliaryEffectSlot(System.UInt32)
+M: System.Void OpenAL.EFX::alAuxiliaryEffectSloti(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.EFX::alAuxiliaryEffectSlotiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alAuxiliaryEffectSlotf(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.EFX::alAuxiliaryEffectSlotfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGetAuxiliaryEffectSloti(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.EFX::alGetAuxiliaryEffectSlotiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alGetAuxiliaryEffectSlotf(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.EFX::alGetAuxiliaryEffectSlotfv(System.UInt32,System.Int32,System.Single[])
+
+R: Gendarme.Rules.Design.MarkAssemblyWithAssemblyVersionRule
+A: OpenAL-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithCLSCompliantRule
+A: OpenAL-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithComVisibleRule
+A: OpenAL-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Interoperability.MarshalBooleansInPInvokeDeclarationsRule
+M: System.Boolean OpenAL.ALC10::alcMakeContextCurrent(System.IntPtr)
+M: System.Boolean OpenAL.ALC10::alcCloseDevice(System.IntPtr)
+M: System.Boolean OpenAL.ALC11::alcIsExtensionPresent(System.IntPtr,System.String)
+M: System.Boolean OpenAL.ALC11::alcCaptureCloseDevice(System.IntPtr)
+M: System.Boolean OpenAL.AL10::alIsEnabled(System.Int32)
+M: System.Void OpenAL.AL10::alGetBooleanv(System.Int32,System.Boolean[])
+M: System.Boolean OpenAL.AL10::alGetBoolean(System.Int32)
+M: System.Boolean OpenAL.AL10::alIsExtensionPresent(System.String)
+M: System.Boolean OpenAL.AL10::alIsSource(System.UInt32)
+M: System.Boolean OpenAL.AL10::alIsBuffer(System.UInt32)
+M: System.Boolean OpenAL.EFX::alIsEffect(System.UInt32)
+M: System.Boolean OpenAL.EFX::alIsFilter(System.UInt32)
+M: System.Boolean OpenAL.EFX::alIsAuxiliaryEffectSlot(System.UInt32)
+
+R: Gendarme.Rules.Naming.UseCorrectCasingRule
+M: System.IntPtr OpenAL.ALC10::alcCreateContext(System.IntPtr,System.Int32[])
+M: System.Boolean OpenAL.ALC10::alcMakeContextCurrent(System.IntPtr)
+M: System.Void OpenAL.ALC10::alcDestroyContext(System.IntPtr)
+M: System.IntPtr OpenAL.ALC10::alcGetCurrentContext()
+M: System.IntPtr OpenAL.ALC10::alcGetContextsDevice(System.IntPtr)
+M: System.IntPtr OpenAL.ALC10::alcOpenDevice(System.String)
+M: System.Boolean OpenAL.ALC10::alcCloseDevice(System.IntPtr)
+M: System.Int32 OpenAL.ALC10::alcGetError(System.IntPtr)
+M: System.IntPtr OpenAL.ALC10::alcGetProcAddress(System.IntPtr,System.String)
+M: System.Int32 OpenAL.ALC10::alcGetEnumValue(System.IntPtr,System.String)
+M: System.IntPtr OpenAL.ALC10::alcGetString(System.IntPtr,System.Int32)
+M: System.Void OpenAL.ALC10::alcGetIntegerv(System.IntPtr,System.Int32,System.IntPtr,System.Int32[])
+M: System.Void OpenAL.ALC11::alcProcessContext(System.IntPtr)
+M: System.Void OpenAL.ALC11::alcSuspendContext(System.IntPtr)
+M: System.Boolean OpenAL.ALC11::alcIsExtensionPresent(System.IntPtr,System.String)
+M: System.IntPtr OpenAL.ALC11::alcCaptureOpenDevice(System.String,System.UInt32,System.Int32,System.IntPtr)
+M: System.Boolean OpenAL.ALC11::alcCaptureCloseDevice(System.IntPtr)
+M: System.Void OpenAL.ALC11::alcCaptureStart(System.IntPtr)
+M: System.Void OpenAL.ALC11::alcCaptureStop(System.IntPtr)
+M: System.Void OpenAL.ALC11::alcCaptureSamples(System.IntPtr,System.IntPtr,System.IntPtr)
+M: System.Void OpenAL.AL10::alDistanceModel(System.Int32)
+M: System.Void OpenAL.AL10::alEnable(System.Int32)
+M: System.Void OpenAL.AL10::alDisable(System.Int32)
+M: System.Boolean OpenAL.AL10::alIsEnabled(System.Int32)
+M: System.String OpenAL.AL10::alGetString(System.Int32)
+M: System.Void OpenAL.AL10::alGetBooleanv(System.Int32,System.Boolean[])
+M: System.Void OpenAL.AL10::alGetIntegerv(System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGetFloatv(System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alGetDoublev(System.Int32,System.Double[])
+M: System.Boolean OpenAL.AL10::alGetBoolean(System.Int32)
+M: System.Int32 OpenAL.AL10::alGetInteger(System.Int32)
+M: System.Single OpenAL.AL10::alGetFloat(System.Int32)
+M: System.Double OpenAL.AL10::alGetDouble(System.Int32)
+M: System.Int32 OpenAL.AL10::alGetError()
+M: System.Boolean OpenAL.AL10::alIsExtensionPresent(System.String)
+M: System.IntPtr OpenAL.AL10::alGetProcAddress(System.String)
+M: System.Int32 OpenAL.AL10::alGetEnumValue(System.String)
+M: System.Void OpenAL.AL10::alListenerf(System.Int32,System.Single)
+M: System.Void OpenAL.AL10::alListener3f(System.Int32,System.Single,System.Single,System.Single)
+M: System.Void OpenAL.AL10::alListenerfv(System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alListeneri(System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alListener3i(System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alListeneriv(System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGetListenerf(System.Int32,System.Single&)
+M: System.Void OpenAL.AL10::alGetListener3f(System.Int32,System.Single&,System.Single&,System.Single&)
+M: System.Void OpenAL.AL10::alGetListenerfv(System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alGetListeneri(System.Int32,System.Int32&)
+M: System.Void OpenAL.AL10::alGetListener3i(System.Int32,System.Int32&,System.Int32&,System.Int32&)
+M: System.Void OpenAL.AL10::alGetListeneriv(System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGenSources(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alGenSources(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.AL10::alDeleteSources(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alDeleteSources(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.AL10::alIsSource(System.UInt32)
+M: System.Void OpenAL.AL10::alSourcef(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.AL10::alSource3f(System.UInt32,System.Int32,System.Single,System.Single,System.Single)
+M: System.Void OpenAL.AL10::alSourcefv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alSourcei(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alSource3i(System.UInt32,System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alSourceiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGetSourcef(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.AL10::alGetSource3f(System.UInt32,System.Int32,System.Single&,System.Single&,System.Single&)
+M: System.Void OpenAL.AL10::alGetSourcefv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alGetSourcei(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.AL10::alGetSource3i(System.UInt32,System.Int32,System.Int32&,System.Int32&,System.Int32&)
+M: System.Void OpenAL.AL10::alGetSourceiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alSourcePlayv(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourceStopv(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourceRewindv(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourcePausev(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourcePlay(System.UInt32)
+M: System.Void OpenAL.AL10::alSourceStop(System.UInt32)
+M: System.Void OpenAL.AL10::alSourceRewind(System.UInt32)
+M: System.Void OpenAL.AL10::alSourcePause(System.UInt32)
+M: System.Void OpenAL.AL10::alSourceQueueBuffers(System.UInt32,System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourceQueueBuffers(System.UInt32,System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.AL10::alSourceUnqueueBuffers(System.UInt32,System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alSourceUnqueueBuffers(System.UInt32,System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.AL10::alGenBuffers(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alGenBuffers(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.AL10::alDeleteBuffers(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.AL10::alDeleteBuffers(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.AL10::alIsBuffer(System.UInt32)
+M: System.Void OpenAL.AL10::alBufferData(System.UInt32,System.Int32,System.Byte[],System.IntPtr,System.IntPtr)
+M: System.Void OpenAL.AL10::alBufferData(System.UInt32,System.Int32,System.Int16[],System.IntPtr,System.IntPtr)
+M: System.Void OpenAL.AL10::alBufferData(System.UInt32,System.Int32,System.Single[],System.IntPtr,System.IntPtr)
+M: System.Void OpenAL.AL10::alBufferf(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.AL10::alBuffer3f(System.UInt32,System.Int32,System.Single,System.Single,System.Single)
+M: System.Void OpenAL.AL10::alBufferfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alBufferi(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alBuffer3i(System.UInt32,System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.Void OpenAL.AL10::alBufferiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.AL10::alGetBufferf(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.AL10::alGetBuffer3f(System.UInt32,System.Int32,System.Single&,System.Single&,System.Single&)
+M: System.Void OpenAL.AL10::alGetBufferfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.AL10::alGetBufferi(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.AL10::alGetBuffer3i(System.UInt32,System.Int32,System.Int32&,System.Int32&,System.Int32&)
+M: System.Void OpenAL.AL10::alGetBufferiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.ALEXT::alGetBufferSamplesSOFT(System.UInt32,System.Int32,System.Int32,System.Int32,System.Int32,System.IntPtr)
+M: System.Void OpenAL.EFX::alGenEffects(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alGenEffects(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.EFX::alDeleteEffects(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alDeleteEffects(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.EFX::alIsEffect(System.UInt32)
+M: System.Void OpenAL.EFX::alEffecti(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.EFX::alEffectiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alEffectf(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.EFX::alEffectfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGetEffecti(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.EFX::alGetEffectiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alGetEffectf(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.EFX::alGetEffectfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGenFilters(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alGenFilters(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.EFX::alDeleteFilters(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alDeleteFilters(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.EFX::alIsFilter(System.UInt32)
+M: System.Void OpenAL.EFX::alFilteri(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.EFX::alFilteriv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alFilterf(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.EFX::alFilterfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGetFilteri(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.EFX::alGetFilteriv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alGetFilterf(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.EFX::alGetFilterfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGenAuxiliaryEffectSlots(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alGenAuxiliaryEffectSlots(System.IntPtr,System.UInt32&)
+M: System.Void OpenAL.EFX::alDeleteAuxiliaryEffectSlots(System.IntPtr,System.UInt32[])
+M: System.Void OpenAL.EFX::alDeleteAuxiliaryEffectSlots(System.IntPtr,System.UInt32&)
+M: System.Boolean OpenAL.EFX::alIsAuxiliaryEffectSlot(System.UInt32)
+M: System.Void OpenAL.EFX::alAuxiliaryEffectSloti(System.UInt32,System.Int32,System.Int32)
+M: System.Void OpenAL.EFX::alAuxiliaryEffectSlotiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alAuxiliaryEffectSlotf(System.UInt32,System.Int32,System.Single)
+M: System.Void OpenAL.EFX::alAuxiliaryEffectSlotfv(System.UInt32,System.Int32,System.Single[])
+M: System.Void OpenAL.EFX::alGetAuxiliaryEffectSloti(System.UInt32,System.Int32,System.Int32&)
+M: System.Void OpenAL.EFX::alGetAuxiliaryEffectSlotiv(System.UInt32,System.Int32,System.Int32[])
+M: System.Void OpenAL.EFX::alGetAuxiliaryEffectSlotf(System.UInt32,System.Int32,System.Single&)
+M: System.Void OpenAL.EFX::alGetAuxiliaryEffectSlotfv(System.UInt32,System.Int32,System.Single[])
+
diff --git a/gendarme/runGendarme.sh b/gendarme/runGendarme.sh
new file mode 100755
index 0000000..9019789
--- /dev/null
+++ b/gendarme/runGendarme.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# Filename of the FNA assembly output
+ASSEMBLYNAME="../bin/Debug/FNA.dll"
+
+# Move to script's directory
+cd "`dirname "$0"`"
+
+# Run Gendarme using the FNA ruleset
+gendarme --ignore fna.ignore --html gendarme.html $ASSEMBLYNAME
diff --git a/gendarme/sdl2.ignore b/gendarme/sdl2.ignore
new file mode 100644
index 0000000..55a1ea1
--- /dev/null
+++ b/gendarme/sdl2.ignore
@@ -0,0 +1,1527 @@
+R: Gendarme.Rules.Design.Generic.AvoidDeclaringCustomDelegatesRule
+T: SDL2.SDL/SDL_LogOutputFunction
+T: SDL2.SDL/SDL_EventFilter
+T: SDL2.SDL/SDL_AudioCallback
+T: SDL2.SDL/SDL_TimerCallback
+T: SDL2.SDL_mixer/MixFuncDelegate
+T: SDL2.SDL_mixer/Mix_EffectFunc_t
+T: SDL2.SDL_mixer/Mix_EffectDone_t
+T: SDL2.SDL_mixer/MusicFinishedDelegate
+T: SDL2.SDL_mixer/ChannelFinishedDelegate
+T: SDL2.SDL_mixer/SoundFontDelegate
+
+R: Gendarme.Rules.Performance.AvoidLargeStructureRule
+T: SDL2.SDL/SDL_PixelFormat
+T: SDL2.SDL/SDL_Surface
+T: SDL2.SDL/SDL_MouseMotionEvent
+T: SDL2.SDL/SDL_TouchFingerEvent
+T: SDL2.SDL/SDL_MultiGestureEvent
+T: SDL2.SDL/SDL_DollarGestureEvent
+T: SDL2.SDL/SDL_Event
+T: SDL2.SDL/SDL_HapticPeriodic
+T: SDL2.SDL/SDL_HapticCondition
+T: SDL2.SDL/SDL_HapticRamp
+T: SDL2.SDL/SDL_HapticCustom
+T: SDL2.SDL/SDL_HapticEffect
+T: SDL2.SDL/SDL_SysWMinfo
+
+R: Gendarme.Rules.Naming.AvoidNonAlphanumericIdentifierRule
+T: SDL2.SDL
+M: System.UInt32 SDL2.SDL::SDL_FOURCC(System.Byte,System.Byte,System.Byte,System.Byte)
+M: System.IntPtr SDL2.SDL::SDL_RWFromMem(System.Byte[],System.Int32)
+M: System.Void SDL2.SDL::SDL_SetMainReady()
+M: System.Int32 SDL2.SDL::SDL_Init(System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_InitSubSystem(System.UInt32)
+M: System.Void SDL2.SDL::SDL_Quit()
+M: System.Void SDL2.SDL::SDL_QuitSubSystem(System.UInt32)
+M: System.UInt32 SDL2.SDL::SDL_WasInit(System.UInt32)
+M: System.String SDL2.SDL::SDL_GetPlatform()
+M: System.Void SDL2.SDL::SDL_ClearHints()
+M: System.String SDL2.SDL::SDL_GetHint(System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_SetHint(System.String,System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_SetHintWithPriority(System.String,System.String,SDL2.SDL/SDL_HintPriority)
+M: System.Void SDL2.SDL::SDL_ClearError()
+M: System.String SDL2.SDL::SDL_GetError()
+M: System.Void SDL2.SDL::SDL_SetError(System.String)
+M: System.Void SDL2.SDL::SDL_Log(System.String)
+M: System.Void SDL2.SDL::SDL_LogVerbose(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogDebug(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogInfo(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogWarn(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogError(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogCritical(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogMessage(System.Int32,SDL2.SDL/SDL_LogPriority,System.String)
+M: System.Void SDL2.SDL::SDL_LogMessageV(System.Int32,SDL2.SDL/SDL_LogPriority,System.String)
+M: SDL2.SDL/SDL_LogPriority SDL2.SDL::SDL_LogGetPriority(System.Int32)
+M: System.Void SDL2.SDL::SDL_LogSetPriority(System.Int32,SDL2.SDL/SDL_LogPriority)
+M: System.Void SDL2.SDL::SDL_LogSetAllPriority(SDL2.SDL/SDL_LogPriority)
+M: System.Void SDL2.SDL::SDL_LogResetPriorities()
+M: System.Void SDL2.SDL::SDL_LogGetOutputFunction(SDL2.SDL/SDL_LogOutputFunction&,System.IntPtr&)
+M: System.Void SDL2.SDL::SDL_LogSetOutputFunction(SDL2.SDL/SDL_LogOutputFunction,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_ShowMessageBox(SDL2.SDL/SDL_MessageBoxData&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_ShowSimpleMessageBox(SDL2.SDL/SDL_MessageBoxFlags,System.String,System.String,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_VERSION(SDL2.SDL/SDL_version&)
+M: System.Int32 SDL2.SDL::SDL_VERSIONNUM(System.Int32,System.Int32,System.Int32)
+M: System.Boolean SDL2.SDL::SDL_VERSION_ATLEAST(System.Int32,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_GetVersion(SDL2.SDL/SDL_version&)
+M: System.String SDL2.SDL::SDL_GetRevision()
+M: System.Int32 SDL2.SDL::SDL_GetRevisionNumber()
+M: System.Int32 SDL2.SDL::SDL_WINDOWPOS_UNDEFINED_DISPLAY(System.Int32)
+M: System.Boolean SDL2.SDL::SDL_WINDOWPOS_ISUNDEFINED(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_WINDOWPOS_CENTERED_DISPLAY(System.Int32)
+M: System.Boolean SDL2.SDL::SDL_WINDOWPOS_ISCENTERED(System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_CreateWindow(System.String,System.Int32,System.Int32,System.Int32,System.Int32,SDL2.SDL/SDL_WindowFlags)
+M: System.Int32 SDL2.SDL::SDL_CreateWindowAndRenderer(System.Int32,System.Int32,SDL2.SDL/SDL_WindowFlags,System.IntPtr&,System.IntPtr&)
+M: System.IntPtr SDL2.SDL::SDL_CreateWindowFrom(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DestroyWindow(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DisableScreenSaver()
+M: System.Void SDL2.SDL::SDL_EnableScreenSaver()
+M: System.IntPtr SDL2.SDL::SDL_GetClosestDisplayMode(System.Int32,SDL2.SDL/SDL_DisplayMode&,SDL2.SDL/SDL_DisplayMode&)
+M: System.Int32 SDL2.SDL::SDL_GetCurrentDisplayMode(System.Int32,SDL2.SDL/SDL_DisplayMode&)
+M: System.String SDL2.SDL::SDL_GetCurrentVideoDriver()
+M: System.Int32 SDL2.SDL::SDL_GetDesktopDisplayMode(System.Int32,SDL2.SDL/SDL_DisplayMode&)
+M: System.Int32 SDL2.SDL::SDL_GetDisplayBounds(System.Int32,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_GetDisplayMode(System.Int32,System.Int32,SDL2.SDL/SDL_DisplayMode&)
+M: System.Int32 SDL2.SDL::SDL_GetNumDisplayModes(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GetNumVideoDisplays()
+M: System.Int32 SDL2.SDL::SDL_GetNumVideoDrivers()
+M: System.String SDL2.SDL::SDL_GetVideoDriver(System.Int32)
+M: System.Single SDL2.SDL::SDL_GetWindowBrightness(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetWindowData(System.IntPtr,System.String)
+M: System.Int32 SDL2.SDL::SDL_GetWindowDisplayIndex(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GetWindowDisplayMode(System.IntPtr,SDL2.SDL/SDL_DisplayMode&)
+M: System.UInt32 SDL2.SDL::SDL_GetWindowFlags(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetWindowFromID(System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_GetWindowGammaRamp(System.IntPtr,System.UInt16[],System.UInt16[],System.UInt16[])
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GetWindowGrab(System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_GetWindowID(System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_GetWindowPixelFormat(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_GetWindowMaximumSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_GetWindowMinimumSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_GetWindowPosition(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_GetWindowSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.IntPtr SDL2.SDL::SDL_GetWindowSurface(System.IntPtr)
+M: System.String SDL2.SDL::SDL_GetWindowTitle(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GL_BindTexture(System.IntPtr,System.Single&,System.Single&)
+M: System.IntPtr SDL2.SDL::SDL_GL_CreateContext(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_GL_DeleteContext(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GL_GetProcAddress(System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GL_ExtensionSupported(System.String)
+M: System.Void SDL2.SDL::SDL_GL_ResetAttributes()
+M: System.Int32 SDL2.SDL::SDL_GL_GetAttribute(SDL2.SDL/SDL_GLattr,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_GL_GetSwapInterval()
+M: System.Int32 SDL2.SDL::SDL_GL_MakeCurrent(System.IntPtr,System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GL_GetCurrentWindow()
+M: System.IntPtr SDL2.SDL::SDL_GL_GetCurrentContext()
+M: System.Void SDL2.SDL::SDL_GL_GetDrawableSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_GL_SetAttribute(SDL2.SDL/SDL_GLattr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GL_SetSwapInterval(System.Int32)
+M: System.Void SDL2.SDL::SDL_GL_SwapWindow(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GL_UnbindTexture(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_HideWindow(System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IsScreenSaverEnabled()
+M: System.Void SDL2.SDL::SDL_MaximizeWindow(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_MinimizeWindow(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_RaiseWindow(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_RestoreWindow(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_SetWindowBrightness(System.IntPtr,System.Single)
+M: System.IntPtr SDL2.SDL::SDL_SetWindowData(System.IntPtr,System.String,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_SetWindowDisplayMode(System.IntPtr,SDL2.SDL/SDL_DisplayMode&)
+M: System.Int32 SDL2.SDL::SDL_SetWindowFullscreen(System.IntPtr,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_SetWindowGammaRamp(System.IntPtr,System.UInt16[],System.UInt16[],System.UInt16[])
+M: System.Void SDL2.SDL::SDL_SetWindowGrab(System.IntPtr,SDL2.SDL/SDL_bool)
+M: System.Void SDL2.SDL::SDL_SetWindowIcon(System.IntPtr,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_SetWindowMaximumSize(System.IntPtr,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_SetWindowMinimumSize(System.IntPtr,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_SetWindowPosition(System.IntPtr,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_SetWindowSize(System.IntPtr,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_SetWindowBordered(System.IntPtr,SDL2.SDL/SDL_bool)
+M: System.Void SDL2.SDL::SDL_SetWindowTitle(System.IntPtr,System.String)
+M: System.Void SDL2.SDL::SDL_ShowWindow(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_UpdateWindowSurface(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_UpdateWindowSurfaceRects(System.IntPtr,SDL2.SDL/SDL_Rect[],System.Int32)
+M: System.Int32 SDL2.SDL::SDL_VideoInit(System.String)
+M: System.Void SDL2.SDL::SDL_VideoQuit()
+M: System.IntPtr SDL2.SDL::SDL_CreateRenderer(System.IntPtr,System.Int32,SDL2.SDL/SDL_RendererFlags)
+M: System.IntPtr SDL2.SDL::SDL_CreateSoftwareRenderer(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_CreateTexture(System.IntPtr,System.UInt32,System.Int32,System.Int32,System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_CreateTextureFromSurface(System.IntPtr,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DestroyRenderer(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DestroyTexture(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GetNumRenderDrivers()
+M: System.Int32 SDL2.SDL::SDL_GetRenderDrawBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode&)
+M: System.Int32 SDL2.SDL::SDL_GetRenderDrawColor(System.IntPtr,System.Byte&,System.Byte&,System.Byte&,System.Byte&)
+M: System.Int32 SDL2.SDL::SDL_GetRenderDriverInfo(System.Int32,SDL2.SDL/SDL_RendererInfo&)
+M: System.IntPtr SDL2.SDL::SDL_GetRenderer(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GetRendererInfo(System.IntPtr,SDL2.SDL/SDL_RendererInfo&)
+M: System.Int32 SDL2.SDL::SDL_GetRendererOutputSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_GetTextureAlphaMod(System.IntPtr,System.Byte&)
+M: System.Int32 SDL2.SDL::SDL_GetTextureBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode&)
+M: System.Int32 SDL2.SDL::SDL_GetTextureColorMod(System.IntPtr,System.Byte&,System.Byte&,System.Byte&)
+M: System.Int32 SDL2.SDL::SDL_LockTexture(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_LockTexture(System.IntPtr,System.IntPtr,System.IntPtr&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_QueryTexture(System.IntPtr,System.UInt32&,System.Int32&,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_QueryTexturePixels(System.IntPtr,System.IntPtr&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_RenderClear(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderCopy(System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderCopy(System.IntPtr,System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderCopy(System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderCopy(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderCopyEx(System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&,System.Double,SDL2.SDL/SDL_Point&,SDL2.SDL/SDL_RendererFlip)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawLine(System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawLines(System.IntPtr,SDL2.SDL/SDL_Point[],System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawPoint(System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawPoints(System.IntPtr,SDL2.SDL/SDL_Point[],System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawRect(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawRects(System.IntPtr,SDL2.SDL/SDL_Rect[],System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderFillRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderFillRect(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderFillRects(System.IntPtr,SDL2.SDL/SDL_Rect[],System.Int32)
+M: System.Void SDL2.SDL::SDL_RenderGetClipRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_RenderGetLogicalSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_RenderGetScale(System.IntPtr,System.Single&,System.Single&)
+M: System.Int32 SDL2.SDL::SDL_RenderGetViewport(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_RenderPresent(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderReadPixels(System.IntPtr,SDL2.SDL/SDL_Rect&,System.UInt32,System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderSetClipRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderSetClipRect(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderSetLogicalSize(System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderSetScale(System.IntPtr,System.Single,System.Single)
+M: System.Int32 SDL2.SDL::SDL_RenderSetViewport(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_SetRenderDrawBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode)
+M: System.Int32 SDL2.SDL::SDL_SetRenderDrawColor(System.IntPtr,System.Byte,System.Byte,System.Byte,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_SetRenderTarget(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_SetTextureAlphaMod(System.IntPtr,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_SetTextureBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode)
+M: System.Int32 SDL2.SDL::SDL_SetTextureColorMod(System.IntPtr,System.Byte,System.Byte,System.Byte)
+M: System.Void SDL2.SDL::SDL_UnlockTexture(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_UpdateTexture(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,System.Int32)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RenderTargetSupported(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetRenderTarget(System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_DEFINE_PIXELFOURCC(System.Byte,System.Byte,System.Byte,System.Byte)
+M: System.UInt32 SDL2.SDL::SDL_DEFINE_PIXELFORMAT(SDL2.SDL/SDL_PIXELTYPE_ENUM,SDL2.SDL/SDL_PIXELORDER_ENUM,SDL2.SDL/SDL_PACKEDLAYOUT_ENUM,System.Byte,System.Byte)
+M: System.Byte SDL2.SDL::SDL_PIXELFLAG(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_PIXELTYPE(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_PIXELORDER(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_PIXELLAYOUT(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_BITSPERPIXEL(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_BYTESPERPIXEL(System.UInt32)
+M: System.Boolean SDL2.SDL::SDL_ISPIXELFORMAT_INDEXED(System.UInt32)
+M: System.Boolean SDL2.SDL::SDL_ISPIXELFORMAT_ALPHA(System.UInt32)
+M: System.Boolean SDL2.SDL::SDL_ISPIXELFORMAT_FOURCC(System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_AllocFormat(System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_AllocPalette(System.Int32)
+M: System.Void SDL2.SDL::SDL_CalculateGammaRamp(System.Single,System.UInt16[])
+M: System.Void SDL2.SDL::SDL_FreeFormat(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_FreePalette(System.IntPtr)
+M: System.String SDL2.SDL::SDL_GetPixelFormatName(System.UInt32)
+M: System.Void SDL2.SDL::SDL_GetRGB(System.UInt32,System.IntPtr,System.Byte&,System.Byte&,System.Byte&)
+M: System.Void SDL2.SDL::SDL_GetRGBA(System.UInt32,System.IntPtr,System.Byte&,System.Byte&,System.Byte&,System.Byte&)
+M: System.UInt32 SDL2.SDL::SDL_MapRGB(System.IntPtr,System.Byte,System.Byte,System.Byte)
+M: System.UInt32 SDL2.SDL::SDL_MapRGBA(System.IntPtr,System.Byte,System.Byte,System.Byte,System.Byte)
+M: System.UInt32 SDL2.SDL::SDL_MasksToPixelFormatEnum(System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_PixelFormatEnumToMasks(System.UInt32,System.Int32&,System.UInt32&,System.UInt32&,System.UInt32&,System.UInt32&)
+M: System.Int32 SDL2.SDL::SDL_SetPaletteColors(System.IntPtr,SDL2.SDL/SDL_Color[],System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_SetPixelFormatPalette(System.IntPtr,System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_EnclosePoints(SDL2.SDL/SDL_Point[],System.Int32,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasIntersection(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IntersectRect(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IntersectRectAndLine(SDL2.SDL/SDL_Rect&,System.Int32&,System.Int32&,System.Int32&,System.Int32&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RectEmpty(SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RectEquals(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_UnionRect(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: System.Boolean SDL2.SDL::SDL_MUSTLOCK(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_BlitSurface(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitSurface(System.IntPtr,System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitSurface(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_BlitSurface(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_BlitScaled(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitScaled(System.IntPtr,System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitScaled(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_BlitScaled(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_ConvertPixels(System.Int32,System.Int32,System.UInt32,System.IntPtr,System.Int32,System.UInt32,System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_ConvertSurface(System.IntPtr,System.IntPtr,System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_ConvertSurfaceFormat(System.IntPtr,System.UInt32,System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_CreateRGBSurface(System.UInt32,System.Int32,System.Int32,System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_CreateRGBSurfaceFrom(System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_FillRect(System.IntPtr,SDL2.SDL/SDL_Rect&,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_FillRects(System.IntPtr,SDL2.SDL/SDL_Rect[],System.Int32,System.UInt32)
+M: System.Void SDL2.SDL::SDL_FreeSurface(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_GetClipRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_GetColorKey(System.IntPtr,System.UInt32&)
+M: System.Int32 SDL2.SDL::SDL_GetSurfaceAlphaMod(System.IntPtr,System.Byte&)
+M: System.Int32 SDL2.SDL::SDL_GetSurfaceBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode&)
+M: System.Int32 SDL2.SDL::SDL_GetSurfaceColorMod(System.IntPtr,System.Byte&,System.Byte&,System.Byte&)
+M: System.IntPtr SDL2.SDL::SDL_LoadBMP(System.String)
+M: System.Int32 SDL2.SDL::SDL_LockSurface(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_LowerBlit(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_LowerBlitScaled(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_SaveBMP(System.IntPtr,System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_SetClipRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_SetColorKey(System.IntPtr,System.Int32,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_SetSurfaceAlphaMod(System.IntPtr,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_SetSurfaceBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode)
+M: System.Int32 SDL2.SDL::SDL_SetSurfaceColorMod(System.IntPtr,System.Byte,System.Byte,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_SetSurfacePalette(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_SetSurfaceRLE(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_SoftStretch(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_UnlockSurface(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_UpperBlit(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_UpperBlitScaled(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasClipboardText()
+M: System.String SDL2.SDL::SDL_GetClipboardText()
+M: System.Int32 SDL2.SDL::SDL_SetClipboardText(System.String)
+M: System.Void SDL2.SDL::SDL_PumpEvents()
+M: System.Int32 SDL2.SDL::SDL_PeepEvents(SDL2.SDL/SDL_Event[],System.Int32,SDL2.SDL/SDL_eventaction,SDL2.SDL/SDL_EventType,SDL2.SDL/SDL_EventType)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasEvent(SDL2.SDL/SDL_EventType)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasEvents(SDL2.SDL/SDL_EventType,SDL2.SDL/SDL_EventType)
+M: System.Void SDL2.SDL::SDL_FlushEvent(SDL2.SDL/SDL_EventType)
+M: System.Void SDL2.SDL::SDL_FlushEvents(SDL2.SDL/SDL_EventType,SDL2.SDL/SDL_EventType)
+M: System.Int32 SDL2.SDL::SDL_PollEvent(SDL2.SDL/SDL_Event&)
+M: System.Int32 SDL2.SDL::SDL_WaitEvent(SDL2.SDL/SDL_Event&)
+M: System.Int32 SDL2.SDL::SDL_WaitEventTimeout(SDL2.SDL/SDL_Event&,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_PushEvent(SDL2.SDL/SDL_Event&)
+M: System.Void SDL2.SDL::SDL_SetEventFilter(SDL2.SDL/SDL_EventFilter,System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GetEventFilter(SDL2.SDL/SDL_EventFilter&,System.IntPtr&)
+M: System.Void SDL2.SDL::SDL_AddEventWatch(SDL2.SDL/SDL_EventFilter,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DelEventWatch(SDL2.SDL/SDL_EventFilter,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_FilterEvents(SDL2.SDL/SDL_EventFilter,System.IntPtr)
+M: System.Byte SDL2.SDL::SDL_EventState(SDL2.SDL/SDL_EventType,System.Int32)
+M: System.Byte SDL2.SDL::SDL_GetEventState(SDL2.SDL/SDL_EventType)
+M: System.UInt32 SDL2.SDL::SDL_RegisterEvents(System.Int32)
+M: SDL2.SDL/SDL_Keycode SDL2.SDL::SDL_SCANCODE_TO_KEYCODE(SDL2.SDL/SDL_Scancode)
+M: System.IntPtr SDL2.SDL::SDL_GetKeyboardFocus()
+M: System.IntPtr SDL2.SDL::SDL_GetKeyboardState(System.Int32&)
+M: SDL2.SDL/SDL_Keymod SDL2.SDL::SDL_GetModState()
+M: System.Void SDL2.SDL::SDL_SetModState(SDL2.SDL/SDL_Keymod)
+M: SDL2.SDL/SDL_Keycode SDL2.SDL::SDL_GetKeyFromScancode(SDL2.SDL/SDL_Scancode)
+M: SDL2.SDL/SDL_Scancode SDL2.SDL::SDL_GetScancodeFromKey(SDL2.SDL/SDL_Keycode)
+M: System.String SDL2.SDL::SDL_GetScancodeName(SDL2.SDL/SDL_Scancode)
+M: SDL2.SDL/SDL_Scancode SDL2.SDL::SDL_GetScancodeFromName(System.String)
+M: System.String SDL2.SDL::SDL_GetKeyName(SDL2.SDL/SDL_Keycode)
+M: SDL2.SDL/SDL_Keycode SDL2.SDL::SDL_GetKeyFromName(System.String)
+M: System.Void SDL2.SDL::SDL_StartTextInput()
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IsTextInputActive()
+M: System.Void SDL2.SDL::SDL_StopTextInput()
+M: System.Void SDL2.SDL::SDL_SetTextInputRect(SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasScreenKeyboardSupport()
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IsScreenKeyboardShown(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetMouseFocus()
+M: System.UInt32 SDL2.SDL::SDL_GetMouseState(System.Int32&,System.Int32&)
+M: System.UInt32 SDL2.SDL::SDL_GetMouseState(System.IntPtr,System.Int32&)
+M: System.UInt32 SDL2.SDL::SDL_GetMouseState(System.Int32&,System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_GetMouseState(System.IntPtr,System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_GetRelativeMouseState(System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_WarpMouseInWindow(System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_SetRelativeMouseMode(SDL2.SDL/SDL_bool)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GetRelativeMouseMode()
+M: System.IntPtr SDL2.SDL::SDL_CreateCursor(System.IntPtr,System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_CreateColorCursor(System.IntPtr,System.Int32,System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_CreateSystemCursor(SDL2.SDL/SDL_SystemCursor)
+M: System.Void SDL2.SDL::SDL_SetCursor(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetCursor()
+M: System.Void SDL2.SDL::SDL_FreeCursor(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_ShowCursor(System.Int32)
+M: System.UInt32 SDL2.SDL::SDL_BUTTON(System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_GetNumTouchDevices()
+M: System.Int64 SDL2.SDL::SDL_GetTouchDevice(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GetNumTouchFingers(System.Int64)
+M: System.IntPtr SDL2.SDL::SDL_GetTouchFinger(System.Int64,System.Int32)
+M: System.Void SDL2.SDL::SDL_JoystickClose(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickEventState(System.Int32)
+M: System.Int16 SDL2.SDL::SDL_JoystickGetAxis(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_JoystickGetBall(System.IntPtr,System.Int32,System.Int32&,System.Int32&)
+M: System.Byte SDL2.SDL::SDL_JoystickGetButton(System.IntPtr,System.Int32)
+M: System.Byte SDL2.SDL::SDL_JoystickGetHat(System.IntPtr,System.Int32)
+M: System.String SDL2.SDL::SDL_JoystickName(System.IntPtr)
+M: System.String SDL2.SDL::SDL_JoystickNameForIndex(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_JoystickNumAxes(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickNumBalls(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickNumButtons(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickNumHats(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_JoystickOpen(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_JoystickOpened(System.Int32)
+M: System.Void SDL2.SDL::SDL_JoystickUpdate()
+M: System.Int32 SDL2.SDL::SDL_NumJoysticks()
+M: System.Guid SDL2.SDL::SDL_JoystickGetDeviceGUID(System.Int32)
+M: System.Guid SDL2.SDL::SDL_JoystickGetGUID(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_JoystickGetGUIDString(System.Guid,System.Byte[],System.Int32)
+M: System.Guid SDL2.SDL::SDL_JoystickGetGUIDFromString(System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_JoystickGetAttached(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickInstanceID(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GameControllerAddMapping(System.String)
+M: System.Int32 SDL2.SDL::SDL_GameControllerAddMappingsFromFile(System.String)
+M: System.String SDL2.SDL::SDL_GameControllerMappingForGUID(System.Guid)
+M: System.String SDL2.SDL::SDL_GameControllerMapping(System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IsGameController(System.Int32)
+M: System.String SDL2.SDL::SDL_GameControllerNameForIndex(System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_GameControllerOpen(System.Int32)
+M: System.String SDL2.SDL::SDL_GameControllerName(System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GameControllerGetAttached(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GameControllerGetJoystick(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GameControllerEventState(System.Int32)
+M: System.Void SDL2.SDL::SDL_GameControllerUpdate()
+M: SDL2.SDL/SDL_GameControllerAxis SDL2.SDL::SDL_GameControllerGetAxisFromString(System.String)
+M: System.String SDL2.SDL::SDL_GameControllerGetStringForAxis(SDL2.SDL/SDL_GameControllerAxis)
+M: SDL2.SDL/SDL_GameControllerButtonBind SDL2.SDL::SDL_GameControllerGetBindForAxis(System.IntPtr,SDL2.SDL/SDL_GameControllerAxis)
+M: System.Int16 SDL2.SDL::SDL_GameControllerGetAxis(System.IntPtr,SDL2.SDL/SDL_GameControllerAxis)
+M: SDL2.SDL/SDL_GameControllerButton SDL2.SDL::SDL_GameControllerGetButtonFromString(System.String)
+M: System.String SDL2.SDL::SDL_GameControllerGetStringForButton(SDL2.SDL/SDL_GameControllerButton)
+M: SDL2.SDL/SDL_GameControllerButtonBind SDL2.SDL::SDL_GameControllerGetBindForButton(System.IntPtr,SDL2.SDL/SDL_GameControllerButton)
+M: System.Byte SDL2.SDL::SDL_GameControllerGetButton(System.IntPtr,SDL2.SDL/SDL_GameControllerButton)
+M: System.Void SDL2.SDL::SDL_GameControllerClose(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_HapticClose(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_HapticDestroyEffect(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticEffectSupported(System.IntPtr,SDL2.SDL/SDL_HapticEffect&)
+M: System.Int32 SDL2.SDL::SDL_HapticGetEffectStatus(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticIndex(System.IntPtr)
+M: System.String SDL2.SDL::SDL_HapticName(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticNewEffect(System.IntPtr,SDL2.SDL/SDL_HapticEffect&)
+M: System.Int32 SDL2.SDL::SDL_HapticNumAxes(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticNumEffects(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticNumEffectsPlaying(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_HapticOpen(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticOpened(System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_HapticOpenFromJoystick(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_HapticOpenFromMouse()
+M: System.Int32 SDL2.SDL::SDL_HapticPause(System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_HapticQuery(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticRumbleInit(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticRumblePlay(System.IntPtr,System.Single,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_HapticRumbleStop(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticRumbleSupported(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticRunEffect(System.IntPtr,System.Int32,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_HapticSetAutocenter(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticSetGain(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticStopAll(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticStopEffect(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticUnpause(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticUpdateEffect(System.IntPtr,System.Int32,SDL2.SDL/SDL_HapticEffect&)
+M: System.Int32 SDL2.SDL::SDL_JoystickIsHaptic(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_MouseIsHaptic()
+M: System.Int32 SDL2.SDL::SDL_NumHaptics()
+M: System.UInt16 SDL2.SDL::SDL_AUDIO_BITSIZE(System.UInt16)
+M: System.Boolean SDL2.SDL::SDL_AUDIO_ISFLOAT(System.UInt16)
+M: System.Boolean SDL2.SDL::SDL_AUDIO_ISBIGENDIAN(System.UInt16)
+M: System.Boolean SDL2.SDL::SDL_AUDIO_ISSIGNED(System.UInt16)
+M: System.Boolean SDL2.SDL::SDL_AUDIO_ISINT(System.UInt16)
+M: System.Boolean SDL2.SDL::SDL_AUDIO_ISLITTLEENDIAN(System.UInt16)
+M: System.Boolean SDL2.SDL::SDL_AUDIO_ISUNSIGNED(System.UInt16)
+M: System.Int32 SDL2.SDL::SDL_AudioDeviceConnected(System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_AudioInit(System.String)
+M: System.Void SDL2.SDL::SDL_AudioQuit()
+M: System.Void SDL2.SDL::SDL_CloseAudio()
+M: System.Void SDL2.SDL::SDL_CloseAudioDevice(System.UInt32)
+M: System.Void SDL2.SDL::SDL_FreeWAV(System.IntPtr)
+M: System.String SDL2.SDL::SDL_GetAudioDeviceName(System.Int32,System.Int32)
+M: SDL2.SDL/SDL_AudioStatus SDL2.SDL::SDL_GetAudioDeviceStatus(System.UInt32)
+M: System.String SDL2.SDL::SDL_GetAudioDriver(System.Int32)
+M: SDL2.SDL/SDL_AudioStatus SDL2.SDL::SDL_GetAudioStatus()
+M: System.String SDL2.SDL::SDL_GetCurrentAudioDriver()
+M: System.Int32 SDL2.SDL::SDL_GetNumAudioDevices(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GetNumAudioDrivers()
+M: SDL2.SDL/SDL_AudioSpec SDL2.SDL::SDL_LoadWAV(System.String,SDL2.SDL/SDL_AudioSpec&,System.IntPtr&,System.UInt32&)
+M: System.Void SDL2.SDL::SDL_LockAudio()
+M: System.Void SDL2.SDL::SDL_LockAudioDevice(System.UInt32)
+M: System.Void SDL2.SDL::SDL_MixAudio(System.Byte[],System.Byte[],System.UInt32,System.Int32)
+M: System.Void SDL2.SDL::SDL_MixAudioFormat(System.Byte[],System.Byte[],System.UInt16,System.UInt32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_OpenAudio(SDL2.SDL/SDL_AudioSpec&,SDL2.SDL/SDL_AudioSpec&)
+M: System.UInt32 SDL2.SDL::SDL_OpenAudioDevice(System.String,System.Int32,SDL2.SDL/SDL_AudioSpec&,SDL2.SDL/SDL_AudioSpec&,System.Int32)
+M: System.Void SDL2.SDL::SDL_PauseAudio(System.Int32)
+M: System.Void SDL2.SDL::SDL_PauseAudioDevice(System.UInt32,System.Int32)
+M: System.Void SDL2.SDL::SDL_UnlockAudio()
+M: System.Void SDL2.SDL::SDL_UnlockAudioDevice(System.UInt32)
+M: System.Boolean SDL2.SDL::SDL_TICKS_PASSED(System.UInt32,System.UInt32)
+M: System.Void SDL2.SDL::SDL_Delay(System.UInt32)
+M: System.UInt32 SDL2.SDL::SDL_GetTicks()
+M: System.UInt64 SDL2.SDL::SDL_GetPerformanceCounter()
+M: System.UInt64 SDL2.SDL::SDL_GetPerformanceFrequency()
+M: System.Int32 SDL2.SDL::SDL_AddTimer(System.UInt32,SDL2.SDL/SDL_TimerCallback,System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RemoveTimer(System.Int32)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GetWindowWMInfo(System.IntPtr,SDL2.SDL/SDL_SysWMinfo&)
+M: System.String SDL2.SDL::SDL_GetBasePath()
+M: System.String SDL2.SDL::SDL_GetPrefPath(System.String,System.String)
+M: System.Int32 SDL2.SDL::SDL_GetCPUCount()
+M: System.Int32 SDL2.SDL::SDL_GetSystemRAM()
+T: SDL2.SDL/SDL_bool
+T: SDL2.SDL/SDL_HintPriority
+T: SDL2.SDL/SDL_LogPriority
+T: SDL2.SDL/SDL_LogOutputFunction
+T: SDL2.SDL/SDL_MessageBoxFlags
+T: SDL2.SDL/SDL_MessageBoxButtonFlags
+T: SDL2.SDL/SDL_MessageBoxButtonData
+T: SDL2.SDL/SDL_MessageBoxColor
+T: SDL2.SDL/SDL_MessageBoxColorType
+T: SDL2.SDL/SDL_MessageBoxColorScheme
+T: SDL2.SDL/SDL_MessageBoxData
+T: SDL2.SDL/SDL_version
+T: SDL2.SDL/SDL_BlendMode
+T: SDL2.SDL/SDL_GLattr
+T: SDL2.SDL/SDL_GLprofile
+T: SDL2.SDL/SDL_GLcontext
+T: SDL2.SDL/SDL_WindowEventID
+T: SDL2.SDL/SDL_WindowFlags
+T: SDL2.SDL/SDL_DisplayMode
+T: SDL2.SDL/SDL_RendererFlags
+T: SDL2.SDL/SDL_RendererFlip
+T: SDL2.SDL/SDL_TextureAccess
+T: SDL2.SDL/SDL_TextureModulate
+T: SDL2.SDL/SDL_RendererInfo
+T: SDL2.SDL/SDL_PIXELTYPE_ENUM
+T: SDL2.SDL/SDL_PIXELORDER_ENUM
+T: SDL2.SDL/SDL_PACKEDLAYOUT_ENUM
+T: SDL2.SDL/SDL_Color
+T: SDL2.SDL/SDL_Palette
+T: SDL2.SDL/SDL_PixelFormat
+T: SDL2.SDL/SDL_Point
+T: SDL2.SDL/SDL_Rect
+T: SDL2.SDL/SDL_Surface
+T: SDL2.SDL/SDL_EventType
+T: SDL2.SDL/SDL_GenericEvent
+T: SDL2.SDL/SDL_WindowEvent
+T: SDL2.SDL/SDL_KeyboardEvent
+T: SDL2.SDL/SDL_TextEditingEvent
+T: SDL2.SDL/SDL_TextInputEvent
+T: SDL2.SDL/SDL_MouseMotionEvent
+T: SDL2.SDL/SDL_MouseButtonEvent
+T: SDL2.SDL/SDL_MouseWheelEvent
+T: SDL2.SDL/SDL_JoyAxisEvent
+T: SDL2.SDL/SDL_JoyBallEvent
+T: SDL2.SDL/SDL_JoyHatEvent
+T: SDL2.SDL/SDL_JoyButtonEvent
+T: SDL2.SDL/SDL_JoyDeviceEvent
+T: SDL2.SDL/SDL_ControllerAxisEvent
+T: SDL2.SDL/SDL_ControllerButtonEvent
+T: SDL2.SDL/SDL_ControllerDeviceEvent
+T: SDL2.SDL/SDL_TouchFingerEvent
+T: SDL2.SDL/SDL_MultiGestureEvent
+T: SDL2.SDL/SDL_DollarGestureEvent
+T: SDL2.SDL/SDL_DropEvent
+T: SDL2.SDL/SDL_QuitEvent
+T: SDL2.SDL/SDL_UserEvent
+T: SDL2.SDL/SDL_SysWMEvent
+T: SDL2.SDL/SDL_Event
+T: SDL2.SDL/SDL_EventFilter
+T: SDL2.SDL/SDL_eventaction
+T: SDL2.SDL/SDL_Scancode
+T: SDL2.SDL/SDL_Keycode
+T: SDL2.SDL/SDL_Keymod
+T: SDL2.SDL/SDL_Keysym
+T: SDL2.SDL/SDL_SystemCursor
+T: SDL2.SDL/SDL_Finger
+T: SDL2.SDL/SDL_GameControllerBindType
+T: SDL2.SDL/SDL_GameControllerAxis
+T: SDL2.SDL/SDL_GameControllerButton
+T: SDL2.SDL/INTERNAL_GameControllerButtonBind_hat
+T: SDL2.SDL/SDL_GameControllerButtonBind
+T: SDL2.SDL/SDL_HapticDirection
+T: SDL2.SDL/SDL_HapticConstant
+T: SDL2.SDL/SDL_HapticPeriodic
+T: SDL2.SDL/SDL_HapticCondition
+T: SDL2.SDL/SDL_HapticRamp
+T: SDL2.SDL/SDL_HapticLeftRight
+T: SDL2.SDL/SDL_HapticCustom
+T: SDL2.SDL/SDL_HapticEffect
+T: SDL2.SDL/SDL_AudioStatus
+T: SDL2.SDL/SDL_AudioSpec
+T: SDL2.SDL/SDL_AudioCallback
+T: SDL2.SDL/SDL_TimerCallback
+T: SDL2.SDL/SDL_SYSWM_TYPE
+T: SDL2.SDL/INTERNAL_windows_wminfo
+T: SDL2.SDL/INTERNAL_x11_wminfo
+T: SDL2.SDL/INTERNAL_directfb_wminfo
+T: SDL2.SDL/INTERNAL_cocoa_wminfo
+T: SDL2.SDL/INTERNAL_uikit_wminfo
+T: SDL2.SDL/INTERNAL_SysWMDriverUnion
+T: SDL2.SDL/SDL_SysWMinfo
+T: SDL2.SDL_image
+M: System.Void SDL2.SDL_image::SDL_IMAGE_VERSION(SDL2.SDL/SDL_version&)
+M: SDL2.SDL/SDL_version SDL2.SDL_image::IMG_LinkedVersion()
+M: System.Int32 SDL2.SDL_image::IMG_Init(SDL2.SDL_image/IMG_InitFlags)
+M: System.Void SDL2.SDL_image::IMG_Quit()
+M: System.IntPtr SDL2.SDL_image::IMG_Load(System.String)
+M: System.IntPtr SDL2.SDL_image::IMG_Load_RW(System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL_image::IMG_LoadTyped_RW(System.IntPtr,System.Int32,System.String)
+M: System.IntPtr SDL2.SDL_image::IMG_LoadTexture(System.IntPtr,System.String)
+M: System.IntPtr SDL2.SDL_image::IMG_LoadTexture_RW(System.IntPtr,System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL_image::IMG_LoadTextureTyped_RW(System.IntPtr,System.IntPtr,System.Int32,System.String)
+M: System.Int32 SDL2.SDL_image::IMG_InvertAlpha(System.Int32)
+M: System.IntPtr SDL2.SDL_image::IMG_ReadXPMFromArray(System.String[])
+M: System.Int32 SDL2.SDL_image::IMG_SavePNG(System.IntPtr,System.String)
+M: System.Int32 SDL2.SDL_image::IMG_SavePNG_RW(System.IntPtr,System.IntPtr,System.Int32)
+T: SDL2.SDL_image/IMG_InitFlags
+T: SDL2.SDL_mixer
+M: System.Void SDL2.SDL_mixer::SDL_MIXER_VERSION(SDL2.SDL/SDL_version&)
+M: SDL2.SDL/SDL_version SDL2.SDL_mixer::MIX_Linked_Version()
+M: System.Int32 SDL2.SDL_mixer::Mix_Init(SDL2.SDL_mixer/MIX_InitFlags)
+M: System.Void SDL2.SDL_mixer::Mix_Quit()
+M: System.Int32 SDL2.SDL_mixer::Mix_OpenAudio(System.Int32,System.UInt16,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_AllocateChannels(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_QuerySpec(System.Int32&,System.UInt16&,System.Int32&)
+M: System.IntPtr SDL2.SDL_mixer::Mix_LoadWAV_RW(System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL_mixer::Mix_LoadWAV(System.String)
+M: System.IntPtr SDL2.SDL_mixer::Mix_LoadMUS(System.String)
+M: System.IntPtr SDL2.SDL_mixer::Mix_QuickLoad_WAV(System.Byte[])
+M: System.IntPtr SDL2.SDL_mixer::Mix_QuickLoad_RAW(System.Byte[],System.UInt32)
+M: System.Void SDL2.SDL_mixer::Mix_FreeChunk(System.IntPtr)
+M: System.Void SDL2.SDL_mixer::Mix_FreeMusic(System.IntPtr)
+M: System.Int32 SDL2.SDL_mixer::Mix_GetNumChunkDecoders()
+M: System.String SDL2.SDL_mixer::Mix_GetChunkDecoder(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GetNumMusicDecoders()
+M: System.String SDL2.SDL_mixer::Mix_GetMusicDecoder(System.Int32)
+M: SDL2.SDL_mixer/Mix_MusicType SDL2.SDL_mixer::Mix_GetMusicType(System.IntPtr)
+M: System.Void SDL2.SDL_mixer::Mix_SetPostMix(SDL2.SDL_mixer/MixFuncDelegate,System.IntPtr)
+M: System.Void SDL2.SDL_mixer::Mix_HookMusic(SDL2.SDL_mixer/MixFuncDelegate,System.IntPtr)
+M: System.Void SDL2.SDL_mixer::Mix_HookMusicFinished(SDL2.SDL_mixer/MusicFinishedDelegate)
+M: System.IntPtr SDL2.SDL_mixer::Mix_GetMusicHookData()
+M: System.Void SDL2.SDL_mixer::Mix_ChannelFinished(SDL2.SDL_mixer/ChannelFinishedDelegate)
+M: System.Int32 SDL2.SDL_mixer::Mix_RegisterEffect(System.Int32,SDL2.SDL_mixer/Mix_EffectFunc_t,SDL2.SDL_mixer/Mix_EffectDone_t,System.IntPtr)
+M: System.Int32 SDL2.SDL_mixer::Mix_UnregisterEffect(System.Int32,SDL2.SDL_mixer/Mix_EffectFunc_t)
+M: System.Int32 SDL2.SDL_mixer::Mix_UnregisterAllEffects(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetPanning(System.Int32,System.Byte,System.Byte)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetPosition(System.Int32,System.Int16,System.Byte)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetDistance(System.Int32,System.Byte)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetReverseStereo(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_ReserveChannels(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupChannel(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupChannels(System.Int32,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupAvailable(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupCount(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupOldest(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupNewer(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_PlayChannel(System.Int32,System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_PlayChannelTimed(System.Int32,System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_PlayMusic(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeInMusic(System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeInMusicPos(System.IntPtr,System.Int32,System.Int32,System.Double)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeInChannel(System.Int32,System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeInChannelTimed(System.Int32,System.IntPtr,System.Int32,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_Volume(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_VolumeChunk(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_VolumeMusic(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_HaltChannel(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_HaltGroup(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_HaltMusic()
+M: System.Int32 SDL2.SDL_mixer::Mix_ExpireChannel(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeOutChannel(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeOutGroup(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeOutMusic(System.Int32)
+M: SDL2.SDL_mixer/Mix_Fading SDL2.SDL_mixer::Mix_FadingMusic()
+M: SDL2.SDL_mixer/Mix_Fading SDL2.SDL_mixer::Mix_FadingChannel(System.Int32)
+M: System.Void SDL2.SDL_mixer::Mix_Pause(System.Int32)
+M: System.Void SDL2.SDL_mixer::Mix_Resume(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_Paused(System.Int32)
+M: System.Void SDL2.SDL_mixer::Mix_PauseMusic()
+M: System.Void SDL2.SDL_mixer::Mix_ResumeMusic()
+M: System.Void SDL2.SDL_mixer::Mix_RewindMusic()
+M: System.Int32 SDL2.SDL_mixer::Mix_PausedMusic()
+M: System.Int32 SDL2.SDL_mixer::Mix_SetMusicPosition(System.Double)
+M: System.Int32 SDL2.SDL_mixer::Mix_Playing(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_PlayingMusic()
+M: System.Int32 SDL2.SDL_mixer::Mix_SetMusicCMD(System.String)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetSynchroValue(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GetSynchroValue()
+M: System.Int32 SDL2.SDL_mixer::Mix_SetSoundFonts(System.String)
+M: System.String SDL2.SDL_mixer::Mix_GetSoundFonts()
+M: System.Int32 SDL2.SDL_mixer::Mix_EachSoundFont(SDL2.SDL_mixer/SoundFontDelegate,System.IntPtr)
+M: System.IntPtr SDL2.SDL_mixer::Mix_GetChunk(System.Int32)
+M: System.Void SDL2.SDL_mixer::Mix_CloseAudio()
+T: SDL2.SDL_mixer/MIX_InitFlags
+T: SDL2.SDL_mixer/Mix_Fading
+T: SDL2.SDL_mixer/Mix_MusicType
+T: SDL2.SDL_mixer/Mix_EffectFunc_t
+T: SDL2.SDL_mixer/Mix_EffectDone_t
+T: SDL2.SDL_ttf
+M: System.Void SDL2.SDL_ttf::SDL_TTF_VERSION(SDL2.SDL/SDL_version&)
+M: SDL2.SDL/SDL_version SDL2.SDL_ttf::TTF_LinkedVersion()
+M: System.Void SDL2.SDL_ttf::TTF_ByteSwappedUNICODE(System.Int32)
+M: System.Int32 SDL2.SDL_ttf::TTF_Init()
+M: System.IntPtr SDL2.SDL_ttf::TTF_OpenFont(System.String,System.Int32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_OpenFontRW(System.IntPtr,System.Int32,System.Int32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_OpenFontIndex(System.String,System.Int32,System.Int64)
+M: System.IntPtr SDL2.SDL_ttf::TTF_OpenFontIndexRW(System.IntPtr,System.Int32,System.Int32,System.Int64)
+M: System.Int32 SDL2.SDL_ttf::TTF_GetFontStyle(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_SetFontStyle(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_ttf::TTF_GetFontOutline(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_SetFontOutline(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_ttf::TTF_GetFontHinting(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_SetFontHinting(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontHeight(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontAscent(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontDescent(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontLineSkip(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_GetFontKerning(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_SetFontKerning(System.IntPtr,System.Int32)
+M: System.Int64 SDL2.SDL_ttf::TTF_FontFaces(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontFaceIsFixedWidth(System.IntPtr)
+M: System.String SDL2.SDL_ttf::TTF_FontFaceFamilyName(System.IntPtr)
+M: System.String SDL2.SDL_ttf::TTF_FontFaceStyleName(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_GlyphIsProvided(System.IntPtr,System.UInt16)
+M: System.Int32 SDL2.SDL_ttf::TTF_GlyphMetrics(System.IntPtr,System.UInt16,System.Int32&,System.Int32&,System.Int32&,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL_ttf::TTF_SizeText(System.IntPtr,System.String,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL_ttf::TTF_SizeUTF8(System.IntPtr,System.String,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL_ttf::TTF_SizeUNICODE(System.IntPtr,System.String,System.Int32&,System.Int32&)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderText_Solid(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUTF8_Solid(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUNICODE_Solid(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderGlyph_Solid(System.IntPtr,System.UInt16,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderText_Shaded(System.IntPtr,System.String,SDL2.SDL/SDL_Color,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUTF8_Shaded(System.IntPtr,System.String,SDL2.SDL/SDL_Color,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUNICODE_Shaded(System.IntPtr,System.String,SDL2.SDL/SDL_Color,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderGlyph_Shaded(System.IntPtr,System.UInt16,SDL2.SDL/SDL_Color,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderText_Blended(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUTF8_Blended(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUNICODE_Blended(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderText_Blended_Wrapped(System.IntPtr,System.String,SDL2.SDL/SDL_Color,System.UInt32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUTF8_Blended_Wrapped(System.IntPtr,System.String,SDL2.SDL/SDL_Color,System.UInt32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUNICODE_Blended_Wrapped(System.IntPtr,System.String,SDL2.SDL/SDL_Color,System.UInt32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderGlyph_Blended(System.IntPtr,System.UInt16,SDL2.SDL/SDL_Color)
+M: System.Void SDL2.SDL_ttf::TTF_CloseFont(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_Quit()
+M: System.Int32 SDL2.SDL_ttf::TTF_WasInit()
+M: System.Int32 SDL2.SDL_ttf::SDL_GetFontKerningSize(System.IntPtr,System.Int32,System.Int32)
+
+R: Gendarme.Rules.Design.AvoidRefAndOutParametersRule
+M: System.Int32 SDL2.SDL::SDL_ShowMessageBox(SDL2.SDL/SDL_MessageBoxData&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_VERSION(SDL2.SDL/SDL_version&)
+M: SDL2.SDL/SDL_AudioSpec SDL2.SDL::SDL_LoadWAV(System.String,SDL2.SDL/SDL_AudioSpec&,System.IntPtr&,System.UInt32&)
+M: System.Void SDL2.SDL_image::SDL_IMAGE_VERSION(SDL2.SDL/SDL_version&)
+M: System.Void SDL2.SDL_mixer::SDL_MIXER_VERSION(SDL2.SDL/SDL_version&)
+M: System.Void SDL2.SDL_ttf::SDL_TTF_VERSION(SDL2.SDL/SDL_version&)
+
+R: Gendarme.Rules.Performance.AvoidUnneededFieldInitializationRule
+M: System.Void SDL2.SDL::.cctor()
+
+R: Gendarme.Rules.Performance.AvoidUnsealedUninheritedInternalTypeRule
+T: SDL2.LPUtf8StrMarshaler
+
+R: Gendarme.Rules.Performance.AvoidUnusedPrivateFieldsRule
+T: SDL2.SDL/SDL_WindowEvent
+T: SDL2.SDL/SDL_KeyboardEvent
+T: SDL2.SDL/SDL_MouseMotionEvent
+T: SDL2.SDL/SDL_MouseButtonEvent
+T: SDL2.SDL/SDL_JoyAxisEvent
+T: SDL2.SDL/SDL_JoyBallEvent
+T: SDL2.SDL/SDL_JoyHatEvent
+T: SDL2.SDL/SDL_JoyButtonEvent
+T: SDL2.SDL/SDL_ControllerAxisEvent
+T: SDL2.SDL/SDL_ControllerButtonEvent
+
+R: Gendarme.Rules.BadPractice.AvoidVisibleConstantFieldRule
+T: SDL2.SDL
+T: SDL2.SDL_image
+T: SDL2.SDL_mixer
+T: SDL2.SDL_ttf
+
+R: Gendarme.Rules.Design.AvoidVisibleFieldsRule
+T: SDL2.SDL/SDL_MessageBoxButtonData
+T: SDL2.SDL/SDL_MessageBoxColor
+T: SDL2.SDL/SDL_MessageBoxColorScheme
+T: SDL2.SDL/SDL_MessageBoxData
+T: SDL2.SDL/SDL_version
+T: SDL2.SDL/SDL_DisplayMode
+T: SDL2.SDL/SDL_RendererInfo
+T: SDL2.SDL/SDL_Color
+T: SDL2.SDL/SDL_Palette
+T: SDL2.SDL/SDL_PixelFormat
+T: SDL2.SDL/SDL_Point
+T: SDL2.SDL/SDL_Rect
+T: SDL2.SDL/SDL_Surface
+T: SDL2.SDL/SDL_GenericEvent
+T: SDL2.SDL/SDL_WindowEvent
+T: SDL2.SDL/SDL_KeyboardEvent
+T: SDL2.SDL/SDL_TextEditingEvent
+T: SDL2.SDL/SDL_TextInputEvent
+T: SDL2.SDL/SDL_MouseMotionEvent
+T: SDL2.SDL/SDL_MouseButtonEvent
+T: SDL2.SDL/SDL_MouseWheelEvent
+T: SDL2.SDL/SDL_JoyAxisEvent
+T: SDL2.SDL/SDL_JoyBallEvent
+T: SDL2.SDL/SDL_JoyHatEvent
+T: SDL2.SDL/SDL_JoyButtonEvent
+T: SDL2.SDL/SDL_JoyDeviceEvent
+T: SDL2.SDL/SDL_ControllerAxisEvent
+T: SDL2.SDL/SDL_ControllerButtonEvent
+T: SDL2.SDL/SDL_ControllerDeviceEvent
+T: SDL2.SDL/SDL_TouchFingerEvent
+T: SDL2.SDL/SDL_MultiGestureEvent
+T: SDL2.SDL/SDL_DollarGestureEvent
+T: SDL2.SDL/SDL_DropEvent
+T: SDL2.SDL/SDL_QuitEvent
+T: SDL2.SDL/SDL_UserEvent
+T: SDL2.SDL/SDL_SysWMEvent
+T: SDL2.SDL/SDL_Event
+T: SDL2.SDL/SDL_Keysym
+T: SDL2.SDL/SDL_Finger
+T: SDL2.SDL/INTERNAL_GameControllerButtonBind_hat
+T: SDL2.SDL/SDL_GameControllerButtonBind
+T: SDL2.SDL/SDL_HapticDirection
+T: SDL2.SDL/SDL_HapticConstant
+T: SDL2.SDL/SDL_HapticPeriodic
+T: SDL2.SDL/SDL_HapticCondition
+T: SDL2.SDL/SDL_HapticRamp
+T: SDL2.SDL/SDL_HapticLeftRight
+T: SDL2.SDL/SDL_HapticCustom
+T: SDL2.SDL/SDL_HapticEffect
+T: SDL2.SDL/SDL_AudioSpec
+T: SDL2.SDL/INTERNAL_windows_wminfo
+T: SDL2.SDL/INTERNAL_x11_wminfo
+T: SDL2.SDL/INTERNAL_directfb_wminfo
+T: SDL2.SDL/INTERNAL_cocoa_wminfo
+T: SDL2.SDL/INTERNAL_uikit_wminfo
+T: SDL2.SDL/INTERNAL_SysWMDriverUnion
+T: SDL2.SDL/SDL_SysWMinfo
+
+R: Gendarme.Rules.Design.AvoidVisibleNestedTypesRule
+T: SDL2.SDL/SDL_bool
+T: SDL2.SDL/SDL_HintPriority
+T: SDL2.SDL/SDL_LogPriority
+T: SDL2.SDL/SDL_LogOutputFunction
+T: SDL2.SDL/SDL_MessageBoxFlags
+T: SDL2.SDL/SDL_MessageBoxButtonFlags
+T: SDL2.SDL/SDL_MessageBoxButtonData
+T: SDL2.SDL/SDL_MessageBoxColor
+T: SDL2.SDL/SDL_MessageBoxColorType
+T: SDL2.SDL/SDL_MessageBoxColorScheme
+T: SDL2.SDL/SDL_MessageBoxData
+T: SDL2.SDL/SDL_version
+T: SDL2.SDL/SDL_BlendMode
+T: SDL2.SDL/SDL_GLattr
+T: SDL2.SDL/SDL_GLprofile
+T: SDL2.SDL/SDL_GLcontext
+T: SDL2.SDL/SDL_WindowEventID
+T: SDL2.SDL/SDL_WindowFlags
+T: SDL2.SDL/SDL_DisplayMode
+T: SDL2.SDL/SDL_RendererFlags
+T: SDL2.SDL/SDL_RendererFlip
+T: SDL2.SDL/SDL_TextureAccess
+T: SDL2.SDL/SDL_TextureModulate
+T: SDL2.SDL/SDL_RendererInfo
+T: SDL2.SDL/SDL_RendererInfo/__FixedBuffer0
+T: SDL2.SDL/SDL_PIXELTYPE_ENUM
+T: SDL2.SDL/SDL_PIXELORDER_ENUM
+T: SDL2.SDL/SDL_PACKEDLAYOUT_ENUM
+T: SDL2.SDL/SDL_Color
+T: SDL2.SDL/SDL_Palette
+T: SDL2.SDL/SDL_PixelFormat
+T: SDL2.SDL/SDL_Point
+T: SDL2.SDL/SDL_Rect
+T: SDL2.SDL/SDL_Surface
+T: SDL2.SDL/SDL_EventType
+T: SDL2.SDL/SDL_GenericEvent
+T: SDL2.SDL/SDL_WindowEvent
+T: SDL2.SDL/SDL_KeyboardEvent
+T: SDL2.SDL/SDL_TextEditingEvent
+T: SDL2.SDL/SDL_TextEditingEvent/__FixedBuffer1
+T: SDL2.SDL/SDL_TextInputEvent
+T: SDL2.SDL/SDL_TextInputEvent/__FixedBuffer2
+T: SDL2.SDL/SDL_MouseMotionEvent
+T: SDL2.SDL/SDL_MouseButtonEvent
+T: SDL2.SDL/SDL_MouseWheelEvent
+T: SDL2.SDL/SDL_JoyAxisEvent
+T: SDL2.SDL/SDL_JoyBallEvent
+T: SDL2.SDL/SDL_JoyHatEvent
+T: SDL2.SDL/SDL_JoyButtonEvent
+T: SDL2.SDL/SDL_JoyDeviceEvent
+T: SDL2.SDL/SDL_ControllerAxisEvent
+T: SDL2.SDL/SDL_ControllerButtonEvent
+T: SDL2.SDL/SDL_ControllerDeviceEvent
+T: SDL2.SDL/SDL_TouchFingerEvent
+T: SDL2.SDL/SDL_MultiGestureEvent
+T: SDL2.SDL/SDL_DollarGestureEvent
+T: SDL2.SDL/SDL_DropEvent
+T: SDL2.SDL/SDL_QuitEvent
+T: SDL2.SDL/SDL_UserEvent
+T: SDL2.SDL/SDL_SysWMEvent
+T: SDL2.SDL/SDL_Event
+T: SDL2.SDL/SDL_EventFilter
+T: SDL2.SDL/SDL_eventaction
+T: SDL2.SDL/SDL_Scancode
+T: SDL2.SDL/SDL_Keycode
+T: SDL2.SDL/SDL_Keymod
+T: SDL2.SDL/SDL_Keysym
+T: SDL2.SDL/SDL_SystemCursor
+T: SDL2.SDL/SDL_Finger
+T: SDL2.SDL/SDL_GameControllerBindType
+T: SDL2.SDL/SDL_GameControllerAxis
+T: SDL2.SDL/SDL_GameControllerButton
+T: SDL2.SDL/INTERNAL_GameControllerButtonBind_hat
+T: SDL2.SDL/SDL_GameControllerButtonBind
+T: SDL2.SDL/SDL_HapticDirection
+T: SDL2.SDL/SDL_HapticDirection/__FixedBuffer3
+T: SDL2.SDL/SDL_HapticConstant
+T: SDL2.SDL/SDL_HapticPeriodic
+T: SDL2.SDL/SDL_HapticCondition
+T: SDL2.SDL/SDL_HapticCondition/__FixedBuffer4
+T: SDL2.SDL/SDL_HapticCondition/__FixedBuffer5
+T: SDL2.SDL/SDL_HapticCondition/__FixedBuffer6
+T: SDL2.SDL/SDL_HapticCondition/__FixedBuffer7
+T: SDL2.SDL/SDL_HapticCondition/__FixedBuffer8
+T: SDL2.SDL/SDL_HapticCondition/__FixedBuffer9
+T: SDL2.SDL/SDL_HapticRamp
+T: SDL2.SDL/SDL_HapticLeftRight
+T: SDL2.SDL/SDL_HapticCustom
+T: SDL2.SDL/SDL_HapticEffect
+T: SDL2.SDL/SDL_AudioStatus
+T: SDL2.SDL/SDL_AudioSpec
+T: SDL2.SDL/SDL_AudioCallback
+T: SDL2.SDL/SDL_TimerCallback
+T: SDL2.SDL/SDL_SYSWM_TYPE
+T: SDL2.SDL/INTERNAL_windows_wminfo
+T: SDL2.SDL/INTERNAL_x11_wminfo
+T: SDL2.SDL/INTERNAL_directfb_wminfo
+T: SDL2.SDL/INTERNAL_cocoa_wminfo
+T: SDL2.SDL/INTERNAL_uikit_wminfo
+T: SDL2.SDL/INTERNAL_SysWMDriverUnion
+T: SDL2.SDL/SDL_SysWMinfo
+T: SDL2.SDL_image/IMG_InitFlags
+T: SDL2.SDL_mixer/MIX_InitFlags
+T: SDL2.SDL_mixer/Mix_Fading
+T: SDL2.SDL_mixer/Mix_MusicType
+T: SDL2.SDL_mixer/MixFuncDelegate
+T: SDL2.SDL_mixer/Mix_EffectFunc_t
+T: SDL2.SDL_mixer/Mix_EffectDone_t
+T: SDL2.SDL_mixer/MusicFinishedDelegate
+T: SDL2.SDL_mixer/ChannelFinishedDelegate
+T: SDL2.SDL_mixer/SoundFontDelegate
+
+R: Gendarme.Rules.Interoperability.CentralizePInvokesIntoNativeMethodsTypeRule
+M: System.IntPtr SDL2.SDL::SDL_malloc(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_free(System.IntPtr)
+M: System.IntPtr SDL2.SDL::INTERNAL_SDL_RWFromFile(System.String,System.String)
+M: System.IntPtr SDL2.SDL::SDL_RWFromMem(System.Byte[],System.Int32)
+M: System.Void SDL2.SDL::SDL_SetMainReady()
+M: System.Int32 SDL2.SDL::SDL_Init(System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_InitSubSystem(System.UInt32)
+M: System.Void SDL2.SDL::SDL_Quit()
+M: System.Void SDL2.SDL::SDL_QuitSubSystem(System.UInt32)
+M: System.UInt32 SDL2.SDL::SDL_WasInit(System.UInt32)
+M: System.String SDL2.SDL::SDL_GetPlatform()
+M: System.Void SDL2.SDL::SDL_ClearHints()
+M: System.String SDL2.SDL::SDL_GetHint(System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_SetHint(System.String,System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_SetHintWithPriority(System.String,System.String,SDL2.SDL/SDL_HintPriority)
+M: System.Void SDL2.SDL::SDL_ClearError()
+M: System.String SDL2.SDL::SDL_GetError()
+M: System.Void SDL2.SDL::SDL_SetError(System.String)
+M: System.Void SDL2.SDL::SDL_Log(System.String)
+M: System.Void SDL2.SDL::SDL_LogVerbose(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogDebug(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogInfo(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogWarn(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogError(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogCritical(System.Int32,System.String)
+M: System.Void SDL2.SDL::SDL_LogMessage(System.Int32,SDL2.SDL/SDL_LogPriority,System.String)
+M: System.Void SDL2.SDL::SDL_LogMessageV(System.Int32,SDL2.SDL/SDL_LogPriority,System.String)
+M: SDL2.SDL/SDL_LogPriority SDL2.SDL::SDL_LogGetPriority(System.Int32)
+M: System.Void SDL2.SDL::SDL_LogSetPriority(System.Int32,SDL2.SDL/SDL_LogPriority)
+M: System.Void SDL2.SDL::SDL_LogSetAllPriority(SDL2.SDL/SDL_LogPriority)
+M: System.Void SDL2.SDL::SDL_LogResetPriorities()
+M: System.Void SDL2.SDL::SDL_LogGetOutputFunction(SDL2.SDL/SDL_LogOutputFunction&,System.IntPtr&)
+M: System.Void SDL2.SDL::SDL_LogSetOutputFunction(SDL2.SDL/SDL_LogOutputFunction,System.IntPtr)
+M: System.Int32 SDL2.SDL::INTERNAL_SDL_ShowMessageBox(SDL2.SDL/INTERNAL_SDL_MessageBoxData&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_ShowSimpleMessageBox(SDL2.SDL/SDL_MessageBoxFlags,System.String,System.String,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_GetVersion(SDL2.SDL/SDL_version&)
+M: System.String SDL2.SDL::SDL_GetRevision()
+M: System.Int32 SDL2.SDL::SDL_GetRevisionNumber()
+M: System.IntPtr SDL2.SDL::SDL_CreateWindow(System.String,System.Int32,System.Int32,System.Int32,System.Int32,SDL2.SDL/SDL_WindowFlags)
+M: System.Int32 SDL2.SDL::SDL_CreateWindowAndRenderer(System.Int32,System.Int32,SDL2.SDL/SDL_WindowFlags,System.IntPtr&,System.IntPtr&)
+M: System.IntPtr SDL2.SDL::SDL_CreateWindowFrom(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DestroyWindow(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DisableScreenSaver()
+M: System.Void SDL2.SDL::SDL_EnableScreenSaver()
+M: System.IntPtr SDL2.SDL::SDL_GetClosestDisplayMode(System.Int32,SDL2.SDL/SDL_DisplayMode&,SDL2.SDL/SDL_DisplayMode&)
+M: System.Int32 SDL2.SDL::SDL_GetCurrentDisplayMode(System.Int32,SDL2.SDL/SDL_DisplayMode&)
+M: System.String SDL2.SDL::SDL_GetCurrentVideoDriver()
+M: System.Int32 SDL2.SDL::SDL_GetDesktopDisplayMode(System.Int32,SDL2.SDL/SDL_DisplayMode&)
+M: System.Int32 SDL2.SDL::SDL_GetDisplayBounds(System.Int32,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_GetDisplayMode(System.Int32,System.Int32,SDL2.SDL/SDL_DisplayMode&)
+M: System.Int32 SDL2.SDL::SDL_GetNumDisplayModes(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GetNumVideoDisplays()
+M: System.Int32 SDL2.SDL::SDL_GetNumVideoDrivers()
+M: System.String SDL2.SDL::SDL_GetVideoDriver(System.Int32)
+M: System.Single SDL2.SDL::SDL_GetWindowBrightness(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetWindowData(System.IntPtr,System.String)
+M: System.Int32 SDL2.SDL::SDL_GetWindowDisplayIndex(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GetWindowDisplayMode(System.IntPtr,SDL2.SDL/SDL_DisplayMode&)
+M: System.UInt32 SDL2.SDL::SDL_GetWindowFlags(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetWindowFromID(System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_GetWindowGammaRamp(System.IntPtr,System.UInt16[],System.UInt16[],System.UInt16[])
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GetWindowGrab(System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_GetWindowID(System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_GetWindowPixelFormat(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_GetWindowMaximumSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_GetWindowMinimumSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_GetWindowPosition(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_GetWindowSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.IntPtr SDL2.SDL::SDL_GetWindowSurface(System.IntPtr)
+M: System.String SDL2.SDL::SDL_GetWindowTitle(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GL_BindTexture(System.IntPtr,System.Single&,System.Single&)
+M: System.IntPtr SDL2.SDL::SDL_GL_CreateContext(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_GL_DeleteContext(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GL_GetProcAddress(System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GL_ExtensionSupported(System.String)
+M: System.Void SDL2.SDL::SDL_GL_ResetAttributes()
+M: System.Int32 SDL2.SDL::SDL_GL_GetAttribute(SDL2.SDL/SDL_GLattr,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_GL_GetSwapInterval()
+M: System.Int32 SDL2.SDL::SDL_GL_MakeCurrent(System.IntPtr,System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GL_GetCurrentWindow()
+M: System.IntPtr SDL2.SDL::SDL_GL_GetCurrentContext()
+M: System.Void SDL2.SDL::SDL_GL_GetDrawableSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_GL_SetAttribute(SDL2.SDL/SDL_GLattr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GL_SetSwapInterval(System.Int32)
+M: System.Void SDL2.SDL::SDL_GL_SwapWindow(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GL_UnbindTexture(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_HideWindow(System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IsScreenSaverEnabled()
+M: System.Void SDL2.SDL::SDL_MaximizeWindow(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_MinimizeWindow(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_RaiseWindow(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_RestoreWindow(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_SetWindowBrightness(System.IntPtr,System.Single)
+M: System.IntPtr SDL2.SDL::SDL_SetWindowData(System.IntPtr,System.String,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_SetWindowDisplayMode(System.IntPtr,SDL2.SDL/SDL_DisplayMode&)
+M: System.Int32 SDL2.SDL::SDL_SetWindowFullscreen(System.IntPtr,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_SetWindowGammaRamp(System.IntPtr,System.UInt16[],System.UInt16[],System.UInt16[])
+M: System.Void SDL2.SDL::SDL_SetWindowGrab(System.IntPtr,SDL2.SDL/SDL_bool)
+M: System.Void SDL2.SDL::SDL_SetWindowIcon(System.IntPtr,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_SetWindowMaximumSize(System.IntPtr,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_SetWindowMinimumSize(System.IntPtr,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_SetWindowPosition(System.IntPtr,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_SetWindowSize(System.IntPtr,System.Int32,System.Int32)
+M: System.Void SDL2.SDL::SDL_SetWindowBordered(System.IntPtr,SDL2.SDL/SDL_bool)
+M: System.Void SDL2.SDL::SDL_SetWindowTitle(System.IntPtr,System.String)
+M: System.Void SDL2.SDL::SDL_ShowWindow(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_UpdateWindowSurface(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_UpdateWindowSurfaceRects(System.IntPtr,SDL2.SDL/SDL_Rect[],System.Int32)
+M: System.Int32 SDL2.SDL::SDL_VideoInit(System.String)
+M: System.Void SDL2.SDL::SDL_VideoQuit()
+M: System.IntPtr SDL2.SDL::SDL_CreateRenderer(System.IntPtr,System.Int32,SDL2.SDL/SDL_RendererFlags)
+M: System.IntPtr SDL2.SDL::SDL_CreateSoftwareRenderer(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_CreateTexture(System.IntPtr,System.UInt32,System.Int32,System.Int32,System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_CreateTextureFromSurface(System.IntPtr,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DestroyRenderer(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DestroyTexture(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GetNumRenderDrivers()
+M: System.Int32 SDL2.SDL::SDL_GetRenderDrawBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode&)
+M: System.Int32 SDL2.SDL::SDL_GetRenderDrawColor(System.IntPtr,System.Byte&,System.Byte&,System.Byte&,System.Byte&)
+M: System.Int32 SDL2.SDL::SDL_GetRenderDriverInfo(System.Int32,SDL2.SDL/SDL_RendererInfo&)
+M: System.IntPtr SDL2.SDL::SDL_GetRenderer(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GetRendererInfo(System.IntPtr,SDL2.SDL/SDL_RendererInfo&)
+M: System.Int32 SDL2.SDL::SDL_GetRendererOutputSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_GetTextureAlphaMod(System.IntPtr,System.Byte&)
+M: System.Int32 SDL2.SDL::SDL_GetTextureBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode&)
+M: System.Int32 SDL2.SDL::SDL_GetTextureColorMod(System.IntPtr,System.Byte&,System.Byte&,System.Byte&)
+M: System.Int32 SDL2.SDL::SDL_LockTexture(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_LockTexture(System.IntPtr,System.IntPtr,System.IntPtr&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_QueryTexture(System.IntPtr,System.UInt32&,System.Int32&,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_QueryTexturePixels(System.IntPtr,System.IntPtr&,System.Int32&)
+M: System.Int32 SDL2.SDL::SDL_RenderClear(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderCopy(System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderCopy(System.IntPtr,System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderCopy(System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderCopy(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderCopyEx(System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&,System.Double,SDL2.SDL/SDL_Point&,SDL2.SDL/SDL_RendererFlip)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawLine(System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawLines(System.IntPtr,SDL2.SDL/SDL_Point[],System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawPoint(System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawPoints(System.IntPtr,SDL2.SDL/SDL_Point[],System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawRect(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderDrawRects(System.IntPtr,SDL2.SDL/SDL_Rect[],System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderFillRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderFillRect(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderFillRects(System.IntPtr,SDL2.SDL/SDL_Rect[],System.Int32)
+M: System.Void SDL2.SDL::SDL_RenderGetClipRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_RenderGetLogicalSize(System.IntPtr,System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_RenderGetScale(System.IntPtr,System.Single&,System.Single&)
+M: System.Int32 SDL2.SDL::SDL_RenderGetViewport(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_RenderPresent(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderReadPixels(System.IntPtr,SDL2.SDL/SDL_Rect&,System.UInt32,System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderSetClipRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_RenderSetClipRect(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_RenderSetLogicalSize(System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_RenderSetScale(System.IntPtr,System.Single,System.Single)
+M: System.Int32 SDL2.SDL::SDL_RenderSetViewport(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_SetRenderDrawBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode)
+M: System.Int32 SDL2.SDL::SDL_SetRenderDrawColor(System.IntPtr,System.Byte,System.Byte,System.Byte,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_SetRenderTarget(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_SetTextureAlphaMod(System.IntPtr,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_SetTextureBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode)
+M: System.Int32 SDL2.SDL::SDL_SetTextureColorMod(System.IntPtr,System.Byte,System.Byte,System.Byte)
+M: System.Void SDL2.SDL::SDL_UnlockTexture(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_UpdateTexture(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,System.Int32)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RenderTargetSupported(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetRenderTarget(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_AllocFormat(System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_AllocPalette(System.Int32)
+M: System.Void SDL2.SDL::SDL_CalculateGammaRamp(System.Single,System.UInt16[])
+M: System.Void SDL2.SDL::SDL_FreeFormat(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_FreePalette(System.IntPtr)
+M: System.String SDL2.SDL::SDL_GetPixelFormatName(System.UInt32)
+M: System.Void SDL2.SDL::SDL_GetRGB(System.UInt32,System.IntPtr,System.Byte&,System.Byte&,System.Byte&)
+M: System.Void SDL2.SDL::SDL_GetRGBA(System.UInt32,System.IntPtr,System.Byte&,System.Byte&,System.Byte&,System.Byte&)
+M: System.UInt32 SDL2.SDL::SDL_MapRGB(System.IntPtr,System.Byte,System.Byte,System.Byte)
+M: System.UInt32 SDL2.SDL::SDL_MapRGBA(System.IntPtr,System.Byte,System.Byte,System.Byte,System.Byte)
+M: System.UInt32 SDL2.SDL::SDL_MasksToPixelFormatEnum(System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_PixelFormatEnumToMasks(System.UInt32,System.Int32&,System.UInt32&,System.UInt32&,System.UInt32&,System.UInt32&)
+M: System.Int32 SDL2.SDL::SDL_SetPaletteColors(System.IntPtr,SDL2.SDL/SDL_Color[],System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_SetPixelFormatPalette(System.IntPtr,System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_EnclosePoints(SDL2.SDL/SDL_Point[],System.Int32,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasIntersection(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IntersectRect(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IntersectRectAndLine(SDL2.SDL/SDL_Rect&,System.Int32&,System.Int32&,System.Int32&,System.Int32&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RectEmpty(SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RectEquals(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_UnionRect(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitSurface(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitSurface(System.IntPtr,System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitSurface(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_BlitSurface(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_BlitScaled(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitScaled(System.IntPtr,System.IntPtr,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_BlitScaled(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_BlitScaled(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_ConvertPixels(System.Int32,System.Int32,System.UInt32,System.IntPtr,System.Int32,System.UInt32,System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_ConvertSurface(System.IntPtr,System.IntPtr,System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_ConvertSurfaceFormat(System.IntPtr,System.UInt32,System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_CreateRGBSurface(System.UInt32,System.Int32,System.Int32,System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_CreateRGBSurfaceFrom(System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_FillRect(System.IntPtr,SDL2.SDL/SDL_Rect&,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_FillRects(System.IntPtr,SDL2.SDL/SDL_Rect[],System.Int32,System.UInt32)
+M: System.Void SDL2.SDL::SDL_FreeSurface(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_GetClipRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_GetColorKey(System.IntPtr,System.UInt32&)
+M: System.Int32 SDL2.SDL::SDL_GetSurfaceAlphaMod(System.IntPtr,System.Byte&)
+M: System.Int32 SDL2.SDL::SDL_GetSurfaceBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode&)
+M: System.Int32 SDL2.SDL::SDL_GetSurfaceColorMod(System.IntPtr,System.Byte&,System.Byte&,System.Byte&)
+M: System.IntPtr SDL2.SDL::INTERNAL_SDL_LoadBMP_RW(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_LockSurface(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_LowerBlit(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_LowerBlitScaled(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::INTERNAL_SDL_SaveBMP_RW(System.IntPtr,System.IntPtr,System.Int32)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_SetClipRect(System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_SetColorKey(System.IntPtr,System.Int32,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_SetSurfaceAlphaMod(System.IntPtr,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_SetSurfaceBlendMode(System.IntPtr,SDL2.SDL/SDL_BlendMode)
+M: System.Int32 SDL2.SDL::SDL_SetSurfaceColorMod(System.IntPtr,System.Byte,System.Byte,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_SetSurfacePalette(System.IntPtr,System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_SetSurfaceRLE(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_SoftStretch(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_UnlockSurface(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_UpperBlit(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: System.Int32 SDL2.SDL::SDL_UpperBlitScaled(System.IntPtr,SDL2.SDL/SDL_Rect&,System.IntPtr,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasClipboardText()
+M: System.String SDL2.SDL::SDL_GetClipboardText()
+M: System.Int32 SDL2.SDL::SDL_SetClipboardText(System.String)
+M: System.Void SDL2.SDL::SDL_PumpEvents()
+M: System.Int32 SDL2.SDL::SDL_PeepEvents(SDL2.SDL/SDL_Event[],System.Int32,SDL2.SDL/SDL_eventaction,SDL2.SDL/SDL_EventType,SDL2.SDL/SDL_EventType)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasEvent(SDL2.SDL/SDL_EventType)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasEvents(SDL2.SDL/SDL_EventType,SDL2.SDL/SDL_EventType)
+M: System.Void SDL2.SDL::SDL_FlushEvent(SDL2.SDL/SDL_EventType)
+M: System.Void SDL2.SDL::SDL_FlushEvents(SDL2.SDL/SDL_EventType,SDL2.SDL/SDL_EventType)
+M: System.Int32 SDL2.SDL::SDL_PollEvent(SDL2.SDL/SDL_Event&)
+M: System.Int32 SDL2.SDL::SDL_WaitEvent(SDL2.SDL/SDL_Event&)
+M: System.Int32 SDL2.SDL::SDL_WaitEventTimeout(SDL2.SDL/SDL_Event&,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_PushEvent(SDL2.SDL/SDL_Event&)
+M: System.Void SDL2.SDL::SDL_SetEventFilter(SDL2.SDL/SDL_EventFilter,System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GetEventFilter(SDL2.SDL/SDL_EventFilter&,System.IntPtr&)
+M: System.Void SDL2.SDL::SDL_AddEventWatch(SDL2.SDL/SDL_EventFilter,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_DelEventWatch(SDL2.SDL/SDL_EventFilter,System.IntPtr)
+M: System.Void SDL2.SDL::SDL_FilterEvents(SDL2.SDL/SDL_EventFilter,System.IntPtr)
+M: System.Byte SDL2.SDL::SDL_EventState(SDL2.SDL/SDL_EventType,System.Int32)
+M: System.UInt32 SDL2.SDL::SDL_RegisterEvents(System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_GetKeyboardFocus()
+M: System.IntPtr SDL2.SDL::SDL_GetKeyboardState(System.Int32&)
+M: SDL2.SDL/SDL_Keymod SDL2.SDL::SDL_GetModState()
+M: System.Void SDL2.SDL::SDL_SetModState(SDL2.SDL/SDL_Keymod)
+M: SDL2.SDL/SDL_Keycode SDL2.SDL::SDL_GetKeyFromScancode(SDL2.SDL/SDL_Scancode)
+M: SDL2.SDL/SDL_Scancode SDL2.SDL::SDL_GetScancodeFromKey(SDL2.SDL/SDL_Keycode)
+M: System.String SDL2.SDL::SDL_GetScancodeName(SDL2.SDL/SDL_Scancode)
+M: SDL2.SDL/SDL_Scancode SDL2.SDL::SDL_GetScancodeFromName(System.String)
+M: System.String SDL2.SDL::SDL_GetKeyName(SDL2.SDL/SDL_Keycode)
+M: SDL2.SDL/SDL_Keycode SDL2.SDL::SDL_GetKeyFromName(System.String)
+M: System.Void SDL2.SDL::SDL_StartTextInput()
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IsTextInputActive()
+M: System.Void SDL2.SDL::SDL_StopTextInput()
+M: System.Void SDL2.SDL::SDL_SetTextInputRect(SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasScreenKeyboardSupport()
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IsScreenKeyboardShown(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetMouseFocus()
+M: System.UInt32 SDL2.SDL::SDL_GetMouseState(System.Int32&,System.Int32&)
+M: System.UInt32 SDL2.SDL::SDL_GetMouseState(System.IntPtr,System.Int32&)
+M: System.UInt32 SDL2.SDL::SDL_GetMouseState(System.Int32&,System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_GetMouseState(System.IntPtr,System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_GetRelativeMouseState(System.Int32&,System.Int32&)
+M: System.Void SDL2.SDL::SDL_WarpMouseInWindow(System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_SetRelativeMouseMode(SDL2.SDL/SDL_bool)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GetRelativeMouseMode()
+M: System.IntPtr SDL2.SDL::SDL_CreateCursor(System.IntPtr,System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_CreateColorCursor(System.IntPtr,System.Int32,System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_CreateSystemCursor(SDL2.SDL/SDL_SystemCursor)
+M: System.Void SDL2.SDL::SDL_SetCursor(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GetCursor()
+M: System.Void SDL2.SDL::SDL_FreeCursor(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_ShowCursor(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GetNumTouchDevices()
+M: System.Int64 SDL2.SDL::SDL_GetTouchDevice(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GetNumTouchFingers(System.Int64)
+M: System.IntPtr SDL2.SDL::SDL_GetTouchFinger(System.Int64,System.Int32)
+M: System.Void SDL2.SDL::SDL_JoystickClose(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickEventState(System.Int32)
+M: System.Int16 SDL2.SDL::SDL_JoystickGetAxis(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_JoystickGetBall(System.IntPtr,System.Int32,System.Int32&,System.Int32&)
+M: System.Byte SDL2.SDL::SDL_JoystickGetButton(System.IntPtr,System.Int32)
+M: System.Byte SDL2.SDL::SDL_JoystickGetHat(System.IntPtr,System.Int32)
+M: System.String SDL2.SDL::SDL_JoystickName(System.IntPtr)
+M: System.String SDL2.SDL::SDL_JoystickNameForIndex(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_JoystickNumAxes(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickNumBalls(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickNumButtons(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickNumHats(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_JoystickOpen(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_JoystickOpened(System.Int32)
+M: System.Void SDL2.SDL::SDL_JoystickUpdate()
+M: System.Int32 SDL2.SDL::SDL_NumJoysticks()
+M: System.Guid SDL2.SDL::SDL_JoystickGetDeviceGUID(System.Int32)
+M: System.Guid SDL2.SDL::SDL_JoystickGetGUID(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_JoystickGetGUIDString(System.Guid,System.Byte[],System.Int32)
+M: System.Guid SDL2.SDL::SDL_JoystickGetGUIDFromString(System.String)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_JoystickGetAttached(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_JoystickInstanceID(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GameControllerAddMapping(System.String)
+M: System.Int32 SDL2.SDL::INTERNAL_SDL_GameControllerAddMappingsFromRW(System.IntPtr,System.Int32)
+M: System.String SDL2.SDL::SDL_GameControllerMappingForGUID(System.Guid)
+M: System.String SDL2.SDL::SDL_GameControllerMapping(System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IsGameController(System.Int32)
+M: System.String SDL2.SDL::SDL_GameControllerNameForIndex(System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_GameControllerOpen(System.Int32)
+M: System.String SDL2.SDL::SDL_GameControllerName(System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GameControllerGetAttached(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_GameControllerGetJoystick(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_GameControllerEventState(System.Int32)
+M: System.Void SDL2.SDL::SDL_GameControllerUpdate()
+M: SDL2.SDL/SDL_GameControllerAxis SDL2.SDL::SDL_GameControllerGetAxisFromString(System.String)
+M: System.String SDL2.SDL::SDL_GameControllerGetStringForAxis(SDL2.SDL/SDL_GameControllerAxis)
+M: SDL2.SDL/SDL_GameControllerButtonBind SDL2.SDL::SDL_GameControllerGetBindForAxis(System.IntPtr,SDL2.SDL/SDL_GameControllerAxis)
+M: System.Int16 SDL2.SDL::SDL_GameControllerGetAxis(System.IntPtr,SDL2.SDL/SDL_GameControllerAxis)
+M: SDL2.SDL/SDL_GameControllerButton SDL2.SDL::SDL_GameControllerGetButtonFromString(System.String)
+M: System.String SDL2.SDL::SDL_GameControllerGetStringForButton(SDL2.SDL/SDL_GameControllerButton)
+M: SDL2.SDL/SDL_GameControllerButtonBind SDL2.SDL::SDL_GameControllerGetBindForButton(System.IntPtr,SDL2.SDL/SDL_GameControllerButton)
+M: System.Byte SDL2.SDL::SDL_GameControllerGetButton(System.IntPtr,SDL2.SDL/SDL_GameControllerButton)
+M: System.Void SDL2.SDL::SDL_GameControllerClose(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_HapticClose(System.IntPtr)
+M: System.Void SDL2.SDL::SDL_HapticDestroyEffect(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticEffectSupported(System.IntPtr,SDL2.SDL/SDL_HapticEffect&)
+M: System.Int32 SDL2.SDL::SDL_HapticGetEffectStatus(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticIndex(System.IntPtr)
+M: System.String SDL2.SDL::SDL_HapticName(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticNewEffect(System.IntPtr,SDL2.SDL/SDL_HapticEffect&)
+M: System.Int32 SDL2.SDL::SDL_HapticNumAxes(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticNumEffects(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticNumEffectsPlaying(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_HapticOpen(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticOpened(System.Int32)
+M: System.IntPtr SDL2.SDL::SDL_HapticOpenFromJoystick(System.IntPtr)
+M: System.IntPtr SDL2.SDL::SDL_HapticOpenFromMouse()
+M: System.Int32 SDL2.SDL::SDL_HapticPause(System.IntPtr)
+M: System.UInt32 SDL2.SDL::SDL_HapticQuery(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticRumbleInit(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticRumblePlay(System.IntPtr,System.Single,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_HapticRumbleStop(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticRumbleSupported(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticRunEffect(System.IntPtr,System.Int32,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_HapticSetAutocenter(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticSetGain(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticStopAll(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticStopEffect(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_HapticUnpause(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_HapticUpdateEffect(System.IntPtr,System.Int32,SDL2.SDL/SDL_HapticEffect&)
+M: System.Int32 SDL2.SDL::SDL_JoystickIsHaptic(System.IntPtr)
+M: System.Int32 SDL2.SDL::SDL_MouseIsHaptic()
+M: System.Int32 SDL2.SDL::SDL_NumHaptics()
+M: System.Int32 SDL2.SDL::SDL_AudioDeviceConnected(System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_AudioInit(System.String)
+M: System.Void SDL2.SDL::SDL_AudioQuit()
+M: System.Void SDL2.SDL::SDL_CloseAudio()
+M: System.Void SDL2.SDL::SDL_CloseAudioDevice(System.UInt32)
+M: System.Void SDL2.SDL::SDL_FreeWAV(System.IntPtr)
+M: System.String SDL2.SDL::SDL_GetAudioDeviceName(System.Int32,System.Int32)
+M: SDL2.SDL/SDL_AudioStatus SDL2.SDL::SDL_GetAudioDeviceStatus(System.UInt32)
+M: System.String SDL2.SDL::SDL_GetAudioDriver(System.Int32)
+M: SDL2.SDL/SDL_AudioStatus SDL2.SDL::SDL_GetAudioStatus()
+M: System.String SDL2.SDL::SDL_GetCurrentAudioDriver()
+M: System.Int32 SDL2.SDL::SDL_GetNumAudioDevices(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_GetNumAudioDrivers()
+M: System.IntPtr SDL2.SDL::INTERNAL_SDL_LoadWAV_RW(System.IntPtr,System.Int32,SDL2.SDL/SDL_AudioSpec&,System.IntPtr&,System.UInt32&)
+M: System.Void SDL2.SDL::SDL_LockAudio()
+M: System.Void SDL2.SDL::SDL_LockAudioDevice(System.UInt32)
+M: System.Void SDL2.SDL::SDL_MixAudio(System.Byte[],System.Byte[],System.UInt32,System.Int32)
+M: System.Void SDL2.SDL::SDL_MixAudioFormat(System.Byte[],System.Byte[],System.UInt16,System.UInt32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_OpenAudio(SDL2.SDL/SDL_AudioSpec&,SDL2.SDL/SDL_AudioSpec&)
+M: System.UInt32 SDL2.SDL::SDL_OpenAudioDevice(System.String,System.Int32,SDL2.SDL/SDL_AudioSpec&,SDL2.SDL/SDL_AudioSpec&,System.Int32)
+M: System.Void SDL2.SDL::SDL_PauseAudio(System.Int32)
+M: System.Void SDL2.SDL::SDL_PauseAudioDevice(System.UInt32,System.Int32)
+M: System.Void SDL2.SDL::SDL_UnlockAudio()
+M: System.Void SDL2.SDL::SDL_UnlockAudioDevice(System.UInt32)
+M: System.Void SDL2.SDL::SDL_Delay(System.UInt32)
+M: System.UInt32 SDL2.SDL::SDL_GetTicks()
+M: System.UInt64 SDL2.SDL::SDL_GetPerformanceCounter()
+M: System.UInt64 SDL2.SDL::SDL_GetPerformanceFrequency()
+M: System.Int32 SDL2.SDL::SDL_AddTimer(System.UInt32,SDL2.SDL/SDL_TimerCallback,System.IntPtr)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RemoveTimer(System.Int32)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_GetWindowWMInfo(System.IntPtr,SDL2.SDL/SDL_SysWMinfo&)
+M: System.String SDL2.SDL::SDL_GetBasePath()
+M: System.String SDL2.SDL::SDL_GetPrefPath(System.String,System.String)
+M: System.Int32 SDL2.SDL::SDL_GetCPUCount()
+M: System.Int32 SDL2.SDL::SDL_GetSystemRAM()
+M: System.IntPtr SDL2.SDL_image::INTERNAL_IMG_LinkedVersion()
+M: System.Int32 SDL2.SDL_image::IMG_Init(SDL2.SDL_image/IMG_InitFlags)
+M: System.Void SDL2.SDL_image::IMG_Quit()
+M: System.IntPtr SDL2.SDL_image::IMG_Load(System.String)
+M: System.IntPtr SDL2.SDL_image::IMG_Load_RW(System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL_image::IMG_LoadTyped_RW(System.IntPtr,System.Int32,System.String)
+M: System.IntPtr SDL2.SDL_image::IMG_LoadTexture(System.IntPtr,System.String)
+M: System.IntPtr SDL2.SDL_image::IMG_LoadTexture_RW(System.IntPtr,System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL_image::IMG_LoadTextureTyped_RW(System.IntPtr,System.IntPtr,System.Int32,System.String)
+M: System.Int32 SDL2.SDL_image::IMG_InvertAlpha(System.Int32)
+M: System.IntPtr SDL2.SDL_image::IMG_ReadXPMFromArray(System.String[])
+M: System.Int32 SDL2.SDL_image::IMG_SavePNG(System.IntPtr,System.String)
+M: System.Int32 SDL2.SDL_image::IMG_SavePNG_RW(System.IntPtr,System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL_mixer::INTERNAL_MIX_Linked_Version()
+M: System.Int32 SDL2.SDL_mixer::Mix_Init(SDL2.SDL_mixer/MIX_InitFlags)
+M: System.Void SDL2.SDL_mixer::Mix_Quit()
+M: System.Int32 SDL2.SDL_mixer::Mix_OpenAudio(System.Int32,System.UInt16,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_AllocateChannels(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_QuerySpec(System.Int32&,System.UInt16&,System.Int32&)
+M: System.IntPtr SDL2.SDL_mixer::Mix_LoadWAV_RW(System.IntPtr,System.Int32)
+M: System.IntPtr SDL2.SDL_mixer::Mix_LoadMUS(System.String)
+M: System.IntPtr SDL2.SDL_mixer::Mix_QuickLoad_WAV(System.Byte[])
+M: System.IntPtr SDL2.SDL_mixer::Mix_QuickLoad_RAW(System.Byte[],System.UInt32)
+M: System.Void SDL2.SDL_mixer::Mix_FreeChunk(System.IntPtr)
+M: System.Void SDL2.SDL_mixer::Mix_FreeMusic(System.IntPtr)
+M: System.Int32 SDL2.SDL_mixer::Mix_GetNumChunkDecoders()
+M: System.String SDL2.SDL_mixer::Mix_GetChunkDecoder(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GetNumMusicDecoders()
+M: System.String SDL2.SDL_mixer::Mix_GetMusicDecoder(System.Int32)
+M: SDL2.SDL_mixer/Mix_MusicType SDL2.SDL_mixer::Mix_GetMusicType(System.IntPtr)
+M: System.Void SDL2.SDL_mixer::Mix_SetPostMix(SDL2.SDL_mixer/MixFuncDelegate,System.IntPtr)
+M: System.Void SDL2.SDL_mixer::Mix_HookMusic(SDL2.SDL_mixer/MixFuncDelegate,System.IntPtr)
+M: System.Void SDL2.SDL_mixer::Mix_HookMusicFinished(SDL2.SDL_mixer/MusicFinishedDelegate)
+M: System.IntPtr SDL2.SDL_mixer::Mix_GetMusicHookData()
+M: System.Void SDL2.SDL_mixer::Mix_ChannelFinished(SDL2.SDL_mixer/ChannelFinishedDelegate)
+M: System.Int32 SDL2.SDL_mixer::Mix_RegisterEffect(System.Int32,SDL2.SDL_mixer/Mix_EffectFunc_t,SDL2.SDL_mixer/Mix_EffectDone_t,System.IntPtr)
+M: System.Int32 SDL2.SDL_mixer::Mix_UnregisterEffect(System.Int32,SDL2.SDL_mixer/Mix_EffectFunc_t)
+M: System.Int32 SDL2.SDL_mixer::Mix_UnregisterAllEffects(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetPanning(System.Int32,System.Byte,System.Byte)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetPosition(System.Int32,System.Int16,System.Byte)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetDistance(System.Int32,System.Byte)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetReverseStereo(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_ReserveChannels(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupChannel(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupChannels(System.Int32,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupAvailable(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupCount(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupOldest(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GroupNewer(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_PlayChannelTimed(System.Int32,System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_PlayMusic(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeInMusic(System.IntPtr,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeInMusicPos(System.IntPtr,System.Int32,System.Int32,System.Double)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeInChannelTimed(System.Int32,System.IntPtr,System.Int32,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_Volume(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_VolumeChunk(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_VolumeMusic(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_HaltChannel(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_HaltGroup(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_HaltMusic()
+M: System.Int32 SDL2.SDL_mixer::Mix_ExpireChannel(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeOutChannel(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeOutGroup(System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_FadeOutMusic(System.Int32)
+M: SDL2.SDL_mixer/Mix_Fading SDL2.SDL_mixer::Mix_FadingMusic()
+M: SDL2.SDL_mixer/Mix_Fading SDL2.SDL_mixer::Mix_FadingChannel(System.Int32)
+M: System.Void SDL2.SDL_mixer::Mix_Pause(System.Int32)
+M: System.Void SDL2.SDL_mixer::Mix_Resume(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_Paused(System.Int32)
+M: System.Void SDL2.SDL_mixer::Mix_PauseMusic()
+M: System.Void SDL2.SDL_mixer::Mix_ResumeMusic()
+M: System.Void SDL2.SDL_mixer::Mix_RewindMusic()
+M: System.Int32 SDL2.SDL_mixer::Mix_PausedMusic()
+M: System.Int32 SDL2.SDL_mixer::Mix_SetMusicPosition(System.Double)
+M: System.Int32 SDL2.SDL_mixer::Mix_Playing(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_PlayingMusic()
+M: System.Int32 SDL2.SDL_mixer::Mix_SetMusicCMD(System.String)
+M: System.Int32 SDL2.SDL_mixer::Mix_SetSynchroValue(System.Int32)
+M: System.Int32 SDL2.SDL_mixer::Mix_GetSynchroValue()
+M: System.Int32 SDL2.SDL_mixer::Mix_SetSoundFonts(System.String)
+M: System.String SDL2.SDL_mixer::Mix_GetSoundFonts()
+M: System.Int32 SDL2.SDL_mixer::Mix_EachSoundFont(SDL2.SDL_mixer/SoundFontDelegate,System.IntPtr)
+M: System.IntPtr SDL2.SDL_mixer::Mix_GetChunk(System.Int32)
+M: System.Void SDL2.SDL_mixer::Mix_CloseAudio()
+M: System.IntPtr SDL2.SDL_ttf::INTERNAL_TTF_LinkedVersion()
+M: System.Void SDL2.SDL_ttf::TTF_ByteSwappedUNICODE(System.Int32)
+M: System.Int32 SDL2.SDL_ttf::TTF_Init()
+M: System.IntPtr SDL2.SDL_ttf::TTF_OpenFont(System.String,System.Int32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_OpenFontRW(System.IntPtr,System.Int32,System.Int32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_OpenFontIndex(System.String,System.Int32,System.Int64)
+M: System.IntPtr SDL2.SDL_ttf::TTF_OpenFontIndexRW(System.IntPtr,System.Int32,System.Int32,System.Int64)
+M: System.Int32 SDL2.SDL_ttf::TTF_GetFontStyle(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_SetFontStyle(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_ttf::TTF_GetFontOutline(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_SetFontOutline(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_ttf::TTF_GetFontHinting(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_SetFontHinting(System.IntPtr,System.Int32)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontHeight(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontAscent(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontDescent(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontLineSkip(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_GetFontKerning(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_SetFontKerning(System.IntPtr,System.Int32)
+M: System.Int64 SDL2.SDL_ttf::TTF_FontFaces(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_FontFaceIsFixedWidth(System.IntPtr)
+M: System.String SDL2.SDL_ttf::TTF_FontFaceFamilyName(System.IntPtr)
+M: System.String SDL2.SDL_ttf::TTF_FontFaceStyleName(System.IntPtr)
+M: System.Int32 SDL2.SDL_ttf::TTF_GlyphIsProvided(System.IntPtr,System.UInt16)
+M: System.Int32 SDL2.SDL_ttf::TTF_GlyphMetrics(System.IntPtr,System.UInt16,System.Int32&,System.Int32&,System.Int32&,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL_ttf::TTF_SizeText(System.IntPtr,System.String,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL_ttf::TTF_SizeUTF8(System.IntPtr,System.String,System.Int32&,System.Int32&)
+M: System.Int32 SDL2.SDL_ttf::TTF_SizeUNICODE(System.IntPtr,System.String,System.Int32&,System.Int32&)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderText_Solid(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUTF8_Solid(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUNICODE_Solid(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderGlyph_Solid(System.IntPtr,System.UInt16,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderText_Shaded(System.IntPtr,System.String,SDL2.SDL/SDL_Color,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUTF8_Shaded(System.IntPtr,System.String,SDL2.SDL/SDL_Color,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUNICODE_Shaded(System.IntPtr,System.String,SDL2.SDL/SDL_Color,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderGlyph_Shaded(System.IntPtr,System.UInt16,SDL2.SDL/SDL_Color,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderText_Blended(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUTF8_Blended(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUNICODE_Blended(System.IntPtr,System.String,SDL2.SDL/SDL_Color)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderText_Blended_Wrapped(System.IntPtr,System.String,SDL2.SDL/SDL_Color,System.UInt32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUTF8_Blended_Wrapped(System.IntPtr,System.String,SDL2.SDL/SDL_Color,System.UInt32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderUNICODE_Blended_Wrapped(System.IntPtr,System.String,SDL2.SDL/SDL_Color,System.UInt32)
+M: System.IntPtr SDL2.SDL_ttf::TTF_RenderGlyph_Blended(System.IntPtr,System.UInt16,SDL2.SDL/SDL_Color)
+M: System.Void SDL2.SDL_ttf::TTF_CloseFont(System.IntPtr)
+M: System.Void SDL2.SDL_ttf::TTF_Quit()
+M: System.Int32 SDL2.SDL_ttf::TTF_WasInit()
+M: System.Int32 SDL2.SDL_ttf::SDL_GetFontKerningSize(System.IntPtr,System.Int32,System.Int32)
+
+R: Gendarme.Rules.Naming.DoNotPrefixValuesWithEnumNameRule
+T: SDL2.SDL/SDL_BlendMode
+T: SDL2.SDL/SDL_TextureAccess
+T: SDL2.SDL/SDL_TextureModulate
+T: SDL2.SDL/SDL_Scancode
+T: SDL2.SDL_mixer/Mix_Fading
+
+R: Gendarme.Rules.Naming.DoNotUseReservedInEnumValueNamesRule
+T: SDL2.SDL/SDL_Keymod
+
+R: Gendarme.Rules.Design.EnumsShouldUseInt32Rule
+T: SDL2.SDL/SDL_MessageBoxFlags
+T: SDL2.SDL/SDL_MessageBoxButtonFlags
+T: SDL2.SDL/SDL_WindowEventID
+T: SDL2.SDL/SDL_WindowFlags
+T: SDL2.SDL/SDL_RendererFlags
+T: SDL2.SDL/SDL_EventType
+T: SDL2.SDL/SDL_Keymod
+
+R: Gendarme.Rules.Design.FlagsShouldNotDefineAZeroValueRule
+T: SDL2.SDL/SDL_BlendMode
+T: SDL2.SDL/SDL_RendererFlip
+T: SDL2.SDL/SDL_TextureModulate
+
+R: Gendarme.Rules.Design.MarkAssemblyWithAssemblyVersionRule
+A: SDL2-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithCLSCompliantRule
+A: SDL2-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithComVisibleRule
+A: SDL2-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Security.NativeFieldsShouldNotBeVisibleRule
+T: SDL2.SDL/SDL_MessageBoxData
+T: SDL2.SDL/SDL_DisplayMode
+T: SDL2.SDL/SDL_RendererInfo
+T: SDL2.SDL/SDL_Palette
+T: SDL2.SDL/SDL_PixelFormat
+T: SDL2.SDL/SDL_Surface
+T: SDL2.SDL/SDL_DropEvent
+T: SDL2.SDL/SDL_UserEvent
+T: SDL2.SDL/SDL_SysWMEvent
+T: SDL2.SDL/SDL_HapticCustom
+T: SDL2.SDL/SDL_AudioSpec
+T: SDL2.SDL/INTERNAL_windows_wminfo
+T: SDL2.SDL/INTERNAL_x11_wminfo
+T: SDL2.SDL/INTERNAL_directfb_wminfo
+T: SDL2.SDL/INTERNAL_cocoa_wminfo
+T: SDL2.SDL/INTERNAL_uikit_wminfo
+
+R: Gendarme.Rules.Performance.PreferLiteralOverInitOnlyFieldsRule
+T: SDL2.SDL
+T: SDL2.SDL_mixer
+
+R: Gendarme.Rules.Naming.UseCorrectCasingRule
+M: System.IntPtr SDL2.LPUtf8StrMarshaler::MarshalManagedToNative(System.Object)
+M: System.Void SDL2.LPUtf8StrMarshaler::CleanUpManagedData(System.Object)
+M: System.UInt32 SDL2.SDL::SDL_FOURCC(System.Byte,System.Byte,System.Byte,System.Byte)
+M: System.Int32 SDL2.SDL::SDL_VERSIONNUM(System.Int32,System.Int32,System.Int32)
+M: System.Boolean SDL2.SDL::SDL_VERSION_ATLEAST(System.Int32,System.Int32,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_WINDOWPOS_UNDEFINED_DISPLAY(System.Int32)
+M: System.Boolean SDL2.SDL::SDL_WINDOWPOS_ISUNDEFINED(System.Int32)
+M: System.Int32 SDL2.SDL::SDL_WINDOWPOS_CENTERED_DISPLAY(System.Int32)
+M: System.Boolean SDL2.SDL::SDL_WINDOWPOS_ISCENTERED(System.Int32)
+M: System.UInt32 SDL2.SDL::SDL_DEFINE_PIXELFOURCC(System.Byte,System.Byte,System.Byte,System.Byte)
+M: System.Byte SDL2.SDL::SDL_PIXELFLAG(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_PIXELTYPE(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_PIXELORDER(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_PIXELLAYOUT(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_BITSPERPIXEL(System.UInt32)
+M: System.Byte SDL2.SDL::SDL_BYTESPERPIXEL(System.UInt32)
+M: System.UInt32 SDL2.SDL::SDL_MasksToPixelFormatEnum(System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_PixelFormatEnumToMasks(System.UInt32,System.Int32&,System.UInt32&,System.UInt32&,System.UInt32&,System.UInt32&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_HasIntersection(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IntersectRect(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_IntersectRectAndLine(SDL2.SDL/SDL_Rect&,System.Int32&,System.Int32&,System.Int32&,System.Int32&)
+M: SDL2.SDL/SDL_bool SDL2.SDL::SDL_RectEquals(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: System.Void SDL2.SDL::SDL_UnionRect(SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&,SDL2.SDL/SDL_Rect&)
+M: System.IntPtr SDL2.SDL::SDL_CreateRGBSurface(System.UInt32,System.Int32,System.Int32,System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: System.IntPtr SDL2.SDL::SDL_CreateRGBSurfaceFrom(System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)
+M: System.Int32 SDL2.SDL::SDL_PollEvent(SDL2.SDL/SDL_Event&)
+M: System.Int32 SDL2.SDL::SDL_WaitEvent(SDL2.SDL/SDL_Event&)
+M: System.Int32 SDL2.SDL::SDL_WaitEventTimeout(SDL2.SDL/SDL_Event&,System.Int32)
+M: System.Int32 SDL2.SDL::SDL_PushEvent(SDL2.SDL/SDL_Event&)
+M: SDL2.SDL/SDL_Keycode SDL2.SDL::SDL_SCANCODE_TO_KEYCODE(SDL2.SDL/SDL_Scancode)
+M: System.UInt32 SDL2.SDL::SDL_BUTTON(System.UInt32)
+M: System.Boolean SDL2.SDL::SDL_TICKS_PASSED(System.UInt32,System.UInt32)
+M: System.Void SDL2.SDL_image::SDL_IMAGE_VERSION(SDL2.SDL/SDL_version&)
+M: System.Void SDL2.SDL_mixer::SDL_MIXER_VERSION(SDL2.SDL/SDL_version&)
+M: System.Void SDL2.SDL_ttf::SDL_TTF_VERSION(SDL2.SDL/SDL_version&)
+
+R: Gendarme.Rules.Naming.UseCorrectSuffixRule
+T: SDL2.SDL/SDL_MessageBoxFlags
+T: SDL2.SDL/SDL_MessageBoxButtonFlags
+T: SDL2.SDL/SDL_WindowFlags
+T: SDL2.SDL/SDL_RendererFlags
+T: SDL2.SDL/SDL_PIXELTYPE_ENUM
+T: SDL2.SDL/SDL_PIXELORDER_ENUM
+T: SDL2.SDL/SDL_PACKEDLAYOUT_ENUM
+T: SDL2.SDL/SDL_HapticCondition
+T: SDL2.SDL_image/IMG_InitFlags
+T: SDL2.SDL_mixer/MIX_InitFlags
+T: SDL2.SDL_mixer/MixFuncDelegate
+T: SDL2.SDL_mixer/MusicFinishedDelegate
+T: SDL2.SDL_mixer/ChannelFinishedDelegate
+T: SDL2.SDL_mixer/SoundFontDelegate
+
+R: Gendarme.Rules.Naming.UsePreferredTermsRule
+M: System.Void SDL2.SDL::SDL_LogInfo(System.Int32,System.String)
+T: SDL2.SDL/SDL_LogOutputFunction
+
+R: Gendarme.Rules.Naming.UseSingularNameInEnumsUnlessAreFlagsRule
+T: SDL2.SDL/SDL_TextureAccess
+T: SDL2.SDL/SDL_GameControllerAxis
+T: SDL2.SDL/SDL_AudioStatus
+
diff --git a/gendarme/theoraplay.ignore b/gendarme/theoraplay.ignore
new file mode 100644
index 0000000..a77657a
--- /dev/null
+++ b/gendarme/theoraplay.ignore
@@ -0,0 +1,61 @@
+R: Gendarme.Rules.Naming.AvoidNonAlphanumericIdentifierRule
+M: System.IntPtr TheoraPlay::THEORAPLAY_startDecodeFile(System.String,System.UInt32,TheoraPlay/THEORAPLAY_VideoFormat)
+M: System.Void TheoraPlay::THEORAPLAY_stopDecode(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_isDecoding(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_decodingError(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_isInitialized(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_hasVideoStream(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_hasAudioStream(System.IntPtr)
+M: System.UInt32 TheoraPlay::THEORAPLAY_availableVideo(System.IntPtr)
+M: System.UInt32 TheoraPlay::THEORAPLAY_availableAudio(System.IntPtr)
+M: System.IntPtr TheoraPlay::THEORAPLAY_getAudio(System.IntPtr)
+M: System.Void TheoraPlay::THEORAPLAY_freeAudio(System.IntPtr)
+M: System.IntPtr TheoraPlay::THEORAPLAY_getVideo(System.IntPtr)
+M: System.Void TheoraPlay::THEORAPLAY_freeVideo(System.IntPtr)
+T: TheoraPlay/THEORAPLAY_VideoFormat
+T: TheoraPlay/THEORAPLAY_VideoFrame
+T: TheoraPlay/THEORAPLAY_AudioPacket
+
+R: Gendarme.Rules.Design.AvoidVisibleFieldsRule
+T: TheoraPlay/THEORAPLAY_VideoFrame
+T: TheoraPlay/THEORAPLAY_AudioPacket
+
+R: Gendarme.Rules.Design.AvoidVisibleNestedTypesRule
+T: TheoraPlay/THEORAPLAY_VideoFormat
+T: TheoraPlay/THEORAPLAY_VideoFrame
+T: TheoraPlay/THEORAPLAY_AudioPacket
+
+R: Gendarme.Rules.Interoperability.CentralizePInvokesIntoNativeMethodsTypeRule
+M: System.IntPtr TheoraPlay::THEORAPLAY_startDecodeFile(System.String,System.UInt32,TheoraPlay/THEORAPLAY_VideoFormat)
+M: System.Void TheoraPlay::THEORAPLAY_stopDecode(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_isDecoding(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_decodingError(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_isInitialized(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_hasVideoStream(System.IntPtr)
+M: System.Int32 TheoraPlay::THEORAPLAY_hasAudioStream(System.IntPtr)
+M: System.UInt32 TheoraPlay::THEORAPLAY_availableVideo(System.IntPtr)
+M: System.UInt32 TheoraPlay::THEORAPLAY_availableAudio(System.IntPtr)
+M: System.IntPtr TheoraPlay::THEORAPLAY_getAudio(System.IntPtr)
+M: System.Void TheoraPlay::THEORAPLAY_freeAudio(System.IntPtr)
+M: System.IntPtr TheoraPlay::THEORAPLAY_getVideo(System.IntPtr)
+M: System.Void TheoraPlay::THEORAPLAY_freeVideo(System.IntPtr)
+
+R: Gendarme.Rules.Design.MarkAssemblyWithAssemblyVersionRule
+A: TheoraPlay-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithCLSCompliantRule
+A: TheoraPlay-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithComVisibleRule
+A: TheoraPlay-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Security.NativeFieldsShouldNotBeVisibleRule
+T: TheoraPlay/THEORAPLAY_VideoFrame
+T: TheoraPlay/THEORAPLAY_AudioPacket
+
+R: Gendarme.Rules.Naming.UseCorrectCasingRule
+M: TheoraPlay/THEORAPLAY_VideoFrame TheoraPlay::getVideoFrame(System.IntPtr)
+M: TheoraPlay/THEORAPLAY_AudioPacket TheoraPlay::getAudioPacket(System.IntPtr)
+M: System.Single[] TheoraPlay::getSamples(System.IntPtr,System.Int32)
+M: System.Byte[] TheoraPlay::getPixels(System.IntPtr,System.Int32)
+
diff --git a/gendarme/vorbisfile.ignore b/gendarme/vorbisfile.ignore
new file mode 100644
index 0000000..e02df67
--- /dev/null
+++ b/gendarme/vorbisfile.ignore
@@ -0,0 +1,94 @@
+R: Gendarme.Rules.Design.Generic.AvoidDeclaringCustomDelegatesRule
+T: Vorbisfile/read_func
+T: Vorbisfile/seek_func
+T: Vorbisfile/close_func
+T: Vorbisfile/tell_func
+
+R: Gendarme.Rules.Performance.AvoidLargeStructureRule
+T: Vorbisfile/vorbis_info
+
+R: Gendarme.Rules.Naming.AvoidNonAlphanumericIdentifierRule
+M: System.Int32 Vorbisfile::ov_fopen(System.String,System.IntPtr&)
+M: System.Int32 Vorbisfile::ov_open_callbacks(System.IntPtr,System.IntPtr&,System.IntPtr,System.IntPtr,Vorbisfile/ov_callbacks)
+M: Vorbisfile/vorbis_info Vorbisfile::ov_info(System.IntPtr,System.Int32)
+M: Vorbisfile/vorbis_comment Vorbisfile::ov_comment(System.IntPtr,System.Int32)
+M: System.Double Vorbisfile::ov_time_total(System.IntPtr,System.Int32)
+M: System.Int64 Vorbisfile::ov_read(System.IntPtr,System.Byte[],System.Int32,System.Int32,System.Int32,System.Int32,System.Int32&)
+M: System.Int64 Vorbisfile::ov_read(System.IntPtr,System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32&)
+M: System.Int32 Vorbisfile::ov_time_seek(System.IntPtr,System.Double)
+M: System.Int32 Vorbisfile::ov_clear(System.IntPtr&)
+T: Vorbisfile/SeekWhence
+T: Vorbisfile/read_func
+T: Vorbisfile/seek_func
+T: Vorbisfile/close_func
+T: Vorbisfile/tell_func
+T: Vorbisfile/vorbis_info
+T: Vorbisfile/vorbis_comment
+T: Vorbisfile/ov_callbacks
+
+R: Gendarme.Rules.Design.AvoidRefAndOutParametersRule
+M: System.Int32 Vorbisfile::ov_fopen(System.String,System.IntPtr&)
+M: System.Int32 Vorbisfile::ov_open_callbacks(System.IntPtr,System.IntPtr&,System.IntPtr,System.IntPtr,Vorbisfile/ov_callbacks)
+M: System.Int32 Vorbisfile::ov_clear(System.IntPtr&)
+
+R: Gendarme.Rules.Design.AvoidVisibleFieldsRule
+T: Vorbisfile/vorbis_info
+T: Vorbisfile/vorbis_comment
+T: Vorbisfile/ov_callbacks
+
+R: Gendarme.Rules.Design.AvoidVisibleNestedTypesRule
+T: Vorbisfile/SeekWhence
+T: Vorbisfile/read_func
+T: Vorbisfile/seek_func
+T: Vorbisfile/close_func
+T: Vorbisfile/tell_func
+T: Vorbisfile/vorbis_info
+T: Vorbisfile/vorbis_comment
+T: Vorbisfile/ov_callbacks
+
+R: Gendarme.Rules.Interoperability.CentralizePInvokesIntoNativeMethodsTypeRule
+M: System.IntPtr Vorbisfile::malloc(System.IntPtr)
+M: System.Void Vorbisfile::free(System.IntPtr)
+M: System.Int32 Vorbisfile::INTERNAL_ov_fopen(System.String,System.IntPtr)
+M: System.Int32 Vorbisfile::INTERNAL_ov_open_callbacks(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr,Vorbisfile/ov_callbacks)
+M: System.IntPtr Vorbisfile::INTERNAL_ov_info(System.IntPtr,System.Int32)
+M: System.IntPtr Vorbisfile::INTERNAL_ov_comment(System.IntPtr,System.Int32)
+M: System.Double Vorbisfile::ov_time_total(System.IntPtr,System.Int32)
+M: System.Int64 Vorbisfile::ov_read(System.IntPtr,System.Byte[],System.Int32,System.Int32,System.Int32,System.Int32,System.Int32&)
+M: System.Int64 Vorbisfile::ov_read(System.IntPtr,System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32&)
+M: System.Int32 Vorbisfile::ov_time_seek(System.IntPtr,System.Double)
+M: System.Int32 Vorbisfile::INTERNAL_ov_clear(System.IntPtr)
+
+R: Gendarme.Rules.Design.MarkAssemblyWithAssemblyVersionRule
+A: Vorbisfile-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithCLSCompliantRule
+A: Vorbisfile-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Design.MarkAssemblyWithComVisibleRule
+A: Vorbisfile-CS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
+R: Gendarme.Rules.Security.NativeFieldsShouldNotBeVisibleRule
+T: Vorbisfile/vorbis_info
+T: Vorbisfile/vorbis_comment
+
+R: Gendarme.Rules.Naming.UseCorrectCasingRule
+M: System.IntPtr Vorbisfile::malloc(System.IntPtr)
+M: System.Void Vorbisfile::free(System.IntPtr)
+M: System.Int32 Vorbisfile::ov_fopen(System.String,System.IntPtr&)
+M: System.Int32 Vorbisfile::ov_open_callbacks(System.IntPtr,System.IntPtr&,System.IntPtr,System.IntPtr,Vorbisfile/ov_callbacks)
+M: Vorbisfile/vorbis_info Vorbisfile::ov_info(System.IntPtr,System.Int32)
+M: Vorbisfile/vorbis_comment Vorbisfile::ov_comment(System.IntPtr,System.Int32)
+M: System.Double Vorbisfile::ov_time_total(System.IntPtr,System.Int32)
+M: System.Int64 Vorbisfile::ov_read(System.IntPtr,System.Byte[],System.Int32,System.Int32,System.Int32,System.Int32,System.Int32&)
+M: System.Int64 Vorbisfile::ov_read(System.IntPtr,System.IntPtr,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32&)
+M: System.Int32 Vorbisfile::ov_time_seek(System.IntPtr,System.Double)
+M: System.Int32 Vorbisfile::ov_clear(System.IntPtr&)
+T: Vorbisfile/read_func
+T: Vorbisfile/seek_func
+T: Vorbisfile/close_func
+T: Vorbisfile/tell_func
+T: Vorbisfile/vorbis_info
+T: Vorbisfile/vorbis_comment
+T: Vorbisfile/ov_callbacks
+
diff --git a/lib/MojoShader-CS b/lib/MojoShader-CS
new file mode 160000
index 0000000..5421230
--- /dev/null
+++ b/lib/MojoShader-CS
@@ -0,0 +1 @@
+Subproject commit 54212309dedb163a05092fc0ed6ef5bf8bba35da
diff --git a/lib/OpenAL-CS b/lib/OpenAL-CS
new file mode 160000
index 0000000..1babf1e
--- /dev/null
+++ b/lib/OpenAL-CS
@@ -0,0 +1 @@
+Subproject commit 1babf1e4baf88d843b98bf1ff7d651a2a1e7e36d
diff --git a/lib/SDL2-CS b/lib/SDL2-CS
new file mode 160000
index 0000000..5d5f415
--- /dev/null
+++ b/lib/SDL2-CS
@@ -0,0 +1 @@
+Subproject commit 5d5f4154bb9b9db5b0922ade470507210de06331
diff --git a/lib/TheoraPlay-CS b/lib/TheoraPlay-CS
new file mode 160000
index 0000000..d5bae69
--- /dev/null
+++ b/lib/TheoraPlay-CS
@@ -0,0 +1 @@
+Subproject commit d5bae691e56d0a4b7334206d6b92b4ff3cb2cd04
diff --git a/lib/Vorbisfile-CS b/lib/Vorbisfile-CS
new file mode 160000
index 0000000..844fbd1
--- /dev/null
+++ b/lib/Vorbisfile-CS
@@ -0,0 +1 @@
+Subproject commit 844fbd1ab7342a95d761f5e177678de954ec2a21
diff --git a/licenses/LICENSE b/licenses/LICENSE
new file mode 100644
index 0000000..2e7a0ba
--- /dev/null
+++ b/licenses/LICENSE
@@ -0,0 +1,63 @@
+Microsoft Public License (Ms-PL)
+FNA - Copyright 2009-2015 Ethan Lee and the MonoGame Team
+
+All rights reserved.
+
+This license governs use of the accompanying software. If you use the software,
+you accept this license. If you do not accept the license, do not use the
+software.
+
+1. Definitions
+
+The terms "reproduce," "reproduction," "derivative works," and "distribution"
+have the same meaning here as under U.S. copyright law.
+
+A "contribution" is the original software, or any additions or changes to the
+software.
+
+A "contributor" is any person that distributes its contribution under this
+license.
+
+"Licensed patents" are a contributor's patent claims that read directly on its
+contribution.
+
+2. Grant of Rights
+
+(A) Copyright Grant- Subject to the terms of this license, including the
+license conditions and limitations in section 3, each contributor grants you a
+non-exclusive, worldwide, royalty-free copyright license to reproduce its
+contribution, prepare derivative works of its contribution, and distribute its
+contribution or any derivative works that you create.
+
+(B) Patent Grant- Subject to the terms of this license, including the license
+conditions and limitations in section 3, each contributor grants you a
+non-exclusive, worldwide, royalty-free license under its licensed patents to
+make, have made, use, sell, offer for sale, import, and/or otherwise dispose of
+its contribution in the software or derivative works of the contribution in the
+software.
+
+3. Conditions and Limitations
+
+(A) No Trademark License- This license does not grant you rights to use any
+contributors' name, logo, or trademarks.
+
+(B) If you bring a patent claim against any contributor over patents that you
+claim are infringed by the software, your patent license from such contributor
+to the software ends automatically.
+
+(C) If you distribute any portion of the software, you must retain all
+copyright, patent, trademark, and attribution notices that are present in the
+software.
+
+(D) If you distribute any portion of the software in source code form, you may
+do so only under this license by including a complete copy of this license with
+your distribution. If you distribute any portion of the software in compiled or
+object code form, you may only do so under a license that complies with this
+license.
+
+(E) The software is licensed "as-is." You bear the risk of using it. The
+contributors give no express warranties, guarantees or conditions. You may have
+additional consumer rights under your local laws which this license cannot
+change. To the extent permitted under your local laws, the contributors exclude
+the implied warranties of merchantability, fitness for a particular purpose and
+non-infringement.
diff --git a/licenses/lzxdecoder.LICENSE b/licenses/lzxdecoder.LICENSE
new file mode 100644
index 0000000..c570d11
--- /dev/null
+++ b/licenses/lzxdecoder.LICENSE
@@ -0,0 +1,29 @@
+LzxDecoder.cs was derived from libmspack
+Copyright 2003-2004 Stuart Caie
+Copyright 2011 Ali Scissons
+
+The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
+by Microsoft Corporation.
+
+This source file is Dual licensed; meaning the end-user of this source file
+may redistribute/modify it under the LGPL 2.1 or MS-PL licenses.
+
+About
+-----
+This derived work is recognized by Stuart Caie and is authorized to adapt
+any changes made to lzxd.c in his libmspack library and will still retain
+this dual licensing scheme. Big thanks to Stuart Caie!
+
+This file is a pure C# port of the lzxd.c file from libmspack, with minor
+changes towards the decompression of XNB files. The original decompression
+software of LZX encoded data was written by Suart Caie in his
+libmspack/cabextract projects, which can be located at
+http://http://www.cabextract.org.uk/
+
+GNU Lesser General Public License, Version 2.1
+----------------------------------------------
+https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
+
+Microsoft Public License
+------------------------
+http://www.opensource.org/licenses/ms-pl.html
diff --git a/licenses/monoxna.LICENSE b/licenses/monoxna.LICENSE
new file mode 100644
index 0000000..185aa38
--- /dev/null
+++ b/licenses/monoxna.LICENSE
@@ -0,0 +1,22 @@
+MIT License
+Copyright 2006 The Mono.Xna Team
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/licenses/unxwb.LICENSE b/licenses/unxwb.LICENSE
new file mode 100644
index 0000000..db65e36
--- /dev/null
+++ b/licenses/unxwb.LICENSE
@@ -0,0 +1,12 @@
+The unxwb project, written by Luigi Auriemma, was released in 2006 under the
+GNU General Public License, version 2.0:
+
+http://www.gnu.org/licenses/gpl-2.0.html
+
+While the unxwb project was released under the GPL, Luigi has given express
+permission to the MonoGame project to use code from unxwb under the MonoGame
+project license. See LICENSE for details.
+
+The unxwb website can be found here:
+
+http://aluigi.altervista.org/papers.htm#xbox
diff --git a/src/Audio/AudioCategory.cs b/src/Audio/AudioCategory.cs
new file mode 100644
index 0000000..dccbe4a
--- /dev/null
+++ b/src/Audio/AudioCategory.cs
@@ -0,0 +1,337 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.audiocategory.aspx
+ public struct AudioCategory : IEquatable
+ {
+ #region Internal Primitive Type Container Class
+
+ internal class PrimitiveInstance
+ {
+ public T Value;
+ public PrimitiveInstance(T initial)
+ {
+ Value = initial;
+ }
+ }
+
+ #endregion
+
+ #region Public Properties
+
+ private string INTERNAL_name;
+ public string Name
+ {
+ get
+ {
+ return INTERNAL_name;
+ }
+ }
+
+ #endregion
+
+ #region Internal Variables
+
+ // Grumble, struct returns...
+ internal PrimitiveInstance INTERNAL_volume;
+
+ internal CrossfadeType crossfadeType;
+
+ #endregion
+
+ #region Private Variables
+
+ private List activeCues;
+
+ private Dictionary cueInstanceCounts;
+
+ private byte maxCueInstances;
+ private MaxInstanceBehavior maxCueBehavior;
+ private ushort maxFadeInMS;
+ private ushort maxFadeOutMS;
+
+ #endregion
+
+ #region Internal Constructor
+
+ internal AudioCategory(
+ string name,
+ float volume,
+ byte maxInstances,
+ int maxBehavior,
+ ushort fadeInMS,
+ ushort fadeOutMS,
+ int fadeType
+ ) {
+ INTERNAL_name = name;
+ INTERNAL_volume = new PrimitiveInstance(volume);
+ activeCues = new List();
+ cueInstanceCounts = new Dictionary();
+
+ maxCueInstances = maxInstances;
+ maxCueBehavior = (MaxInstanceBehavior) maxBehavior;
+ maxFadeInMS = fadeInMS;
+ maxFadeOutMS = fadeOutMS;
+ crossfadeType = (CrossfadeType) fadeType;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public void Pause()
+ {
+ lock (activeCues)
+ {
+ foreach (Cue curCue in activeCues)
+ {
+ curCue.Pause();
+ }
+ }
+ }
+
+ public void Resume()
+ {
+ lock (activeCues)
+ {
+ foreach (Cue curCue in activeCues)
+ {
+ curCue.Resume();
+ }
+ }
+ }
+
+ public void SetVolume(float volume)
+ {
+ lock (activeCues)
+ {
+ INTERNAL_volume.Value = volume;
+ }
+ }
+
+ public void Stop(AudioStopOptions options)
+ {
+ lock (activeCues)
+ {
+ while (activeCues.Count > 0)
+ {
+ Cue curCue = activeCues[0];
+ curCue.Stop(options);
+ curCue.SetVariable("NumCueInstances", 0);
+ cueInstanceCounts[curCue.Name] -= 1;
+ }
+ activeCues.Clear();
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return Name.GetHashCode();
+ }
+
+ public bool Equals(AudioCategory other)
+ {
+ return (GetHashCode() == other.GetHashCode());
+ }
+
+ public override bool Equals(Object obj)
+ {
+ if (obj is AudioCategory)
+ {
+ return Equals((AudioCategory) obj);
+ }
+ return false;
+ }
+
+ public static bool operator ==(
+ AudioCategory value1,
+ AudioCategory value2
+ ) {
+ return value1.Equals(value2);
+ }
+
+ public static bool operator !=(
+ AudioCategory value1,
+ AudioCategory value2
+ ) {
+ return !(value1.Equals(value2));
+ }
+
+ #endregion
+
+ #region Internal Methods
+
+ internal void INTERNAL_update()
+ {
+ /* Believe it or not, someone might run the update on a thread.
+ * So, we're going to give a lock to this method.
+ * -flibit
+ */
+ lock (activeCues)
+ {
+ for (int i = 0; i < activeCues.Count; i += 1)
+ {
+ if (!activeCues[i].INTERNAL_update())
+ {
+ i -= 1;
+ }
+ }
+ foreach (Cue curCue in activeCues)
+ {
+ curCue.SetVariable(
+ "NumCueInstances",
+ cueInstanceCounts[curCue.Name]
+ );
+ }
+ }
+ }
+
+ internal void INTERNAL_initCue(Cue newCue)
+ {
+ lock (activeCues)
+ {
+ if (!cueInstanceCounts.ContainsKey(newCue.Name))
+ {
+ cueInstanceCounts.Add(newCue.Name, 0);
+ }
+ newCue.SetVariable("NumCueInstances", cueInstanceCounts[newCue.Name]);
+ }
+ }
+
+ internal bool INTERNAL_addCue(Cue newCue)
+ {
+ lock (activeCues)
+ {
+ if (activeCues.Count >= maxCueInstances)
+ {
+ if (maxCueBehavior == MaxInstanceBehavior.Fail)
+ {
+ return false; // Just ignore us...
+ }
+ else if (maxCueBehavior == MaxInstanceBehavior.Queue)
+ {
+ newCue.INTERNAL_startFadeIn(maxFadeInMS);
+ activeCues[0].INTERNAL_startFadeOut(maxFadeOutMS);
+ }
+ else if (maxCueBehavior == MaxInstanceBehavior.ReplaceOldest)
+ {
+ INTERNAL_removeOldestCue(activeCues[0].Name);
+ }
+ else if (maxCueBehavior == MaxInstanceBehavior.ReplaceQuietest)
+ {
+ float lowestVolume = float.MaxValue;
+ int lowestIndex = -1;
+ for (int i = 0; i < activeCues.Count; i += 1)
+ {
+ float vol = activeCues[i].INTERNAL_calculateVolume();
+ if (vol < lowestVolume)
+ {
+ lowestVolume = vol;
+ lowestIndex = i;
+ }
+ }
+ if (lowestIndex > -1)
+ {
+ cueInstanceCounts[activeCues[lowestIndex].Name] -= 1;
+ activeCues[lowestIndex].Stop(AudioStopOptions.AsAuthored);
+ }
+ }
+ else if (maxCueBehavior == MaxInstanceBehavior.ReplaceLowestPriority)
+ {
+ // FIXME: Priority?
+ INTERNAL_removeOldestCue(activeCues[0].Name);
+ }
+ }
+ cueInstanceCounts[newCue.Name] += 1;
+ newCue.SetVariable("NumCueInstances", cueInstanceCounts[newCue.Name]);
+ activeCues.Add(newCue);
+ }
+ return true;
+ }
+
+ internal void INTERNAL_removeLatestCue()
+ {
+ lock (activeCues)
+ {
+ Cue toDie = activeCues[activeCues.Count - 1];
+ cueInstanceCounts[toDie.Name] -= 1;
+ activeCues.RemoveAt(activeCues.Count - 1);
+ }
+ }
+
+ internal void INTERNAL_removeOldestCue(string name)
+ {
+ lock (activeCues)
+ {
+ for (int i = 0; i < activeCues.Count; i += 1)
+ {
+ if (activeCues[i].Name.Equals(name))
+ {
+ activeCues[i].Stop(AudioStopOptions.AsAuthored);
+ return;
+ }
+ }
+ }
+ }
+
+ internal void INTERNAL_removeQuietestCue(string name)
+ {
+ float lowestVolume = float.MaxValue;
+ int lowestIndex = -1;
+
+ lock (activeCues)
+ {
+ for (int i = 0; i < activeCues.Count; i += 1)
+ {
+ if (activeCues[i].Name.Equals(name))
+ {
+ float vol = activeCues[i].INTERNAL_calculateVolume();
+ if (vol < lowestVolume)
+ {
+ lowestVolume = vol;
+ lowestIndex = i;
+ }
+ }
+ }
+
+ if (lowestIndex > -1)
+ {
+ cueInstanceCounts[name] -= 1;
+ activeCues[lowestIndex].Stop(AudioStopOptions.AsAuthored);
+ }
+ }
+ }
+
+ internal void INTERNAL_removeActiveCue(Cue cue)
+ {
+ // FIXME: Avoid calling this when a Cue is GC'd! -flibit
+ if (activeCues != null)
+ {
+ lock (activeCues)
+ {
+ if (activeCues.Contains(cue))
+ {
+ activeCues.Remove(cue);
+ cueInstanceCounts[cue.Name] -= 1;
+ }
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/AudioChannels.cs b/src/Audio/AudioChannels.cs
new file mode 100644
index 0000000..f36c02a
--- /dev/null
+++ b/src/Audio/AudioChannels.cs
@@ -0,0 +1,18 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.audiochannels.aspx
+ public enum AudioChannels
+ {
+ Mono = 1,
+ Stereo = 2
+ }
+}
diff --git a/src/Audio/AudioDevice.cs b/src/Audio/AudioDevice.cs
new file mode 100644
index 0000000..4806f2d
--- /dev/null
+++ b/src/Audio/AudioDevice.cs
@@ -0,0 +1,207 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ internal static class AudioDevice
+ {
+ #region RendererDetail List
+
+ public static ReadOnlyCollection Renderers;
+
+ #endregion
+
+ #region Internal AL Device
+
+ // FIXME: readonly? -flibit
+ public static IALDevice ALDevice;
+
+ #endregion
+
+ #region SoundEffect Management Variables
+
+ // FIXME: readonly? -flibit
+
+ // Used to store SoundEffectInstances generated internally.
+ public static List InstancePool;
+
+ // Used to store all DynamicSoundEffectInstances, to check buffer counts.
+ public static List DynamicInstancePool;
+
+ #endregion
+
+ #region Microphone Management Variables
+
+ // FIXME: readonly? -flibit
+
+ // Used to store Microphones that are currently recording
+ public static List ActiveMics;
+
+ #endregion
+
+ #region Public Static Initialize Method
+
+ public static void Initialize()
+ {
+ // We should only have one of these!
+ if (ALDevice != null)
+ {
+ System.Console.WriteLine("ALDevice already exists, overwriting!");
+ }
+
+ bool disableSound = Environment.GetEnvironmentVariable(
+ "FNA_AUDIO_DISABLE_SOUND"
+ ) == "1";
+
+ if (disableSound)
+ {
+ ALDevice = new NullDevice();
+ }
+ else
+ {
+ try
+ {
+ ALDevice = new OpenALDevice();
+ }
+ catch(DllNotFoundException e)
+ {
+ System.Console.WriteLine("OpenAL not found! Need FNA.dll.config?");
+ throw e;
+ }
+ catch(Exception)
+ {
+ /* We ignore and device creation exceptions,
+ * as they are handled down the line with Instance != null
+ */
+ }
+ }
+
+ // Populate device list
+ if (ALDevice != null)
+ {
+ Renderers = ALDevice.GetDevices();
+ Microphone.All = ALDevice.GetCaptureDevices();
+
+ InstancePool = new List();
+ DynamicInstancePool = new List();
+ ActiveMics = new List();
+ }
+ else
+ {
+ Renderers = new ReadOnlyCollection(new List());
+ Microphone.All = new ReadOnlyCollection(new List());
+ }
+ }
+
+ #endregion
+
+ #region Public Static Dispose Method
+
+ public static void Dispose()
+ {
+ if (ALDevice != null)
+ {
+ InstancePool.Clear();
+ DynamicInstancePool.Clear();
+ ALDevice.Dispose();
+ // ALDevice = null; <- May cause Exceptions!
+ }
+ }
+
+ #endregion
+
+ #region Public Static Update Methods
+
+ public static void Update()
+ {
+ if (ALDevice != null)
+ {
+ ALDevice.Update();
+
+ for (int i = 0; i < InstancePool.Count; i += 1)
+ {
+ if (InstancePool[i].State == SoundState.Stopped)
+ {
+ InstancePool[i].Dispose();
+ InstancePool.RemoveAt(i);
+ i -= 1;
+ }
+ }
+
+ foreach (DynamicSoundEffectInstance sfi in DynamicInstancePool)
+ {
+ sfi.Update();
+ }
+
+ foreach (Microphone mic in ActiveMics)
+ {
+ mic.CheckBuffer();
+ }
+ }
+ }
+
+ #endregion
+
+ #region Public Static Buffer Methods
+
+ public static IALBuffer GenBuffer()
+ {
+ if (ALDevice == null)
+ {
+ throw new NoAudioHardwareException();
+ }
+ return ALDevice.GenBuffer();
+ }
+
+ public static IALBuffer GenBuffer(
+ byte[] data,
+ uint sampleRate,
+ uint channels,
+ uint loopStart,
+ uint loopEnd,
+ bool isADPCM,
+ uint formatParameter
+ ) {
+ if (ALDevice == null)
+ {
+ throw new NoAudioHardwareException();
+ }
+ return ALDevice.GenBuffer(
+ data,
+ sampleRate,
+ channels,
+ loopStart,
+ loopEnd,
+ isADPCM,
+ formatParameter
+ );
+ }
+
+ #endregion
+
+ #region Public Static Reverb Methods
+
+ public static IALReverb GenReverb(DSPParameter[] parameters)
+ {
+ if (ALDevice == null)
+ {
+ throw new NoAudioHardwareException();
+ }
+ return ALDevice.GenReverb(parameters);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/AudioEmitter.cs b/src/Audio/AudioEmitter.cs
new file mode 100644
index 0000000..f8e7199
--- /dev/null
+++ b/src/Audio/AudioEmitter.cs
@@ -0,0 +1,78 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.audioemitter.aspx
+ public class AudioEmitter
+ {
+ #region Public Properties
+
+ private float INTERNAL_dopplerScale;
+ public float DopplerScale
+ {
+ get
+ {
+ return INTERNAL_dopplerScale;
+ }
+ set
+ {
+ if (value < 0.0f)
+ {
+ throw new ArgumentOutOfRangeException("AudioEmitter.DopplerScale must be greater than or equal to 0.0f");
+ }
+ INTERNAL_dopplerScale = value;
+ }
+ }
+
+ public Vector3 Forward
+ {
+ get;
+ set;
+ }
+
+ public Vector3 Position
+ {
+ get;
+ set;
+ }
+
+
+ public Vector3 Up
+ {
+ get;
+ set;
+ }
+
+ public Vector3 Velocity
+ {
+ get;
+ set;
+ }
+
+ #endregion
+
+ #region Public Constructor
+
+ public AudioEmitter()
+ {
+ DopplerScale = 1.0f;
+ Forward = Vector3.Forward;
+ Position = Vector3.Zero;
+ Up = Vector3.Up;
+ Velocity = Vector3.Zero;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/AudioEngine.cs b/src/Audio/AudioEngine.cs
new file mode 100644
index 0000000..c7d5e50
--- /dev/null
+++ b/src/Audio/AudioEngine.cs
@@ -0,0 +1,617 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/dd940262.aspx
+ public class AudioEngine : IDisposable
+ {
+ #region Public Constants
+
+ public const int ContentVersion = 46;
+
+ #endregion
+
+ #region Public Properties
+
+ public ReadOnlyCollection RendererDetails
+ {
+ get
+ {
+ return AudioDevice.Renderers;
+ }
+ }
+
+ public bool IsDisposed
+ {
+ get;
+ private set;
+ }
+
+ #endregion
+
+ #region Private Variables
+
+ private Dictionary INTERNAL_waveBanks;
+
+ private List INTERNAL_categories;
+ private List INTERNAL_variables;
+ private Dictionary INTERNAL_RPCs;
+ private List INTERNAL_dspParameters;
+ private Dictionary INTERNAL_dspPresets;
+
+ #endregion
+
+ #region Disposing Event
+
+ public event EventHandler Disposing;
+
+ #endregion
+
+ #region Public Constructors
+
+ public AudioEngine(string settingsFile)
+ {
+ if (String.IsNullOrEmpty(settingsFile))
+ {
+ throw new ArgumentNullException("settingsFile");
+ }
+
+ using (Stream stream = TitleContainer.OpenStream(settingsFile))
+ using (BinaryReader reader = new BinaryReader(stream))
+ {
+ // Check the file header. Should be 'XGSF'
+ if (reader.ReadUInt32() != 0x46534758)
+ {
+ throw new ArgumentException("XGSF format not recognized!");
+ }
+
+ // Check the Content and Tool versions
+ if (reader.ReadUInt16() != ContentVersion)
+ {
+ throw new ArgumentException("XGSF Content version!");
+ }
+ if (reader.ReadUInt16() != 42)
+ {
+ throw new ArgumentException("XGSF Tool version!");
+ }
+
+ // Unknown value
+ reader.ReadUInt16();
+
+ // Last Modified, Unused
+ reader.ReadUInt64();
+
+ // XACT Version, Unused
+ reader.ReadByte();
+
+ // Number of AudioCategories
+ ushort numCategories = reader.ReadUInt16();
+
+ // Number of XACT Variables
+ ushort numVariables = reader.ReadUInt16();
+
+ // KEY#1 Length
+ /*ushort numKeyOne =*/ reader.ReadUInt16();
+
+ // KEY#2 Length
+ /*ushort numKeyTwo =*/ reader.ReadUInt16();
+
+ // Number of RPC Variables
+ ushort numRPCs = reader.ReadUInt16();
+
+ // Number of DSP Presets/Parameters
+ ushort numDSPPresets = reader.ReadUInt16();
+ ushort numDSPParameters = reader.ReadUInt16();
+
+ // Category Offset in XGS File
+ uint categoryOffset = reader.ReadUInt32();
+
+ // Variable Offset in XGS File
+ uint variableOffset = reader.ReadUInt32();
+
+ // KEY#1 Offset
+ /*uint keyOneOffset =*/ reader.ReadUInt32();
+
+ // Category Name Index Offset, unused
+ reader.ReadUInt32();
+
+ // KEY#2 Offset
+ /*uint keyTwoOffset =*/ reader.ReadUInt32();
+
+ // Variable Name Index Offset, unused
+ reader.ReadUInt32();
+
+ // Category Name Offset in XGS File
+ uint categoryNameOffset = reader.ReadUInt32();
+
+ // Variable Name Offset in XGS File
+ uint variableNameOffset = reader.ReadUInt32();
+
+ // RPC Variable Offset in XGS File
+ uint rpcOffset = reader.ReadUInt32();
+
+ // DSP Preset/Parameter Offsets in XGS File
+ uint dspPresetOffset = reader.ReadUInt32();
+ uint dspParameterOffset = reader.ReadUInt32();
+
+ /* Unknown table #1
+ reader.BaseStream.Seek(keyOneOffset, SeekOrigin.Begin);
+ for (int i = 0; i < numKeyOne; i += 1)
+ {
+ // Appears to consistently be 16 shorts?
+ System.Console.WriteLine(reader.ReadInt16());
+ }
+ /* OhGodNo
+ * 1, -1, 4, -1,
+ * 3, -1, -1, 7,
+ * -1, 2, 5, -1,
+ * 6, 0, -1, -1
+ *
+ * Naddachance
+ * 1, -1, 4, -1,
+ * 5, -1, -1, -1,
+ * -1, 2, -1, -1,
+ * 3, 0, -1, -1
+ *
+ * TFA
+ * 1, -1, -1, -1,
+ * -1, -1, -1, -1,
+ * -1, 2, -1, -1,
+ * -1, -0, -1, -1
+ */
+
+ /* Unknown table #2
+ reader.BaseStream.Seek(keyTwoOffset, SeekOrigin.Begin);
+ for (int i = 0; i < numKeyTwo; i += 1)
+ {
+ // Appears to be between 16-20 shorts?
+ System.Console.WriteLine(reader.ReadInt16());
+ }
+ /* OhGodNo
+ * 2, 7, 1, -1,
+ * -1, 10, 19, -1,
+ * 11, 3, -1, -1,
+ * 8, -1, 14, 5,
+ * 12, 0, 4, 6
+ *
+ * Naddachance
+ * 2, 3, -1, -1,
+ * 9, -1, 7, -1,
+ * 10, 0, 1, 5,
+ * -1, -1, -1, -1
+ *
+ * TFA
+ * 2, 3, -1, -1,
+ * -1, -1, -1, -1,
+ * -1, 0, 1, 5,
+ * -1, -1, -1, -1
+ */
+
+ // Obtain the Audio Category Names
+ reader.BaseStream.Seek(categoryNameOffset, SeekOrigin.Begin);
+ string[] categoryNames = new string[numCategories];
+ for (int i = 0; i < numCategories; i += 1)
+ {
+ List builtString = new List();
+ while (reader.PeekChar() != 0)
+ {
+ builtString.Add(reader.ReadChar());
+ }
+ reader.ReadChar(); // Null terminator
+ categoryNames[i] = new string(builtString.ToArray());
+ }
+
+ // Obtain the Audio Categories
+ reader.BaseStream.Seek(categoryOffset, SeekOrigin.Begin);
+ INTERNAL_categories = new List();
+ for (int i = 0; i < numCategories; i += 1)
+ {
+ // Maximum instances
+ byte maxInstances = reader.ReadByte();
+
+ // Fade In/Out
+ ushort fadeInMS = reader.ReadUInt16();
+ ushort fadeOutMS = reader.ReadUInt16();
+
+ // Instance Behavior Flags
+ byte instanceFlags = reader.ReadByte();
+ int fadeType = instanceFlags & 0x07;
+ int maxBehavior = instanceFlags >> 3;
+
+ // Unknown value
+ reader.ReadUInt16();
+
+ // Volume
+ float volume = XACTCalculator.CalculateVolume(reader.ReadByte());
+
+ // Visibility Flags, unused
+ reader.ReadByte();
+
+ // Add to the engine list
+ INTERNAL_categories.Add(
+ new AudioCategory(
+ categoryNames[i],
+ volume,
+ maxInstances,
+ maxBehavior,
+ fadeInMS,
+ fadeOutMS,
+ fadeType
+ )
+ );
+ }
+
+ // Obtain the Variable Names
+ reader.BaseStream.Seek(variableNameOffset, SeekOrigin.Begin);
+ string[] variableNames = new string[numVariables];
+ for (int i = 0; i < numVariables; i += 1)
+ {
+ List builtString = new List();
+ while (reader.PeekChar() != 0)
+ {
+ builtString.Add(reader.ReadChar());
+ }
+ reader.ReadChar(); // Null terminator
+ variableNames[i] = new string(builtString.ToArray());
+ }
+
+ // Obtain the Variables
+ reader.BaseStream.Seek(variableOffset, SeekOrigin.Begin);
+ INTERNAL_variables = new List();
+ for (int i = 0; i < numVariables; i += 1)
+ {
+ // Variable Accessibility (See Variable constructor)
+ byte varFlags = reader.ReadByte();
+
+ // Variable Value, Boundaries
+ float initialValue = reader.ReadSingle();
+ float minValue = reader.ReadSingle();
+ float maxValue = reader.ReadSingle();
+
+ // Add to the engine list
+ INTERNAL_variables.Add(
+ new Variable(
+ variableNames[i],
+ (varFlags & 0x01) != 0,
+ (varFlags & 0x02) != 0,
+ (varFlags & 0x04) == 0,
+ (varFlags & 0x08) != 0,
+ initialValue,
+ minValue,
+ maxValue
+ )
+ );
+ }
+
+ // Obtain the RPC Curves
+ reader.BaseStream.Seek(rpcOffset, SeekOrigin.Begin);
+ INTERNAL_RPCs = new Dictionary();
+ for (int i = 0; i < numRPCs; i += 1)
+ {
+ // RPC "Code", used by the SoundBanks
+ long rpcCode = reader.BaseStream.Position;
+
+ // RPC Variable
+ ushort rpcVariable = reader.ReadUInt16();
+
+ // Number of RPC Curve Points
+ byte numPoints = reader.ReadByte();
+
+ // RPC Parameter
+ ushort rpcParameter = reader.ReadUInt16();
+
+ // RPC Curve Points
+ RPCPoint[] rpcPoints = new RPCPoint[numPoints];
+ for (byte j = 0; j < numPoints; j += 1)
+ {
+ float x = reader.ReadSingle();
+ float y = reader.ReadSingle();
+ byte type = reader.ReadByte();
+ rpcPoints[j] = new RPCPoint(
+ x, y,
+ (RPCPointType) type
+ );
+ }
+
+ // Add to the engine list
+ INTERNAL_RPCs.Add(
+ rpcCode,
+ new RPC(
+ INTERNAL_variables[rpcVariable].Name,
+ rpcParameter,
+ rpcPoints
+ )
+ );
+ }
+
+ // Obtain the DSP Parameters
+ reader.BaseStream.Seek(dspParameterOffset, SeekOrigin.Begin);
+ INTERNAL_dspParameters = new List();
+ for (int i = 0; i < numDSPParameters; i += 1)
+ {
+ // Effect Parameter Type
+ byte type = reader.ReadByte();
+
+ // Effect value, boundaries
+ float value = reader.ReadSingle();
+ float minVal = reader.ReadSingle();
+ float maxVal = reader.ReadSingle();
+
+ // Unknown value
+ reader.ReadUInt16();
+
+ // Add to Parameter list
+ INTERNAL_dspParameters.Add(
+ new DSPParameter(
+ type,
+ value,
+ minVal,
+ maxVal
+ )
+ );
+ }
+
+ // Obtain the DSP Presets
+ reader.BaseStream.Seek(dspPresetOffset, SeekOrigin.Begin);
+ INTERNAL_dspPresets = new Dictionary();
+ int total = 0;
+ for (int i = 0; i < numDSPPresets; i += 1)
+ {
+ // DSP "Code", used by the SoundBanks
+ long dspCode = reader.BaseStream.Position;
+
+ // Preset Accessibility
+ bool global = (reader.ReadByte() == 1);
+
+ // Number of preset parameters
+ uint numParams = reader.ReadUInt32();
+
+ // Obtain DSP Parameters
+ DSPParameter[] parameters = new DSPParameter[numParams];
+ for (uint j = 0; j < numParams; j += 1)
+ {
+ parameters[j] = INTERNAL_dspParameters[total];
+ total += 1;
+ }
+
+ // Add to DSP Preset list
+ INTERNAL_dspPresets.Add(
+ dspCode,
+ new DSPPreset(
+ global,
+ parameters
+ )
+ );
+ }
+ }
+
+ // Create the WaveBank Dictionary
+ INTERNAL_waveBanks = new Dictionary();
+
+ // Finally.
+ IsDisposed = false;
+ }
+
+ public AudioEngine(
+ string settingsFile,
+ TimeSpan lookAheadTime,
+ string rendererId
+ ) {
+ /* TODO: May require either resetting the ALDevice,
+ * or adding a second AL device/context for this engine.
+ * -flibit
+ */
+ throw new NotSupportedException();
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~AudioEngine()
+ {
+ Dispose();
+ }
+
+ #endregion
+
+ #region Public Dispose Methods
+
+ public void Dispose()
+ {
+ if (!IsDisposed)
+ {
+ if (Disposing != null)
+ {
+ Disposing.Invoke(this, null);
+ }
+ foreach (AudioCategory curCategory in INTERNAL_categories)
+ {
+ curCategory.Stop(AudioStopOptions.Immediate);
+ }
+ INTERNAL_categories.Clear();
+ foreach (KeyValuePair curDSP in INTERNAL_dspPresets)
+ {
+ curDSP.Value.Dispose();
+ }
+ INTERNAL_dspPresets.Clear();
+ INTERNAL_dspParameters.Clear();
+ INTERNAL_variables.Clear();
+ INTERNAL_RPCs.Clear();
+ IsDisposed = true;
+ }
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public AudioCategory GetCategory(string name)
+ {
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+ for (int i = 0; i < INTERNAL_categories.Count; i += 1)
+ {
+ if (INTERNAL_categories[i].Name.Equals(name))
+ {
+ return INTERNAL_categories[i];
+ }
+ }
+ throw new InvalidOperationException("Category not found!");
+ }
+
+ public float GetGlobalVariable(string name)
+ {
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+ for (int i = 0; i < INTERNAL_variables.Count; i += 1)
+ {
+ if (name.Equals(INTERNAL_variables[i].Name))
+ {
+ if (!INTERNAL_variables[i].IsGlobal)
+ {
+ throw new InvalidOperationException("Variable not global!");
+ }
+ return INTERNAL_variables[i].GetValue();
+ }
+ }
+ throw new InvalidOperationException("Variable not found!");
+ }
+
+ public void SetGlobalVariable(string name, float value)
+ {
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+ for (int i = 0; i < INTERNAL_variables.Count; i += 1)
+ {
+ if (name.Equals(INTERNAL_variables[i].Name))
+ {
+ if (!INTERNAL_variables[i].IsGlobal)
+ {
+ throw new InvalidOperationException("Variable not global!");
+ }
+ INTERNAL_variables[i].SetValue(value);
+ return; // We made it!
+ }
+ }
+ throw new InvalidOperationException("Variable not found!");
+ }
+
+ public void Update()
+ {
+ // Update Global RPCs
+ foreach (RPC curRPC in INTERNAL_RPCs.Values)
+ if (curRPC.Parameter >= RPCParameter.NUM_PARAMETERS)
+ foreach (Variable curVar in INTERNAL_variables)
+ if (curVar.Name.Equals(curRPC.Variable) && curVar.IsGlobal)
+ foreach (DSPPreset curDSP in INTERNAL_dspPresets.Values)
+ {
+ /* FIXME: This affects all DSP presets!
+ * What if there's more than one?
+ * -flibit
+ */
+ curDSP.SetParameter(
+ (int) curRPC.Parameter - (int) RPCParameter.NUM_PARAMETERS,
+ curRPC.CalculateRPC(GetGlobalVariable(curVar.Name))
+ );
+ }
+
+ // Apply all DSP changes once they have been made
+ foreach (DSPPreset curDSP in INTERNAL_dspPresets.Values)
+ {
+ AudioDevice.ALDevice.CommitReverbChanges(curDSP.Effect);
+ }
+
+ // Update Cues
+ foreach (AudioCategory curCategory in INTERNAL_categories)
+ {
+ curCategory.INTERNAL_update();
+ }
+ }
+
+ #endregion
+
+ #region Internal Methods
+
+ internal void INTERNAL_addWaveBank(string name, WaveBank waveBank)
+ {
+ INTERNAL_waveBanks.Add(name, waveBank);
+ }
+
+ internal void INTERNAL_removeWaveBank(string name)
+ {
+ INTERNAL_waveBanks.Remove(name);
+ }
+
+ internal SoundEffect INTERNAL_getWaveBankTrack(string name, ushort track)
+ {
+ return INTERNAL_waveBanks[name].INTERNAL_getTrack(track);
+ }
+
+ internal string INTERNAL_getVariableName(ushort index)
+ {
+ return INTERNAL_variables[index].Name;
+ }
+
+ internal RPC INTERNAL_getRPC(uint code)
+ {
+ return INTERNAL_RPCs[code];
+ }
+
+ internal IALReverb INTERNAL_getDSP(uint code)
+ {
+ return INTERNAL_dspPresets[code].Effect;
+ }
+
+ internal AudioCategory INTERNAL_initCue(Cue newCue, ushort category)
+ {
+ List cueVariables = new List();
+ foreach (Variable curVar in INTERNAL_variables)
+ {
+ if (!curVar.IsGlobal)
+ {
+ cueVariables.Add(curVar.Clone());
+ }
+ }
+ newCue.INTERNAL_genVariables(cueVariables);
+ return INTERNAL_categories[category];
+ }
+
+ internal bool INTERNAL_isGlobalVariable(string name)
+ {
+ // FIXME: Any way to speed this up? -flibit
+ foreach (Variable curVar in INTERNAL_variables)
+ {
+ if (name.Equals(curVar.Name))
+ {
+ return curVar.IsGlobal;
+ }
+ }
+
+ // Variable doesn't even exist here...!
+ return false;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/AudioListener.cs b/src/Audio/AudioListener.cs
new file mode 100644
index 0000000..f590d4f
--- /dev/null
+++ b/src/Audio/AudioListener.cs
@@ -0,0 +1,56 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.audiolistener.aspx
+ public class AudioListener
+ {
+ #region Public Properties
+
+ public Vector3 Forward
+ {
+ get;
+ set;
+ }
+
+ public Vector3 Position
+ {
+ get;
+ set;
+ }
+
+
+ public Vector3 Up
+ {
+ get;
+ set;
+ }
+
+ public Vector3 Velocity
+ {
+ get;
+ set;
+ }
+
+ #endregion
+
+ #region Public Constructor
+
+ public AudioListener()
+ {
+ Forward = Vector3.Forward;
+ Position = Vector3.Zero;
+ Up = Vector3.Up;
+ Velocity = Vector3.Zero;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/AudioStopOptions.cs b/src/Audio/AudioStopOptions.cs
new file mode 100644
index 0000000..9284429
--- /dev/null
+++ b/src/Audio/AudioStopOptions.cs
@@ -0,0 +1,18 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.audiostopoptions.aspx
+ public enum AudioStopOptions
+ {
+ AsAuthored,
+ Immediate
+ }
+}
diff --git a/src/Audio/Cue.cs b/src/Audio/Cue.cs
new file mode 100644
index 0000000..b07fdae
--- /dev/null
+++ b/src/Audio/Cue.cs
@@ -0,0 +1,898 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.cue.aspx
+ public sealed class Cue : IDisposable
+ {
+ #region Public Properties
+
+ public bool IsCreated
+ {
+ get;
+ private set;
+ }
+
+ public bool IsDisposed
+ {
+ get;
+ private set;
+ }
+
+ public bool IsPaused
+ {
+ get
+ {
+ return ( !INTERNAL_timer.IsRunning &&
+ INTERNAL_timer.ElapsedTicks > 0 );
+ }
+ }
+
+ public bool IsPlaying
+ {
+ get
+ {
+ return ( INTERNAL_timer.IsRunning ||
+ INTERNAL_timer.ElapsedTicks > 0 );
+ }
+ }
+
+ public bool IsPrepared
+ {
+ get;
+ private set;
+ }
+
+ public bool IsPreparing
+ {
+ get;
+ private set;
+ }
+
+ public bool IsStopped
+ {
+ get
+ {
+ return !IsPlaying;
+ }
+ }
+
+ public bool IsStopping
+ {
+ get
+ {
+ return INTERNAL_fadeMode == FadeMode.FadeOut;
+ }
+ }
+
+ public string Name
+ {
+ get;
+ private set;
+ }
+
+ #endregion
+
+ #region Private Variables
+
+ private AudioEngine INTERNAL_baseEngine;
+
+ // Cue information parsed from the SoundBank
+ private CueData INTERNAL_data;
+
+ // Current sound and its events
+ private XACTSound INTERNAL_activeSound;
+ private List INTERNAL_eventList;
+ private List INTERNAL_eventPlayed;
+ private Dictionary INTERNAL_eventLoops;
+ private Dictionary INTERNAL_waveEventSounds;
+
+ // Used for event timestamps
+ private Stopwatch INTERNAL_timer;
+
+ // Sound list
+ private List INTERNAL_instancePool;
+ private List INTERNAL_instanceVolumes;
+ private List INTERNAL_instancePitches;
+
+ // RPC data list
+ private List INTERNAL_rpcTrackVolumes;
+ private List INTERNAL_rpcTrackPitches;
+
+ // Events can control volume/pitch as well!
+ private float eventVolume;
+ private float eventPitch;
+
+ // User-controlled sounds require a bit more trickery.
+ private bool INTERNAL_userControlledPlaying;
+ private float INTERNAL_controlledValue;
+
+ // 3D audio variables
+ private bool INTERNAL_isPositional;
+ private AudioListener INTERNAL_listener;
+ private AudioEmitter INTERNAL_emitter;
+
+ // XACT instance variables
+ private List INTERNAL_variables;
+
+ // Category managing this Cue, and whether or not it's user-managed
+ private AudioCategory INTERNAL_category;
+ private bool INTERNAL_isManaged;
+
+ // Fading
+ private enum FadeMode
+ {
+ None,
+ FadeOut,
+ FadeIn
+ }
+ private long INTERNAL_fadeStart;
+ private long INTERNAL_fadeEnd;
+ private FadeMode INTERNAL_fadeMode = FadeMode.None;
+
+ #endregion
+
+ #region Private Static Random Number Generator
+
+ private static Random random = new Random();
+
+ #endregion
+
+ #region Disposing Event
+
+ public event EventHandler Disposing;
+
+ #endregion
+
+ #region Internal Constructor
+
+ internal Cue(
+ AudioEngine audioEngine,
+ List waveBankNames,
+ string name,
+ CueData data,
+ bool managed
+ ) {
+ INTERNAL_baseEngine = audioEngine;
+
+ Name = name;
+
+ INTERNAL_data = data;
+ foreach (XACTSound curSound in data.Sounds)
+ {
+ if (!curSound.HasLoadedTracks)
+ {
+ curSound.LoadTracks(
+ INTERNAL_baseEngine,
+ waveBankNames
+ );
+ }
+ }
+
+ INTERNAL_isManaged = managed;
+
+ INTERNAL_category = INTERNAL_baseEngine.INTERNAL_initCue(
+ this,
+ data.Category
+ );
+
+ eventVolume = 1.0f;
+ eventPitch = 0.0f;
+
+ INTERNAL_userControlledPlaying = false;
+ INTERNAL_isPositional = false;
+
+ INTERNAL_eventList = new List();
+ INTERNAL_eventPlayed = new List();
+ INTERNAL_eventLoops = new Dictionary();
+ INTERNAL_waveEventSounds = new Dictionary();
+
+ INTERNAL_timer = new Stopwatch();
+
+ INTERNAL_instancePool = new List();
+ INTERNAL_instanceVolumes = new List();
+ INTERNAL_instancePitches = new List();
+
+ INTERNAL_rpcTrackVolumes = new List();
+ INTERNAL_rpcTrackPitches = new List();
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~Cue()
+ {
+ Dispose();
+ }
+
+ #endregion
+
+ #region Public Dispose Method
+
+ public void Dispose()
+ {
+ if (!IsDisposed)
+ {
+ if (Disposing != null)
+ {
+ Disposing.Invoke(this, null);
+ }
+ if (INTERNAL_instancePool != null)
+ {
+ foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
+ {
+ sfi.Dispose();
+ }
+ INTERNAL_instancePool.Clear();
+ INTERNAL_instanceVolumes.Clear();
+ INTERNAL_instancePitches.Clear();
+ INTERNAL_rpcTrackVolumes.Clear();
+ INTERNAL_rpcTrackPitches.Clear();
+ INTERNAL_timer.Stop();
+ }
+ INTERNAL_category.INTERNAL_removeActiveCue(this);
+ IsDisposed = true;
+ }
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public void Apply3D(AudioListener listener, AudioEmitter emitter)
+ {
+ if (IsPlaying && !INTERNAL_isPositional)
+ {
+ throw new InvalidOperationException("Apply3D call after Play!");
+ }
+ if (listener == null)
+ {
+ throw new ArgumentNullException("listener");
+ }
+ if (emitter == null)
+ {
+ throw new ArgumentNullException("emitter");
+ }
+ INTERNAL_listener = listener;
+ INTERNAL_emitter = emitter;
+ SetVariable(
+ "Distance",
+ Vector3.Distance(
+ INTERNAL_emitter.Position,
+ INTERNAL_listener.Position
+ )
+ );
+ // TODO: DopplerPitchScaler, OrientationAngle
+ INTERNAL_isPositional = true;
+ }
+
+ public float GetVariable(string name)
+ {
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+ foreach (Variable curVar in INTERNAL_variables)
+ {
+ if (name.Equals(curVar.Name))
+ {
+ return curVar.GetValue();
+ }
+ }
+ throw new Exception("Instance variable not found!");
+ }
+
+ public void Pause()
+ {
+ if (IsPlaying)
+ {
+ INTERNAL_timer.Stop();
+ foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
+ {
+ sfi.Pause();
+ }
+ }
+ }
+
+ public void Play()
+ {
+ if (IsPlaying)
+ {
+ throw new InvalidOperationException("Cue already playing!");
+ }
+
+ INTERNAL_category.INTERNAL_initCue(this);
+
+ if (GetVariable("NumCueInstances") >= INTERNAL_data.InstanceLimit)
+ {
+ if (INTERNAL_data.MaxCueBehavior == MaxInstanceBehavior.Fail)
+ {
+ return; // Just ignore us...
+ }
+ else if (INTERNAL_data.MaxCueBehavior == MaxInstanceBehavior.Queue)
+ {
+ throw new Exception("Cue Queueing not handled!");
+ }
+ else if (INTERNAL_data.MaxCueBehavior == MaxInstanceBehavior.ReplaceOldest)
+ {
+ INTERNAL_category.INTERNAL_removeOldestCue(Name);
+ }
+ else if (INTERNAL_data.MaxCueBehavior == MaxInstanceBehavior.ReplaceQuietest)
+ {
+ INTERNAL_category.INTERNAL_removeQuietestCue(Name);
+ }
+ else if (INTERNAL_data.MaxCueBehavior == MaxInstanceBehavior.ReplaceLowestPriority)
+ {
+ // FIXME: Priority?
+ INTERNAL_category.INTERNAL_removeOldestCue(Name);
+ }
+ }
+
+ if (!INTERNAL_category.INTERNAL_addCue(this))
+ {
+ return;
+ }
+
+ INTERNAL_timer.Start();
+ if (INTERNAL_data.FadeInMS > 0)
+ {
+ INTERNAL_startFadeIn(INTERNAL_data.FadeInMS);
+ }
+
+ if (!INTERNAL_calculateNextSound())
+ {
+ return;
+ }
+
+ INTERNAL_activeSound.GatherEvents(INTERNAL_eventList);
+ foreach (XACTEvent evt in INTERNAL_eventList)
+ {
+ INTERNAL_eventPlayed.Add(false);
+ INTERNAL_eventLoops.Add(evt, 0);
+ }
+ }
+
+ public void Resume()
+ {
+ if (IsPaused)
+ {
+ INTERNAL_timer.Start();
+ foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
+ {
+ sfi.Resume();
+ }
+ }
+ }
+
+ public void SetVariable(string name, float value)
+ {
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+ foreach (Variable curVar in INTERNAL_variables)
+ {
+ if (name.Equals(curVar.Name))
+ {
+ curVar.SetValue(value);
+ return;
+ }
+ }
+ throw new Exception("Instance variable not found!");
+ }
+
+ public void Stop(AudioStopOptions options)
+ {
+ if (IsPlaying)
+ {
+ if ( options == AudioStopOptions.AsAuthored &&
+ INTERNAL_data.FadeOutMS > 0 )
+ {
+ INTERNAL_startFadeOut(INTERNAL_data.FadeOutMS);
+ return;
+ }
+ INTERNAL_timer.Stop();
+ INTERNAL_timer.Reset();
+ foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
+ {
+ sfi.Stop();
+ sfi.Dispose();
+ }
+ INTERNAL_instancePool.Clear();
+ INTERNAL_instanceVolumes.Clear();
+ INTERNAL_instancePitches.Clear();
+ INTERNAL_rpcTrackVolumes.Clear();
+ INTERNAL_rpcTrackPitches.Clear();
+ INTERNAL_userControlledPlaying = false;
+ INTERNAL_category.INTERNAL_removeActiveCue(this);
+
+ // If this is a managed Cue, we're done here.
+ if (INTERNAL_isManaged)
+ {
+ Dispose();
+ }
+ }
+ }
+
+ #endregion
+
+ #region Internal Methods
+
+ internal bool INTERNAL_update()
+ {
+ // If we're not running, save some instructions...
+ if (!INTERNAL_timer.IsRunning)
+ {
+ return true;
+ }
+
+ // Play events when the timestamp has been hit.
+ for (int i = 0; i < INTERNAL_eventList.Count; i += 1)
+ {
+ if ( !INTERNAL_eventPlayed[i] &&
+ INTERNAL_timer.ElapsedMilliseconds > INTERNAL_eventList[i].Timestamp )
+ {
+ uint type = INTERNAL_eventList[i].Type;
+ if (type == 1)
+ {
+ PlayWave((PlayWaveEvent) INTERNAL_eventList[i]);
+ }
+ else if (type == 2)
+ {
+ eventVolume = ((SetVolumeEvent) INTERNAL_eventList[i]).GetVolume();
+ }
+ else if (type == 3)
+ {
+ eventPitch = ((SetPitchEvent) INTERNAL_eventList[i]).GetPitch();
+ }
+ else
+ {
+ throw new Exception("Unhandled XACTEvent type!");
+ }
+ INTERNAL_eventPlayed[i] = true;
+ }
+ }
+
+ // Clear out sound effect instances as they finish
+ for (int i = 0; i < INTERNAL_instancePool.Count; i += 1)
+ {
+ if (INTERNAL_instancePool[i].State == SoundState.Stopped)
+ {
+ // Get the event that spawned this instance...
+ PlayWaveEvent evt = (PlayWaveEvent) INTERNAL_waveEventSounds[INTERNAL_instancePool[i]];
+
+ // Then delete all the guff
+ INTERNAL_waveEventSounds.Remove(INTERNAL_instancePool[i]);
+ INTERNAL_instancePool[i].Dispose();
+ INTERNAL_instancePool.RemoveAt(i);
+ INTERNAL_instanceVolumes.RemoveAt(i);
+ INTERNAL_instancePitches.RemoveAt(i);
+ INTERNAL_rpcTrackVolumes.RemoveAt(i);
+ INTERNAL_rpcTrackPitches.RemoveAt(i);
+
+ // Increment the loop counter, try to get another loop
+ INTERNAL_eventLoops[evt] += 1;
+ PlayWave(evt);
+
+ // Removed a wave, have to step back...
+ i -= 1;
+ }
+ }
+
+ // Fade in/out
+ float fadePerc = 1.0f;
+ if (INTERNAL_fadeMode != FadeMode.None)
+ {
+ if (INTERNAL_fadeMode == FadeMode.FadeOut)
+ {
+ if (INTERNAL_category.crossfadeType == CrossfadeType.Linear)
+ {
+ fadePerc = (INTERNAL_fadeEnd - (INTERNAL_timer.ElapsedMilliseconds - INTERNAL_fadeStart)) / (float) INTERNAL_fadeEnd;
+ }
+ else
+ {
+ throw new NotImplementedException("Unhandled CrossfadeType!");
+ }
+ if (fadePerc <= 0.0f)
+ {
+ Stop(AudioStopOptions.Immediate);
+ INTERNAL_fadeMode = FadeMode.None;
+ return false;
+ }
+ }
+ else
+ {
+ if (INTERNAL_category.crossfadeType == CrossfadeType.Linear)
+ {
+ fadePerc = INTERNAL_timer.ElapsedMilliseconds / (float) INTERNAL_fadeEnd;
+ }
+ else
+ {
+ throw new NotImplementedException("Unhandled CrossfadeType!");
+ }
+ if (fadePerc > 1.0f)
+ {
+ fadePerc = 1.0f;
+ INTERNAL_fadeMode = FadeMode.None;
+ }
+ }
+ }
+
+ // User control updates
+ if (INTERNAL_data.IsUserControlled)
+ {
+ string varName = INTERNAL_data.UserControlVariable;
+ if ( INTERNAL_userControlledPlaying &&
+ (INTERNAL_baseEngine.INTERNAL_isGlobalVariable(varName) ?
+ !MathHelper.WithinEpsilon(INTERNAL_controlledValue, INTERNAL_baseEngine.GetGlobalVariable(varName)) :
+ !MathHelper.WithinEpsilon(INTERNAL_controlledValue, GetVariable(INTERNAL_data.UserControlVariable))) )
+ {
+ // TODO: Crossfading
+ foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
+ {
+ sfi.Stop();
+ sfi.Dispose();
+ }
+ INTERNAL_instancePool.Clear();
+ INTERNAL_instanceVolumes.Clear();
+ INTERNAL_instancePitches.Clear();
+ INTERNAL_rpcTrackVolumes.Clear();
+ INTERNAL_rpcTrackPitches.Clear();
+ if (!INTERNAL_calculateNextSound())
+ {
+ // Nothing to play, bail.
+ return true;
+ }
+ INTERNAL_activeSound.GatherEvents(INTERNAL_eventList);
+ foreach (XACTEvent evt in INTERNAL_eventList)
+ {
+ INTERNAL_eventPlayed.Add(false);
+ INTERNAL_eventLoops.Add(evt, 0);
+ }
+ INTERNAL_timer.Stop();
+ INTERNAL_timer.Reset();
+ INTERNAL_timer.Start();
+ }
+
+ if (INTERNAL_activeSound == null)
+ {
+ return INTERNAL_userControlledPlaying;
+ }
+ }
+
+ // If everything has been played and finished, we're done here.
+ if (INTERNAL_instancePool.Count == 0)
+ {
+ bool allPlayed = true;
+ foreach (bool played in INTERNAL_eventPlayed)
+ {
+ if (!played)
+ {
+ allPlayed = false;
+ break;
+ }
+ }
+ if (allPlayed)
+ {
+ // If this is managed, we're done completely.
+ if (INTERNAL_isManaged)
+ {
+ Dispose();
+ }
+ else
+ {
+ INTERNAL_timer.Stop();
+ INTERNAL_timer.Reset();
+ INTERNAL_category.INTERNAL_removeActiveCue(this);
+ }
+ return INTERNAL_userControlledPlaying;
+ }
+ }
+
+ // RPC updates
+ float rpcVolume = 1.0f;
+ float rpcPitch = 0.0f;
+ float hfGain = 1.0f;
+ float lfGain = 1.0f;
+ for (int i = 0; i < INTERNAL_activeSound.RPCCodes.Count; i += 1)
+ {
+ if (i > INTERNAL_instancePool.Count)
+ {
+ break;
+ }
+ if (i > 0)
+ {
+ INTERNAL_rpcTrackVolumes[i - 1] = 1.0f;
+ INTERNAL_rpcTrackPitches[i - 1] = 0.0f;
+ }
+ foreach (uint curCode in INTERNAL_activeSound.RPCCodes[i])
+ {
+ RPC curRPC = INTERNAL_baseEngine.INTERNAL_getRPC(curCode);
+ float result;
+ if (!INTERNAL_baseEngine.INTERNAL_isGlobalVariable(curRPC.Variable))
+ {
+ result = curRPC.CalculateRPC(GetVariable(curRPC.Variable));
+ }
+ else
+ {
+ // It's a global variable we're looking for!
+ result = curRPC.CalculateRPC(
+ INTERNAL_baseEngine.GetGlobalVariable(
+ curRPC.Variable
+ )
+ );
+ }
+ if (curRPC.Parameter == RPCParameter.Volume)
+ {
+ float vol = XACTCalculator.CalculateAmplitudeRatio(result / 100.0);
+ if (i == 0)
+ {
+ rpcVolume *= vol;
+ }
+ else
+ {
+ INTERNAL_rpcTrackVolumes[i - 1] *= vol;
+ }
+ }
+ else if (curRPC.Parameter == RPCParameter.Pitch)
+ {
+ float pitch = result / 1000.0f;
+ if (i == 0)
+ {
+ rpcPitch += pitch;
+ }
+ else
+ {
+ INTERNAL_rpcTrackPitches[i - 1] += pitch;
+ }
+ }
+ else if (curRPC.Parameter == RPCParameter.FilterFrequency)
+ {
+ // FIXME: Just listening to the last RPC!
+ float hf = result / 20000.0f;
+ float lf = 1.0f - hf;
+ if (i == 0)
+ {
+ hfGain = hf;
+ lfGain = lf;
+ }
+ else
+ {
+ throw new NotImplementedException("Per-track filter RPCs!");
+ }
+ }
+ else
+ {
+ throw new Exception("RPC Parameter Type: " + curRPC.Parameter.ToString());
+ }
+ }
+ }
+
+ // Sound effect instance updates
+ for (int i = 0; i < INTERNAL_instancePool.Count; i += 1)
+ {
+ /* The final volume should be the combination of the
+ * authored volume, category volume, RPC/Event volumes, and fade.
+ */
+ INTERNAL_instancePool[i].Volume = (
+ INTERNAL_instanceVolumes[i] *
+ INTERNAL_category.INTERNAL_volume.Value *
+ rpcVolume *
+ INTERNAL_rpcTrackVolumes[i] *
+ eventVolume *
+ fadePerc
+ );
+
+ /* The final pitch should be the combination of the
+ * authored pitch and RPC/Event pitch results.
+ */
+ INTERNAL_instancePool[i].Pitch = (
+ INTERNAL_instancePitches[i] +
+ rpcPitch +
+ eventPitch +
+ INTERNAL_rpcTrackPitches[i]
+ );
+
+ /* The final filter is determined by the instance's filter type,
+ * in addition to our calculation of the HF/LF gain values.
+ */
+ byte fType = INTERNAL_instancePool[i].FilterType;
+ if (fType == 0xFF)
+ {
+ // No-op, no filter!
+ }
+ else if (fType == 0)
+ {
+ INTERNAL_instancePool[i].INTERNAL_applyLowPassFilter(hfGain);
+ }
+ else if (fType == 1)
+ {
+ INTERNAL_instancePool[i].INTERNAL_applyHighPassFilter(lfGain);
+ }
+ else if (fType == 2)
+ {
+ INTERNAL_instancePool[i].INTERNAL_applyBandPassFilter(hfGain, lfGain);
+ }
+ else
+ {
+ throw new InvalidOperationException("Unhandled filter type!");
+ }
+
+ // Update 3D position, if applicable
+ if (INTERNAL_isPositional)
+ {
+ INTERNAL_instancePool[i].Apply3D(
+ INTERNAL_listener,
+ INTERNAL_emitter
+ );
+ }
+ }
+
+ return true;
+ }
+
+ internal void INTERNAL_genVariables(List cueVariables)
+ {
+ INTERNAL_variables = cueVariables;
+ }
+
+ internal float INTERNAL_calculateVolume()
+ {
+ float retval = 1.0f;
+ for (int i = 0; i < INTERNAL_activeSound.RPCCodes.Count; i += 1)
+ foreach (uint curCode in INTERNAL_activeSound.RPCCodes[i])
+ {
+ RPC curRPC = INTERNAL_baseEngine.INTERNAL_getRPC(curCode);
+ if (curRPC.Parameter != RPCParameter.Volume)
+ {
+ continue;
+ }
+ float result;
+ if (!INTERNAL_baseEngine.INTERNAL_isGlobalVariable(curRPC.Variable))
+ {
+ result = curRPC.CalculateRPC(GetVariable(curRPC.Variable));
+ }
+ else
+ {
+ // It's a global variable we're looking for!
+ result = curRPC.CalculateRPC(
+ INTERNAL_baseEngine.GetGlobalVariable(
+ curRPC.Variable
+ )
+ );
+ }
+ retval *= XACTCalculator.CalculateAmplitudeRatio(result / 100.0);
+ }
+ return retval;
+ }
+
+ internal void INTERNAL_startFadeIn(ushort ms)
+ {
+ // start is not used, since it's always 0 anyway -flibit
+ INTERNAL_fadeEnd = ms;
+ INTERNAL_fadeMode = FadeMode.FadeIn;
+ }
+
+ internal void INTERNAL_startFadeOut(ushort ms)
+ {
+ INTERNAL_fadeStart = INTERNAL_timer.ElapsedMilliseconds;
+ INTERNAL_fadeEnd = ms;
+ INTERNAL_fadeMode = FadeMode.FadeOut;
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private bool INTERNAL_calculateNextSound()
+ {
+ INTERNAL_activeSound = null;
+ INTERNAL_eventList.Clear();
+ INTERNAL_eventPlayed.Clear();
+ INTERNAL_eventLoops.Clear();
+ INTERNAL_waveEventSounds.Clear();
+
+ // Pick a sound based on a Cue instance variable
+ if (INTERNAL_data.IsUserControlled)
+ {
+ INTERNAL_userControlledPlaying = true;
+ if (INTERNAL_baseEngine.INTERNAL_isGlobalVariable(INTERNAL_data.UserControlVariable))
+ {
+ INTERNAL_controlledValue = INTERNAL_baseEngine.GetGlobalVariable(
+ INTERNAL_data.UserControlVariable
+ );
+ }
+ else
+ {
+ INTERNAL_controlledValue = GetVariable(
+ INTERNAL_data.UserControlVariable
+ );
+ }
+ for (int i = 0; i < INTERNAL_data.Probabilities.Length / 2; i += 1)
+ {
+ if ( INTERNAL_controlledValue <= INTERNAL_data.Probabilities[i, 0] &&
+ INTERNAL_controlledValue >= INTERNAL_data.Probabilities[i, 1] )
+ {
+ INTERNAL_activeSound = INTERNAL_data.Sounds[i];
+ return true;
+ }
+ }
+
+ /* This should only happen when the
+ * UserControlVariable is none of the sound
+ * probabilities, in which case we are just
+ * silent. But, we are still claiming to be
+ * "playing" in the meantime.
+ * -flibit
+ */
+ return false;
+ }
+
+ // Randomly pick a sound
+ double max = 0.0;
+ for (int i = 0; i < INTERNAL_data.Probabilities.GetLength(0); i += 1)
+ {
+ max += INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1];
+ }
+ double next = random.NextDouble() * max;
+
+ for (int i = INTERNAL_data.Probabilities.GetLength(0) - 1; i >= 0; i -= 1)
+ {
+ if (next > max - (INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1]))
+ {
+ INTERNAL_activeSound = INTERNAL_data.Sounds[i];
+ break;
+ }
+ max -= INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1];
+ }
+
+ return true;
+ }
+
+ private void PlayWave(PlayWaveEvent evt)
+ {
+ SoundEffectInstance sfi = evt.GenerateInstance(
+ INTERNAL_activeSound.Volume,
+ INTERNAL_activeSound.Pitch,
+ INTERNAL_eventLoops[evt]
+ );
+ if (sfi != null)
+ {
+ if (INTERNAL_isPositional)
+ {
+ sfi.Apply3D(INTERNAL_listener, INTERNAL_emitter);
+ }
+ foreach (uint curDSP in INTERNAL_activeSound.DSPCodes)
+ {
+ // FIXME: This only applies the last DSP!
+ sfi.INTERNAL_applyReverb(
+ INTERNAL_baseEngine.INTERNAL_getDSP(curDSP)
+ );
+ }
+ INTERNAL_instancePool.Add(sfi);
+ INTERNAL_instanceVolumes.Add(sfi.Volume);
+ INTERNAL_instancePitches.Add(sfi.Pitch);
+ INTERNAL_waveEventSounds.Add(sfi, evt);
+ INTERNAL_rpcTrackVolumes.Add(1.0f);
+ INTERNAL_rpcTrackPitches.Add(0.0f);
+ sfi.Play();
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/CueData.cs b/src/Audio/CueData.cs
new file mode 100644
index 0000000..1e01da4
--- /dev/null
+++ b/src/Audio/CueData.cs
@@ -0,0 +1,985 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.IO;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ internal class CueData
+ {
+ public XACTSound[] Sounds
+ {
+ get;
+ private set;
+ }
+
+ public ushort Category
+ {
+ get;
+ private set;
+ }
+
+ public float[,] Probabilities
+ {
+ get;
+ private set;
+ }
+
+ public bool IsUserControlled
+ {
+ get;
+ private set;
+ }
+
+ public string UserControlVariable
+ {
+ get;
+ private set;
+ }
+
+ public byte InstanceLimit
+ {
+ get;
+ private set;
+ }
+
+ public MaxInstanceBehavior MaxCueBehavior
+ {
+ get;
+ private set;
+ }
+
+ public ushort FadeInMS
+ {
+ get;
+ private set;
+ }
+
+ public ushort FadeOutMS
+ {
+ get;
+ private set;
+ }
+
+ public CueData(XACTSound sound)
+ {
+ Sounds = new XACTSound[1];
+ Probabilities = new float[1, 2];
+
+ Sounds[0] = sound;
+ Category = sound.Category;
+ Probabilities[0, 0] = 1.0f;
+ Probabilities[0, 1] = 0.0f;
+ IsUserControlled = false;
+
+ // Assume we can have max instances, for now.
+ InstanceLimit = 255;
+ MaxCueBehavior = MaxInstanceBehavior.ReplaceOldest;
+ FadeInMS = 0;
+ FadeOutMS = 0;
+ }
+
+ public CueData(
+ XACTSound[] sounds,
+ float[,] probabilities,
+ string controlVariable
+ ) {
+ Sounds = sounds;
+ Category = Sounds[0].Category; // FIXME: Assumption!
+ Probabilities = probabilities;
+ IsUserControlled = !String.IsNullOrEmpty(controlVariable);
+ UserControlVariable = controlVariable;
+
+ // Assume we can have max instances, for now.
+ InstanceLimit = 255;
+ MaxCueBehavior = MaxInstanceBehavior.ReplaceOldest;
+ FadeInMS = 0;
+ FadeOutMS = 0;
+ }
+
+ public void SetLimit(
+ byte instanceLimit,
+ byte behavior,
+ ushort fadeIn,
+ ushort fadeOut
+ ) {
+ InstanceLimit = instanceLimit;
+ MaxCueBehavior = (MaxInstanceBehavior) (behavior >> 3);
+ FadeInMS = fadeIn;
+ FadeOutMS = fadeOut;
+ }
+ }
+
+ internal class XACTSound
+ {
+ private XACTClip[] INTERNAL_clips;
+
+ public double Volume
+ {
+ get;
+ private set;
+ }
+
+ public float Pitch
+ {
+ get;
+ private set;
+ }
+
+ public ushort Category
+ {
+ get;
+ private set;
+ }
+
+ public bool HasLoadedTracks
+ {
+ get;
+ private set;
+ }
+
+ public List RPCCodes
+ {
+ get;
+ private set;
+ }
+
+ public uint[] DSPCodes
+ {
+ get;
+ private set;
+ }
+
+ public XACTSound(ushort track, byte waveBank)
+ {
+ INTERNAL_clips = new XACTClip[1];
+ INTERNAL_clips[0] = new XACTClip(track, waveBank);
+ Category = 0;
+ Volume = 0.0;
+ HasLoadedTracks = false;
+ }
+
+ public XACTSound(BinaryReader reader)
+ {
+ // Sound Effect Flags
+ byte soundFlags = reader.ReadByte();
+ bool complex = (soundFlags & 0x01) != 0;
+
+ // AudioCategory Index
+ Category = reader.ReadUInt16();
+
+ // Sound Volume
+ Volume = XACTCalculator.ParseDecibel(reader.ReadByte());
+
+ // Sound Pitch
+ Pitch = (reader.ReadInt16() / 1000.0f);
+
+ // Unknown value
+ reader.ReadByte();
+
+ // Length of Sound Entry, unused
+ reader.ReadUInt16();
+
+ // Number of Sound Clips
+ if (complex)
+ {
+ INTERNAL_clips = new XACTClip[reader.ReadByte()];
+ }
+ else
+ {
+ // Simple Sounds always have 1 PlayWaveEvent.
+ INTERNAL_clips = new XACTClip[1];
+ ushort track = reader.ReadUInt16();
+ byte waveBank = reader.ReadByte();
+ INTERNAL_clips[0] = new XACTClip(track, waveBank);
+ }
+
+ // Parse RPC Properties
+ RPCCodes = new List();
+ if ((soundFlags & 0x0E) != 0)
+ {
+ // RPC data length
+ ushort rpcDataLength = reader.ReadUInt16();
+ ushort totalDataRead = 2;
+
+ while (totalDataRead < rpcDataLength)
+ {
+ // Number of RPC Presets (for this track)
+ uint[] codeList = new uint[reader.ReadByte()];
+
+ // Obtain RPC curve codes (in this block)
+ for (int i = 0; i < codeList.Length; i += 1)
+ {
+ codeList[i] = reader.ReadUInt32();
+ }
+
+ // Add this track's code list to the master list
+ RPCCodes.Add(codeList);
+
+ totalDataRead += (ushort) (1 + (4 * codeList.Length));
+ }
+ }
+
+ // Parse DSP Presets
+ DSPCodes = new uint[0]; // Eww... -flibit
+ if ((soundFlags & 0x10) != 0)
+ {
+ // DSP Presets Length, unused
+ reader.ReadUInt16();
+
+ // Number of DSP Presets
+ DSPCodes = new uint[reader.ReadByte()];
+
+ // Obtain DSP Preset codes
+ for (byte j = 0; j < DSPCodes.Length; j += 1)
+ {
+ DSPCodes[j] = reader.ReadUInt32();
+ }
+ }
+
+ // Parse Sound Events
+ if (complex)
+ {
+ for (int i = 0; i < INTERNAL_clips.Length; i += 1)
+ {
+ // XACT Clip volume
+ double clipVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
+
+ // XACT Clip Offset in Bank
+ uint offset = reader.ReadUInt32();
+
+ // XACT Clip filter
+ byte filterFlags = reader.ReadByte();
+ byte filterType;
+ if ((filterFlags & 0x01) == 0x01)
+ {
+ filterType = (byte) ((filterFlags >> 1) & 0x02);
+ }
+ else
+ {
+ filterType = 0xFF;
+ }
+ reader.ReadByte(); // QFactor?
+ reader.ReadUInt16(); // Frequency
+
+ // Store this for when we're done reading the clip.
+ long curPos = reader.BaseStream.Position;
+
+ // Go to the Clip in the Bank.
+ reader.BaseStream.Seek(offset, SeekOrigin.Begin);
+
+ // Parse the Clip.
+ INTERNAL_clips[i] = new XACTClip(reader, clipVolume, filterType);
+
+ // Back to where we were...
+ reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
+ }
+ }
+
+ HasLoadedTracks = false;
+ }
+
+ public void LoadTracks(AudioEngine audioEngine, List waveBankNames)
+ {
+ foreach (XACTClip curClip in INTERNAL_clips)
+ {
+ curClip.LoadTracks(audioEngine, waveBankNames);
+ }
+ HasLoadedTracks = true;
+ }
+
+ public void GatherEvents(List eventList)
+ {
+ foreach (XACTClip curClip in INTERNAL_clips)
+ {
+ eventList.AddRange(curClip.Events);
+ }
+ }
+ }
+
+ internal class XACTClip
+ {
+ public XACTEvent[] Events
+ {
+ get;
+ private set;
+ }
+
+ public XACTClip(ushort track, byte waveBank)
+ {
+ Events = new XACTEvent[1];
+ Events[0] = new PlayWaveEvent(
+ 0,
+ new ushort[] { track },
+ new byte[] { waveBank },
+ 0,
+ 0,
+ 1.0,
+ 1.0,
+ 0xFF,
+ 0,
+ 0,
+ false,
+ new byte[] { 0xFF }
+ );
+ }
+
+ public XACTClip(BinaryReader reader, double clipVolume, byte filterType)
+ {
+ // Number of XACT Events
+ Events = new XACTEvent[reader.ReadByte()];
+
+ for (int i = 0; i < Events.Length; i += 1)
+ {
+ // Full Event information
+ uint eventInfo = reader.ReadUInt32();
+
+ // XACT Event Type, Timestamp
+ uint eventType = eventInfo & 0x0000001F;
+ uint eventTimestamp = (eventInfo >> 5) & 0x0000FFFF;
+ // uint eventUnknown = eventInfo >> 21;
+
+ // Random offset, unused
+ reader.ReadUInt16();
+
+ // Load the Event
+ if (eventType == 0)
+ {
+ // TODO: Codename OhGodNo
+ // Stop Event
+ }
+ else if (eventType == 1)
+ {
+ // Unknown value
+ reader.ReadByte();
+
+ /* Event Flags
+ * 0x01 = Break Loop
+ * 0x02 = Use Speaker Position
+ * 0x04 = Use Center Speaker
+ * 0x08 = New Speaker Position On Loop
+ */
+ reader.ReadByte();
+
+ // WaveBank Track Index
+ ushort track = reader.ReadUInt16();
+
+ // WaveBank Index
+ byte waveBank = reader.ReadByte();
+
+ // Number of times to loop wave (255 is infinite)
+ byte loopCount = reader.ReadByte();
+
+ // Speaker position angle/arc, unused
+ reader.ReadUInt16();
+ reader.ReadUInt16();
+
+ // Finally.
+ Events[i] = new PlayWaveEvent(
+ eventTimestamp,
+ new ushort[] { track },
+ new byte[] { waveBank },
+ 0,
+ 0,
+ clipVolume,
+ clipVolume,
+ filterType,
+ loopCount,
+ 0,
+ false,
+ new byte[] { 0xFF }
+ );
+ }
+ else if (eventType == 3)
+ {
+ // Unknown value
+ reader.ReadByte();
+
+ /* Event Flags
+ * 0x01 = Break Loop
+ * 0x02 = Use Speaker Position
+ * 0x04 = Use Center Speaker
+ * 0x08 = New Speaker Position On Loop
+ */
+ reader.ReadByte();
+
+ // Number of times to loop wave (255 is infinite)
+ byte loopCount = reader.ReadByte();
+
+ // Speaker position angle/arc, unused
+ reader.ReadUInt16();
+ reader.ReadUInt16();
+
+ // Number of WaveBank tracks
+ ushort numTracks = reader.ReadUInt16();
+
+ /* Variation Playlist Type.
+ * First 4 bytes indicates Variation Type.
+ * Next 4 bytes appear to indicate New Variation On Loop.
+ * The rest is currently unknown.
+ * -flibit
+ */
+ ushort variationValues = reader.ReadUInt16();
+ ushort variationType = (ushort)(variationValues & 0x000F);
+ bool variationOnLoop = (variationValues & 0x00F0) > 0;
+
+ // Unknown values
+ reader.ReadBytes(4);
+
+ // Obtain WaveBank track information
+ ushort[] tracks = new ushort[numTracks];
+ byte[] waveBanks = new byte[numTracks];
+ byte[] weights = new byte[numTracks];
+ for (ushort j = 0; j < numTracks; j += 1)
+ {
+ tracks[j] = reader.ReadUInt16();
+ waveBanks[j] = reader.ReadByte();
+ byte minWeight = reader.ReadByte();
+ byte maxWeight = reader.ReadByte();
+ weights[j] = (byte) (maxWeight - minWeight);
+ }
+
+ // Finally.
+ Events[i] = new PlayWaveEvent(
+ eventTimestamp,
+ tracks,
+ waveBanks,
+ 0,
+ 0,
+ clipVolume,
+ clipVolume,
+ filterType,
+ loopCount,
+ variationType,
+ variationOnLoop,
+ weights
+ );
+ }
+ else if (eventType == 4)
+ {
+ // Unknown value
+ reader.ReadByte();
+
+ /* Event Flags
+ * 0x01 = Break Loop
+ * 0x02 = Use Speaker Position
+ * 0x04 = Use Center Speaker
+ * 0x08 = New Speaker Position On Loop
+ */
+ reader.ReadByte();
+
+ // WaveBank track
+ ushort track = reader.ReadUInt16();
+
+ // WaveBank index, unconfirmed
+ byte waveBank = reader.ReadByte();
+
+ // Loop Count, unconfirmed
+ byte loopCount = reader.ReadByte();
+
+ // Speaker position angle/arc, unused
+ reader.ReadUInt16();
+ reader.ReadUInt16();
+
+ // Pitch Variation
+ short minPitch = reader.ReadInt16();
+ short maxPitch = reader.ReadInt16();
+
+ // Volume Variation
+ double minVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
+ double maxVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
+
+ // Frequency Variation, unusued
+ reader.ReadSingle();
+ reader.ReadSingle();
+
+ // Q Factor Variation, unused
+ reader.ReadSingle();
+ reader.ReadSingle();
+
+ // Unknown value
+ reader.ReadUInt16();
+
+ // Finally.
+ Events[i] = new PlayWaveEvent(
+ eventTimestamp,
+ new ushort[] { track },
+ new byte[] { waveBank },
+ minPitch,
+ maxPitch,
+ minVolume,
+ maxVolume,
+ filterType,
+ loopCount,
+ 0,
+ false,
+ new byte[] { 0xFF }
+ );
+ }
+ else if (eventType == 6)
+ {
+ // Unknown value
+ reader.ReadByte();
+
+ /* Event Flags
+ * 0x01 = Break Loop
+ * 0x02 = Use Speaker Position
+ * 0x04 = Use Center Speaker
+ * 0x08 = New Speaker Position On Loop
+ */
+ reader.ReadByte();
+
+ // Number of times to loop wave (255 is infinite)
+ byte loopCount = reader.ReadByte();
+
+ // Speaker position angle/arc, unused
+ reader.ReadUInt16();
+ reader.ReadUInt16();
+
+ // Pitch variation
+ short minPitch = reader.ReadInt16();
+ short maxPitch = reader.ReadInt16();
+
+ // Volume variation
+ double minVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
+ double maxVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
+
+ // Frequency Variation, unusued
+ reader.ReadSingle();
+ reader.ReadSingle();
+
+ // Q Factor Variation, unused
+ reader.ReadSingle();
+ reader.ReadSingle();
+
+ // Unknown value
+ reader.ReadByte();
+
+ // Variation flags
+ // FIXME: There's probably more to these flags...
+ byte varFlags = reader.ReadByte();
+ if ((varFlags & 0x20) != 0x20)
+ {
+ // Throw out the volume variation.
+ minVolume = clipVolume;
+ maxVolume = clipVolume;
+ }
+ if ((varFlags & 0x10) != 0x10)
+ {
+ // Throw out the pitch variation
+ minPitch = 0;
+ maxPitch = 0;
+ }
+
+ // Number of WaveBank tracks
+ ushort numTracks = reader.ReadUInt16();
+
+ /* Variation Playlist Type.
+ * First 4 bytes indicates Variation Type.
+ * Next 4 bytes appear to indicate New Variation On Loop.
+ * The rest is currently unknown.
+ * -flibit
+ */
+ ushort variationValues = reader.ReadUInt16();
+ ushort variationType = (ushort)(variationValues & 0x000F);
+ bool variationOnLoop = (variationValues & 0x00F0) > 0;
+
+ // Unknown values
+ reader.ReadBytes(4);
+
+ // Obtain WaveBank track information
+ ushort[] tracks = new ushort[numTracks];
+ byte[] waveBanks = new byte[numTracks];
+ byte[] weights = new byte[numTracks];
+ for (ushort j = 0; j < numTracks; j += 1)
+ {
+ tracks[j] = reader.ReadUInt16();
+ waveBanks[j] = reader.ReadByte();
+ byte minWeight = reader.ReadByte();
+ byte maxWeight = reader.ReadByte();
+ weights[j] = (byte) (maxWeight - minWeight);
+ }
+
+ // Finally.
+ Events[i] = new PlayWaveEvent(
+ eventTimestamp,
+ tracks,
+ waveBanks,
+ minPitch,
+ maxPitch,
+ minVolume,
+ maxVolume,
+ filterType,
+ loopCount,
+ variationType,
+ variationOnLoop,
+ weights
+ );
+ }
+ else if (eventType == 7)
+ {
+ // Unknown values
+ reader.ReadBytes(2);
+
+ /* Event Flags
+ * 0x08 = Min/Max Values
+ * Rest is unknown
+ */
+ bool minMax = (reader.ReadByte() & 0x08) == 0x08;
+
+ // Min/Max Random
+ float min = reader.ReadSingle() / 1000.0f;
+ float max;
+ if (minMax)
+ {
+ max = reader.ReadSingle() / 1000.0f;
+ }
+ else
+ {
+ max = min;
+ }
+
+ // FIXME: Any more...? -flibit
+
+ Events[i] = new SetPitchEvent(
+ eventTimestamp,
+ min,
+ max
+ );
+ }
+ else if (eventType == 8)
+ {
+ // Unknown values
+ reader.ReadBytes(2);
+
+ /* Event Flags
+ * 0x08 = Min/Max Values
+ * 0x01 = Add, rather than replace
+ * Rest is unknown
+ */
+ byte flags = reader.ReadByte();
+ bool addVolume = (flags & 0x01) == 0x01;
+ bool minMax = (flags & 0x08) == 0x08;
+
+ // Operand Constant
+ float min = reader.ReadSingle() / 100.0f;
+ float max;
+ if (minMax)
+ {
+ max = reader.ReadSingle() / 100.0f;
+
+ // Unknown bytes
+ reader.ReadBytes(5);
+ }
+ else
+ {
+ max = min;
+
+ // Unknown values
+ reader.ReadBytes(8);
+ }
+ if (addVolume)
+ {
+ min += (float) clipVolume;
+ max += (float) clipVolume;
+ }
+
+ Events[i] = new SetVolumeEvent(
+ eventTimestamp,
+ XACTCalculator.CalculateAmplitudeRatio(min),
+ XACTCalculator.CalculateAmplitudeRatio(max)
+ );
+ }
+ else if (eventType == 15)
+ {
+ // TODO: Codename OhGodNo -flibit
+ // Unknown Event!
+ }
+ else if (eventType == 17)
+ {
+ // TODO: Codename OhGodNo -flibit
+ // Volume Repeat Event
+ }
+ else
+ {
+ /* TODO: All XACT Events.
+ * The following type information is based on
+ * third-party contributions:
+ * Type 9 - Marker Event
+ * -flibit
+ */
+ throw new Exception(
+ "EVENT TYPE " + eventType.ToString() + " NOT IMPLEMENTED!"
+ );
+ }
+ }
+ }
+
+ public void LoadTracks(AudioEngine audioEngine, List waveBankNames)
+ {
+ foreach (XACTEvent curEvent in Events)
+ {
+ if (curEvent.Type == 1)
+ {
+ ((PlayWaveEvent) curEvent).LoadTracks(
+ audioEngine,
+ waveBankNames
+ );
+ }
+ }
+ }
+ }
+
+ internal abstract class XACTEvent
+ {
+ public uint Type
+ {
+ get;
+ private set;
+ }
+
+ public uint Timestamp
+ {
+ get;
+ private set;
+ }
+
+ protected static Random random = new Random();
+
+ public XACTEvent(uint type, uint timestamp)
+ {
+ Type = type;
+ Timestamp = timestamp;
+ }
+ }
+
+ internal class PlayWaveEvent : XACTEvent
+ {
+ private enum VariationPlaylistType : ushort
+ {
+ Ordered,
+ OrderedFromRandom,
+ Random,
+ RandomNoImmediateRepeats,
+ Shuffle
+ }
+
+ private ushort[] INTERNAL_tracks;
+ private byte[] INTERNAL_waveBanks;
+
+ private short INTERNAL_minPitch;
+ private short INTERNAL_maxPitch;
+
+ private double INTERNAL_minVolume;
+ private double INTERNAL_maxVolume;
+
+ private byte INTERNAL_filterType;
+
+ private byte INTERNAL_loopCount;
+
+ private VariationPlaylistType INTERNAL_variationType;
+ private bool INTERNAL_variationOnLoop;
+ private byte[] INTERNAL_weights;
+ private int INTERNAL_curWave;
+
+ private SoundEffect[] INTERNAL_waves;
+
+ public PlayWaveEvent(
+ uint timestamp,
+ ushort[] tracks,
+ byte[] waveBanks,
+ short minPitch,
+ short maxPitch,
+ double minVolume,
+ double maxVolume,
+ byte filterType,
+ byte loopCount,
+ ushort variationType,
+ bool variationOnLoop,
+ byte[] weights
+ ) : base(1, timestamp) {
+ INTERNAL_tracks = tracks;
+ INTERNAL_waveBanks = waveBanks;
+ INTERNAL_minPitch = minPitch;
+ INTERNAL_maxPitch = maxPitch;
+ INTERNAL_minVolume = minVolume;
+ INTERNAL_maxVolume = maxVolume;
+ INTERNAL_filterType = filterType;
+ INTERNAL_loopCount = loopCount;
+ INTERNAL_variationType = (VariationPlaylistType) variationType;
+ INTERNAL_variationOnLoop = variationOnLoop;
+ INTERNAL_weights = weights;
+ INTERNAL_waves = new SoundEffect[tracks.Length];
+ INTERNAL_curWave = -1;
+ }
+
+ public void LoadTracks(AudioEngine audioEngine, List waveBankNames)
+ {
+ for (int i = 0; i < INTERNAL_waves.Length; i += 1)
+ {
+ INTERNAL_waves[i] = audioEngine.INTERNAL_getWaveBankTrack(
+ waveBankNames[INTERNAL_waveBanks[i]],
+ INTERNAL_tracks[i]
+ );
+ }
+ }
+
+ public SoundEffectInstance GenerateInstance(
+ double soundVolume,
+ float soundPitch,
+ int currentLoop
+ ) {
+ if (currentLoop > INTERNAL_loopCount && INTERNAL_loopCount != 255)
+ {
+ // We've finished all the loops!
+ return null;
+ }
+ INTERNAL_getNextSound();
+ SoundEffectInstance result = INTERNAL_waves[INTERNAL_curWave].CreateInstance();
+ result.INTERNAL_isXACTSource = true;
+ result.Volume = XACTCalculator.CalculateAmplitudeRatio(
+ soundVolume + (
+ random.NextDouble() *
+ (INTERNAL_maxVolume - INTERNAL_minVolume)
+ ) + INTERNAL_minVolume
+ );
+ result.Pitch = (
+ random.Next(
+ INTERNAL_minPitch,
+ INTERNAL_maxPitch
+ ) / 1000.0f
+ ) + soundPitch;
+ result.FilterType = INTERNAL_filterType;
+ result.IsLooped = !INTERNAL_variationOnLoop && (INTERNAL_loopCount == 255);
+ return result;
+ }
+
+ private void INTERNAL_getNextSound()
+ {
+ if (INTERNAL_variationType == VariationPlaylistType.Ordered)
+ {
+ INTERNAL_curWave += 1;
+ if (INTERNAL_curWave >= INTERNAL_waves.Length)
+ {
+ INTERNAL_curWave = 0;
+ }
+ }
+ else if (INTERNAL_variationType == VariationPlaylistType.OrderedFromRandom)
+ {
+ // FIXME: It seems like XACT organizes this for us?
+ INTERNAL_curWave += 1;
+ if (INTERNAL_curWave >= INTERNAL_waves.Length)
+ {
+ INTERNAL_curWave = 0;
+ }
+ }
+ else if (INTERNAL_variationType == VariationPlaylistType.Random)
+ {
+ double max = 0.0;
+ for (int i = 0; i < INTERNAL_weights.Length; i += 1)
+ {
+ max += INTERNAL_weights[i];
+ }
+ double next = random.NextDouble() * max;
+ for (int i = INTERNAL_weights.Length - 1; i >= 0; i -= 1)
+ {
+ if (next > max - INTERNAL_weights[i])
+ {
+ INTERNAL_curWave = i;
+ return;
+ }
+ max -= INTERNAL_weights[i];
+ }
+ }
+ else if ( INTERNAL_variationType == VariationPlaylistType.RandomNoImmediateRepeats ||
+ INTERNAL_variationType == VariationPlaylistType.Shuffle )
+ {
+ // FIXME: Is Shuffle really any different from this?
+ double max = 0.0;
+ for (int i = 0; i < INTERNAL_weights.Length; i += 1)
+ {
+ if (i == INTERNAL_curWave)
+ {
+ continue;
+ }
+ max += INTERNAL_weights[i];
+ }
+ double next = random.NextDouble() * max;
+ for (int i = INTERNAL_weights.Length - 1; i >= 0; i -= 1)
+ {
+ if (i == INTERNAL_curWave)
+ {
+ continue;
+ }
+ if (next > max - INTERNAL_weights[i])
+ {
+ INTERNAL_curWave = i;
+ return;
+ }
+ max -= INTERNAL_weights[i];
+ }
+ }
+ else
+ {
+ throw new Exception(
+ "Variation Playlist Type unhandled: " +
+ INTERNAL_variationType.ToString()
+ );
+ }
+ }
+ }
+
+ internal class SetVolumeEvent : XACTEvent
+ {
+ private float INTERNAL_min;
+ private float INTERNAL_max;
+
+ public SetVolumeEvent(
+ uint timestamp,
+ float min,
+ float max
+ ) : base(2, timestamp) {
+ INTERNAL_min = min;
+ INTERNAL_max = max;
+ }
+
+ public float GetVolume()
+ {
+ return INTERNAL_min + (float) (
+ random.NextDouble() * (INTERNAL_max - INTERNAL_min)
+ );
+ }
+ }
+
+ internal class SetPitchEvent : XACTEvent
+ {
+ private float INTERNAL_min;
+ private float INTERNAL_max;
+
+ public SetPitchEvent(
+ uint timestamp,
+ float min,
+ float max
+ ) : base(3, timestamp) {
+ INTERNAL_min = min;
+ INTERNAL_max = max;
+ }
+
+ public float GetPitch()
+ {
+ return INTERNAL_min + (float) (
+ random.NextDouble() * (INTERNAL_max - INTERNAL_min)
+ );
+ }
+ }
+}
diff --git a/src/Audio/DynamicSoundEffectInstance.cs b/src/Audio/DynamicSoundEffectInstance.cs
new file mode 100644
index 0000000..ed3ccc3
--- /dev/null
+++ b/src/Audio/DynamicSoundEffectInstance.cs
@@ -0,0 +1,395 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.dynamicsoundeffectinstance.aspx
+ public sealed class DynamicSoundEffectInstance : SoundEffectInstance
+ {
+ #region Public Properties
+
+ public int PendingBufferCount
+ {
+ get;
+ private set;
+ }
+
+ public override bool IsLooped
+ {
+ get
+ {
+ return false;
+ }
+ set
+ {
+ // No-op, DynamicSoundEffectInstance cannot be looped!
+ }
+ }
+
+ #endregion
+
+ #region Private XNA Variables
+
+ private int sampleRate;
+ private AudioChannels channels;
+
+ private const int MINIMUM_BUFFER_CHECK = 3;
+
+ #endregion
+
+ #region Private AL Variables
+
+ private Queue queuedBuffers;
+ private Queue buffersToQueue;
+ private Queue availableBuffers;
+
+ #endregion
+
+ #region BufferNeeded Event
+
+ public event EventHandler BufferNeeded;
+
+ #endregion
+
+ #region Public Constructor
+
+ public DynamicSoundEffectInstance(int sampleRate, AudioChannels channels) : base(null)
+ {
+ this.sampleRate = sampleRate;
+ this.channels = channels;
+
+ PendingBufferCount = 0;
+
+ isDynamic = true;
+ queuedBuffers = new Queue();
+ buffersToQueue = new Queue();
+ availableBuffers = new Queue();
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~DynamicSoundEffectInstance()
+ {
+ Dispose();
+ }
+
+ #endregion
+
+ #region Public Dispose Method
+
+ public override void Dispose()
+ {
+ if (!IsDisposed)
+ {
+ base.Dispose(); // Will call Stop(true);
+
+ // Delete all known buffer objects
+ while (queuedBuffers.Count > 0)
+ {
+ AudioDevice.ALDevice.DeleteBuffer(queuedBuffers.Dequeue());
+ }
+ queuedBuffers = null;
+ while (availableBuffers.Count > 0)
+ {
+ AudioDevice.ALDevice.DeleteBuffer(availableBuffers.Dequeue());
+ }
+ availableBuffers = null;
+ while (buffersToQueue.Count > 0)
+ {
+ AudioDevice.ALDevice.DeleteBuffer(buffersToQueue.Dequeue());
+ }
+ buffersToQueue = null;
+
+ IsDisposed = true;
+ }
+ }
+
+ #endregion
+
+ #region Public Time/Sample Information Methods
+
+ public TimeSpan GetSampleDuration(int sizeInBytes)
+ {
+ return SoundEffect.GetSampleDuration(
+ sizeInBytes,
+ sampleRate,
+ channels
+ );
+ }
+
+ public int GetSampleSizeInBytes(TimeSpan duration)
+ {
+ return SoundEffect.GetSampleSizeInBytes(
+ duration,
+ sampleRate,
+ channels
+ );
+ }
+
+ #endregion
+
+ #region Public SubmitBuffer Methods
+
+ public void SubmitBuffer(byte[] buffer)
+ {
+ this.SubmitBuffer(buffer, 0, buffer.Length);
+ }
+
+ public void SubmitBuffer(byte[] buffer, int offset, int count)
+ {
+ // Generate a buffer if we don't have any to use.
+ if (availableBuffers.Count == 0)
+ {
+ availableBuffers.Enqueue(
+ AudioDevice.ALDevice.GenBuffer()
+ );
+ }
+
+ // Push the data to OpenAL.
+ IALBuffer newBuf = availableBuffers.Dequeue();
+ AudioDevice.ALDevice.SetBufferData(
+ newBuf,
+ channels,
+ buffer, // TODO: offset -flibit
+ count,
+ sampleRate
+ );
+
+ // If we're already playing, queue immediately.
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.QueueSourceBuffer(
+ INTERNAL_alSource,
+ newBuf
+ );
+ queuedBuffers.Enqueue(newBuf);
+
+ // If the source stopped, reboot it now.
+ if (AudioDevice.ALDevice.GetSourceState(INTERNAL_alSource) == SoundState.Stopped)
+ {
+ AudioDevice.ALDevice.PlaySource(INTERNAL_alSource);
+ }
+ }
+ else
+ {
+ buffersToQueue.Enqueue(newBuf);
+ }
+
+ PendingBufferCount += 1;
+ }
+
+ #endregion
+
+ #region Public Play Method
+
+ public override void Play()
+ {
+ Play(true);
+ }
+
+ #endregion
+
+ #region Internal Play Method
+
+ internal void Play(bool isManaged)
+ {
+ if (State != SoundState.Stopped)
+ {
+ return; // No-op if we're already playing.
+ }
+
+ if (INTERNAL_alSource != null)
+ {
+ // The sound has stopped, but hasn't cleaned up yet...
+ AudioDevice.ALDevice.StopAndDisposeSource(INTERNAL_alSource);
+ INTERNAL_alSource = null;
+ }
+ while (queuedBuffers.Count > 0)
+ {
+ availableBuffers.Enqueue(queuedBuffers.Dequeue());
+ PendingBufferCount -= 1;
+ }
+
+ INTERNAL_alSource = AudioDevice.ALDevice.GenSource();
+ if (INTERNAL_alSource == null)
+ {
+ System.Console.WriteLine("WARNING: AL SOURCE WAS NOT AVAILABLE. SKIPPING.");
+ return;
+ }
+
+ // Queue the buffers to this source
+ while (buffersToQueue.Count > 0)
+ {
+ IALBuffer nextBuf = buffersToQueue.Dequeue();
+ queuedBuffers.Enqueue(nextBuf);
+ AudioDevice.ALDevice.QueueSourceBuffer(INTERNAL_alSource, nextBuf);
+ }
+
+ // Apply Pan/Position
+ if (INTERNAL_positionalAudio)
+ {
+ INTERNAL_positionalAudio = false;
+ AudioDevice.ALDevice.SetSourcePosition(
+ INTERNAL_alSource,
+ position
+ );
+ }
+ else
+ {
+ Pan = Pan;
+ }
+
+ // Reassign Properties, in case the AL properties need to be applied.
+ Volume = Volume;
+ Pitch = Pitch;
+
+ // ... but wait! What if we need moar buffers?
+ for (
+ int i = MINIMUM_BUFFER_CHECK - PendingBufferCount;
+ (i > 0) && BufferNeeded != null;
+ i -= 1
+ ) {
+ BufferNeeded(this, null);
+ }
+
+ // Finally.
+ AudioDevice.ALDevice.PlaySource(INTERNAL_alSource);
+ if (isManaged)
+ {
+ AudioDevice.DynamicInstancePool.Add(this);
+ }
+ }
+
+ #endregion
+
+ #region Internal Update Method
+
+ internal void Update()
+ {
+ // Get the number of processed buffers.
+ int finishedBuffers = AudioDevice.ALDevice.CheckProcessedBuffers(
+ INTERNAL_alSource
+ );
+ if (finishedBuffers == 0)
+ {
+ // Nothing to do... yet.
+ return;
+ }
+
+ // Dequeue the processed buffers, error checking as needed.
+ AudioDevice.ALDevice.DequeueSourceBuffers(
+ INTERNAL_alSource,
+ finishedBuffers,
+ queuedBuffers
+ );
+
+ // The processed buffers are now available.
+ for (int i = 0; i < finishedBuffers; i += 1)
+ {
+ availableBuffers.Enqueue(queuedBuffers.Dequeue());
+ }
+
+ // PendingBufferCount changed during playback, trigger now!
+ PendingBufferCount -= finishedBuffers;
+ if (BufferNeeded != null)
+ {
+ BufferNeeded(this, null);
+ }
+
+ // Do we need even moar buffers?
+ for (
+ int i = MINIMUM_BUFFER_CHECK - PendingBufferCount;
+ (i > 0) && BufferNeeded != null;
+ i -= 1
+ ) {
+ BufferNeeded(this, null);
+ }
+ }
+
+ #endregion
+
+ #region Internal Sample Data Retrieval Method
+
+ internal void GetSamples(float[] samples)
+ {
+ if (INTERNAL_alSource != null && queuedBuffers.Count > 0)
+ {
+ AudioDevice.ALDevice.GetBufferData(
+ INTERNAL_alSource,
+ queuedBuffers.ToArray(), // FIXME: Blech -flibit
+ samples,
+ channels
+ );
+ }
+ else
+ {
+ Array.Clear(samples, 0, samples.Length);
+ }
+ }
+
+ #endregion
+
+ #region Public FNA Extension Methods
+
+ /* THIS IS AN EXTENSION OF THE XNA4 API! */
+ public void SubmitFloatBufferEXT(float[] buffer)
+ {
+ /* Float samples are the typical format received from decoders.
+ * We currently use this for the VideoPlayer.
+ * -flibit
+ */
+
+ // Generate a buffer if we don't have any to use.
+ if (availableBuffers.Count == 0)
+ {
+ availableBuffers.Enqueue(AudioDevice.ALDevice.GenBuffer());
+ }
+
+ // Push buffer to the AL.
+ IALBuffer newBuf = availableBuffers.Dequeue();
+ AudioDevice.ALDevice.SetBufferData(
+ newBuf,
+ channels,
+ buffer,
+ sampleRate
+ );
+
+ // If we're already playing, queue immediately.
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.QueueSourceBuffer(
+ INTERNAL_alSource,
+ newBuf
+ );
+ queuedBuffers.Enqueue(newBuf);
+
+ // If the source stopped, reboot it now.
+ if (AudioDevice.ALDevice.GetSourceState(INTERNAL_alSource) == SoundState.Stopped)
+ {
+ AudioDevice.ALDevice.PlaySource(INTERNAL_alSource);
+ }
+ }
+ else
+ {
+ buffersToQueue.Enqueue(newBuf);
+ }
+
+ PendingBufferCount += 1;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/IALDevice.cs b/src/Audio/IALDevice.cs
new file mode 100644
index 0000000..b666460
--- /dev/null
+++ b/src/Audio/IALDevice.cs
@@ -0,0 +1,127 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ internal interface IALDevice
+ {
+ void Update();
+ void Dispose();
+ ReadOnlyCollection GetDevices();
+ ReadOnlyCollection GetCaptureDevices();
+
+ IALBuffer GenBuffer();
+ IALBuffer GenBuffer(
+ byte[] data,
+ uint sampleRate,
+ uint channels,
+ uint loopStart,
+ uint loopEnd,
+ bool isADPCM,
+ uint formatParameter
+ );
+ void DeleteBuffer(IALBuffer buffer);
+ void SetBufferData(
+ IALBuffer buffer,
+ AudioChannels channels,
+ byte[] data,
+ int count,
+ int sampleRate
+ );
+ void SetBufferData(
+ IALBuffer buffer,
+ AudioChannels channels,
+ float[] data,
+ int sampleRate
+ );
+
+ IALSource GenSource();
+ IALSource GenSource(IALBuffer buffer);
+ void StopAndDisposeSource(IALSource source);
+ void PlaySource(IALSource source);
+ void PauseSource(IALSource source);
+ void ResumeSource(IALSource source);
+ SoundState GetSourceState(IALSource source);
+ void SetSourceVolume(IALSource source, float volume);
+ void SetSourceLooped(IALSource source, bool looped);
+ void SetSourcePan(IALSource source, float pan);
+ void SetSourcePosition(IALSource source, Vector3 pos);
+ void SetSourcePitch(IALSource source, float pitch, bool clamp);
+ void SetSourceReverb(IALSource source, IALReverb reverb);
+ void SetSourceLowPassFilter(IALSource source, float hfGain);
+ void SetSourceHighPassFilter(IALSource source, float lfGain);
+ void SetSourceBandPassFilter(IALSource source, float hfGain, float lfGain);
+ void QueueSourceBuffer(IALSource source, IALBuffer buffer);
+ void DequeueSourceBuffers(
+ IALSource source,
+ int buffersToDequeue,
+ Queue errorCheck
+ );
+ int CheckProcessedBuffers(IALSource source);
+ void GetBufferData(
+ IALSource source,
+ IALBuffer[] buffer,
+ float[] samples,
+ AudioChannels channels
+ );
+
+ IALReverb GenReverb(DSPParameter[] parameters);
+ void DeleteReverb(IALReverb reverb);
+ void CommitReverbChanges(IALReverb reverb);
+ void SetReverbReflectionsDelay(IALReverb reverb, float value);
+ void SetReverbDelay(IALReverb reverb, float value);
+ void SetReverbPositionLeft(IALReverb reverb, float value);
+ void SetReverbPositionRight(IALReverb reverb, float value);
+ void SetReverbPositionLeftMatrix(IALReverb reverb, float value);
+ void SetReverbPositionRightMatrix(IALReverb reverb, float value);
+ void SetReverbEarlyDiffusion(IALReverb reverb, float value);
+ void SetReverbLateDiffusion(IALReverb reverb, float value);
+ void SetReverbLowEQGain(IALReverb reverb, float value);
+ void SetReverbLowEQCutoff(IALReverb reverb, float value);
+ void SetReverbHighEQGain(IALReverb reverb, float value);
+ void SetReverbHighEQCutoff(IALReverb reverb, float value);
+ void SetReverbRearDelay(IALReverb reverb, float value);
+ void SetReverbRoomFilterFrequency(IALReverb reverb, float value);
+ void SetReverbRoomFilterMain(IALReverb reverb, float value);
+ void SetReverbRoomFilterHighFrequency(IALReverb reverb, float value);
+ void SetReverbReflectionsGain(IALReverb reverb, float value);
+ void SetReverbGain(IALReverb reverb, float value);
+ void SetReverbDecayTime(IALReverb reverb, float value);
+ void SetReverbDensity(IALReverb reverb, float value);
+ void SetReverbRoomSize(IALReverb reverb, float value);
+ void SetReverbWetDryMix(IALReverb reverb, float value);
+
+ IntPtr StartDeviceCapture(string name, int sampleRate, int bufSize);
+ void StopDeviceCapture(IntPtr handle);
+ int CaptureSamples(IntPtr handle, IntPtr buffer, int count);
+ bool CaptureHasSamples(IntPtr handle);
+ }
+
+ internal interface IALBuffer
+ {
+ TimeSpan Duration
+ {
+ get;
+ }
+ }
+
+ internal interface IALSource
+ {
+ }
+
+ internal interface IALReverb
+ {
+ }
+}
diff --git a/src/Audio/InstancePlayLimitException.cs b/src/Audio/InstancePlayLimitException.cs
new file mode 100644
index 0000000..c9537f3
--- /dev/null
+++ b/src/Audio/InstancePlayLimitException.cs
@@ -0,0 +1,22 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Runtime.InteropServices;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.instanceplaylimitexception.aspx
+ [Serializable]
+ public sealed class InstancePlayLimitException : ExternalException
+ {
+ }
+}
diff --git a/src/Audio/Microphone.cs b/src/Audio/Microphone.cs
new file mode 100644
index 0000000..dd3feee
--- /dev/null
+++ b/src/Audio/Microphone.cs
@@ -0,0 +1,221 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.ObjectModel;
+using System.Runtime.InteropServices;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ public class Microphone
+ {
+ #region Public Static Properties
+
+ public static ReadOnlyCollection All
+ {
+ get;
+ internal set;
+ }
+
+ public static Microphone Default
+ {
+ get
+ {
+ if (All.Count == 0)
+ {
+ return null;
+ }
+ return All[0];
+ }
+ }
+
+ #endregion
+
+ #region Public Properties
+
+ public TimeSpan BufferDuration
+ {
+ get
+ {
+ return bufferDuration;
+ }
+ set
+ {
+ if ( value.Milliseconds < 100 ||
+ value.Milliseconds > 1000 ||
+ value.Milliseconds % 10 != 0 )
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+ bufferDuration = value;
+ }
+ }
+
+ public bool IsHeadset
+ {
+ get
+ {
+ // FIXME: I think this is just for Windows Phone? -flibit
+ return false;
+ }
+ }
+
+ public int SampleRate
+ {
+ get
+ {
+ return SAMPLERATE;
+ }
+ }
+
+ public MicrophoneState State
+ {
+ get;
+ private set;
+ }
+
+ #endregion
+
+ #region Public Variables
+
+ public readonly string Name;
+
+ #endregion
+
+ #region Private Variables
+
+ private TimeSpan bufferDuration;
+ private IntPtr nativeMic;
+
+ #endregion
+
+ #region Events
+
+ public event EventHandler BufferReady;
+
+ #endregion
+
+ #region Private Constants
+
+ /* FIXME: This is what XNA4 aims for, but it _could_ be lower.
+ * Something work looking at is falling back to lower sample rates in
+ * powers of two, i.e. 44100, 22050, 11025, etc.
+ * -flibit
+ */
+ private const int SAMPLERATE = 44100;
+
+ #endregion
+
+ #region Internal Constructor
+
+ internal Microphone(string name)
+ {
+ Name = name;
+ bufferDuration = TimeSpan.FromSeconds(1.0);
+ State = MicrophoneState.Stopped;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public int GetData(byte[] buffer)
+ {
+ return GetData(buffer, 0, buffer.Length);
+ }
+
+ public int GetData(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentException("buffer is null!");
+ }
+ if (offset < 0 || offset > buffer.Length)
+ {
+ throw new ArgumentException("offset");
+ }
+ if (count <= 0 || (offset + count) > buffer.Length)
+ {
+ throw new ArgumentException("count");
+ }
+ GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+ int read = AudioDevice.ALDevice.CaptureSamples(
+ nativeMic,
+ handle.AddrOfPinnedObject() + offset,
+ count
+ );
+ handle.Free();
+ return read;
+ }
+
+ public TimeSpan GetSampleDuration(int sizeInBytes)
+ {
+ return SoundEffect.GetSampleDuration(
+ sizeInBytes,
+ SampleRate,
+ AudioChannels.Mono
+ );
+ }
+
+ public int GetSampleSizeInBytes(TimeSpan duration)
+ {
+ return SoundEffect.GetSampleSizeInBytes(
+ duration,
+ SampleRate,
+ AudioChannels.Mono
+ );
+ }
+
+ public void Start()
+ {
+ if (State == MicrophoneState.Stopped)
+ {
+ nativeMic = AudioDevice.ALDevice.StartDeviceCapture(
+ Name,
+ SampleRate,
+ GetSampleSizeInBytes(bufferDuration)
+ );
+ if (nativeMic == IntPtr.Zero)
+ {
+ throw new NoMicrophoneConnectedException(Name);
+ }
+ AudioDevice.ActiveMics.Add(this);
+ State = MicrophoneState.Started;
+ }
+ }
+
+ public void Stop()
+ {
+ if (State == MicrophoneState.Started)
+ {
+ AudioDevice.ActiveMics.Remove(this);
+ AudioDevice.ALDevice.StopDeviceCapture(nativeMic);
+ nativeMic = IntPtr.Zero;
+ State = MicrophoneState.Stopped;
+ }
+ }
+
+ #endregion
+
+ #region Internal Methods
+
+ internal void CheckBuffer()
+ {
+ if ( BufferReady != null &&
+ AudioDevice.ALDevice.CaptureHasSamples(nativeMic) )
+ {
+ BufferReady(this, EventArgs.Empty);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/MicrophoneState.cs b/src/Audio/MicrophoneState.cs
new file mode 100644
index 0000000..06bd7e0
--- /dev/null
+++ b/src/Audio/MicrophoneState.cs
@@ -0,0 +1,17 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ public enum MicrophoneState
+ {
+ Started,
+ Stopped
+ }
+}
diff --git a/src/Audio/NoAudioHardwareException.cs b/src/Audio/NoAudioHardwareException.cs
new file mode 100644
index 0000000..3c8fe95
--- /dev/null
+++ b/src/Audio/NoAudioHardwareException.cs
@@ -0,0 +1,35 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Runtime.InteropServices;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.noaudiohardwareexception.aspx
+ [Serializable]
+ public sealed class NoAudioHardwareException : ExternalException
+ {
+ public NoAudioHardwareException()
+ {
+ }
+
+ public NoAudioHardwareException(String message)
+ : base(message)
+ {
+ }
+
+ public NoAudioHardwareException(String message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/src/Audio/NoMicrophoneConnectedException.cs b/src/Audio/NoMicrophoneConnectedException.cs
new file mode 100644
index 0000000..6fb815e
--- /dev/null
+++ b/src/Audio/NoMicrophoneConnectedException.cs
@@ -0,0 +1,35 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Runtime.InteropServices;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.nomicrophoneconnectedexception.aspx
+ [Serializable]
+ public sealed class NoMicrophoneConnectedException : Exception
+ {
+ public NoMicrophoneConnectedException()
+ {
+ }
+
+ public NoMicrophoneConnectedException(String message)
+ : base(message)
+ {
+ }
+
+ public NoMicrophoneConnectedException(String message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/src/Audio/NullDevice.cs b/src/Audio/NullDevice.cs
new file mode 100644
index 0000000..ff8d7a0
--- /dev/null
+++ b/src/Audio/NullDevice.cs
@@ -0,0 +1,370 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ /* This is a device that deliberately does as little as possible, allowing
+ * for no sound without throwing NoAudioHardwareExceptions. This is not a
+ * part of the XNA4 spec, however, so behavior here is entirely undefined!
+ * -flibit
+ */
+ internal class NullDevice : IALDevice
+ {
+ private class NullBuffer : IALBuffer
+ {
+ public TimeSpan Duration
+ {
+ get
+ {
+ // FIXME: Maybe read the PCM/ADPCM lengths? -flibit
+ return TimeSpan.Zero;
+ }
+ }
+ }
+
+ private class NullSource : IALSource
+ {
+ }
+
+ private class NullReverb : IALReverb
+ {
+ }
+
+ public void Update()
+ {
+ // No-op, duh.
+ }
+
+ public void Dispose()
+ {
+ // No-op, duh.
+ }
+
+ public ReadOnlyCollection GetDevices()
+ {
+ return new ReadOnlyCollection(
+ new List()
+ );
+ }
+
+ public ReadOnlyCollection GetCaptureDevices()
+ {
+ return new ReadOnlyCollection(
+ new List()
+ );
+ }
+
+ public IALBuffer GenBuffer()
+ {
+ return new NullBuffer();
+ }
+
+ public IALBuffer GenBuffer(
+ byte[] data,
+ uint sampleRate,
+ uint channels,
+ uint loopStart,
+ uint loopEnd,
+ bool isADPCM,
+ uint formatParameter
+ ) {
+ return new NullBuffer();
+ }
+
+ public void DeleteBuffer(IALBuffer buffer)
+ {
+ // No-op, duh.
+ }
+
+ public void SetBufferData(
+ IALBuffer buffer,
+ AudioChannels channels,
+ byte[] data,
+ int count,
+ int sampleRate
+ ) {
+ // No-op, duh.
+ }
+
+ public void SetBufferData(
+ IALBuffer buffer,
+ AudioChannels channels,
+ float[] data,
+ int sampleRate
+ ) {
+ // No-op, duh.
+ }
+
+ public IALSource GenSource()
+ {
+ return new NullSource();
+ }
+
+ public IALSource GenSource(IALBuffer buffer)
+ {
+ return new NullSource();
+ }
+
+ public void StopAndDisposeSource(IALSource source)
+ {
+ // No-op, duh.
+ }
+
+ public void PlaySource(IALSource source)
+ {
+ // No-op, duh.
+ }
+
+ public void PauseSource(IALSource source)
+ {
+ // No-op, duh.
+ }
+
+ public void ResumeSource(IALSource source)
+ {
+ // No-op, duh.
+ }
+
+ public SoundState GetSourceState(IALSource source)
+ {
+ /* FIXME: This return value is highly volatile!
+ * You can't necessarily do Stopped, because then stuff like Song
+ * explodes, but SoundState.Playing doesn't make a whole lot of
+ * sense either. This at least prevents annoyances like Song errors
+ * from happening and, for the most part, claims to be "playing"
+ * depending on how you ask for a source's state.
+ * -flibit
+ */
+ return SoundState.Paused;
+ }
+
+ public void SetSourceVolume(IALSource source, float volume)
+ {
+ // No-op, duh.
+ }
+
+ public void SetSourceLooped(IALSource source, bool looped)
+ {
+ // No-op, duh.
+ }
+
+ public void SetSourcePan(IALSource source, float pan)
+ {
+ // No-op, duh.
+ }
+
+ public void SetSourcePosition(IALSource source, Vector3 pos)
+ {
+ // No-op, duh.
+ }
+
+ public void SetSourcePitch(IALSource source, float pitch, bool clamp)
+ {
+ // No-op, duh.
+ }
+
+ public void SetSourceReverb(IALSource source, IALReverb reverb)
+ {
+ // No-op, duh.
+ }
+
+ public void SetSourceLowPassFilter(IALSource source, float hfGain)
+ {
+ // No-op, duh.
+ }
+
+ public void SetSourceHighPassFilter(IALSource source, float lfGain)
+ {
+ // No-op, duh.
+ }
+
+ public void SetSourceBandPassFilter(IALSource source, float hfGain, float lfGain)
+ {
+ // No-op, duh.
+ }
+
+ public void QueueSourceBuffer(IALSource source, IALBuffer buffer)
+ {
+ // No-op, duh.
+ }
+
+ public void DequeueSourceBuffers(
+ IALSource source,
+ int buffersToDequeue,
+ Queue errorCheck
+ ) {
+ // No-op, duh.
+ }
+
+ public int CheckProcessedBuffers(IALSource source)
+ {
+ return 0;
+ }
+
+ public void GetBufferData(
+ IALSource source,
+ IALBuffer[] buffer,
+ float[] samples,
+ AudioChannels channels
+ ) {
+ // No-op, duh.
+ }
+
+ public IALReverb GenReverb(DSPParameter[] parameters)
+ {
+ return new NullReverb();
+ }
+
+ public void DeleteReverb(IALReverb reverb)
+ {
+ // No-op, duh.
+ }
+
+ public void CommitReverbChanges(IALReverb reverb)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbReflectionsDelay(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbDelay(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbPositionLeft(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbPositionRight(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbPositionLeftMatrix(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbPositionRightMatrix(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbEarlyDiffusion(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbLateDiffusion(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbLowEQGain(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbLowEQCutoff(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbHighEQGain(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbHighEQCutoff(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbRearDelay(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbRoomFilterFrequency(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbRoomFilterMain(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbRoomFilterHighFrequency(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbReflectionsGain(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbGain(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbDecayTime(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbDensity(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbRoomSize(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public void SetReverbWetDryMix(IALReverb reverb, float value)
+ {
+ // No-op, duh.
+ }
+
+ public IntPtr StartDeviceCapture(string name, int sampleRate, int bufSize)
+ {
+ return IntPtr.Zero;
+ }
+
+ public void StopDeviceCapture(IntPtr handle)
+ {
+ // No-op, duh.
+ }
+
+ public int CaptureSamples(IntPtr handle, IntPtr buffer, int count)
+ {
+ return 0;
+ }
+
+ public bool CaptureHasSamples(IntPtr handle)
+ {
+ return false;
+ }
+ }
+}
diff --git a/src/Audio/OpenALDevice.cs b/src/Audio/OpenALDevice.cs
new file mode 100644
index 0000000..8a0ba40
--- /dev/null
+++ b/src/Audio/OpenALDevice.cs
@@ -0,0 +1,1191 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region VERBOSE_AL_DEBUGGING Option
+// #define VERBOSE_AL_DEBUGGING
+/* OpenAL does not have a function similar to ARB_debug_output. Because of this,
+ * we only have alGetError to debug. In DEBUG, we call this once per frame.
+ *
+ * If you enable this define, we call this after every single AL operation, and
+ * throw an Exception when any errors show up. This makes finding problems a lot
+ * easier, but calling alGetError so often can slow things down.
+ * -flibit
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Runtime.InteropServices;
+
+using OpenAL;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ internal class OpenALDevice : IALDevice
+ {
+ #region OpenAL Buffer Container Class
+
+ private class OpenALBuffer : IALBuffer
+ {
+ public uint Handle
+ {
+ get;
+ private set;
+ }
+
+ public TimeSpan Duration
+ {
+ get;
+ private set;
+ }
+
+ public OpenALBuffer(uint handle, TimeSpan duration)
+ {
+ Handle = handle;
+ Duration = duration;
+ }
+ }
+
+ #endregion
+
+ #region OpenAL Source Container Class
+
+ private class OpenALSource : IALSource
+ {
+ public uint Handle
+ {
+ get;
+ private set;
+ }
+
+ public OpenALSource(uint handle)
+ {
+ Handle = handle;
+ }
+ }
+
+ #endregion
+
+ #region OpenAL Reverb Effect Container Class
+
+ private class OpenALReverb : IALReverb
+ {
+ public uint SlotHandle
+ {
+ get;
+ private set;
+ }
+
+ public uint EffectHandle
+ {
+ get;
+ private set;
+ }
+
+ public OpenALReverb(uint slot, uint effect)
+ {
+ SlotHandle = slot;
+ EffectHandle = effect;
+ }
+ }
+
+ #endregion
+
+ #region Private ALC Variables
+
+ // OpenAL Device/Context Handles
+ private IntPtr alDevice;
+ private IntPtr alContext;
+
+ #endregion
+
+ #region Private EFX Variables
+
+ // OpenAL Filter Handle
+ private uint INTERNAL_alFilter;
+
+ #endregion
+
+ #region Public Constructor
+
+ public OpenALDevice()
+ {
+ string envDevice = Environment.GetEnvironmentVariable("FNA_AUDIO_DEVICE_NAME");
+ if (String.IsNullOrEmpty(envDevice))
+ {
+ /* Be sure ALC won't explode if the variable doesn't exist.
+ * But, fail if the device name is wrong. The user needs to know
+ * if their environment variable was incorrect.
+ * -flibit
+ */
+ envDevice = String.Empty;
+ }
+ alDevice = ALC10.alcOpenDevice(envDevice);
+ if (CheckALCError() || alDevice == IntPtr.Zero)
+ {
+ throw new Exception("Could not open audio device!");
+ }
+
+ int[] attribute = new int[0];
+ alContext = ALC10.alcCreateContext(alDevice, attribute);
+ if (CheckALCError() || alContext == IntPtr.Zero)
+ {
+ Dispose();
+ throw new Exception("Could not create OpenAL context");
+ }
+
+ ALC10.alcMakeContextCurrent(alContext);
+ if (CheckALCError())
+ {
+ Dispose();
+ throw new Exception("Could not make OpenAL context current");
+ }
+
+ float[] ori = new float[]
+ {
+ 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f
+ };
+ AL10.alListenerfv(AL10.AL_ORIENTATION, ori);
+ AL10.alListener3f(AL10.AL_POSITION, 0.0f, 0.0f, 0.0f);
+ AL10.alListener3f(AL10.AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+ AL10.alListenerf(AL10.AL_GAIN, 1.0f);
+
+ // We do NOT use automatic attenuation! XNA does not do this!
+ AL10.alDistanceModel(AL10.AL_NONE);
+
+ EFX.alGenFilters((IntPtr) 1, out INTERNAL_alFilter);
+ }
+
+ #endregion
+
+ #region Public Dispose Method
+
+ public void Dispose()
+ {
+ EFX.alDeleteFilters((IntPtr) 1, ref INTERNAL_alFilter);
+
+ ALC10.alcMakeContextCurrent(IntPtr.Zero);
+ if (alContext != IntPtr.Zero)
+ {
+ ALC10.alcDestroyContext(alContext);
+ alContext = IntPtr.Zero;
+ }
+ if (alDevice != IntPtr.Zero)
+ {
+ ALC10.alcCloseDevice(alDevice);
+ alDevice = IntPtr.Zero;
+ }
+ }
+
+ #endregion
+
+ #region Public Update Method
+
+ public void Update()
+ {
+#if DEBUG
+ CheckALError();
+#endif
+ }
+
+ #endregion
+
+ #region OpenAL Buffer Methods
+
+ public IALBuffer GenBuffer()
+ {
+ uint result;
+ AL10.alGenBuffers((IntPtr) 1, out result);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ return new OpenALBuffer(result, TimeSpan.Zero);
+ }
+
+ public IALBuffer GenBuffer(
+ byte[] data,
+ uint sampleRate,
+ uint channels,
+ uint loopStart,
+ uint loopEnd,
+ bool isADPCM,
+ uint formatParameter
+ ) {
+ uint result;
+
+ // Generate the buffer now, in case we need to perform alBuffer ops.
+ AL10.alGenBuffers((IntPtr) 1, out result);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+
+ int format;
+ if (isADPCM)
+ {
+ format = (channels == 2) ?
+ ALEXT.AL_FORMAT_STEREO_MSADPCM_SOFT :
+ ALEXT.AL_FORMAT_MONO_MSADPCM_SOFT;
+ AL10.alBufferi(
+ result,
+ ALEXT.AL_UNPACK_BLOCK_ALIGNMENT_SOFT,
+ (int) formatParameter
+ );
+ }
+ else
+ {
+ if (formatParameter == 1)
+ {
+ format = (channels == 2) ?
+ AL10.AL_FORMAT_STEREO16:
+ AL10.AL_FORMAT_MONO16;
+ }
+ else
+ {
+ format = (channels == 2) ?
+ AL10.AL_FORMAT_STEREO8:
+ AL10.AL_FORMAT_MONO8;
+ }
+ }
+
+ // Load it!
+ AL10.alBufferData(
+ result,
+ format,
+ data,
+ (IntPtr) data.Length,
+ (IntPtr) sampleRate
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+
+ // Calculate the duration now, after we've unpacked the buffer
+ int bufLen, bits;
+ AL10.alGetBufferi(
+ result,
+ AL10.AL_SIZE,
+ out bufLen
+ );
+ AL10.alGetBufferi(
+ result,
+ AL10.AL_BITS,
+ out bits
+ );
+ if (bufLen == 0 || bits == 0)
+ {
+ throw new InvalidOperationException(
+ "OpenAL buffer allocation failed!"
+ );
+ }
+ TimeSpan resultDur = TimeSpan.FromSeconds(
+ bufLen /
+ (bits / 8) /
+ channels /
+ ((double) sampleRate)
+ );
+
+ // Set the loop points, if applicable
+ if (loopStart > 0 || loopEnd > 0)
+ {
+ AL10.alBufferiv(
+ result,
+ ALEXT.AL_LOOP_POINTS_SOFT,
+ new int[]
+ {
+ (int) loopStart,
+ (int) loopEnd
+ }
+ );
+ }
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+
+ // Finally.
+ return new OpenALBuffer(result, resultDur);
+ }
+
+ public void DeleteBuffer(IALBuffer buffer)
+ {
+ uint handle = (buffer as OpenALBuffer).Handle;
+ AL10.alDeleteBuffers((IntPtr) 1, ref handle);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetBufferData(
+ IALBuffer buffer,
+ AudioChannels channels,
+ byte[] data,
+ int count,
+ int sampleRate
+ ) {
+ AL10.alBufferData(
+ (buffer as OpenALBuffer).Handle,
+ XNAToShort[(int) channels],
+ data, // TODO: offset -flibit
+ (IntPtr) count,
+ (IntPtr) sampleRate
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetBufferData(
+ IALBuffer buffer,
+ AudioChannels channels,
+ float[] data,
+ int sampleRate
+ ) {
+ AL10.alBufferData(
+ (buffer as OpenALBuffer).Handle,
+ XNAToFloat[(int) channels],
+ data,
+ (IntPtr) (data.Length * 4),
+ (IntPtr) sampleRate
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ #endregion
+
+ #region OpenAL Source Methods
+
+ public IALSource GenSource()
+ {
+ uint result;
+ AL10.alGenSources((IntPtr) 1, out result);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ if (result == 0)
+ {
+ return null;
+ }
+ return new OpenALSource(result);
+ }
+
+ public IALSource GenSource(IALBuffer buffer)
+ {
+ uint result;
+ AL10.alGenSources((IntPtr) 1, out result);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ if (result == 0)
+ {
+ return null;
+ }
+ AL10.alSourcei(
+ result,
+ AL10.AL_BUFFER,
+ (int) (buffer as OpenALBuffer).Handle
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ return new OpenALSource(result);
+ }
+
+ public void StopAndDisposeSource(IALSource source)
+ {
+ uint handle = (source as OpenALSource).Handle;
+ AL10.alSourceStop(handle);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ AL10.alDeleteSources((IntPtr) 1, ref handle);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void PlaySource(IALSource source)
+ {
+ AL10.alSourcePlay((source as OpenALSource).Handle);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void PauseSource(IALSource source)
+ {
+ AL10.alSourcePause((source as OpenALSource).Handle);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void ResumeSource(IALSource source)
+ {
+ AL10.alSourcePlay((source as OpenALSource).Handle);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public SoundState GetSourceState(IALSource source)
+ {
+ int state;
+ AL10.alGetSourcei(
+ (source as OpenALSource).Handle,
+ AL10.AL_SOURCE_STATE,
+ out state
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ if (state == AL10.AL_PLAYING)
+ {
+ return SoundState.Playing;
+ }
+ else if (state == AL10.AL_PAUSED)
+ {
+ return SoundState.Paused;
+ }
+ return SoundState.Stopped;
+ }
+
+ public void SetSourceVolume(IALSource source, float volume)
+ {
+ AL10.alSourcef(
+ (source as OpenALSource).Handle,
+ AL10.AL_GAIN,
+ volume * SoundEffect.MasterVolume
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetSourceLooped(IALSource source, bool looped)
+ {
+ AL10.alSourcei(
+ (source as OpenALSource).Handle,
+ AL10.AL_LOOPING,
+ looped ? 1 : 0
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetSourcePan(IALSource source, float pan)
+ {
+ AL10.alSource3f(
+ (source as OpenALSource).Handle,
+ AL10.AL_POSITION,
+ pan,
+ 0.0f,
+ (float) Math.Sqrt(1 - Math.Pow(pan, 2))
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetSourcePosition(IALSource source, Vector3 pos)
+ {
+ AL10.alSource3f(
+ (source as OpenALSource).Handle,
+ AL10.AL_POSITION,
+ pos.X,
+ pos.Y,
+ pos.Z
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetSourcePitch(IALSource source, float pitch, bool clamp)
+ {
+ /* XNA sets pitch bounds to [-1.0f, 1.0f], each end being one octave.
+ * OpenAL's AL_PITCH boundaries are (0.0f, INF).
+ * Consider the function f(x) = 2 ^ x
+ * The domain is (-INF, INF) and the range is (0, INF).
+ * 0.0f is the original pitch for XNA, 1.0f is the original pitch for OpenAL.
+ * Note that f(0) = 1, f(1) = 2, f(-1) = 0.5, and so on.
+ * XNA's pitch values are on the domain, OpenAL's are on the range.
+ * Remember: the XNA limit is arbitrarily between two octaves on the domain.
+ * To convert, we just plug XNA pitch into f(x).
+ * -flibit
+ */
+ if (clamp && (pitch < -1.0f || pitch > 1.0f))
+ {
+ throw new Exception("XNA PITCH MUST BE WITHIN [-1.0f, 1.0f]!");
+ }
+ AL10.alSourcef(
+ (source as OpenALSource).Handle,
+ AL10.AL_PITCH,
+ (float) Math.Pow(2, pitch)
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetSourceReverb(IALSource source, IALReverb reverb)
+ {
+ AL10.alSource3i(
+ (source as OpenALSource).Handle,
+ EFX.AL_AUXILIARY_SEND_FILTER,
+ (int) (reverb as OpenALReverb).SlotHandle,
+ 0,
+ 0
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetSourceLowPassFilter(IALSource source, float hfGain)
+ {
+ EFX.alFilteri(INTERNAL_alFilter, EFX.AL_FILTER_TYPE, EFX.AL_FILTER_LOWPASS);
+ EFX.alFilterf(INTERNAL_alFilter, EFX.AL_LOWPASS_GAINHF, hfGain);
+ AL10.alSourcei(
+ (source as OpenALSource).Handle,
+ EFX.AL_DIRECT_FILTER,
+ (int) INTERNAL_alFilter
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetSourceHighPassFilter(IALSource source, float lfGain)
+ {
+ EFX.alFilteri(INTERNAL_alFilter, EFX.AL_FILTER_TYPE, EFX.AL_FILTER_HIGHPASS);
+ EFX.alFilterf(INTERNAL_alFilter, EFX.AL_HIGHPASS_GAINLF, lfGain);
+ AL10.alSourcei(
+ (source as OpenALSource).Handle,
+ EFX.AL_DIRECT_FILTER,
+ (int) INTERNAL_alFilter
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetSourceBandPassFilter(IALSource source, float hfGain, float lfGain)
+ {
+ EFX.alFilteri(INTERNAL_alFilter, EFX.AL_FILTER_TYPE, EFX.AL_FILTER_BANDPASS);
+ EFX.alFilterf(INTERNAL_alFilter, EFX.AL_BANDPASS_GAINHF, hfGain);
+ EFX.alFilterf(INTERNAL_alFilter, EFX.AL_BANDPASS_GAINLF, lfGain);
+ AL10.alSourcei(
+ (source as OpenALSource).Handle,
+ EFX.AL_DIRECT_FILTER,
+ (int) INTERNAL_alFilter
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void QueueSourceBuffer(IALSource source, IALBuffer buffer)
+ {
+ uint buf = (buffer as OpenALBuffer).Handle;
+ AL10.alSourceQueueBuffers(
+ (source as OpenALSource).Handle,
+ (IntPtr) 1,
+ ref buf
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void DequeueSourceBuffers(
+ IALSource source,
+ int buffersToDequeue,
+ Queue errorCheck
+ ) {
+ uint[] bufs = new uint[buffersToDequeue];
+ AL10.alSourceUnqueueBuffers(
+ (source as OpenALSource).Handle,
+ (IntPtr) buffersToDequeue,
+ bufs
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+#if DEBUG
+ // Error check our queuedBuffers list.
+ IALBuffer[] sync = errorCheck.ToArray();
+ for (int i = 0; i < buffersToDequeue; i += 1)
+ {
+ if (bufs[i] != (sync[i] as OpenALBuffer).Handle)
+ {
+ throw new Exception("Buffer desync!");
+ }
+ }
+#endif
+ }
+
+ public int CheckProcessedBuffers(IALSource source)
+ {
+ int result;
+ AL10.alGetSourcei(
+ (source as OpenALSource).Handle,
+ AL10.AL_BUFFERS_PROCESSED,
+ out result
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ return result;
+ }
+
+ public void GetBufferData(
+ IALSource source,
+ IALBuffer[] buffer,
+ float[] samples,
+ AudioChannels channels
+ ) {
+ int copySize1 = samples.Length / (int) channels;
+ int copySize2 = 0;
+
+ // Where are we now?
+ int offset;
+ AL10.alGetSourcei(
+ (source as OpenALSource).Handle,
+ AL11.AL_SAMPLE_OFFSET,
+ out offset
+ );
+
+ // Is that longer than what the active buffer has left...?
+ uint buf = (buffer[0] as OpenALBuffer).Handle;
+ int len;
+ AL10.alGetBufferi(
+ buf,
+ AL10.AL_SIZE,
+ out len
+ );
+ len /= 2; // FIXME: Assuming 16-bit!
+ len /= (int) channels;
+ if (offset > len)
+ {
+ copySize2 = copySize1;
+ copySize1 = 0;
+ offset -= len;
+ }
+ else if (offset + copySize1 > len)
+ {
+ copySize2 = copySize1 - (len - offset);
+ copySize1 = (len - offset);
+ }
+
+ // Copy!
+ GCHandle handle = GCHandle.Alloc(samples, GCHandleType.Pinned);
+ if (copySize1 > 0)
+ {
+ ALEXT.alGetBufferSamplesSOFT(
+ buf,
+ offset,
+ copySize1,
+ channels == AudioChannels.Stereo ?
+ ALEXT.AL_STEREO_SOFT :
+ ALEXT.AL_MONO_SOFT,
+ ALEXT.AL_FLOAT_SOFT,
+ handle.AddrOfPinnedObject()
+ );
+ offset = 0;
+ }
+ if (buffer.Length > 1 && copySize2 > 0)
+ {
+ ALEXT.alGetBufferSamplesSOFT(
+ (buffer[1] as OpenALBuffer).Handle,
+ 0,
+ copySize2,
+ channels == AudioChannels.Stereo ?
+ ALEXT.AL_STEREO_SOFT :
+ ALEXT.AL_MONO_SOFT,
+ ALEXT.AL_FLOAT_SOFT,
+ handle.AddrOfPinnedObject() + (copySize1 * (int) channels)
+ );
+ }
+ handle.Free();
+ }
+
+ #endregion
+
+ #region OpenAL Reverb Effect Methods
+
+ public IALReverb GenReverb(DSPParameter[] parameters)
+ {
+ uint slot, effect;
+ EFX.alGenAuxiliaryEffectSlots((IntPtr) 1, out slot);
+ EFX.alGenEffects((IntPtr) 1, out effect);
+ // Set up the Reverb Effect
+ EFX.alEffecti(
+ effect,
+ EFX.AL_EFFECT_TYPE,
+ EFX.AL_EFFECT_EAXREVERB
+ );
+
+ IALReverb result = new OpenALReverb(slot, effect);
+
+ // Apply initial values
+ SetReverbReflectionsDelay(result, parameters[0].Value);
+ SetReverbDelay(result, parameters[1].Value);
+ SetReverbPositionLeft(result, parameters[2].Value);
+ SetReverbPositionRight(result, parameters[3].Value);
+ SetReverbPositionLeftMatrix(result, parameters[4].Value);
+ SetReverbPositionRightMatrix(result, parameters[5].Value);
+ SetReverbEarlyDiffusion(result, parameters[6].Value);
+ SetReverbLateDiffusion(result, parameters[7].Value);
+ SetReverbLowEQGain(result, parameters[8].Value);
+ SetReverbLowEQCutoff(result, parameters[9].Value);
+ SetReverbHighEQGain(result, parameters[10].Value);
+ SetReverbHighEQCutoff(result, parameters[11].Value);
+ SetReverbRearDelay(result, parameters[12].Value);
+ SetReverbRoomFilterFrequency(result, parameters[13].Value);
+ SetReverbRoomFilterMain(result, parameters[14].Value);
+ SetReverbRoomFilterHighFrequency(result, parameters[15].Value);
+ SetReverbReflectionsGain(result, parameters[16].Value);
+ SetReverbGain(result, parameters[17].Value);
+ SetReverbDecayTime(result, parameters[18].Value);
+ SetReverbDensity(result, parameters[19].Value);
+ SetReverbRoomSize(result, parameters[20].Value);
+ SetReverbWetDryMix(result, parameters[21].Value);
+
+ // Bind the Effect to the EffectSlot. XACT will use the EffectSlot.
+ EFX.alAuxiliaryEffectSloti(
+ slot,
+ EFX.AL_EFFECTSLOT_EFFECT,
+ (int) effect
+ );
+
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ return result;
+ }
+
+ public void DeleteReverb(IALReverb reverb)
+ {
+ OpenALReverb rv = (reverb as OpenALReverb);
+ uint slot = rv.SlotHandle;
+ uint effect = rv.EffectHandle;
+ EFX.alDeleteAuxiliaryEffectSlots((IntPtr) 1, ref slot);
+ EFX.alDeleteEffects((IntPtr) 1, ref effect);
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void CommitReverbChanges(IALReverb reverb)
+ {
+ OpenALReverb rv = (reverb as OpenALReverb);
+ EFX.alAuxiliaryEffectSloti(
+ rv.SlotHandle,
+ EFX.AL_EFFECTSLOT_EFFECT,
+ (int) rv.EffectHandle
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbReflectionsDelay(IALReverb reverb, float value)
+ {
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_REFLECTIONS_DELAY,
+ value / 1000.0f
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbDelay(IALReverb reverb, float value)
+ {
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_LATE_REVERB_DELAY,
+ value / 1000.0f
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbPositionLeft(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbPositionRight(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbPositionLeftMatrix(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbPositionRightMatrix(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbEarlyDiffusion(IALReverb reverb, float value)
+ {
+ // Same as late diffusion, whatever... -flibit
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_DIFFUSION,
+ value / 15.0f
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbLateDiffusion(IALReverb reverb, float value)
+ {
+ // Same as early diffusion, whatever... -flibit
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_DIFFUSION,
+ value / 15.0f
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbLowEQGain(IALReverb reverb, float value)
+ {
+ // Cutting off volumes from 0db to 4db! -flibit
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_GAINLF,
+ Math.Min(
+ XACTCalculator.CalculateAmplitudeRatio(
+ value - 8.0f
+ ),
+ 1.0f
+ )
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbLowEQCutoff(IALReverb reverb, float value)
+ {
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_LFREFERENCE,
+ (value * 50.0f) + 50.0f
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbHighEQGain(IALReverb reverb, float value)
+ {
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_GAINHF,
+ XACTCalculator.CalculateAmplitudeRatio(
+ value - 8.0f
+ )
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbHighEQCutoff(IALReverb reverb, float value)
+ {
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_HFREFERENCE,
+ (value * 500.0f) + 1000.0f
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbRearDelay(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbRoomFilterFrequency(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbRoomFilterMain(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbRoomFilterHighFrequency(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbReflectionsGain(IALReverb reverb, float value)
+ {
+ // Cutting off possible float values above 3.16, for EFX -flibit
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_REFLECTIONS_GAIN,
+ Math.Min(
+ XACTCalculator.CalculateAmplitudeRatio(value),
+ 3.16f
+ )
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbGain(IALReverb reverb, float value)
+ {
+ // Cutting off volumes from 0db to 20db! -flibit
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_GAIN,
+ Math.Min(
+ XACTCalculator.CalculateAmplitudeRatio(value),
+ 1.0f
+ )
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbDecayTime(IALReverb reverb, float value)
+ {
+ /* FIXME: WTF is with this XACT value?
+ * XACT: 0-30 equal to 0.1-inf seconds?!
+ * EFX: 0.1-20 seconds
+ * -flibit
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_GAIN,
+ value
+ );
+ */
+ }
+
+ public void SetReverbDensity(IALReverb reverb, float value)
+ {
+ EFX.alEffectf(
+ (reverb as OpenALReverb).EffectHandle,
+ EFX.AL_EAXREVERB_DENSITY,
+ value / 100.0f
+ );
+#if VERBOSE_AL_DEBUGGING
+ CheckALError();
+#endif
+ }
+
+ public void SetReverbRoomSize(IALReverb reverb, float value)
+ {
+ // No known mapping :(
+ }
+
+ public void SetReverbWetDryMix(IALReverb reverb, float value)
+ {
+ /* FIXME: Note that were dividing by 200, not 100.
+ * For some ridiculous reason the mix is WAY too wet
+ * when we actually do the correct math, but cutting
+ * the ratio in half mysteriously makes it sound right.
+ *
+ * Or, well, "more" right. I'm sure we're still off.
+ * -flibit
+ */
+ EFX.alAuxiliaryEffectSlotf(
+ (reverb as OpenALReverb).SlotHandle,
+ EFX.AL_EFFECTSLOT_GAIN,
+ value / 200.0f
+ );
+ }
+
+ #endregion
+
+ #region OpenAL Capture Methods
+
+ public IntPtr StartDeviceCapture(string name, int sampleRate, int bufSize)
+ {
+ IntPtr result = ALC11.alcCaptureOpenDevice(
+ name,
+ (uint) sampleRate,
+ AL10.AL_FORMAT_MONO16,
+ (IntPtr) bufSize
+ );
+ ALC11.alcCaptureStart(result);
+#if VERBOSE_AL_DEBUGGING
+ if (CheckALCError())
+ {
+ throw new InvalidOperationException("AL device error!");
+ }
+#endif
+ return result;
+ }
+
+ public void StopDeviceCapture(IntPtr handle)
+ {
+ ALC11.alcCaptureStop(handle);
+ ALC11.alcCaptureCloseDevice(handle);
+#if VERBOSE_AL_DEBUGGING
+ if (CheckALCError())
+ {
+ throw new InvalidOperationException("AL device error!");
+ }
+#endif
+ }
+
+ public int CaptureSamples(IntPtr handle, IntPtr buffer, int count)
+ {
+ int[] samples = new int[1] { 0 };
+ ALC10.alcGetIntegerv(
+ handle,
+ ALC11.ALC_CAPTURE_SAMPLES,
+ (IntPtr) 1,
+ samples
+ );
+ samples[0] = Math.Min(samples[0], count / 2);
+ if (samples[0] > 0)
+ {
+ ALC11.alcCaptureSamples(handle, buffer, (IntPtr) samples[0]);
+ }
+#if VERBOSE_AL_DEBUGGING
+ if (CheckALCError())
+ {
+ throw new InvalidOperationException("AL device error!");
+ }
+#endif
+ return samples[0] * 2;
+ }
+
+ public bool CaptureHasSamples(IntPtr handle)
+ {
+ int[] samples = new int[1] { 0 };
+ ALC10.alcGetIntegerv(
+ handle,
+ ALC11.ALC_CAPTURE_SAMPLES,
+ (IntPtr) 1,
+ samples
+ );
+ return samples[0] > 0;
+ }
+
+ #endregion
+
+ #region Private OpenAL Error Check Methods
+
+ private void CheckALError()
+ {
+ int err = AL10.alGetError();
+
+ if (err == AL10.AL_NO_ERROR)
+ {
+ return;
+ }
+
+ System.Console.WriteLine("OpenAL Error: {0:X}", err);
+#if VERBOSE_AL_DEBUGGING
+ throw new InvalidOperationException("OpenAL Error!");
+#endif
+ }
+
+ private bool CheckALCError()
+ {
+ int err = ALC10.alcGetError(alDevice);
+
+ if (err == ALC10.ALC_NO_ERROR)
+ {
+ return false;
+ }
+
+ System.Console.WriteLine("OpenAL Device Error: {0:X}", err);
+ return true;
+ }
+
+ #endregion
+
+ #region Private Static XNA->AL Dictionaries
+
+ private static readonly int[] XNAToShort = new int[]
+ {
+ AL10.AL_NONE, // NOPE
+ AL10.AL_FORMAT_MONO16, // AudioChannels.Mono
+ AL10.AL_FORMAT_STEREO16, // AudioChannels.Stereo
+ };
+
+ private static readonly int[] XNAToFloat = new int[]
+ {
+ AL10.AL_NONE, // NOPE
+ ALEXT.AL_FORMAT_MONO_FLOAT32, // AudioChannels.Mono
+ ALEXT.AL_FORMAT_STEREO_FLOAT32 // AudioChannels.Stereo
+ };
+
+ #endregion
+
+ #region OpenAL Device Enumerators
+
+ public ReadOnlyCollection GetDevices()
+ {
+ IntPtr deviceList = ALC10.alcGetString(IntPtr.Zero, ALC11.ALC_ALL_DEVICES_SPECIFIER);
+ List renderers = new List();
+
+ int i = 0;
+ string curString = Marshal.PtrToStringAnsi(deviceList);
+ while (!String.IsNullOrEmpty(curString))
+ {
+ renderers.Add(new RendererDetail(
+ curString,
+ i.ToString()
+ ));
+ i += 1;
+ deviceList += curString.Length + 1;
+ curString = Marshal.PtrToStringAnsi(deviceList);
+ }
+
+ return new ReadOnlyCollection(renderers);
+ }
+
+ public ReadOnlyCollection GetCaptureDevices()
+ {
+ IntPtr deviceList = ALC10.alcGetString(IntPtr.Zero, ALC11.ALC_CAPTURE_DEVICE_SPECIFIER);
+ List microphones = new List();
+
+ string curString = Marshal.PtrToStringAnsi(deviceList);
+ while (!String.IsNullOrEmpty(curString))
+ {
+ microphones.Add(new Microphone(curString));
+ deviceList += curString.Length + 1;
+ curString = Marshal.PtrToStringAnsi(deviceList);
+ }
+
+ return new ReadOnlyCollection(microphones);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/RendererDetail.cs b/src/Audio/RendererDetail.cs
new file mode 100644
index 0000000..f8da3b4
--- /dev/null
+++ b/src/Audio/RendererDetail.cs
@@ -0,0 +1,79 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ [Serializable]
+ public struct RendererDetail
+ {
+ #region Public Properties
+
+ public string FriendlyName
+ {
+ get;
+ private set;
+ }
+
+ public string RendererId
+ {
+ get;
+ private set;
+ }
+
+ #endregion
+
+ #region Internal Constructor
+
+ internal RendererDetail(string name, string id) : this()
+ {
+ FriendlyName = name;
+ RendererId = id;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public override bool Equals(object obj)
+ {
+ return ( (obj is RendererDetail) &&
+ RendererId.Equals(((RendererDetail) obj).RendererId) );
+ }
+
+ public override int GetHashCode()
+ {
+ return RendererId.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return FriendlyName;
+ }
+
+ #endregion
+
+ #region Public Static Operator Overloads
+
+ public static bool operator==(RendererDetail left, RendererDetail right)
+ {
+ return left.RendererId.Equals(right.RendererId);
+ }
+
+ public static bool operator!=(RendererDetail left, RendererDetail right)
+ {
+ return !left.RendererId.Equals(right.RendererId);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/SoundBank.cs b/src/Audio/SoundBank.cs
new file mode 100644
index 0000000..0c5ca35
--- /dev/null
+++ b/src/Audio/SoundBank.cs
@@ -0,0 +1,487 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.IO;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.soundbank.aspx
+ public class SoundBank : IDisposable
+ {
+ #region Public Properties
+
+ public bool IsDisposed
+ {
+ get;
+ private set;
+ }
+
+ public bool IsInUse
+ {
+ get
+ {
+ throw new NotImplementedException("Bank Cue instance count tracking!");
+ }
+ }
+
+ #endregion
+
+ #region Private Variables
+
+ private AudioEngine INTERNAL_baseEngine;
+
+ private List INTERNAL_waveBankNames;
+ private Dictionary INTERNAL_cueData;
+
+ #endregion
+
+ #region Disposing Event
+
+ public event EventHandler Disposing;
+
+ #endregion
+
+ #region Public Constructor
+
+ public SoundBank(AudioEngine audioEngine, string filename)
+ {
+ if (audioEngine == null)
+ {
+ throw new ArgumentNullException("audioEngine");
+ }
+ if (String.IsNullOrEmpty(filename))
+ {
+ throw new ArgumentNullException("filename");
+ }
+
+ INTERNAL_baseEngine = audioEngine;
+
+ using (Stream soundBankStream = TitleContainer.OpenStream(filename))
+ using (BinaryReader reader = new BinaryReader(soundBankStream))
+ {
+ // Check the file header. Should be 'SDBK'
+ if (reader.ReadUInt32() != 0x4B424453)
+ {
+ throw new ArgumentException("SDBK format not recognized!");
+ }
+
+ // Check the content version. Assuming XNA4 Refresh.
+ if (reader.ReadUInt16() != AudioEngine.ContentVersion)
+ {
+ throw new ArgumentException("SDBK Content version!");
+ }
+
+ // Check the tool version. Assuming XNA4 Refresh.
+ if (reader.ReadUInt16() != 43)
+ {
+ throw new ArgumentException("SDBK Tool version!");
+ }
+
+ // CRC, unused
+ reader.ReadUInt16();
+
+ // Last modified, unused
+ reader.ReadUInt64();
+
+ // Unknown value, Internet suggests platform
+ reader.ReadByte();
+
+ // Cue Counts
+ ushort numCueSimple = reader.ReadUInt16();
+ ushort numCueComplex = reader.ReadUInt16();
+
+ // Unknown value
+ reader.ReadUInt16();
+
+ // Total Cues, unused
+ reader.ReadUInt16();
+
+ // Number of associated WaveBanks
+ byte numWaveBanks = reader.ReadByte();
+
+ // Unknown, Internet suggest number of "sounds"
+ reader.ReadUInt16();
+
+ // Cue Name Table Length
+ ushort cueNameTableLength = reader.ReadUInt16();
+
+ // Unknown value
+ reader.ReadUInt16();
+
+ // Cue Offsets
+ uint cueSimpleOffset = reader.ReadUInt32();
+ uint cueComplexOffset = reader.ReadUInt32();
+
+ // Cue Name Table Offset
+ uint cueNameTableOffset = reader.ReadUInt32();
+
+ // Unknown value
+ reader.ReadUInt32();
+
+ // Variable Tables Offset, unused
+ reader.ReadUInt32();
+
+ // Unknown value
+ reader.ReadUInt32();
+
+ // WaveBank Name Table Offset
+ uint waveBankNameTableOffset = reader.ReadUInt32();
+
+ // Cue Name Hash Offsets, unused
+ reader.ReadUInt32();
+ reader.ReadUInt32();
+
+ // Unknown value, Internet suggest "sounds" offset
+ reader.ReadUInt32();
+
+ // SoundBank Name, unused
+ reader.ReadBytes(64);
+
+ // Parse WaveBank names
+ soundBankStream.Seek(waveBankNameTableOffset, SeekOrigin.Begin);
+ INTERNAL_waveBankNames = new List();
+ for (byte i = 0; i < numWaveBanks; i += 1)
+ {
+ INTERNAL_waveBankNames.Add(
+ System.Text.Encoding.UTF8.GetString(
+ reader.ReadBytes(64), 0, 64
+ ).Replace("\0", "")
+ );
+ }
+
+ // Parse Cue name list
+ soundBankStream.Seek(cueNameTableOffset, SeekOrigin.Begin);
+ string[] cueNames = System.Text.Encoding.UTF8.GetString(
+ reader.ReadBytes(cueNameTableLength),
+ 0,
+ cueNameTableLength
+ ).Split('\0');
+
+ // Create our CueData Dictionary
+ INTERNAL_cueData = new Dictionary();
+
+ // Parse Simple Cues
+ soundBankStream.Seek(cueSimpleOffset, SeekOrigin.Begin);
+ for (ushort i = 0; i < numCueSimple; i += 1)
+ {
+ // Cue flags, unused
+ reader.ReadByte();
+
+ // Cue Sound Offset
+ uint offset = reader.ReadUInt32();
+
+ // Store this for when we're done reading the sound.
+ long curPos = reader.BaseStream.Position;
+
+ // Go to the sound in the Bank.
+ reader.BaseStream.Seek(offset, SeekOrigin.Begin);
+
+ // Parse the Sound
+ INTERNAL_cueData.Add(
+ cueNames[i],
+ new CueData(new XACTSound(reader))
+ );
+
+ // Back to where we were...
+ reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
+ }
+
+ // Parse Complex Cues
+ soundBankStream.Seek(cueComplexOffset, SeekOrigin.Begin);
+ for (ushort i = 0; i < numCueComplex; i += 1)
+ {
+ // Cue flags
+ byte cueFlags = reader.ReadByte();
+
+ if ((cueFlags & 0x04) != 0) // FIXME: ???
+ {
+ // Cue Sound Offset
+ uint offset = reader.ReadUInt32();
+
+ // Unknown value
+ reader.ReadUInt32();
+
+ // Store this for when we're done reading the sound.
+ long curPos = reader.BaseStream.Position;
+
+ // Go to the sound in the bank
+ reader.BaseStream.Seek(offset, SeekOrigin.Begin);
+
+ // Parse the Sound
+ INTERNAL_cueData.Add(
+ cueNames[numCueSimple + i],
+ new CueData(new XACTSound(reader))
+ );
+
+ // Back to where we were...
+ reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
+ }
+ else
+ {
+ // Variation Table Offset for this Cue
+ uint offset = reader.ReadUInt32();
+
+ // Transition Table Offset for this Cue, unused
+ reader.ReadUInt32();
+
+ // Store this for when we're done reading the Variation Table
+ long curPos = reader.BaseStream.Position;
+
+ // Seek to the Variation Table in the file
+ reader.BaseStream.Seek(offset, SeekOrigin.Begin);
+
+ // Number of Variations in the Table
+ ushort numVariations = reader.ReadUInt16();
+
+ // Variation Table Flags
+ ushort varTableFlags = reader.ReadUInt16();
+
+ // Unknown value
+ reader.ReadUInt16();
+
+ // Probability Control Variable, if applicable
+ ushort variable = reader.ReadUInt16();
+
+ // Create data for the CueData
+ XACTSound[] cueSounds = new XACTSound[numVariations];
+ float[,] cueProbs = new float[numVariations, 2];
+
+ // Used to determine Variation storage format
+ int varTableType = (varTableFlags >> 3) & 0x0007;
+
+ for (ushort j = 0; j < numVariations; j += 1)
+ {
+ if (varTableType == 0)
+ {
+ // Wave with byte min/max
+ ushort track = reader.ReadUInt16();
+ byte waveBank = reader.ReadByte();
+ byte wMin = reader.ReadByte();
+ byte wMax = reader.ReadByte();
+
+ // Create the Sound
+ cueSounds[j] = new XACTSound(track, waveBank);
+
+ // Calculate probability based on weight
+ cueProbs[j, 0] = wMax / 255.0f;
+ cueProbs[j, 1] = wMin / 255.0f;
+ }
+ else if (varTableType == 1)
+ {
+ // Complex with byte min/max
+ uint varOffset = reader.ReadUInt32();
+ byte wMin = reader.ReadByte();
+ byte wMax = reader.ReadByte();
+
+ // Store for sound read
+ long varPos = reader.BaseStream.Position;
+
+ // Seek to the sound in the Bank
+ reader.BaseStream.Seek(varOffset, SeekOrigin.Begin);
+
+ // Read the sound
+ cueSounds[j] = new XACTSound(reader);
+
+ // Back to where we were...
+ reader.BaseStream.Seek(varPos, SeekOrigin.Begin);
+
+ // Calculate probability based on weight
+ cueProbs[j, 0] = wMax / 255.0f;
+ cueProbs[j, 1] = wMin / 255.0f;
+ }
+ else if (varTableType == 3)
+ {
+ // Complex with float min/max
+ uint varOffset = reader.ReadUInt32();
+ float wMin = reader.ReadSingle();
+ float wMax = reader.ReadSingle();
+
+ // Unknown value
+ reader.ReadUInt32();
+
+ // Store for sound read
+ long varPos = reader.BaseStream.Position;
+
+ // Seek to the sound in the Bank
+ reader.BaseStream.Seek(varOffset, SeekOrigin.Begin);
+
+ // Read the sound
+ cueSounds[j] = new XACTSound(reader);
+
+ // Back to where we were...
+ reader.BaseStream.Seek(varPos, SeekOrigin.Begin);
+
+ // Calculate probability based on weight
+ cueProbs[j, 0] = wMax;
+ cueProbs[j, 1] = wMin;
+ }
+ else if (varTableType == 4)
+ {
+ // Compact Wave
+ ushort track = reader.ReadUInt16();
+ byte waveBank = reader.ReadByte();
+
+ // Create the Sound
+ cueSounds[j] = new XACTSound(track, waveBank);
+
+ // FIXME: Assume Sound weight is 100%
+ cueProbs[j, 0] = 1.0f;
+ cueProbs[j, 1] = 0.0f;
+ }
+ else
+ {
+ throw new NotSupportedException();
+ }
+ }
+
+ // Back to where we were...
+ reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
+
+ // Add Built CueData to Dictionary
+ INTERNAL_cueData.Add(
+ cueNames[numCueSimple + i],
+ new CueData(
+ cueSounds,
+ cueProbs,
+ (varTableType == 3) ? INTERNAL_baseEngine.INTERNAL_getVariableName(variable) : String.Empty
+ )
+ );
+ }
+
+ // Cue instance limit
+ byte instanceLimit = reader.ReadByte();
+
+ // Fade In/Out
+ ushort fadeIn = reader.ReadUInt16();
+ ushort fadeOut = reader.ReadUInt16();
+
+ // Cue max instance behavior
+ byte behavior = reader.ReadByte();
+
+ INTERNAL_cueData[cueNames[numCueSimple + i]].SetLimit(
+ instanceLimit,
+ behavior,
+ fadeIn,
+ fadeOut
+ );
+ }
+ }
+ IsDisposed = false;
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~SoundBank()
+ {
+ Dispose(true);
+ }
+
+ #endregion
+
+ #region Public Dispose Method
+
+ public void Dispose()
+ {
+ Dispose(false);
+ }
+
+ #endregion
+
+ #region Protected Dispose Method
+
+ protected void Dispose(bool disposing)
+ {
+ if (!IsDisposed)
+ {
+ if (Disposing != null)
+ {
+ Disposing.Invoke(this, null);
+ }
+ INTERNAL_waveBankNames.Clear();
+ INTERNAL_cueData.Clear();
+ IsDisposed = true;
+ }
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public Cue GetCue(string name)
+ {
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+ if (!INTERNAL_cueData.ContainsKey(name))
+ {
+ throw new ArgumentException("Cue name not found: " + name);
+ }
+ return new Cue(
+ INTERNAL_baseEngine,
+ INTERNAL_waveBankNames,
+ name,
+ INTERNAL_cueData[name],
+ false
+ );
+ }
+
+ public void PlayCue(string name)
+ {
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+ if (!INTERNAL_cueData.ContainsKey(name))
+ {
+ throw new InvalidOperationException("name not found!");
+ }
+ Cue newCue = new Cue(
+ INTERNAL_baseEngine,
+ INTERNAL_waveBankNames,
+ name,
+ INTERNAL_cueData[name],
+ true
+ );
+ newCue.Play();
+ }
+
+ public void PlayCue(
+ string name,
+ AudioListener listener,
+ AudioEmitter emitter
+ ) {
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+ if (!INTERNAL_cueData.ContainsKey(name))
+ {
+ throw new InvalidOperationException("name not found!");
+ }
+ Cue newCue = new Cue(
+ INTERNAL_baseEngine,
+ INTERNAL_waveBankNames,
+ name,
+ INTERNAL_cueData[name],
+ true
+ );
+ newCue.Apply3D(listener, emitter);
+ newCue.Play();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/SoundEffect.cs b/src/Audio/SoundEffect.cs
new file mode 100644
index 0000000..72128f0
--- /dev/null
+++ b/src/Audio/SoundEffect.cs
@@ -0,0 +1,408 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.IO;
+using System.Collections.Generic;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.soundeffect.aspx
+ public sealed class SoundEffect : IDisposable
+ {
+ #region Public Properties
+
+ public TimeSpan Duration
+ {
+ get
+ {
+ return INTERNAL_buffer.Duration;
+ }
+ }
+
+ public bool IsDisposed
+ {
+ get;
+ private set;
+ }
+
+ public string Name
+ {
+ get;
+ set;
+ }
+
+ #endregion
+
+ #region Public Static Properties
+
+ // FIXME: This should affect all sounds! alListener? -flibit
+ private static float INTERNAL_masterVolume = 1.0f;
+ public static float MasterVolume
+ {
+ get
+ {
+ return INTERNAL_masterVolume;
+ }
+ set
+ {
+ INTERNAL_masterVolume = value;
+ }
+ }
+
+ // FIXME: How does this affect OpenAL? -flibit
+ private static float INTERNAL_distanceScale = 1.0f;
+ public static float DistanceScale
+ {
+ get
+ {
+ return INTERNAL_distanceScale;
+ }
+ set
+ {
+ if (value <= 0.0f)
+ {
+ throw new ArgumentOutOfRangeException("value of DistanceScale");
+ }
+ INTERNAL_distanceScale = value;
+ }
+ }
+
+ // FIXME: How does this affect OpenAL? -flibit
+ private static float INTERNAL_dopplerScale = 1.0f;
+ public static float DopplerScale
+ {
+ get
+ {
+ return INTERNAL_dopplerScale;
+ }
+ set
+ {
+ if (value <= 0.0f)
+ {
+ throw new ArgumentOutOfRangeException("value of DopplerScale");
+ }
+ INTERNAL_dopplerScale = value;
+ }
+ }
+
+ // FIXME: How does this affect OpenAL? -flibit
+ private static float INTERNAL_speedOfSound = 343.5f;
+ public static float SpeedOfSound
+ {
+ get
+ {
+ return INTERNAL_speedOfSound;
+ }
+ set
+ {
+ INTERNAL_speedOfSound = value;
+ }
+ }
+
+ #endregion
+
+ #region Internal Variables
+
+ internal List Instances = new List();
+ internal IALBuffer INTERNAL_buffer;
+
+ #endregion
+
+ #region Public Constructors
+
+ public SoundEffect(
+ byte[] buffer,
+ int sampleRate,
+ AudioChannels channels
+ ) {
+ INTERNAL_buffer = AudioDevice.GenBuffer(
+ buffer,
+ (uint) sampleRate,
+ (uint) channels,
+ 0,
+ 0,
+ false,
+ 1
+ );
+ }
+
+ public SoundEffect(
+ byte[] buffer,
+ int offset,
+ int count,
+ int sampleRate,
+ AudioChannels channels,
+ int loopStart,
+ int loopLength
+ ) {
+ byte[] sendBuf;
+ if (offset != 0 || count != buffer.Length)
+ {
+ // I kind of hate this. -flibit
+ sendBuf = new byte[count];
+ Array.Copy(buffer, offset, sendBuf, 0, count);
+ }
+ else
+ {
+ sendBuf = buffer;
+ }
+
+ INTERNAL_buffer = AudioDevice.GenBuffer(
+ sendBuf,
+ (uint) sampleRate,
+ (uint) channels,
+ (uint) loopStart,
+ (uint) (loopStart + loopLength),
+ false,
+ 1
+ );
+ }
+
+ #endregion
+
+ #region Internal Constructors
+
+ internal SoundEffect(Stream s)
+ {
+ INTERNAL_loadAudioStream(s);
+ }
+
+ internal SoundEffect(
+ string name,
+ byte[] buffer,
+ uint sampleRate,
+ uint channels,
+ uint loopStart,
+ uint loopLength,
+ bool isADPCM,
+ uint formatParameter
+ ) {
+ Name = name;
+ INTERNAL_buffer = AudioDevice.GenBuffer(
+ buffer,
+ sampleRate,
+ channels,
+ loopStart,
+ loopStart + loopLength,
+ isADPCM,
+ formatParameter
+ );
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~SoundEffect()
+ {
+ Dispose();
+ }
+
+ #endregion
+
+ #region Public Dispose Method
+
+ public void Dispose()
+ {
+ if (!IsDisposed)
+ {
+ /* FIXME: Is it ironic that we're generating
+ * garbage with ToArray while cleaning up after
+ * the program's leaks?
+ * -flibit
+ */
+ foreach (WeakReference instance in Instances.ToArray())
+ {
+ object target = instance.Target;
+ if (target != null)
+ {
+ (target as IDisposable).Dispose();
+ }
+ }
+ Instances.Clear();
+ if (INTERNAL_buffer != null)
+ {
+ AudioDevice.ALDevice.DeleteBuffer(INTERNAL_buffer);
+ }
+ IsDisposed = true;
+ }
+ }
+
+ #endregion
+
+ #region Additional SoundEffect/SoundEffectInstance Creation Methods
+
+ public SoundEffectInstance CreateInstance()
+ {
+ return new SoundEffectInstance(this);
+ }
+
+ public static SoundEffect FromStream(Stream stream)
+ {
+ return new SoundEffect(stream);
+ }
+
+ #endregion
+
+ #region Public Play Methods
+
+ public bool Play()
+ {
+ // FIXME: Perhaps MasterVolume should be applied to alListener? -flibit
+ return Play(MasterVolume, 0.0f, 0.0f);
+ }
+
+ public bool Play(float volume, float pitch, float pan)
+ {
+ SoundEffectInstance instance = CreateInstance();
+ instance.Volume = volume;
+ instance.Pitch = pitch;
+ instance.Pan = pan;
+ instance.Play();
+ if (instance.State != SoundState.Playing)
+ {
+ // Ran out of AL sources, probably.
+ instance.Dispose();
+ return false;
+ }
+ AudioDevice.InstancePool.Add(instance);
+ return true;
+ }
+
+ #endregion
+
+ #region Private WAV Loading Method
+
+ private void INTERNAL_loadAudioStream(Stream s)
+ {
+ byte[] data;
+ uint sampleRate = 0;
+ uint numChannels = 0;
+ bool isADPCM = false;
+ uint formatParameter = 0;
+
+ using (BinaryReader reader = new BinaryReader(s))
+ {
+ // RIFF Signature
+ string signature = new string(reader.ReadChars(4));
+ if (signature != "RIFF")
+ {
+ throw new NotSupportedException("Specified stream is not a wave file.");
+ }
+
+ reader.ReadUInt32(); // Riff Chunk Size
+
+ string wformat = new string(reader.ReadChars(4));
+ if (wformat != "WAVE")
+ {
+ throw new NotSupportedException("Specified stream is not a wave file.");
+ }
+
+ // WAVE Header
+ string format_signature = new string(reader.ReadChars(4));
+ while (format_signature != "fmt ")
+ {
+ reader.ReadBytes(reader.ReadInt32());
+ format_signature = new string(reader.ReadChars(4));
+ }
+
+ int format_chunk_size = reader.ReadInt32();
+
+ // Header Information
+ uint audio_format = reader.ReadUInt16(); // 2
+ numChannels = reader.ReadUInt16(); // 4
+ sampleRate = reader.ReadUInt32(); // 8
+ reader.ReadUInt32(); // 12, Byte Rate
+ ushort blockAlign = reader.ReadUInt16(); // 14, Block Align
+ ushort bitDepth = reader.ReadUInt16(); // 16, Bits Per Sample
+
+ if (audio_format == 1)
+ {
+ System.Diagnostics.Debug.Assert(bitDepth == 8 || bitDepth == 16);
+ formatParameter = (uint) (bitDepth / 16); // 1 for 16, 0 for 8
+ }
+ else if (audio_format != 2)
+ {
+ isADPCM = true;
+ formatParameter = (((blockAlign / numChannels) - 6) * 2);
+ }
+ else
+ {
+ throw new NotSupportedException("Wave format is not supported.");
+ }
+
+ // Reads residual bytes
+ if (format_chunk_size > 16)
+ {
+ reader.ReadBytes(format_chunk_size - 16);
+ }
+
+ // data Signature
+ string data_signature = new string(reader.ReadChars(4));
+ while (data_signature.ToLowerInvariant() != "data")
+ {
+ reader.ReadBytes(reader.ReadInt32());
+ data_signature = new string(reader.ReadChars(4));
+ }
+ if (data_signature != "data")
+ {
+ throw new NotSupportedException("Specified wave file is not supported.");
+ }
+
+ int waveDataLength = reader.ReadInt32();
+ data = reader.ReadBytes(waveDataLength);
+ }
+
+ INTERNAL_buffer = AudioDevice.GenBuffer(
+ data,
+ sampleRate,
+ numChannels,
+ 0,
+ 0,
+ isADPCM,
+ formatParameter
+ );
+ }
+
+ #endregion
+
+ #region Public Static Methods
+
+ public static TimeSpan GetSampleDuration(
+ int sizeInBytes,
+ int sampleRate,
+ AudioChannels channels
+ ) {
+ sizeInBytes /= 2; // 16-bit PCM!
+ int ms = (int) (
+ (sizeInBytes / (int) channels) /
+ (sampleRate / 1000.0f)
+ );
+ return new TimeSpan(0, 0, 0, 0, ms);
+ }
+
+ public static int GetSampleSizeInBytes(
+ TimeSpan duration,
+ int sampleRate,
+ AudioChannels channels
+ ) {
+ return (int) (
+ duration.TotalSeconds *
+ sampleRate *
+ (int) channels *
+ 2 // 16-bit PCM!
+ );
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/SoundEffectInstance.cs b/src/Audio/SoundEffectInstance.cs
new file mode 100644
index 0000000..9dfb26a
--- /dev/null
+++ b/src/Audio/SoundEffectInstance.cs
@@ -0,0 +1,388 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.soundeffectinstance.aspx
+ public class SoundEffectInstance : IDisposable
+ {
+ #region Public Properties
+
+ public bool IsDisposed
+ {
+ get;
+ protected set;
+ }
+
+ private bool INTERNAL_looped = false;
+ public virtual bool IsLooped
+ {
+ get
+ {
+ return INTERNAL_looped;
+ }
+ set
+ {
+ INTERNAL_looped = value;
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.SetSourceLooped(
+ INTERNAL_alSource,
+ value
+ );
+ }
+ }
+ }
+
+ private float INTERNAL_pan = 0.0f;
+ public float Pan
+ {
+ get
+ {
+ return INTERNAL_pan;
+ }
+ set
+ {
+ INTERNAL_pan = value;
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.SetSourcePan(
+ INTERNAL_alSource,
+ value
+ );
+ }
+ }
+ }
+
+ private float INTERNAL_pitch = 0f;
+ public float Pitch
+ {
+ get
+ {
+ return INTERNAL_pitch;
+ }
+ set
+ {
+ INTERNAL_pitch = value;
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.SetSourcePitch(
+ INTERNAL_alSource,
+ value,
+ !INTERNAL_isXACTSource
+ );
+ }
+ }
+ }
+
+ public SoundState State
+ {
+ get
+ {
+ if (INTERNAL_alSource == null)
+ {
+ return SoundState.Stopped;
+ }
+ SoundState result = AudioDevice.ALDevice.GetSourceState(
+ INTERNAL_alSource
+ );
+ if (result == SoundState.Stopped && isDynamic)
+ {
+ // Force playing at all times for DSFI!
+ return SoundState.Playing;
+ }
+ return result;
+ }
+ }
+
+ private float INTERNAL_volume = 1.0f;
+ public float Volume
+ {
+ get
+ {
+ return INTERNAL_volume;
+ }
+ set
+ {
+ INTERNAL_volume = value;
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.SetSourceVolume(
+ INTERNAL_alSource,
+ value
+ );
+ }
+ }
+ }
+
+ #endregion
+
+ #region Internal Variables: XACT Filters
+
+ internal byte FilterType;
+
+ #endregion
+
+ #region Private Variables: XNA Implementation
+
+ private SoundEffect INTERNAL_parentEffect;
+ private WeakReference selfReference;
+
+ internal bool isDynamic;
+
+ /* FNA' XACT runtime wraps around SoundEffect for audio output.
+ * Only problem: XACT pitch has no boundaries, SoundEffect does.
+ * So, we're going to use this to tell the pitch clamp to STFU.
+ * -flibit
+ */
+ internal bool INTERNAL_isXACTSource = false;
+
+ #endregion
+
+ #region Private Variables: AL Source, EffectSlot
+
+ internal IALSource INTERNAL_alSource;
+ private IALReverb INTERNAL_alReverb;
+
+ #endregion
+
+ #region Private Variables: 3D Audio
+
+ protected Vector3 position = new Vector3(0.0f, 0.0f, 0.1f);
+
+ // Used to prevent outdated positional audio data from being used
+ protected bool INTERNAL_positionalAudio = false;
+
+ #endregion
+
+ #region Internal Constructor
+
+ internal SoundEffectInstance(SoundEffect parent)
+ {
+ INTERNAL_parentEffect = parent;
+ if (INTERNAL_parentEffect != null)
+ {
+ selfReference = new WeakReference(this);
+ INTERNAL_parentEffect.Instances.Add(selfReference);
+ }
+ isDynamic = false;
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~SoundEffectInstance()
+ {
+ Dispose();
+ }
+
+ #endregion
+
+ #region Public Dispose Method
+
+ public virtual void Dispose()
+ {
+ if (!IsDisposed)
+ {
+ Stop(true);
+ if (INTERNAL_parentEffect != null)
+ {
+ INTERNAL_parentEffect.Instances.Remove(selfReference);
+ selfReference = null;
+ }
+ IsDisposed = true;
+ }
+ }
+
+ #endregion
+
+ #region Public 3D Audio Methods
+
+ public void Apply3D(AudioListener listener, AudioEmitter emitter)
+ {
+ if (INTERNAL_alSource == null)
+ {
+ return;
+ }
+
+ // Set up orientation matrix
+ Matrix orientation = Matrix.CreateWorld(Vector3.Zero, listener.Forward, listener.Up);
+
+ // Set up our final position according to orientation of listener
+ position = Vector3.Transform(emitter.Position - listener.Position, orientation);
+ if (position != Vector3.Zero)
+ {
+ position.Normalize();
+ }
+
+ // Set the position based on relative positon
+ AudioDevice.ALDevice.SetSourcePosition(
+ INTERNAL_alSource,
+ position
+ );
+
+ // We positional now
+ INTERNAL_positionalAudio = true;
+ }
+
+ public void Apply3D(AudioListener[] listeners, AudioEmitter emitter)
+ {
+ throw new NotSupportedException("OpenAL can only make use of one listener.");
+ }
+
+ #endregion
+
+ #region Public Playback Methods
+
+ public virtual void Play()
+ {
+ if (State != SoundState.Stopped)
+ {
+ return;
+ }
+
+ if (INTERNAL_alSource != null)
+ {
+ // The sound has stopped, but hasn't cleaned up yet...
+ AudioDevice.ALDevice.StopAndDisposeSource(INTERNAL_alSource);
+ INTERNAL_alSource = null;
+ }
+
+ INTERNAL_alSource = AudioDevice.ALDevice.GenSource(
+ INTERNAL_parentEffect.INTERNAL_buffer
+ );
+ if (INTERNAL_alSource == null)
+ {
+ System.Console.WriteLine("WARNING: AL SOURCE WAS NOT AVAILABLE. SKIPPING.");
+ return;
+ }
+
+ // Apply Pan/Position
+ if (INTERNAL_positionalAudio)
+ {
+ INTERNAL_positionalAudio = false;
+ AudioDevice.ALDevice.SetSourcePosition(
+ INTERNAL_alSource,
+ position
+ );
+ }
+ else
+ {
+ Pan = Pan;
+ }
+
+ // Reassign Properties, in case the AL properties need to be applied.
+ Volume = Volume;
+ IsLooped = IsLooped;
+ Pitch = Pitch;
+
+ // Apply EFX
+ if (INTERNAL_alReverb != null)
+ {
+ AudioDevice.ALDevice.SetSourceReverb(
+ INTERNAL_alSource,
+ INTERNAL_alReverb
+ );
+ }
+
+ AudioDevice.ALDevice.PlaySource(INTERNAL_alSource);
+ }
+
+ public void Pause()
+ {
+ if (INTERNAL_alSource != null && State == SoundState.Playing)
+ {
+ AudioDevice.ALDevice.PauseSource(INTERNAL_alSource);
+ }
+ }
+
+ public void Resume()
+ {
+ if (INTERNAL_alSource == null)
+ {
+ // XNA4 just plays if we've not started yet.
+ Play();
+ }
+ else if (State == SoundState.Paused)
+ {
+ AudioDevice.ALDevice.ResumeSource(INTERNAL_alSource);
+ }
+ }
+
+ public void Stop()
+ {
+ if (INTERNAL_alSource != null)
+ {
+ // TODO: GraphicsResource-like reference management -flibit
+ if (AudioDevice.ALDevice != null)
+ {
+ AudioDevice.ALDevice.StopAndDisposeSource(INTERNAL_alSource);
+ DynamicSoundEffectInstance dsfi = this as DynamicSoundEffectInstance;
+ if (dsfi != null && AudioDevice.DynamicInstancePool.Contains(dsfi))
+ {
+ AudioDevice.DynamicInstancePool.Remove(dsfi);
+ }
+ }
+ INTERNAL_alSource = null;
+ }
+ }
+
+ public void Stop(bool immediate)
+ {
+ Stop();
+ }
+
+ #endregion
+
+ #region Internal Effects Methods
+
+ internal void INTERNAL_applyReverb(IALReverb reverb)
+ {
+ INTERNAL_alReverb = reverb;
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.SetSourceReverb(
+ INTERNAL_alSource,
+ INTERNAL_alReverb
+ );
+ }
+ }
+
+ internal void INTERNAL_applyLowPassFilter(float hfGain)
+ {
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.SetSourceLowPassFilter(INTERNAL_alSource, hfGain);
+ }
+ }
+
+ internal void INTERNAL_applyHighPassFilter(float lfGain)
+ {
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.SetSourceHighPassFilter(INTERNAL_alSource, lfGain);
+ }
+ }
+
+ internal void INTERNAL_applyBandPassFilter(float hfGain, float lfGain)
+ {
+ if (INTERNAL_alSource != null)
+ {
+ AudioDevice.ALDevice.SetSourceBandPassFilter(INTERNAL_alSource, hfGain, lfGain);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/SoundState.cs b/src/Audio/SoundState.cs
new file mode 100644
index 0000000..e9ba1e1
--- /dev/null
+++ b/src/Audio/SoundState.cs
@@ -0,0 +1,19 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.soundstate.aspx
+ public enum SoundState
+ {
+ Playing,
+ Paused,
+ Stopped
+ }
+}
diff --git a/src/Audio/WaveBank.cs b/src/Audio/WaveBank.cs
new file mode 100644
index 0000000..e3d3079
--- /dev/null
+++ b/src/Audio/WaveBank.cs
@@ -0,0 +1,529 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+
+/* The unxwb project, written by Luigi Auriemma, was released in 2006 under the
+ * GNU General Public License, version 2.0:
+ *
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * While the unxwb project was released under the GPL, Luigi has given express
+ * permission to the MonoGame project to use code from unxwb under the MonoGame
+ * project license. See LICENSE for details.
+ *
+ * The unxwb website can be found here:
+ *
+ * http://aluigi.altervista.org/papers.htm#xbox
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.IO;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.wavebank.aspx
+ public class WaveBank : IDisposable
+ {
+ #region Private Sound Entry Container Class
+
+ // Used to store sound entry data, mainly for streaming WaveBanks
+ private class SoundStreamEntry
+ {
+ public uint PlayOffset
+ {
+ get;
+ private set;
+ }
+
+ public uint PlayLength
+ {
+ get;
+ private set;
+ }
+
+ public uint Codec
+ {
+ get;
+ private set;
+ }
+
+ public uint Frequency
+ {
+ get;
+ private set;
+ }
+
+ public uint Channels
+ {
+ get;
+ private set;
+ }
+
+ public uint LoopOffset
+ {
+ get;
+ private set;
+ }
+
+ public uint LoopLength
+ {
+ get;
+ private set;
+ }
+
+ public uint Alignment
+ {
+ get;
+ private set;
+ }
+
+ public uint BitDepth
+ {
+ get;
+ private set;
+ }
+
+ public SoundStreamEntry(
+ uint playOffset,
+ uint playLength,
+ uint codec,
+ uint frequency,
+ uint channels,
+ uint loopOffset,
+ uint loopLength,
+ uint alignment,
+ uint bitDepth
+ ) {
+ PlayOffset = playOffset;
+ PlayLength = playLength;
+ Codec = codec;
+ Frequency = frequency;
+ Channels = channels;
+ LoopOffset = loopOffset;
+ LoopLength = loopLength;
+ Alignment = alignment;
+ BitDepth = bitDepth;
+ }
+ }
+
+ #endregion
+
+ #region Public Properties
+
+ public bool IsDisposed
+ {
+ get;
+ private set;
+ }
+
+ public bool IsPrepared
+ {
+ get;
+ private set;
+ }
+
+ public bool IsInUse
+ {
+ get
+ {
+ throw new NotImplementedException("Cue wave entry dependency tracking!");
+ }
+ }
+
+ #endregion
+
+ #region Private Variables
+
+ // We keep this in order to Dispose ourselves later.
+ private AudioEngine INTERNAL_baseEngine;
+ private string INTERNAL_name;
+
+ // These are only used for streaming WaveBanks
+ private BinaryReader INTERNAL_waveBankReader;
+ private SoundStreamEntry[] INTERNAL_soundStreamEntries;
+
+ // Stores the actual wavedata
+ private SoundEffect[] INTERNAL_sounds;
+
+ #endregion
+
+ #region Disposing Event
+
+ public event EventHandler Disposing;
+
+ #endregion
+
+ #region Public Constructors
+
+ public WaveBank(
+ AudioEngine audioEngine,
+ string nonStreamingWaveBankFilename
+ ) {
+ if (audioEngine == null)
+ {
+ throw new ArgumentNullException("audioEngine");
+ }
+ if (String.IsNullOrEmpty(nonStreamingWaveBankFilename))
+ {
+ throw new ArgumentNullException("nonStreamingWaveBankFilename");
+ }
+
+ using (Stream stream = TitleContainer.OpenStream(nonStreamingWaveBankFilename))
+ using (BinaryReader reader = new BinaryReader(stream))
+ {
+ LoadWaveBank(audioEngine, reader, false);
+ }
+ }
+
+ public WaveBank(
+ AudioEngine audioEngine,
+ string streamingWaveBankFilename,
+ int offset,
+ short packetsize
+ ) {
+ /* Note that offset and packetsize go unused,
+ * because we're frauds and aren't actually streaming.
+ * -flibit
+ */
+
+ if (audioEngine == null)
+ {
+ throw new ArgumentNullException("audioEngine");
+ }
+ if (String.IsNullOrEmpty(streamingWaveBankFilename))
+ {
+ throw new ArgumentNullException("streamingWaveBankFilename");
+ }
+
+ INTERNAL_waveBankReader = new BinaryReader(
+ TitleContainer.OpenStream(streamingWaveBankFilename)
+ );
+ LoadWaveBank(audioEngine, INTERNAL_waveBankReader, true);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~WaveBank()
+ {
+ Dispose(true);
+ }
+
+ #endregion
+
+ #region Public Dispose Method
+
+ public void Dispose()
+ {
+ Dispose(false);
+ }
+
+ #endregion
+
+ #region Protected Dispose Method
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!IsDisposed)
+ {
+ if (Disposing != null)
+ {
+ Disposing.Invoke(this, null);
+ }
+ foreach (SoundEffect se in INTERNAL_sounds)
+ {
+ if (se != null)
+ {
+ se.Dispose();
+ }
+ }
+ INTERNAL_baseEngine.INTERNAL_removeWaveBank(INTERNAL_name);
+ INTERNAL_sounds = null;
+ if (INTERNAL_waveBankReader != null)
+ {
+ INTERNAL_waveBankReader.Close();
+ INTERNAL_waveBankReader = null;
+ }
+ IsDisposed = true;
+ IsPrepared = false;
+ }
+ }
+
+ #endregion
+
+ #region Internal Method
+
+ internal SoundEffect INTERNAL_getTrack(ushort track)
+ {
+ if (INTERNAL_sounds[track] == null)
+ {
+ LoadWaveEntry(
+ INTERNAL_soundStreamEntries[track],
+ track,
+ INTERNAL_waveBankReader
+ );
+ }
+ return INTERNAL_sounds[track];
+ }
+
+ #endregion
+
+ #region Private WaveBank Load Method
+
+ private void LoadWaveBank(AudioEngine audioEngine, BinaryReader reader, bool streaming)
+ {
+ /* Until we finish the LoadWaveBank process, this WaveBank is NOT
+ * ready to run. For us this doesn't really matter, but the game
+ * could be loading WaveBanks asynchronously, so let's be careful.
+ * -flibit
+ */
+ IsPrepared = false;
+
+ INTERNAL_baseEngine = audioEngine;
+
+ // Check the file header. Should be 'WBND'
+ if (reader.ReadUInt32() != 0x444E4257)
+ {
+ throw new ArgumentException("WBND format not recognized!");
+ }
+
+ // Check the content version. Assuming XNA4 Refresh.
+ if (reader.ReadUInt32() != AudioEngine.ContentVersion)
+ {
+ throw new ArgumentException("WBND Content version!");
+ }
+
+ // Check the tool version. Assuming XNA4 Refresh.
+ if (reader.ReadUInt32() != 44)
+ {
+ throw new ArgumentException("WBND Tool version!");
+ }
+
+ // Obtain WaveBank chunk offsets/lengths
+ uint[] offsets = new uint[5];
+ uint[] lengths = new uint[5];
+ for (int i = 0; i < 5; i += 1)
+ {
+ offsets[i] = reader.ReadUInt32();
+ lengths[i] = reader.ReadUInt32();
+ }
+
+ // Seek to the first offset, obtain WaveBank info
+ reader.BaseStream.Seek(offsets[0], SeekOrigin.Begin);
+
+ // IsStreaming bool, unused
+ reader.ReadUInt16();
+
+ // WaveBank Flags
+ ushort wavebankFlags = reader.ReadUInt16();
+ // bool containsEntryNames = (wavebankFlags & 0x0001) != 0;
+ bool compact = (wavebankFlags & 0x0002) != 0;
+ // bool syncDisabled = (wavebankFlags & 0x0004) != 0;
+ // bool containsSeekTables = (wavebankFlags & 0x0008) != 0;
+
+ // WaveBank Entry Count
+ uint numEntries = reader.ReadUInt32();
+
+ // WaveBank Name
+ INTERNAL_name = System.Text.Encoding.UTF8.GetString(
+ reader.ReadBytes(64), 0, 64
+ ).Replace("\0", "");
+
+ // WaveBank entry information
+ uint metadataElementSize = reader.ReadUInt32();
+ reader.ReadUInt32(); // nameElementSize
+ uint alignment = reader.ReadUInt32();
+
+ // Determine the generic play region offset
+ uint playRegionOffset = offsets[4];
+ if (playRegionOffset == 0)
+ {
+ playRegionOffset = offsets[1] + (numEntries * metadataElementSize);
+ }
+
+ // Entry format. Read early for Compact data
+ uint entryFormat = 0;
+ if (compact)
+ {
+ entryFormat = reader.ReadUInt32();
+ }
+
+ // Read in the wavedata
+ INTERNAL_sounds = new SoundEffect[numEntries];
+ if (streaming)
+ {
+ INTERNAL_soundStreamEntries = new SoundStreamEntry[numEntries];
+ }
+ uint curOffset = offsets[1];
+ for (int curEntry = 0; curEntry < numEntries; curEntry += 1)
+ {
+ // Seek to the current entry
+ reader.BaseStream.Seek(curOffset, SeekOrigin.Begin);
+
+ // Entry Information
+ uint entryPlayOffset = 0;
+ uint entryPlayLength = 0;
+ uint entryLoopOffset = 0;
+ uint entryLoopLength = 0;
+
+ // Obtain Entry Information
+ if (compact)
+ {
+ uint entryLength = reader.ReadUInt32();
+
+ entryPlayOffset =
+ (entryLength & ((1 << 21) - 1)) *
+ alignment;
+ entryPlayLength =
+ (entryLength >> 21) & ((1 << 11) - 1);
+
+ // FIXME: Deviation Length
+ reader.BaseStream.Seek(
+ curOffset + metadataElementSize,
+ SeekOrigin.Begin
+ );
+
+ if (curEntry == (numEntries - 1))
+ {
+ // Last track, last length.
+ entryLength = lengths[4];
+ }
+ else
+ {
+ entryLength = (
+ (
+ reader.ReadUInt32() &
+ ((1 << 21) - 1)
+ ) * alignment
+ );
+ }
+ entryPlayLength = entryLength - entryPlayOffset;
+ }
+ else
+ {
+ if (metadataElementSize >= 4)
+ reader.ReadUInt32(); // Flags/Duration, unused
+ if (metadataElementSize >= 8)
+ entryFormat = reader.ReadUInt32();
+ if (metadataElementSize >= 12)
+ entryPlayOffset = reader.ReadUInt32();
+ if (metadataElementSize >= 16)
+ entryPlayLength = reader.ReadUInt32();
+ if (metadataElementSize >= 20)
+ entryLoopOffset = reader.ReadUInt32();
+ if (metadataElementSize >= 24)
+ entryLoopLength = reader.ReadUInt32();
+ else
+ {
+ // FIXME: This is a bit hacky.
+ if (entryPlayLength != 0)
+ {
+ entryPlayLength = lengths[4];
+ }
+ }
+ }
+
+ // Update seek offsets
+ curOffset += metadataElementSize;
+ entryPlayOffset += playRegionOffset;
+
+ // Parse Format for Wavedata information
+ uint entryCodec = (entryFormat >> 0) & ((1 << 2) - 1);
+ uint entryChannels = (entryFormat >> 2) & ((1 << 3) - 1);
+ uint entryFrequency = (entryFormat >> (2 + 3)) & ((1 << 18) - 1);
+ uint entryAlignment = (entryFormat >> (2 + 3 + 18)) & ((1 << 8) - 1);
+ uint entryBitDepth = (entryFormat >> (2 + 3 + 18 + 8));
+
+ if (streaming)
+ {
+ INTERNAL_soundStreamEntries[curEntry] = new SoundStreamEntry(
+ entryPlayOffset,
+ entryPlayLength,
+ entryCodec,
+ entryFrequency,
+ entryChannels,
+ entryLoopOffset,
+ entryLoopLength,
+ entryAlignment,
+ entryBitDepth
+ );
+ }
+ else
+ {
+ SoundStreamEntry filler = new SoundStreamEntry(
+ entryPlayOffset,
+ entryPlayLength,
+ entryCodec,
+ entryFrequency,
+ entryChannels,
+ entryLoopOffset,
+ entryLoopLength,
+ entryAlignment,
+ entryBitDepth
+ );
+ LoadWaveEntry(filler, (ushort) curEntry, reader);
+ }
+ }
+
+ // Add this WaveBank to the AudioEngine Dictionary
+ audioEngine.INTERNAL_addWaveBank(INTERNAL_name, this);
+
+ // Finally.
+ IsDisposed = false;
+ IsPrepared = true;
+ }
+
+ #endregion
+
+ #region Private WaveBank Entry Load Method
+
+ private void LoadWaveEntry(SoundStreamEntry entry, ushort track, BinaryReader reader)
+ {
+ // Read Wavedata
+ reader.BaseStream.Seek(entry.PlayOffset, SeekOrigin.Begin);
+ byte[] entryData = reader.ReadBytes((int) entry.PlayLength);
+
+ // Load SoundEffect based on codec
+ if (entry.Codec == 0x0) // PCM
+ {
+ INTERNAL_sounds[track] = new SoundEffect(
+ "WaveBank Sound",
+ entryData,
+ entry.Frequency,
+ entry.Channels,
+ entry.LoopOffset,
+ entry.LoopLength,
+ false,
+ entry.BitDepth
+ );
+ }
+ else if (entry.Codec == 0x2) // ADPCM
+ {
+ INTERNAL_sounds[track] = new SoundEffect(
+ "WaveBank Sound",
+ entryData,
+ entry.Frequency,
+ entry.Channels,
+ entry.LoopOffset,
+ entry.LoopLength,
+ true,
+ (entry.Alignment + 16) * 2
+ );
+ }
+ else // Includes 0x1 - XMA, 0x3 - WMA
+ {
+ throw new NotSupportedException("Rebuild your WaveBanks with ADPCM!");
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Audio/XACTInternal.cs b/src/Audio/XACTInternal.cs
new file mode 100644
index 0000000..4677ef3
--- /dev/null
+++ b/src/Audio/XACTInternal.cs
@@ -0,0 +1,466 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+#endregion
+
+namespace Microsoft.Xna.Framework.Audio
+{
+ internal static class XACTCalculator
+ {
+ public static double ParseDecibel(byte binaryValue)
+ {
+ /* FIXME: This calculation probably came from someone's TI-83.
+ * I plotted out Codename Naddachance's bytes out, and
+ * the closest formula I could come up with (hastily)
+ * was this:
+ * dBValue = 37.5 * Math.Log10(binaryValue * 2.0) - 96.0
+ * But of course, volumes are still wrong. So I dunno.
+ * -flibit
+ */
+ return (
+ (-96.0 - 67.7385212334047) /
+ (1 + Math.Pow(
+ binaryValue / 80.1748600297963,
+ 0.432254984608615
+ ))
+ ) + 67.7385212334047;
+ }
+
+ public static float CalculateAmplitudeRatio(double decibel)
+ {
+ return (float) Math.Pow(10, decibel / 20.0);
+ }
+
+ public static float CalculateVolume(byte binaryValue)
+ {
+ return CalculateAmplitudeRatio(ParseDecibel(binaryValue));
+ }
+ }
+
+ internal enum MaxInstanceBehavior : byte
+ {
+ Fail,
+ Queue,
+ ReplaceOldest,
+ ReplaceQuietest,
+ ReplaceLowestPriority
+ }
+
+ internal enum CrossfadeType : byte
+ {
+ Linear,
+ Logarithmic,
+ EqualPower
+ }
+
+ internal class Variable
+ {
+ public string Name
+ {
+ get;
+ private set;
+ }
+
+ // Variable Accessibility
+ public bool IsPublic
+ {
+ get;
+ private set;
+ }
+
+ public bool IsReadOnly
+ {
+ get;
+ private set;
+ }
+
+ public bool IsGlobal
+ {
+ get;
+ private set;
+ }
+
+ public bool IsReserved
+ {
+ get;
+ private set;
+ }
+
+ // Variable Value, Boundaries
+ private float value;
+ private float minValue;
+ private float maxValue;
+
+ public Variable(
+ string name,
+ bool varIsPublic,
+ bool varIsReadOnly,
+ bool varIsGlobal,
+ bool varIsReserved,
+ float varInitialValue,
+ float varMinValue,
+ float varMaxValue
+ ) {
+ Name = name;
+ IsPublic = varIsPublic;
+ IsReadOnly = varIsReadOnly;
+ IsGlobal = varIsGlobal;
+ IsReserved = varIsReserved;
+ value = varInitialValue;
+ minValue = varMinValue;
+ maxValue = varMaxValue;
+ }
+
+ public void SetValue(float newValue)
+ {
+ if (newValue < minValue)
+ {
+ value = minValue;
+ }
+ else if (newValue > maxValue)
+ {
+ value = maxValue;
+ }
+ else
+ {
+ value = newValue;
+ }
+ }
+
+ public float GetValue()
+ {
+ return value;
+ }
+
+ public Variable Clone()
+ {
+ return new Variable(
+ Name,
+ IsPublic,
+ IsReadOnly,
+ IsGlobal,
+ IsReserved,
+ value,
+ minValue,
+ maxValue
+ );
+ }
+ }
+
+ internal enum RPCPointType : byte
+ {
+ Linear,
+ Fast,
+ Slow,
+ SinCos
+ }
+
+ internal enum RPCParameter : ushort
+ {
+ Volume,
+ Pitch,
+ ReverbSend,
+ FilterFrequency,
+ FilterQFactor,
+ NUM_PARAMETERS // If >=, DSP Parameter!
+ }
+
+ internal class RPCPoint
+ {
+ public float X
+ {
+ get;
+ private set;
+ }
+
+ public float Y
+ {
+ get;
+ private set;
+ }
+
+ public RPCPointType Type
+ {
+ get;
+ private set;
+ }
+
+ public RPCPoint(float x, float y, RPCPointType type)
+ {
+ X = x;
+ Y = y;
+ Type = type;
+ }
+ }
+
+ internal class RPC
+ {
+ // Parent Variable
+ public string Variable
+ {
+ get;
+ private set;
+ }
+
+ // RPC Parameter
+ public RPCParameter Parameter
+ {
+ get;
+ private set;
+ }
+
+ // RPC Curve Points
+ private RPCPoint[] Points;
+
+ public RPC(
+ string rpcVariable,
+ ushort rpcParameter,
+ RPCPoint[] rpcPoints
+ ) {
+ Variable = rpcVariable;
+ Parameter = (RPCParameter) rpcParameter;
+ Points = rpcPoints;
+ }
+
+ public float CalculateRPC(float varInput)
+ {
+ // TODO: Non-linear curves
+ if (varInput == 0.0f)
+ {
+ if (Points[0].X == 0.0f)
+ {
+ // Some curves may start X->0 elsewhere.
+ return Points[0].Y;
+ }
+ return 0.0f;
+ }
+ else if (varInput <= Points[0].X)
+ {
+ // Zero to first defined point
+ return Points[0].Y / (varInput / Points[0].X);
+ }
+ else if (varInput >= Points[Points.Length - 1].X)
+ {
+ // Last defined point to infinity
+ return Points[Points.Length - 1].Y / (Points[Points.Length - 1].X / varInput);
+ }
+ else
+ {
+ // Something between points...
+ float result = 0.0f;
+ for (int i = 0; i < Points.Length - 1; i += 1)
+ {
+ // y = b
+ result = Points[i].Y;
+ if (varInput >= Points[i].X && varInput <= Points[i + 1].X)
+ {
+ // y += mx
+ result +=
+ ((Points[i + 1].Y - Points[i].Y) /
+ (Points[i + 1].X - Points[i].X)) *
+ (varInput - Points[i].X);
+ // Pre-algebra, rockin`!
+ break;
+ }
+ }
+ return result;
+ }
+ }
+ }
+
+ internal class DSPParameter
+ {
+ public byte Type
+ {
+ get;
+ private set;
+ }
+
+ public float Minimum
+ {
+ get;
+ private set;
+ }
+
+ public float Maximum
+ {
+ get;
+ private set;
+ }
+
+ private float INTERNAL_value;
+ public float Value
+ {
+ get
+ {
+ return INTERNAL_value;
+ }
+ set
+ {
+ if (value < Minimum)
+ {
+ INTERNAL_value = Minimum;
+ }
+ else if (value > Maximum)
+ {
+ INTERNAL_value = Maximum;
+ }
+ else
+ {
+ INTERNAL_value = value;
+ }
+ }
+ }
+ public DSPParameter(byte type, float val, float min, float max)
+ {
+ Type = type;
+ Minimum = min;
+ Maximum = max;
+ INTERNAL_value = val;
+ }
+ }
+
+ internal class DSPPreset
+ {
+ public IALReverb Effect
+ {
+ get;
+ private set;
+ }
+
+ public bool IsGlobal
+ {
+ get;
+ private set;
+ }
+
+ public DSPParameter[] Parameters
+ {
+ get;
+ private set;
+ }
+
+ public DSPPreset(
+ bool global,
+ DSPParameter[] parameters
+ ) {
+ IsGlobal = global;
+ Parameters = parameters;
+
+ // FIXME: Did XACT ever go past Reverb? -flibit
+ Effect = AudioDevice.GenReverb(Parameters);
+ }
+
+ public void Dispose()
+ {
+ AudioDevice.ALDevice.DeleteReverb(Effect);
+ }
+
+ public void SetParameter(int index, float value)
+ {
+ Parameters[index].Value = value;
+
+ // Apply the value to the effect
+ if (index == 0)
+ {
+ AudioDevice.ALDevice.SetReverbReflectionsDelay(Effect, Parameters[index].Value);
+ }
+ else if (index == 1)
+ {
+ AudioDevice.ALDevice.SetReverbDelay(Effect, Parameters[index].Value);
+ }
+ else if (index == 2)
+ {
+ AudioDevice.ALDevice.SetReverbPositionLeft(Effect, Parameters[index].Value);
+ }
+ else if (index == 3)
+ {
+ AudioDevice.ALDevice.SetReverbPositionRight(Effect, Parameters[index].Value);
+ }
+ else if (index == 4)
+ {
+ AudioDevice.ALDevice.SetReverbPositionLeftMatrix(Effect, Parameters[index].Value);
+ }
+ else if (index == 5)
+ {
+ AudioDevice.ALDevice.SetReverbPositionRightMatrix(Effect, Parameters[index].Value);
+ }
+ else if (index == 6)
+ {
+ AudioDevice.ALDevice.SetReverbEarlyDiffusion(Effect, Parameters[index].Value);
+ }
+ else if (index == 7)
+ {
+ AudioDevice.ALDevice.SetReverbLateDiffusion(Effect, Parameters[index].Value);
+ }
+ else if (index == 8)
+ {
+ AudioDevice.ALDevice.SetReverbLowEQGain(Effect, Parameters[index].Value);
+ }
+ else if (index == 9)
+ {
+ AudioDevice.ALDevice.SetReverbLowEQCutoff(Effect, Parameters[index].Value);
+ }
+ else if (index == 10)
+ {
+ AudioDevice.ALDevice.SetReverbHighEQGain(Effect, Parameters[index].Value);
+ }
+ else if (index == 11)
+ {
+ AudioDevice.ALDevice.SetReverbHighEQCutoff(Effect, Parameters[index].Value);
+ }
+ else if (index == 12)
+ {
+ AudioDevice.ALDevice.SetReverbRearDelay(Effect, Parameters[index].Value);
+ }
+ else if (index == 13)
+ {
+ AudioDevice.ALDevice.SetReverbRoomFilterFrequency(Effect, Parameters[index].Value);
+ }
+ else if (index == 14)
+ {
+ AudioDevice.ALDevice.SetReverbRoomFilterMain(Effect, Parameters[index].Value);
+ }
+ else if (index == 15)
+ {
+ AudioDevice.ALDevice.SetReverbRoomFilterHighFrequency(Effect, Parameters[index].Value);
+ }
+ else if (index == 16)
+ {
+ AudioDevice.ALDevice.SetReverbReflectionsGain(Effect, Parameters[index].Value);
+ }
+ else if (index == 17)
+ {
+ AudioDevice.ALDevice.SetReverbGain(Effect, Parameters[index].Value);
+ }
+ else if (index == 18)
+ {
+ AudioDevice.ALDevice.SetReverbDecayTime(Effect, Parameters[index].Value);
+ }
+ else if (index == 19)
+ {
+ AudioDevice.ALDevice.SetReverbDensity(Effect, Parameters[index].Value);
+ }
+ else if (index == 20)
+ {
+ AudioDevice.ALDevice.SetReverbRoomSize(Effect, Parameters[index].Value);
+ }
+ else if (index == 21)
+ {
+ AudioDevice.ALDevice.SetReverbWetDryMix(Effect, Parameters[index].Value);
+ }
+ else
+ {
+ throw new Exception("DSP parameter unhandled: " + index.ToString());
+ }
+ }
+ }
+}
diff --git a/src/BoundingBox.cs b/src/BoundingBox.cs
new file mode 100644
index 0000000..2e8aa82
--- /dev/null
+++ b/src/BoundingBox.cs
@@ -0,0 +1,624 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+
+/* Derived from code by the Mono.Xna Team (Copyright 2006).
+ * Released under the MIT License. See monoxna.LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+
+using Microsoft.Xna.Framework.Design;
+#endregion
+
+namespace Microsoft.Xna.Framework
+{
+ [Serializable]
+ [TypeConverter(typeof(BoundingBoxConverter))]
+ [DebuggerDisplay("{DebugDisplayString,nq}")]
+ public struct BoundingBox : IEquatable
+ {
+ #region Internal Properties
+
+ internal string DebugDisplayString
+ {
+ get
+ {
+ return string.Concat(
+ "Min( ", Min.DebugDisplayString, " ) \r\n",
+ "Max( ", Max.DebugDisplayString, " )"
+ );
+ }
+ }
+
+ #endregion
+
+ #region Public Fields
+
+ public Vector3 Min;
+
+ public Vector3 Max;
+
+ public const int CornerCount = 8;
+
+ #endregion
+
+ #region Private Static Variables
+
+ private static readonly Vector3 MaxVector3 = new Vector3(float.MaxValue);
+ private static readonly Vector3 MinVector3 = new Vector3(float.MinValue);
+
+ #endregion
+
+ #region Public Constructors
+
+ public BoundingBox(Vector3 min, Vector3 max)
+ {
+ this.Min = min;
+ this.Max = max;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public void Contains(ref BoundingBox box, out ContainmentType result)
+ {
+ result = Contains(box);
+ }
+
+ public void Contains(ref BoundingSphere sphere, out ContainmentType result)
+ {
+ result = this.Contains(sphere);
+ }
+
+ public ContainmentType Contains(Vector3 point)
+ {
+ ContainmentType result;
+ this.Contains(ref point, out result);
+ return result;
+ }
+
+ public ContainmentType Contains(BoundingBox box)
+ {
+ // Test if all corner is in the same side of a face by just checking min and max
+ if ( box.Max.X < Min.X ||
+ box.Min.X > Max.X ||
+ box.Max.Y < Min.Y ||
+ box.Min.Y > Max.Y ||
+ box.Max.Z < Min.Z ||
+ box.Min.Z > Max.Z )
+ {
+ return ContainmentType.Disjoint;
+ }
+
+
+ if ( box.Min.X >= Min.X &&
+ box.Max.X <= Max.X &&
+ box.Min.Y >= Min.Y &&
+ box.Max.Y <= Max.Y &&
+ box.Min.Z >= Min.Z &&
+ box.Max.Z <= Max.Z )
+ {
+ return ContainmentType.Contains;
+ }
+
+ return ContainmentType.Intersects;
+ }
+
+ public ContainmentType Contains(BoundingFrustum frustum)
+ {
+ /* TODO: bad done here need a fix.
+ * Because the question is not if frustum contains box but the reverse and
+ * this is not the same.
+ */
+ int i;
+ ContainmentType contained;
+ Vector3[] corners = frustum.GetCorners();
+
+ // First we check if frustum is in box.
+ for (i = 0; i < corners.Length; i += 1)
+ {
+ this.Contains(ref corners[i], out contained);
+ if (contained == ContainmentType.Disjoint)
+ {
+ break;
+ }
+ }
+
+ // This means we checked all the corners and they were all contain or instersect
+ if (i == corners.Length)
+ {
+ return ContainmentType.Contains;
+ }
+
+ // If i is not equal to zero, we can fastpath and say that this box intersects
+ if (i != 0)
+ {
+ return ContainmentType.Intersects;
+ }
+
+
+ /* If we get here, it means the first (and only) point we checked was
+ * actually contained in the frustum. So we assume that all other points
+ * will also be contained. If one of the points is disjoint, we can
+ * exit immediately saying that the result is Intersects
+ */
+ i += 1;
+ for (; i < corners.Length; i += 1)
+ {
+ this.Contains(ref corners[i], out contained);
+ if (contained != ContainmentType.Contains)
+ {
+ return ContainmentType.Intersects;
+ }
+
+ }
+
+ /* If we get here, then we know all the points were actually contained,
+ * therefore result is Contains.
+ */
+ return ContainmentType.Contains;
+ }
+
+ public ContainmentType Contains(BoundingSphere sphere)
+ {
+ if ( sphere.Center.X - Min.X >= sphere.Radius &&
+ sphere.Center.Y - Min.Y >= sphere.Radius &&
+ sphere.Center.Z - Min.Z >= sphere.Radius &&
+ Max.X - sphere.Center.X >= sphere.Radius &&
+ Max.Y - sphere.Center.Y >= sphere.Radius &&
+ Max.Z - sphere.Center.Z >= sphere.Radius )
+ {
+ return ContainmentType.Contains;
+ }
+
+ double dmin = 0;
+
+ double e = sphere.Center.X - Min.X;
+ if (e < 0)
+ {
+ if (e < -sphere.Radius)
+ {
+ return ContainmentType.Disjoint;
+ }
+ dmin += e * e;
+ }
+ else
+ {
+ e = sphere.Center.X - Max.X;
+ if (e > 0)
+ {
+ if (e > sphere.Radius)
+ {
+ return ContainmentType.Disjoint;
+ }
+ dmin += e * e;
+ }
+ }
+
+ e = sphere.Center.Y - Min.Y;
+ if (e < 0)
+ {
+ if (e < -sphere.Radius)
+ {
+ return ContainmentType.Disjoint;
+ }
+ dmin += e * e;
+ }
+ else
+ {
+ e = sphere.Center.Y - Max.Y;
+ if (e > 0)
+ {
+ if (e > sphere.Radius)
+ {
+ return ContainmentType.Disjoint;
+ }
+ dmin += e * e;
+ }
+ }
+
+ e = sphere.Center.Z - Min.Z;
+ if (e < 0)
+ {
+ if (e < -sphere.Radius)
+ {
+ return ContainmentType.Disjoint;
+ }
+ dmin += e * e;
+ }
+ else
+ {
+ e = sphere.Center.Z - Max.Z;
+ if (e > 0)
+ {
+ if (e > sphere.Radius)
+ {
+ return ContainmentType.Disjoint;
+ }
+ dmin += e * e;
+ }
+ }
+
+ if (dmin <= sphere.Radius * sphere.Radius)
+ {
+ return ContainmentType.Intersects;
+ }
+
+ return ContainmentType.Disjoint;
+ }
+
+ public void Contains(ref Vector3 point, out ContainmentType result)
+ {
+ // First determine if point is outside of this box.
+ if ( point.X < this.Min.X ||
+ point.X > this.Max.X ||
+ point.Y < this.Min.Y ||
+ point.Y > this.Max.Y ||
+ point.Z < this.Min.Z ||
+ point.Z > this.Max.Z )
+ {
+ result = ContainmentType.Disjoint;
+ }
+ // Or, if the point is on box because coordinate is less than or equal.
+ else if ( MathHelper.WithinEpsilon(point.X, this.Min.X) ||
+ MathHelper.WithinEpsilon(point.X, this.Max.X) ||
+ MathHelper.WithinEpsilon(point.Y, this.Min.Y) ||
+ MathHelper.WithinEpsilon(point.Y, this.Max.Y) ||
+ MathHelper.WithinEpsilon(point.Z, this.Min.Z) ||
+ MathHelper.WithinEpsilon(point.Z, this.Max.Z) )
+ {
+ result = ContainmentType.Intersects;
+ }
+ else
+ {
+ result = ContainmentType.Contains;
+ }
+ }
+
+ public Vector3[] GetCorners()
+ {
+ return new Vector3[] {
+ new Vector3(this.Min.X, this.Max.Y, this.Max.Z),
+ new Vector3(this.Max.X, this.Max.Y, this.Max.Z),
+ new Vector3(this.Max.X, this.Min.Y, this.Max.Z),
+ new Vector3(this.Min.X, this.Min.Y, this.Max.Z),
+ new Vector3(this.Min.X, this.Max.Y, this.Min.Z),
+ new Vector3(this.Max.X, this.Max.Y, this.Min.Z),
+ new Vector3(this.Max.X, this.Min.Y, this.Min.Z),
+ new Vector3(this.Min.X, this.Min.Y, this.Min.Z)
+ };
+ }
+
+ public void GetCorners(Vector3[] corners)
+ {
+ if (corners == null)
+ {
+ throw new ArgumentNullException("corners");
+ }
+ if (corners.Length < 8)
+ {
+ throw new ArgumentOutOfRangeException("corners", "Not Enought Corners");
+ }
+ corners[0].X = this.Min.X;
+ corners[0].Y = this.Max.Y;
+ corners[0].Z = this.Max.Z;
+ corners[1].X = this.Max.X;
+ corners[1].Y = this.Max.Y;
+ corners[1].Z = this.Max.Z;
+ corners[2].X = this.Max.X;
+ corners[2].Y = this.Min.Y;
+ corners[2].Z = this.Max.Z;
+ corners[3].X = this.Min.X;
+ corners[3].Y = this.Min.Y;
+ corners[3].Z = this.Max.Z;
+ corners[4].X = this.Min.X;
+ corners[4].Y = this.Max.Y;
+ corners[4].Z = this.Min.Z;
+ corners[5].X = this.Max.X;
+ corners[5].Y = this.Max.Y;
+ corners[5].Z = this.Min.Z;
+ corners[6].X = this.Max.X;
+ corners[6].Y = this.Min.Y;
+ corners[6].Z = this.Min.Z;
+ corners[7].X = this.Min.X;
+ corners[7].Y = this.Min.Y;
+ corners[7].Z = this.Min.Z;
+ }
+
+ public Nullable Intersects(Ray ray)
+ {
+ return ray.Intersects(this);
+ }
+
+ public void Intersects(ref Ray ray, out Nullable result)
+ {
+ result = Intersects(ray);
+ }
+
+ public bool Intersects(BoundingFrustum frustum)
+ {
+ return frustum.Intersects(this);
+ }
+
+ public void Intersects(ref BoundingSphere sphere, out bool result)
+ {
+ result = Intersects(sphere);
+ }
+
+ public bool Intersects(BoundingBox box)
+ {
+ bool result;
+ Intersects(ref box, out result);
+ return result;
+ }
+
+ public PlaneIntersectionType Intersects(Plane plane)
+ {
+ PlaneIntersectionType result;
+ Intersects(ref plane, out result);
+ return result;
+ }
+
+ public void Intersects(ref BoundingBox box, out bool result)
+ {
+ if ((this.Max.X >= box.Min.X) && (this.Min.X <= box.Max.X))
+ {
+ if ((this.Max.Y < box.Min.Y) || (this.Min.Y > box.Max.Y))
+ {
+ result = false;
+ return;
+ }
+
+ result = (this.Max.Z >= box.Min.Z) && (this.Min.Z <= box.Max.Z);
+ return;
+ }
+
+ result = false;
+ return;
+ }
+
+ public bool Intersects(BoundingSphere sphere)
+ {
+ if ( sphere.Center.X - Min.X > sphere.Radius &&
+ sphere.Center.Y - Min.Y > sphere.Radius &&
+ sphere.Center.Z - Min.Z > sphere.Radius &&
+ Max.X - sphere.Center.X > sphere.Radius &&
+ Max.Y - sphere.Center.Y > sphere.Radius &&
+ Max.Z - sphere.Center.Z > sphere.Radius )
+ {
+ return true;
+ }
+
+ double dmin = 0;
+
+ if (sphere.Center.X - Min.X <= sphere.Radius)
+ {
+ dmin += (sphere.Center.X - Min.X) * (sphere.Center.X - Min.X);
+ }
+ else if (Max.X - sphere.Center.X <= sphere.Radius)
+ {
+ dmin += (sphere.Center.X - Max.X) * (sphere.Center.X - Max.X);
+ }
+
+ if (sphere.Center.Y - Min.Y <= sphere.Radius)
+ {
+ dmin += (sphere.Center.Y - Min.Y) * (sphere.Center.Y - Min.Y);
+ }
+ else if (Max.Y - sphere.Center.Y <= sphere.Radius)
+ {
+ dmin += (sphere.Center.Y - Max.Y) * (sphere.Center.Y - Max.Y);
+ }
+
+ if (sphere.Center.Z - Min.Z <= sphere.Radius)
+ {
+ dmin += (sphere.Center.Z - Min.Z) * (sphere.Center.Z - Min.Z);
+ }
+ else if (Max.Z - sphere.Center.Z <= sphere.Radius)
+ {
+ dmin += (sphere.Center.Z - Max.Z) * (sphere.Center.Z - Max.Z);
+ }
+
+ if (dmin <= sphere.Radius * sphere.Radius)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public void Intersects(ref Plane plane, out PlaneIntersectionType result)
+ {
+ // See http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html
+
+ Vector3 positiveVertex;
+ Vector3 negativeVertex;
+
+ if (plane.Normal.X >= 0)
+ {
+ positiveVertex.X = Max.X;
+ negativeVertex.X = Min.X;
+ }
+ else
+ {
+ positiveVertex.X = Min.X;
+ negativeVertex.X = Max.X;
+ }
+
+ if (plane.Normal.Y >= 0)
+ {
+ positiveVertex.Y = Max.Y;
+ negativeVertex.Y = Min.Y;
+ }
+ else
+ {
+ positiveVertex.Y = Min.Y;
+ negativeVertex.Y = Max.Y;
+ }
+
+ if (plane.Normal.Z >= 0)
+ {
+ positiveVertex.Z = Max.Z;
+ negativeVertex.Z = Min.Z;
+ }
+ else
+ {
+ positiveVertex.Z = Min.Z;
+ negativeVertex.Z = Max.Z;
+ }
+
+ // Inline Vector3.Dot(plane.Normal, negativeVertex) + plane.D;
+ float distance = (
+ plane.Normal.X * negativeVertex.X +
+ plane.Normal.Y * negativeVertex.Y +
+ plane.Normal.Z * negativeVertex.Z +
+ plane.D
+ );
+ if (distance > 0)
+ {
+ result = PlaneIntersectionType.Front;
+ return;
+ }
+
+ // Inline Vector3.Dot(plane.Normal, positiveVertex) + plane.D;
+ distance = (
+ plane.Normal.X * positiveVertex.X +
+ plane.Normal.Y * positiveVertex.Y +
+ plane.Normal.Z * positiveVertex.Z +
+ plane.D
+ );
+ if (distance < 0)
+ {
+ result = PlaneIntersectionType.Back;
+ return;
+ }
+
+ result = PlaneIntersectionType.Intersecting;
+ }
+
+ public bool Equals(BoundingBox other)
+ {
+ return (this.Min == other.Min) && (this.Max == other.Max);
+ }
+
+ #endregion
+
+ #region Public Static Methods
+
+ ///
+ /// Create a bounding box from the given list of points.
+ ///
+ ///
+ /// The list of Vector3 instances defining the point cloud to bound.
+ ///
+ /// A bounding box that encapsulates the given point cloud.
+ ///
+ /// Thrown if the given list has no points.
+ ///
+ public static BoundingBox CreateFromPoints(IEnumerable points)
+ {
+ if (points == null)
+ {
+ throw new ArgumentNullException("points");
+ }
+
+ bool empty = true;
+ Vector3 minVec = MaxVector3;
+ Vector3 maxVec = MinVector3;
+ foreach (Vector3 ptVector in points)
+ {
+ minVec.X = (minVec.X < ptVector.X) ? minVec.X : ptVector.X;
+ minVec.Y = (minVec.Y < ptVector.Y) ? minVec.Y : ptVector.Y;
+ minVec.Z = (minVec.Z < ptVector.Z) ? minVec.Z : ptVector.Z;
+
+ maxVec.X = (maxVec.X > ptVector.X) ? maxVec.X : ptVector.X;
+ maxVec.Y = (maxVec.Y > ptVector.Y) ? maxVec.Y : ptVector.Y;
+ maxVec.Z = (maxVec.Z > ptVector.Z) ? maxVec.Z : ptVector.Z;
+
+ empty = false;
+ }
+ if (empty)
+ {
+ throw new ArgumentException("Collection is empty", "points");
+ }
+
+ return new BoundingBox(minVec, maxVec);
+ }
+
+ public static BoundingBox CreateFromSphere(BoundingSphere sphere)
+ {
+ BoundingBox result;
+ CreateFromSphere(ref sphere, out result);
+ return result;
+ }
+
+ public static void CreateFromSphere(ref BoundingSphere sphere, out BoundingBox result)
+ {
+ Vector3 corner = new Vector3(sphere.Radius);
+ result.Min = sphere.Center - corner;
+ result.Max = sphere.Center + corner;
+ }
+
+ public static BoundingBox CreateMerged(BoundingBox original, BoundingBox additional)
+ {
+ BoundingBox result;
+ CreateMerged(ref original, ref additional, out result);
+ return result;
+ }
+
+ public static void CreateMerged(ref BoundingBox original, ref BoundingBox additional, out BoundingBox result)
+ {
+ result.Min.X = Math.Min(original.Min.X, additional.Min.X);
+ result.Min.Y = Math.Min(original.Min.Y, additional.Min.Y);
+ result.Min.Z = Math.Min(original.Min.Z, additional.Min.Z);
+ result.Max.X = Math.Max(original.Max.X, additional.Max.X);
+ result.Max.Y = Math.Max(original.Max.Y, additional.Max.Y);
+ result.Max.Z = Math.Max(original.Max.Z, additional.Max.Z);
+ }
+
+ #endregion
+
+ #region Public Static Operators and Override Methods
+
+ public override bool Equals(object obj)
+ {
+ return (obj is BoundingBox) ? this.Equals((BoundingBox)obj) : false;
+ }
+
+ public override int GetHashCode()
+ {
+ return this.Min.GetHashCode() + this.Max.GetHashCode();
+ }
+
+ public static bool operator ==(BoundingBox a, BoundingBox b)
+ {
+ return a.Equals(b);
+ }
+
+ public static bool operator !=(BoundingBox a, BoundingBox b)
+ {
+ return !a.Equals(b);
+ }
+
+ public override string ToString()
+ {
+ return (
+ "{{Min:" + Min.ToString() +
+ " Max:" + Max.ToString() +
+ "}}"
+ );
+ }
+
+ #endregion
+ }
+}
diff --git a/src/BoundingFrustum.cs b/src/BoundingFrustum.cs
new file mode 100644
index 0000000..43a6d0b
--- /dev/null
+++ b/src/BoundingFrustum.cs
@@ -0,0 +1,785 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+
+/* Derived from code by the Mono.Xna Team (Copyright 2006).
+ * Released under the MIT License. See monoxna.LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Diagnostics;
+using System.Text;
+#endregion
+
+namespace Microsoft.Xna.Framework
+{
+ ///
+ /// Defines a viewing frustum for intersection operations.
+ ///
+ [DebuggerDisplay("{DebugDisplayString,nq}")]
+ public class BoundingFrustum : IEquatable
+ {
+ #region Public Properties
+
+ ///
+ /// Gets or sets the of the frustum.
+ ///
+ public Matrix Matrix
+ {
+ get
+ {
+ return this.matrix;
+ }
+ set
+ {
+ /* FIXME: The odds are the planes will be used a lot more often than
+ * the matrix is updated, so this should help performance. I hope. ;)
+ */
+ this.matrix = value;
+ this.CreatePlanes();
+ this.CreateCorners();
+ }
+ }
+
+ ///
+ /// Gets the near plane of the frustum.
+ ///
+ public Plane Near
+ {
+ get
+ {
+ return this.planes[0];
+ }
+ }
+
+ ///
+ /// Gets the far plane of the frustum.
+ ///
+ public Plane Far
+ {
+ get
+ {
+ return this.planes[1];
+ }
+ }
+
+ ///
+ /// Gets the left plane of the frustum.
+ ///
+ public Plane Left
+ {
+ get
+ {
+ return this.planes[2];
+ }
+ }
+
+ ///
+ /// Gets the right plane of the frustum.
+ ///
+ public Plane Right
+ {
+ get
+ {
+ return this.planes[3];
+ }
+ }
+
+ ///
+ /// Gets the top plane of the frustum.
+ ///
+ public Plane Top
+ {
+ get
+ {
+ return this.planes[4];
+ }
+ }
+
+ ///
+ /// Gets the bottom plane of the frustum.
+ ///
+ public Plane Bottom
+ {
+ get
+ {
+ return this.planes[5];
+ }
+ }
+
+ #endregion
+
+ #region Internal Properties
+
+ internal string DebugDisplayString
+ {
+ get
+ {
+ return string.Concat(
+ "Near( ", planes[0].DebugDisplayString, " ) \r\n",
+ "Far( ", planes[1].DebugDisplayString, " ) \r\n",
+ "Left( ", planes[2].DebugDisplayString, " ) \r\n",
+ "Right( ", planes[3].DebugDisplayString, " ) \r\n",
+ "Top( ", planes[4].DebugDisplayString, " ) \r\n",
+ "Bottom( ", planes[5].DebugDisplayString, " ) "
+ );
+ }
+ }
+
+ #endregion
+
+ #region Public Fields
+
+ ///
+ /// The number of corner points in the frustum.
+ ///
+ public const int CornerCount = 8;
+
+ #endregion
+
+ #region Private Fields
+
+ private Matrix matrix;
+ private readonly Vector3[] corners = new Vector3[CornerCount];
+ private readonly Plane[] planes = new Plane[PlaneCount];
+
+ ///
+ /// The number of planes in the frustum.
+ ///
+ private const int PlaneCount = 6;
+
+ #endregion
+
+ #region Public Constructors
+
+ ///
+ /// Constructs the frustum by extracting the view planes from a matrix.
+ ///
+ /// Combined matrix which usually is (View * Projection).
+ public BoundingFrustum(Matrix value)
+ {
+ this.matrix = value;
+ this.CreatePlanes();
+ this.CreateCorners();
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ ///
+ /// Containment test between this and specified .
+ ///
+ /// A for testing.
+ /// Result of testing for containment between this and specified .
+ public ContainmentType Contains(BoundingFrustum frustum)
+ {
+ if (this == frustum)
+ {
+ return ContainmentType.Contains;
+ }
+ bool intersects = false;
+ for (int i = 0; i < PlaneCount; i += 1)
+ {
+ PlaneIntersectionType planeIntersectionType;
+ frustum.Intersects(ref planes[i], out planeIntersectionType);
+ if (planeIntersectionType == PlaneIntersectionType.Front)
+ {
+ return ContainmentType.Disjoint;
+ }
+ else if (planeIntersectionType == PlaneIntersectionType.Intersecting)
+ {
+ intersects = true;
+ }
+ }
+ return intersects ? ContainmentType.Intersects : ContainmentType.Contains;
+ }
+
+ ///
+ /// Containment test between this and specified .
+ ///
+ /// A for testing.
+ /// Result of testing for containment between this and specified .
+ public ContainmentType Contains(BoundingBox box)
+ {
+ ContainmentType result = default(ContainmentType);
+ this.Contains(ref box, out result);
+ return result;
+ }
+
+ ///
+ /// Containment test between this and specified .
+ ///
+ /// A for testing.
+ /// Result of testing for containment between this and specified as an output parameter.
+ public void Contains(ref BoundingBox box, out ContainmentType result)
+ {
+ bool intersects = false;
+ for (int i = 0; i < PlaneCount; i += 1)
+ {
+ PlaneIntersectionType planeIntersectionType = default(PlaneIntersectionType);
+ box.Intersects(ref this.planes[i], out planeIntersectionType);
+ switch (planeIntersectionType)
+ {
+ case PlaneIntersectionType.Front:
+ result = ContainmentType.Disjoint;
+ return;
+ case PlaneIntersectionType.Intersecting:
+ intersects = true;
+ break;
+ }
+ }
+ result = intersects ? ContainmentType.Intersects : ContainmentType.Contains;
+ }
+
+ ///
+ /// Containment test between this and specified .
+ ///
+ /// A for testing.
+ /// Result of testing for containment between this and specified .
+ public ContainmentType Contains(BoundingSphere sphere)
+ {
+ ContainmentType result = default(ContainmentType);
+ this.Contains(ref sphere, out result);
+ return result;
+ }
+
+ ///
+ /// Containment test between this and specified .
+ ///
+ /// A for testing.
+ /// Result of testing for containment between this and specified as an output parameter.
+ public void Contains(ref BoundingSphere sphere, out ContainmentType result)
+ {
+ bool intersects = false;
+ for (int i = 0; i < PlaneCount; i += 1)
+ {
+ PlaneIntersectionType planeIntersectionType = default(PlaneIntersectionType);
+
+ // TODO: We might want to inline this for performance reasons.
+ sphere.Intersects(ref this.planes[i], out planeIntersectionType);
+ switch (planeIntersectionType)
+ {
+ case PlaneIntersectionType.Front:
+ result = ContainmentType.Disjoint;
+ return;
+ case PlaneIntersectionType.Intersecting:
+ intersects = true;
+ break;
+ }
+ }
+ result = intersects ? ContainmentType.Intersects : ContainmentType.Contains;
+ }
+
+ ///
+ /// Containment test between this and specified .
+ ///
+ /// A for testing.
+ /// Result of testing for containment between this and specified .
+ public ContainmentType Contains(Vector3 point)
+ {
+ ContainmentType result = default(ContainmentType);
+ this.Contains(ref point, out result);
+ return result;
+ }
+
+ ///
+ /// Containment test between this and specified .
+ ///
+ /// A for testing.
+ /// Result of testing for containment between this and specified as an output parameter.
+ public void Contains(ref Vector3 point, out ContainmentType result)
+ {
+ bool intersects = false;
+ for (int i = 0; i < PlaneCount; i += 1)
+ {
+ float classifyPoint = (
+ (point.X * planes[i].Normal.X) +
+ (point.Y * planes[i].Normal.Y) +
+ (point.Z * planes[i].Normal.Z) +
+ planes[i].D
+ );
+ if (classifyPoint > 0)
+ {
+ result = ContainmentType.Disjoint;
+ return;
+ }
+ else if (classifyPoint == 0)
+ {
+ intersects = true;
+ break;
+ }
+ }
+ result = intersects ? ContainmentType.Intersects : ContainmentType.Contains;
+ }
+
+ ///
+ /// Returns a copy of internal corners array.
+ ///
+ /// The array of corners.
+ public Vector3[] GetCorners()
+ {
+ return (Vector3[]) this.corners.Clone();
+ }
+
+ ///
+ /// Returns a copy of internal corners array.
+ ///
+ /// The array which values will be replaced to corner values of this instance. It must have size of .
+ public void GetCorners(Vector3[] corners)
+ {
+ if (corners == null)
+ {
+ throw new ArgumentNullException("corners");
+ }
+ if (corners.Length < CornerCount)
+ {
+ throw new ArgumentOutOfRangeException("corners");
+ }
+
+ this.corners.CopyTo(corners, 0);
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this .
+ ///
+ /// An other for intersection test.
+ /// true if other intersects with this ; false otherwise.
+ public bool Intersects(BoundingFrustum frustum)
+ {
+ return (Contains(frustum) != ContainmentType.Disjoint);
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this .
+ ///
+ /// A for intersection test.
+ /// true if specified intersects with this ; false otherwise.
+ public bool Intersects(BoundingBox box)
+ {
+ bool result = false;
+ this.Intersects(ref box, out result);
+ return result;
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this .
+ ///
+ /// A for intersection test.
+ /// true if specified intersects with this ; false otherwise as an output parameter.
+ public void Intersects(ref BoundingBox box, out bool result)
+ {
+ ContainmentType containment = default(ContainmentType);
+ this.Contains(ref box, out containment);
+ result = containment != ContainmentType.Disjoint;
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this .
+ ///
+ /// A for intersection test.
+ /// true if specified intersects with this ; false otherwise.
+ public bool Intersects(BoundingSphere sphere)
+ {
+ bool result = default(bool);
+ this.Intersects(ref sphere, out result);
+ return result;
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this .
+ ///
+ /// A for intersection test.
+ /// true if specified intersects with this ; false otherwise as an output parameter.
+ public void Intersects(ref BoundingSphere sphere, out bool result)
+ {
+ ContainmentType containment = default(ContainmentType);
+ this.Contains(ref sphere, out containment);
+ result = containment != ContainmentType.Disjoint;
+ }
+
+ ///
+ /// Gets type of intersection between specified and this .
+ ///
+ /// A for intersection test.
+ /// A plane intersection type.
+ public PlaneIntersectionType Intersects(Plane plane)
+ {
+ PlaneIntersectionType result;
+ Intersects(ref plane, out result);
+ return result;
+ }
+
+ ///
+ /// Gets type of intersection between specified and this .
+ ///
+ /// A for intersection test.
+ /// A plane intersection type as an output parameter.
+ public void Intersects(ref Plane plane, out PlaneIntersectionType result)
+ {
+ result = plane.Intersects(ref corners[0]);
+ for (int i = 1; i < corners.Length; i += 1)
+ {
+ if (plane.Intersects(ref corners[i]) != result)
+ {
+ result = PlaneIntersectionType.Intersecting;
+ }
+ }
+ }
+
+ ///
+ /// Gets the distance of intersection of and this or null if no intersection happens.
+ ///
+ /// A for intersection test.
+ /// Distance at which ray intersects with this or null if no intersection happens.
+ public float? Intersects(Ray ray)
+ {
+ float? result;
+ Intersects(ref ray, out result);
+ return result;
+ }
+
+ ///
+ /// Gets the distance of intersection of and this or null if no intersection happens.
+ ///
+ /// A for intersection test.
+ /// Distance at which ray intersects with this or null if no intersection happens as an output parameter.
+ public void Intersects(ref Ray ray, out float? result)
+ {
+ ContainmentType ctype;
+ Contains(ref ray.Position, out ctype);
+
+ if (ctype == ContainmentType.Disjoint)
+ {
+ result = null;
+ return;
+ }
+ if (ctype == ContainmentType.Contains)
+ {
+ result = 0.0f;
+ return;
+ }
+ if (ctype != ContainmentType.Intersects)
+ {
+ throw new ArgumentOutOfRangeException("ctype");
+ }
+
+ // TODO: Needs additional test for not 0.0 and null results.
+ result = null;
+ float min = float.MinValue;
+ float max = float.MaxValue;
+ foreach (Plane plane in planes)
+ {
+ Vector3 normal = plane.Normal;
+ float result2;
+ Vector3.Dot(ref ray.Direction, ref normal, out result2);
+ float result3;
+ Vector3.Dot(ref ray.Position, ref normal, out result3);
+ result3 += plane.D;
+ if ((double) Math.Abs(result2) < 9.99999974737875E-06)
+ {
+ if ((double) result3 > 0.0)
+ {
+ return;
+ }
+ }
+ else
+ {
+ float result4 = -result3 / result2;
+ if ((double) result2 < 0.0)
+ {
+ if ((double) result4 > (double) max)
+ {
+ return;
+ }
+ if ((double) result4 > (double) min)
+ {
+ min = result4;
+ }
+ }
+ else
+ {
+ if ((double) result4 < (double) min)
+ {
+ return;
+ }
+ if ((double) result4 < (double) max)
+ {
+ max = result4;
+ }
+ }
+ }
+ float? distance = ray.Intersects(plane);
+ if (distance.HasValue)
+ {
+ min = Math.Min(min, distance.Value);
+ max = Math.Max(max, distance.Value);
+ }
+ }
+ float temp = min >= 0.0 ? min : max;
+ if (temp < 0.0)
+ {
+ return;
+ }
+ result = temp;
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private void CreateCorners()
+ {
+ IntersectionPoint(
+ ref this.planes[0],
+ ref this.planes[2],
+ ref this.planes[4],
+ out this.corners[0]
+ );
+ IntersectionPoint(
+ ref this.planes[0],
+ ref this.planes[3],
+ ref this.planes[4],
+ out this.corners[1]
+ );
+ IntersectionPoint(
+ ref this.planes[0],
+ ref this.planes[3],
+ ref this.planes[5],
+ out this.corners[2]
+ );
+ IntersectionPoint(
+ ref this.planes[0],
+ ref this.planes[2],
+ ref this.planes[5],
+ out this.corners[3]
+ );
+ IntersectionPoint(
+ ref this.planes[1],
+ ref this.planes[2],
+ ref this.planes[4],
+ out this.corners[4]
+ );
+ IntersectionPoint(
+ ref this.planes[1],
+ ref this.planes[3],
+ ref this.planes[4],
+ out this.corners[5]
+ );
+ IntersectionPoint(
+ ref this.planes[1],
+ ref this.planes[3],
+ ref this.planes[5],
+ out this.corners[6]
+ );
+ IntersectionPoint(
+ ref this.planes[1],
+ ref this.planes[2],
+ ref this.planes[5],
+ out this.corners[7]
+ );
+ }
+
+ private void CreatePlanes()
+ {
+ this.planes[0] = new Plane(
+ -this.matrix.M13,
+ -this.matrix.M23,
+ -this.matrix.M33,
+ -this.matrix.M43
+ );
+ this.planes[1] = new Plane(
+ this.matrix.M13 - this.matrix.M14,
+ this.matrix.M23 - this.matrix.M24,
+ this.matrix.M33 - this.matrix.M34,
+ this.matrix.M43 - this.matrix.M44
+ );
+ this.planes[2] = new Plane(
+ -this.matrix.M14 - this.matrix.M11,
+ -this.matrix.M24 - this.matrix.M21,
+ -this.matrix.M34 - this.matrix.M31,
+ -this.matrix.M44 - this.matrix.M41
+ );
+ this.planes[3] = new Plane(
+ this.matrix.M11 - this.matrix.M14,
+ this.matrix.M21 - this.matrix.M24,
+ this.matrix.M31 - this.matrix.M34,
+ this.matrix.M41 - this.matrix.M44
+ );
+ this.planes[4] = new Plane(
+ this.matrix.M12 - this.matrix.M14,
+ this.matrix.M22 - this.matrix.M24,
+ this.matrix.M32 - this.matrix.M34,
+ this.matrix.M42 - this.matrix.M44
+ );
+ this.planes[5] = new Plane(
+ -this.matrix.M14 - this.matrix.M12,
+ -this.matrix.M24 - this.matrix.M22,
+ -this.matrix.M34 - this.matrix.M32,
+ -this.matrix.M44 - this.matrix.M42
+ );
+
+ this.NormalizePlane(ref this.planes[0]);
+ this.NormalizePlane(ref this.planes[1]);
+ this.NormalizePlane(ref this.planes[2]);
+ this.NormalizePlane(ref this.planes[3]);
+ this.NormalizePlane(ref this.planes[4]);
+ this.NormalizePlane(ref this.planes[5]);
+ }
+
+ private void NormalizePlane(ref Plane p)
+ {
+ float factor = 1f / p.Normal.Length();
+ p.Normal.X *= factor;
+ p.Normal.Y *= factor;
+ p.Normal.Z *= factor;
+ p.D *= factor;
+ }
+
+ #endregion
+
+ #region Private Static Methods
+
+ private static void IntersectionPoint(
+ ref Plane a,
+ ref Plane b,
+ ref Plane c,
+ out Vector3 result
+ ) {
+ /* Formula used
+ * d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 )
+ * P = -------------------------------------------------------------------
+ * N1 . ( N2 * N3 )
+ *
+ * Note: N refers to the normal, d refers to the displacement. '.' means dot
+ * product. '*' means cross product
+ */
+
+ Vector3 v1, v2, v3;
+ Vector3 cross;
+
+ Vector3.Cross(ref b.Normal, ref c.Normal, out cross);
+
+ float f;
+ Vector3.Dot(ref a.Normal, ref cross, out f);
+ f *= -1.0f;
+
+ Vector3.Cross(ref b.Normal, ref c.Normal, out cross);
+ Vector3.Multiply(ref cross, a.D, out v1);
+ // v1 = (a.D * (Vector3.Cross(b.Normal, c.Normal)));
+
+
+ Vector3.Cross(ref c.Normal, ref a.Normal, out cross);
+ Vector3.Multiply(ref cross, b.D, out v2);
+ // v2 = (b.D * (Vector3.Cross(c.Normal, a.Normal)));
+
+
+ Vector3.Cross(ref a.Normal, ref b.Normal, out cross);
+ Vector3.Multiply(ref cross, c.D, out v3);
+ // v3 = (c.D * (Vector3.Cross(a.Normal, b.Normal)));
+
+ result.X = (v1.X + v2.X + v3.X) / f;
+ result.Y = (v1.Y + v2.Y + v3.Y) / f;
+ result.Z = (v1.Z + v2.Z + v3.Z) / f;
+ }
+
+ #endregion
+
+ #region Public Static Operators and Override Methods
+
+ ///
+ /// Compares whether two instances are equal.
+ ///
+ /// instance on the left of the equal sign.
+ /// instance on the right of the equal sign.
+ /// true if the instances are equal; false otherwise.
+ public static bool operator ==(BoundingFrustum a, BoundingFrustum b)
+ {
+ if (object.Equals(a, null))
+ {
+ return (object.Equals(b, null));
+ }
+
+ if (object.Equals(b, null))
+ {
+ return (object.Equals(a, null));
+ }
+
+ return a.matrix == (b.matrix);
+ }
+
+ ///
+ /// Compares whether two instances are not equal.
+ ///
+ /// instance on the left of the not equal sign.
+ /// instance on the right of the not equal sign.
+ /// true if the instances are not equal; false otherwise.
+ public static bool operator !=(BoundingFrustum a, BoundingFrustum b)
+ {
+ return !(a == b);
+ }
+
+ ///
+ /// Compares whether current instance is equal to specified .
+ ///
+ /// The to compare.
+ /// true if the instances are equal; false otherwise.
+ public bool Equals(BoundingFrustum other)
+ {
+ return (this == other);
+ }
+
+ ///
+ /// Compares whether current instance is equal to specified .
+ ///
+ /// The to compare.
+ /// true if the instances are equal; false otherwise.
+ public override bool Equals(object obj)
+ {
+ BoundingFrustum f = obj as BoundingFrustum;
+ return (object.Equals(f, null)) ? false : (this == f);
+ }
+
+ ///
+ /// Returns a representation of this in the format:
+ /// {Near:[nearPlane] Far:[farPlane] Left:[leftPlane] Right:[rightPlane] Top:[topPlane] Bottom:[bottomPlane]}
+ ///
+ /// representation of this .
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder(256);
+ sb.Append("{Near:");
+ sb.Append(this.planes[0].ToString());
+ sb.Append(" Far:");
+ sb.Append(this.planes[1].ToString());
+ sb.Append(" Left:");
+ sb.Append(this.planes[2].ToString());
+ sb.Append(" Right:");
+ sb.Append(this.planes[3].ToString());
+ sb.Append(" Top:");
+ sb.Append(this.planes[4].ToString());
+ sb.Append(" Bottom:");
+ sb.Append(this.planes[5].ToString());
+ sb.Append("}");
+ return sb.ToString();
+ }
+
+ ///
+ /// Gets the hash code of this .
+ ///
+ /// Hash code of this .
+ public override int GetHashCode()
+ {
+ return this.matrix.GetHashCode();
+ }
+
+ #endregion
+ }
+}
+
diff --git a/src/BoundingSphere.cs b/src/BoundingSphere.cs
new file mode 100644
index 0000000..a226b71
--- /dev/null
+++ b/src/BoundingSphere.cs
@@ -0,0 +1,688 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+
+/* Derived from code by the Mono.Xna Team (Copyright 2006).
+ * Released under the MIT License. See monoxna.LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+
+using Microsoft.Xna.Framework.Design;
+#endregion
+
+namespace Microsoft.Xna.Framework
+{
+ ///
+ /// Describes a sphere in 3D-space for bounding operations.
+ ///
+ [Serializable]
+ [TypeConverter(typeof(BoundingSphereConverter))]
+ [DebuggerDisplay("{DebugDisplayString,nq}")]
+ public struct BoundingSphere : IEquatable
+ {
+ #region Internal Properties
+
+ internal string DebugDisplayString
+ {
+ get
+ {
+ return string.Concat(
+ "Center( ", Center.DebugDisplayString, " ) \r\n",
+ "Radius( ", Radius.ToString(), " ) "
+ );
+ }
+ }
+
+ #endregion
+
+ #region Public Fields
+
+ ///
+ /// The sphere center.
+ ///
+ public Vector3 Center;
+
+ ///
+ /// The sphere radius.
+ ///
+ public float Radius;
+
+ #endregion
+
+ #region Public Constructors
+
+ ///
+ /// Constructs a bounding sphere with the specified center and radius.
+ ///
+ /// The sphere center.
+ /// The sphere radius.
+ public BoundingSphere(Vector3 center, float radius)
+ {
+ this.Center = center;
+ this.Radius = radius;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ ///
+ /// Creates a new that contains a transformation of translation and scale from this sphere by the specified .
+ ///
+ /// The transformation .
+ /// Transformed .
+ public BoundingSphere Transform(Matrix matrix)
+ {
+ BoundingSphere sphere = new BoundingSphere();
+ sphere.Center = Vector3.Transform(this.Center, matrix);
+ sphere.Radius = this.Radius *
+ (
+ (float) Math.Sqrt((double) Math.Max(
+ ((matrix.M11 * matrix.M11) + (matrix.M12 * matrix.M12)) + (matrix.M13 * matrix.M13),
+ Math.Max(
+ ((matrix.M21 * matrix.M21) + (matrix.M22 * matrix.M22)) + (matrix.M23 * matrix.M23),
+ ((matrix.M31 * matrix.M31) + (matrix.M32 * matrix.M32)) + (matrix.M33 * matrix.M33))
+ )
+ )
+ );
+ return sphere;
+ }
+
+ ///
+ /// Creates a new that contains a transformation of translation and scale from this sphere by the specified .
+ ///
+ /// The transformation .
+ /// Transformed as an output parameter.
+ public void Transform(ref Matrix matrix, out BoundingSphere result)
+ {
+ result.Center = Vector3.Transform(this.Center, matrix);
+ result.Radius = this.Radius *
+ (
+ (float) Math.Sqrt((double) Math.Max(
+ ((matrix.M11 * matrix.M11) + (matrix.M12 * matrix.M12)) + (matrix.M13 * matrix.M13),
+ Math.Max(
+ ((matrix.M21 * matrix.M21) + (matrix.M22 * matrix.M22)) + (matrix.M23 * matrix.M23),
+ ((matrix.M31 * matrix.M31) + (matrix.M32 * matrix.M32)) + (matrix.M33 * matrix.M33))
+ )
+ )
+ );
+ }
+
+ ///
+ /// Test if a bounding box is fully inside, outside, or just intersecting the sphere.
+ ///
+ /// The box for testing.
+ /// The containment type as an output parameter.
+ public void Contains(ref BoundingBox box, out ContainmentType result)
+ {
+ result = this.Contains(box);
+ }
+
+ ///
+ /// Test if a sphere is fully inside, outside, or just intersecting the sphere.
+ ///
+ /// The other sphere for testing.
+ /// The containment type as an output parameter.
+ public void Contains(ref BoundingSphere sphere, out ContainmentType result)
+ {
+ result = Contains(sphere);
+ }
+
+ ///
+ /// Test if a point is fully inside, outside, or just intersecting the sphere.
+ ///
+ /// The vector in 3D-space for testing.
+ /// The containment type as an output parameter.
+ public void Contains(ref Vector3 point, out ContainmentType result)
+ {
+ result = Contains(point);
+ }
+
+ ///
+ /// Test if a bounding box is fully inside, outside, or just intersecting the sphere.
+ ///
+ /// The box for testing.
+ /// The containment type.
+ public ContainmentType Contains(BoundingBox box)
+ {
+ // Check if all corners are in sphere.
+ bool inside = true;
+ foreach (Vector3 corner in box.GetCorners())
+ {
+ if (this.Contains(corner) == ContainmentType.Disjoint)
+ {
+ inside = false;
+ break;
+ }
+ }
+
+ if (inside)
+ {
+ return ContainmentType.Contains;
+ }
+
+ // Check if the distance from sphere center to cube face is less than radius.
+ double dmin = 0;
+
+ if (Center.X < box.Min.X)
+ {
+ dmin += (Center.X - box.Min.X) * (Center.X - box.Min.X);
+ }
+ else if (Center.X > box.Max.X)
+ {
+ dmin += (Center.X - box.Max.X) * (Center.X - box.Max.X);
+ }
+
+ if (Center.Y < box.Min.Y)
+ {
+ dmin += (Center.Y - box.Min.Y) * (Center.Y - box.Min.Y);
+ }
+ else if (Center.Y > box.Max.Y)
+ {
+ dmin += (Center.Y - box.Max.Y) * (Center.Y - box.Max.Y);
+ }
+
+ if (Center.Z < box.Min.Z)
+ {
+ dmin += (Center.Z - box.Min.Z) * (Center.Z - box.Min.Z);
+ }
+ else if (Center.Z > box.Max.Z)
+ {
+ dmin += (Center.Z - box.Max.Z) * (Center.Z - box.Max.Z);
+ }
+
+ if (dmin <= Radius * Radius)
+ {
+ return ContainmentType.Intersects;
+ }
+
+ // Else disjoint
+ return ContainmentType.Disjoint;
+ }
+
+ ///
+ /// Test if a frustum is fully inside, outside, or just intersecting the sphere.
+ ///
+ /// The box for testing.
+ /// The containment type as an output parameter.
+ public ContainmentType Contains(BoundingFrustum frustum)
+ {
+ // Check if all corners are in sphere.
+ bool inside = true;
+
+ Vector3[] corners = frustum.GetCorners();
+ foreach (Vector3 corner in corners)
+ {
+ if (this.Contains(corner) == ContainmentType.Disjoint)
+ {
+ inside = false;
+ break;
+ }
+ }
+ if (inside)
+ {
+ return ContainmentType.Contains;
+ }
+
+ // Check if the distance from sphere center to frustrum face is less than radius.
+ double dmin = 0;
+ // TODO : calcul dmin
+
+ if (dmin <= Radius * Radius)
+ {
+ return ContainmentType.Intersects;
+ }
+
+ // Else disjoint
+ return ContainmentType.Disjoint;
+ }
+
+ ///
+ /// Test if a sphere is fully inside, outside, or just intersecting the sphere.
+ ///
+ /// The other sphere for testing.
+ /// The containment type.
+ public ContainmentType Contains(BoundingSphere sphere)
+ {
+ float sqDistance;
+ Vector3.DistanceSquared(ref sphere.Center, ref Center, out sqDistance);
+
+ if (sqDistance > (sphere.Radius + Radius) * (sphere.Radius + Radius))
+ {
+ return ContainmentType.Disjoint;
+ }
+ else if (sqDistance <= (Radius * sphere.Radius) * (Radius - sphere.Radius))
+ {
+ return ContainmentType.Contains;
+ }
+ return ContainmentType.Intersects;
+ }
+
+ ///
+ /// Test if a point is fully inside, outside, or just intersecting the sphere.
+ ///
+ /// The vector in 3D-space for testing.
+ /// The containment type.
+ public ContainmentType Contains(Vector3 point)
+ {
+ float sqRadius = Radius * Radius;
+ float sqDistance;
+ Vector3.DistanceSquared(ref point, ref Center, out sqDistance);
+
+ if (sqDistance > sqRadius)
+ {
+ return ContainmentType.Disjoint;
+ }
+ else if (sqDistance < sqRadius)
+ {
+ return ContainmentType.Contains;
+ }
+ return ContainmentType.Intersects;
+ }
+
+ ///
+ /// Compares whether current instance is equal to specified .
+ ///
+ /// The to compare.
+ /// true if the instances are equal; false otherwise.
+ public bool Equals(BoundingSphere other)
+ {
+ return ( this.Center == other.Center &&
+ MathHelper.WithinEpsilon(this.Radius, other.Radius) );
+ }
+
+ #endregion
+
+ #region Public Static Methods
+
+ ///
+ /// Creates the smallest that can contain a specified .
+ ///
+ /// The box to create the sphere from.
+ /// The new .
+ public static BoundingSphere CreateFromBoundingBox(BoundingBox box)
+ {
+ BoundingSphere result;
+ CreateFromBoundingBox(ref box, out result);
+ return result;
+ }
+
+ ///
+ /// Creates the smallest that can contain a specified .
+ ///
+ /// The box to create the sphere from.
+ /// The new as an output parameter.
+ public static void CreateFromBoundingBox(ref BoundingBox box, out BoundingSphere result)
+ {
+ // Find the center of the box.
+ Vector3 center = new Vector3(
+ (box.Min.X + box.Max.X) / 2.0f,
+ (box.Min.Y + box.Max.Y) / 2.0f,
+ (box.Min.Z + box.Max.Z) / 2.0f
+ );
+
+ // Find the distance between the center and one of the corners of the box.
+ float radius = Vector3.Distance(center, box.Max);
+
+ result = new BoundingSphere(center, radius);
+ }
+
+ ///
+ /// Creates the smallest that can contain a specified .
+ ///
+ /// The frustum to create the sphere from.
+ /// The new .
+ public static BoundingSphere CreateFromFrustum(BoundingFrustum frustum)
+ {
+ return CreateFromPoints(frustum.GetCorners());
+ }
+
+ ///
+ /// Creates the smallest that can contain a specified list of points in 3D-space.
+ ///
+ /// List of point to create the sphere from.
+ /// The new .
+ public static BoundingSphere CreateFromPoints(IEnumerable points)
+ {
+ if (points == null)
+ {
+ throw new ArgumentNullException("points");
+ }
+
+ // From "Real-Time Collision Detection" (Page 89)
+
+ Vector3 minx = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
+ Vector3 maxx = -minx;
+ Vector3 miny = minx;
+ Vector3 maxy = -minx;
+ Vector3 minz = minx;
+ Vector3 maxz = -minx;
+
+ // Find the most extreme points along the principle axis.
+ int numPoints = 0;
+ foreach (Vector3 pt in points)
+ {
+ numPoints += 1;
+
+ if (pt.X < minx.X)
+ {
+ minx = pt;
+ }
+ if (pt.X > maxx.X)
+ {
+ maxx = pt;
+ }
+ if (pt.Y < miny.Y)
+ {
+ miny = pt;
+ }
+ if (pt.Y > maxy.Y)
+ {
+ maxy = pt;
+ }
+ if (pt.Z < minz.Z)
+ {
+ minz = pt;
+ }
+ if (pt.Z > maxz.Z)
+ {
+ maxz = pt;
+ }
+ }
+
+ if (numPoints == 0)
+ {
+ throw new ArgumentException(
+ "You should have at least one point in points."
+ );
+ }
+
+ float sqDistX = Vector3.DistanceSquared(maxx, minx);
+ float sqDistY = Vector3.DistanceSquared(maxy, miny);
+ float sqDistZ = Vector3.DistanceSquared(maxz, minz);
+
+ // Pick the pair of most distant points.
+ Vector3 min = minx;
+ Vector3 max = maxx;
+ if (sqDistY > sqDistX && sqDistY > sqDistZ)
+ {
+ max = maxy;
+ min = miny;
+ }
+ if (sqDistZ > sqDistX && sqDistZ > sqDistY)
+ {
+ max = maxz;
+ min = minz;
+ }
+
+ Vector3 center = (min + max) * 0.5f;
+ float radius = Vector3.Distance(max, center);
+
+ // Test every point and expand the sphere.
+ // The current bounding sphere is just a good approximation and may not enclose all points.
+ // From: Mathematics for 3D Game Programming and Computer Graphics, Eric Lengyel, Third Edition.
+ // Page 218
+ float sqRadius = radius * radius;
+ foreach (Vector3 pt in points)
+ {
+ Vector3 diff = (pt - center);
+ float sqDist = diff.LengthSquared();
+ if (sqDist > sqRadius)
+ {
+ float distance = (float) Math.Sqrt(sqDist); // equal to diff.Length();
+ Vector3 direction = diff / distance;
+ Vector3 G = center - radius * direction;
+ center = (G + pt) / 2;
+ radius = Vector3.Distance(pt, center);
+ sqRadius = radius * radius;
+ }
+ }
+
+ return new BoundingSphere(center, radius);
+ }
+
+ ///
+ /// Creates the smallest that can contain two spheres.
+ ///
+ /// First sphere.
+ /// Second sphere.
+ /// The new .
+ public static BoundingSphere CreateMerged(BoundingSphere original, BoundingSphere additional)
+ {
+ BoundingSphere result;
+ CreateMerged(ref original, ref additional, out result);
+ return result;
+ }
+
+ ///
+ /// Creates the smallest that can contain two spheres.
+ ///
+ /// First sphere.
+ /// Second sphere.
+ /// The new as an output parameter.
+ public static void CreateMerged(
+ ref BoundingSphere original,
+ ref BoundingSphere additional,
+ out BoundingSphere result
+ ) {
+ Vector3 ocenterToaCenter = Vector3.Subtract(additional.Center, original.Center);
+ float distance = ocenterToaCenter.Length();
+
+ // Intersect
+ if (distance <= original.Radius + additional.Radius)
+ {
+ // Original contains additional.
+ if (distance <= original.Radius - additional.Radius)
+ {
+ result = original;
+ return;
+ }
+
+ // Additional contains original.
+ if (distance <= additional.Radius - original.Radius)
+ {
+ result = additional;
+ return;
+ }
+ }
+
+ // Else find center of new sphere and radius
+ float leftRadius = Math.Max(original.Radius - distance, additional.Radius);
+ float Rightradius = Math.Max(original.Radius + distance, additional.Radius);
+
+ // oCenterToResultCenter
+ ocenterToaCenter = ocenterToaCenter +
+ (
+ ((leftRadius - Rightradius) / (2 * ocenterToaCenter.Length()))
+ * ocenterToaCenter
+ );
+
+ result = new BoundingSphere();
+ result.Center = original.Center + ocenterToaCenter;
+ result.Radius = (leftRadius + Rightradius) / 2;
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this sphere.
+ ///
+ /// The box for testing.
+ /// true if intersects with this sphere; false otherwise.
+ public bool Intersects(BoundingBox box)
+ {
+ return box.Intersects(this);
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this sphere.
+ ///
+ /// The box for testing.
+ /// true if intersects with this sphere; false otherwise. As an output parameter.
+ public void Intersects(ref BoundingBox box, out bool result)
+ {
+ box.Intersects(ref this, out result);
+ }
+
+ public bool Intersects(BoundingFrustum frustum)
+ {
+ return frustum.Intersects(this);
+ }
+
+ ///
+ /// Gets whether or not the other intersects with this sphere.
+ ///
+ /// The other sphere for testing.
+ /// true if other intersects with this sphere; false otherwise.
+ public bool Intersects(BoundingSphere sphere)
+ {
+ bool result;
+ Intersects(ref sphere, out result);
+ return result;
+ }
+
+ ///
+ /// Gets whether or not the other intersects with this sphere.
+ ///
+ /// The other sphere for testing.
+ /// true if other intersects with this sphere; false otherwise. As an output parameter.
+ public void Intersects(ref BoundingSphere sphere, out bool result)
+ {
+ float sqDistance;
+ Vector3.DistanceSquared(ref sphere.Center, ref Center, out sqDistance);
+ result = !(sqDistance > (sphere.Radius + Radius) * (sphere.Radius + Radius));
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this sphere.
+ ///
+ /// The ray for testing.
+ /// Distance of ray intersection or null if there is no intersection.
+ public float? Intersects(Ray ray)
+ {
+ return ray.Intersects(this);
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this sphere.
+ ///
+ /// The ray for testing.
+ /// Distance of ray intersection or null if there is no intersection as an output parameter.
+ public void Intersects(ref Ray ray, out float? result)
+ {
+ ray.Intersects(ref this, out result);
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this sphere.
+ ///
+ /// The plane for testing.
+ /// Type of intersection.
+ public PlaneIntersectionType Intersects(Plane plane)
+ {
+ PlaneIntersectionType result = default(PlaneIntersectionType);
+ // TODO: We might want to inline this for performance reasons.
+ this.Intersects(ref plane, out result);
+ return result;
+ }
+
+ ///
+ /// Gets whether or not a specified intersects with this sphere.
+ ///
+ /// The plane for testing.
+ /// Type of intersection as an output parameter.
+ public void Intersects(ref Plane plane, out PlaneIntersectionType result)
+ {
+ float distance = default(float);
+ // TODO: We might want to inline this for performance reasons.
+ Vector3.Dot(ref plane.Normal, ref this.Center, out distance);
+ distance += plane.D;
+ if (distance > this.Radius)
+ {
+ result = PlaneIntersectionType.Front;
+ }
+ else if (distance < -this.Radius)
+ {
+ result = PlaneIntersectionType.Back;
+ }
+ else
+ {
+ result = PlaneIntersectionType.Intersecting;
+ }
+ }
+
+ #endregion
+
+ #region Public Static Operators and Override Methods
+
+ ///
+ /// Compares whether current instance is equal to specified .
+ ///
+ /// The to compare.
+ /// true if the instances are equal; false otherwise.
+ public override bool Equals(object obj)
+ {
+ if (obj is BoundingSphere)
+ {
+ return this.Equals((BoundingSphere)obj);
+ }
+
+ return false;
+ }
+
+ ///
+ /// Gets the hash code of this .
+ ///
+ /// Hash code of this .
+ public override int GetHashCode()
+ {
+ return this.Center.GetHashCode() + this.Radius.GetHashCode();
+ }
+
+ ///
+ /// Returns a representation of this in the format:
+ /// {Center:[] Radius:[]}
+ ///
+ /// A representation of this .
+ public override string ToString()
+ {
+ return (
+ "{Center:" + Center.ToString() +
+ " Radius:" + Radius.ToString() +
+ "}"
+ );
+ }
+
+ ///
+ /// Compares whether two instances are equal.
+ ///
+ /// instance on the left of the equal sign.
+ /// instance on the right of the equal sign.
+ /// true if the instances are equal; false otherwise.
+ public static bool operator ==(BoundingSphere a, BoundingSphere b)
+ {
+ return a.Equals(b);
+ }
+
+ ///
+ /// Compares whether two instances are not equal.
+ ///
+ /// instance on the left of the not equal sign.
+ /// instance on the right of the not equal sign.
+ /// true if the instances are not equal; false otherwise.
+ public static bool operator !=(BoundingSphere a, BoundingSphere b)
+ {
+ return !a.Equals(b);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Color.cs b/src/Color.cs
new file mode 100644
index 0000000..9c96974
--- /dev/null
+++ b/src/Color.cs
@@ -0,0 +1,1903 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+
+/* Derived from code by the Mono.Xna Team (Copyright 2006).
+ * Released under the MIT License. See monoxna.LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Text;
+
+using Microsoft.Xna.Framework.Design;
+#endregion
+
+namespace Microsoft.Xna.Framework
+{
+ ///
+ /// Describes a 32-bit packed color.
+ ///
+ [Serializable]
+ [TypeConverter(typeof(ColorConverter))]
+ [DebuggerDisplay("{DebugDisplayString,nq}")]
+ public struct Color : IEquatable
+ {
+ #region Public Properties
+
+ ///
+ /// Gets or sets the blue component.
+ ///
+ public byte B
+ {
+ get
+ {
+ unchecked
+ {
+ return (byte) (this._packedValue >> 16);
+ }
+ }
+ set
+ {
+ this._packedValue = (this._packedValue & 0xff00ffff) | ((uint) value << 16);
+ }
+ }
+
+ ///
+ /// Gets or sets the green component.
+ ///
+ public byte G
+ {
+ get
+ {
+ unchecked
+ {
+ return (byte) (this._packedValue >> 8);
+ }
+ }
+ set
+ {
+ this._packedValue = (this._packedValue & 0xffff00ff) | ((uint) value << 8);
+ }
+ }
+
+ ///
+ /// Gets or sets the red component.
+ ///
+ public byte R
+ {
+ get
+ {
+ unchecked
+ {
+ return (byte) (this._packedValue);
+ }
+ }
+ set
+ {
+ this._packedValue = (this._packedValue & 0xffffff00) | value;
+ }
+ }
+
+ ///
+ /// Gets or sets the alpha component.
+ ///
+ public byte A
+ {
+ get
+ {
+ unchecked
+ {
+ return (byte) (this._packedValue >> 24);
+ }
+ }
+ set
+ {
+ this._packedValue = (this._packedValue & 0x00ffffff) | ((uint) value << 24);
+ }
+ }
+
+ ///
+ /// Gets or sets packed value of this .
+ ///
+ [CLSCompliant(false)]
+ public UInt32 PackedValue
+ {
+ get
+ {
+ return _packedValue;
+ }
+ set
+ {
+ _packedValue = value;
+ }
+ }
+
+ #endregion
+
+ #region Public Static Color Properties
+
+ ///
+ /// Transparent color (R:0,G:0,B:0,A:0).
+ ///
+ public static Color Transparent
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// AliceBlue color (R:240,G:248,B:255,A:255).
+ ///
+ public static Color AliceBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// AntiqueWhite color (R:250,G:235,B:215,A:255).
+ ///
+ public static Color AntiqueWhite
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Aqua color (R:0,G:255,B:255,A:255).
+ ///
+ public static Color Aqua
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Aquamarine color (R:127,G:255,B:212,A:255).
+ ///
+ public static Color Aquamarine
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Azure color (R:240,G:255,B:255,A:255).
+ ///
+ public static Color Azure
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Beige color (R:245,G:245,B:220,A:255).
+ ///
+ public static Color Beige
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Bisque color (R:255,G:228,B:196,A:255).
+ ///
+ public static Color Bisque
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Black color (R:0,G:0,B:0,A:255).
+ ///
+ public static Color Black
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// BlanchedAlmond color (R:255,G:235,B:205,A:255).
+ ///
+ public static Color BlanchedAlmond
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Blue color (R:0,G:0,B:255,A:255).
+ ///
+ public static Color Blue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// BlueViolet color (R:138,G:43,B:226,A:255).
+ ///
+ public static Color BlueViolet
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Brown color (R:165,G:42,B:42,A:255).
+ ///
+ public static Color Brown
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// BurlyWood color (R:222,G:184,B:135,A:255).
+ ///
+ public static Color BurlyWood
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// CadetBlue color (R:95,G:158,B:160,A:255).
+ ///
+ public static Color CadetBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Chartreuse color (R:127,G:255,B:0,A:255).
+ ///
+ public static Color Chartreuse
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Chocolate color (R:210,G:105,B:30,A:255).
+ ///
+ public static Color Chocolate
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Coral color (R:255,G:127,B:80,A:255).
+ ///
+ public static Color Coral
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// CornflowerBlue color (R:100,G:149,B:237,A:255).
+ ///
+ public static Color CornflowerBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Cornsilk color (R:255,G:248,B:220,A:255).
+ ///
+ public static Color Cornsilk
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Crimson color (R:220,G:20,B:60,A:255).
+ ///
+ public static Color Crimson
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Cyan color (R:0,G:255,B:255,A:255).
+ ///
+ public static Color Cyan
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkBlue color (R:0,G:0,B:139,A:255).
+ ///
+ public static Color DarkBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkCyan color (R:0,G:139,B:139,A:255).
+ ///
+ public static Color DarkCyan
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkGoldenrod color (R:184,G:134,B:11,A:255).
+ ///
+ public static Color DarkGoldenrod
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkGray color (R:169,G:169,B:169,A:255).
+ ///
+ public static Color DarkGray
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkGreen color (R:0,G:100,B:0,A:255).
+ ///
+ public static Color DarkGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkKhaki color (R:189,G:183,B:107,A:255).
+ ///
+ public static Color DarkKhaki
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkMagenta color (R:139,G:0,B:139,A:255).
+ ///
+ public static Color DarkMagenta
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkOliveGreen color (R:85,G:107,B:47,A:255).
+ ///
+ public static Color DarkOliveGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkOrange color (R:255,G:140,B:0,A:255).
+ ///
+ public static Color DarkOrange
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkOrchid color (R:153,G:50,B:204,A:255).
+ ///
+ public static Color DarkOrchid
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkRed color (R:139,G:0,B:0,A:255).
+ ///
+ public static Color DarkRed
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkSalmon color (R:233,G:150,B:122,A:255).
+ ///
+ public static Color DarkSalmon
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkSeaGreen color (R:143,G:188,B:139,A:255).
+ ///
+ public static Color DarkSeaGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkSlateBlue color (R:72,G:61,B:139,A:255).
+ ///
+ public static Color DarkSlateBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkSlateGray color (R:47,G:79,B:79,A:255).
+ ///
+ public static Color DarkSlateGray
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkTurquoise color (R:0,G:206,B:209,A:255).
+ ///
+ public static Color DarkTurquoise
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DarkViolet color (R:148,G:0,B:211,A:255).
+ ///
+ public static Color DarkViolet
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DeepPink color (R:255,G:20,B:147,A:255).
+ ///
+ public static Color DeepPink
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DeepSkyBlue color (R:0,G:191,B:255,A:255).
+ ///
+ public static Color DeepSkyBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DimGray color (R:105,G:105,B:105,A:255).
+ ///
+ public static Color DimGray
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// DodgerBlue color (R:30,G:144,B:255,A:255).
+ ///
+ public static Color DodgerBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Firebrick color (R:178,G:34,B:34,A:255).
+ ///
+ public static Color Firebrick
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// FloralWhite color (R:255,G:250,B:240,A:255).
+ ///
+ public static Color FloralWhite
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// ForestGreen color (R:34,G:139,B:34,A:255).
+ ///
+ public static Color ForestGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Fuchsia color (R:255,G:0,B:255,A:255).
+ ///
+ public static Color Fuchsia
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Gainsboro color (R:220,G:220,B:220,A:255).
+ ///
+ public static Color Gainsboro
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// GhostWhite color (R:248,G:248,B:255,A:255).
+ ///
+ public static Color GhostWhite
+ {
+ get;
+ private set;
+ }
+ ///
+ /// Gold color (R:255,G:215,B:0,A:255).
+ ///
+ public static Color Gold
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Goldenrod color (R:218,G:165,B:32,A:255).
+ ///
+ public static Color Goldenrod
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Gray color (R:128,G:128,B:128,A:255).
+ ///
+ public static Color Gray
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Green color (R:0,G:128,B:0,A:255).
+ ///
+ public static Color Green
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// GreenYellow color (R:173,G:255,B:47,A:255).
+ ///
+ public static Color GreenYellow
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Honeydew color (R:240,G:255,B:240,A:255).
+ ///
+ public static Color Honeydew
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// HotPink color (R:255,G:105,B:180,A:255).
+ ///
+ public static Color HotPink
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// IndianRed color (R:205,G:92,B:92,A:255).
+ ///
+ public static Color IndianRed
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Indigo color (R:75,G:0,B:130,A:255).
+ ///
+ public static Color Indigo
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Ivory color (R:255,G:255,B:240,A:255).
+ ///
+ public static Color Ivory
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Khaki color (R:240,G:230,B:140,A:255).
+ ///
+ public static Color Khaki
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Lavender color (R:230,G:230,B:250,A:255).
+ ///
+ public static Color Lavender
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LavenderBlush color (R:255,G:240,B:245,A:255).
+ ///
+ public static Color LavenderBlush
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LawnGreen color (R:124,G:252,B:0,A:255).
+ ///
+ public static Color LawnGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LemonChiffon color (R:255,G:250,B:205,A:255).
+ ///
+ public static Color LemonChiffon
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightBlue color (R:173,G:216,B:230,A:255).
+ ///
+ public static Color LightBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightCoral color (R:240,G:128,B:128,A:255).
+ ///
+ public static Color LightCoral
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightCyan color (R:224,G:255,B:255,A:255).
+ ///
+ public static Color LightCyan
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightGoldenrodYellow color (R:250,G:250,B:210,A:255).
+ ///
+ public static Color LightGoldenrodYellow
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightGray color (R:211,G:211,B:211,A:255).
+ ///
+ public static Color LightGray
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightGreen color (R:144,G:238,B:144,A:255).
+ ///
+ public static Color LightGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightPink color (R:255,G:182,B:193,A:255).
+ ///
+ public static Color LightPink
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightSalmon color (R:255,G:160,B:122,A:255).
+ ///
+ public static Color LightSalmon
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightSeaGreen color (R:32,G:178,B:170,A:255).
+ ///
+ public static Color LightSeaGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightSkyBlue color (R:135,G:206,B:250,A:255).
+ ///
+ public static Color LightSkyBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightSlateGray color (R:119,G:136,B:153,A:255).
+ ///
+ public static Color LightSlateGray
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightSteelBlue color (R:176,G:196,B:222,A:255).
+ ///
+ public static Color LightSteelBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LightYellow color (R:255,G:255,B:224,A:255).
+ ///
+ public static Color LightYellow
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Lime color (R:0,G:255,B:0,A:255).
+ ///
+ public static Color Lime
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// LimeGreen color (R:50,G:205,B:50,A:255).
+ ///
+ public static Color LimeGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Linen color (R:250,G:240,B:230,A:255).
+ ///
+ public static Color Linen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Magenta color (R:255,G:0,B:255,A:255).
+ ///
+ public static Color Magenta
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Maroon color (R:128,G:0,B:0,A:255).
+ ///
+ public static Color Maroon
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumAquamarine color (R:102,G:205,B:170,A:255).
+ ///
+ public static Color MediumAquamarine
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumBlue color (R:0,G:0,B:205,A:255).
+ ///
+ public static Color MediumBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumOrchid color (R:186,G:85,B:211,A:255).
+ ///
+ public static Color MediumOrchid
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumPurple color (R:147,G:112,B:219,A:255).
+ ///
+ public static Color MediumPurple
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumSeaGreen color (R:60,G:179,B:113,A:255).
+ ///
+ public static Color MediumSeaGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumSlateBlue color (R:123,G:104,B:238,A:255).
+ ///
+ public static Color MediumSlateBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumSpringGreen color (R:0,G:250,B:154,A:255).
+ ///
+ public static Color MediumSpringGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumTurquoise color (R:72,G:209,B:204,A:255).
+ ///
+ public static Color MediumTurquoise
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MediumVioletRed color (R:199,G:21,B:133,A:255).
+ ///
+ public static Color MediumVioletRed
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MidnightBlue color (R:25,G:25,B:112,A:255).
+ ///
+ public static Color MidnightBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MintCream color (R:245,G:255,B:250,A:255).
+ ///
+ public static Color MintCream
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// MistyRose color (R:255,G:228,B:225,A:255).
+ ///
+ public static Color MistyRose
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Moccasin color (R:255,G:228,B:181,A:255).
+ ///
+ public static Color Moccasin
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// NavajoWhite color (R:255,G:222,B:173,A:255).
+ ///
+ public static Color NavajoWhite
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Navy color (R:0,G:0,B:128,A:255).
+ ///
+ public static Color Navy
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// OldLace color (R:253,G:245,B:230,A:255).
+ ///
+ public static Color OldLace
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Olive color (R:128,G:128,B:0,A:255).
+ ///
+ public static Color Olive
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// OliveDrab color (R:107,G:142,B:35,A:255).
+ ///
+ public static Color OliveDrab
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Orange color (R:255,G:165,B:0,A:255).
+ ///
+ public static Color Orange
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// OrangeRed color (R:255,G:69,B:0,A:255).
+ ///
+ public static Color OrangeRed
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Orchid color (R:218,G:112,B:214,A:255).
+ ///
+ public static Color Orchid
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// PaleGoldenrod color (R:238,G:232,B:170,A:255).
+ ///
+ public static Color PaleGoldenrod
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// PaleGreen color (R:152,G:251,B:152,A:255).
+ ///
+ public static Color PaleGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// PaleTurquoise color (R:175,G:238,B:238,A:255).
+ ///
+ public static Color PaleTurquoise
+ {
+ get;
+ private set;
+ }
+ ///
+ /// PaleVioletRed color (R:219,G:112,B:147,A:255).
+ ///
+ public static Color PaleVioletRed
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// PapayaWhip color (R:255,G:239,B:213,A:255).
+ ///
+ public static Color PapayaWhip
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// PeachPuff color (R:255,G:218,B:185,A:255).
+ ///
+ public static Color PeachPuff
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Peru color (R:205,G:133,B:63,A:255).
+ ///
+ public static Color Peru
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Pink color (R:255,G:192,B:203,A:255).
+ ///
+ public static Color Pink
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Plum color (R:221,G:160,B:221,A:255).
+ ///
+ public static Color Plum
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// PowderBlue color (R:176,G:224,B:230,A:255).
+ ///
+ public static Color PowderBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Purple color (R:128,G:0,B:128,A:255).
+ ///
+ public static Color Purple
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Red color (R:255,G:0,B:0,A:255).
+ ///
+ public static Color Red
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// RosyBrown color (R:188,G:143,B:143,A:255).
+ ///
+ public static Color RosyBrown
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// RoyalBlue color (R:65,G:105,B:225,A:255).
+ ///
+ public static Color RoyalBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SaddleBrown color (R:139,G:69,B:19,A:255).
+ ///
+ public static Color SaddleBrown
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Salmon color (R:250,G:128,B:114,A:255).
+ ///
+ public static Color Salmon
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SandyBrown color (R:244,G:164,B:96,A:255).
+ ///
+ public static Color SandyBrown
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SeaGreen color (R:46,G:139,B:87,A:255).
+ ///
+ public static Color SeaGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SeaShell color (R:255,G:245,B:238,A:255).
+ ///
+ public static Color SeaShell
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Sienna color (R:160,G:82,B:45,A:255).
+ ///
+ public static Color Sienna
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Silver color (R:192,G:192,B:192,A:255).
+ ///
+ public static Color Silver
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SkyBlue color (R:135,G:206,B:235,A:255).
+ ///
+ public static Color SkyBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SlateBlue color (R:106,G:90,B:205,A:255).
+ ///
+ public static Color SlateBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SlateGray color (R:112,G:128,B:144,A:255).
+ ///
+ public static Color SlateGray
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Snow color (R:255,G:250,B:250,A:255).
+ ///
+ public static Color Snow
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SpringGreen color (R:0,G:255,B:127,A:255).
+ ///
+ public static Color SpringGreen
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// SteelBlue color (R:70,G:130,B:180,A:255).
+ ///
+ public static Color SteelBlue
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Tan color (R:210,G:180,B:140,A:255).
+ ///
+ public static Color Tan
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Teal color (R:0,G:128,B:128,A:255).
+ ///
+ public static Color Teal
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Thistle color (R:216,G:191,B:216,A:255).
+ ///
+ public static Color Thistle
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Tomato color (R:255,G:99,B:71,A:255).
+ ///
+ public static Color Tomato
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Turquoise color (R:64,G:224,B:208,A:255).
+ ///
+ public static Color Turquoise
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Violet color (R:238,G:130,B:238,A:255).
+ ///
+ public static Color Violet
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Wheat color (R:245,G:222,B:179,A:255).
+ ///
+ public static Color Wheat
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// White color (R:255,G:255,B:255,A:255).
+ ///
+ public static Color White
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// WhiteSmoke color (R:245,G:245,B:245,A:255).
+ ///
+ public static Color WhiteSmoke
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Yellow color (R:255,G:255,B:0,A:255).
+ ///
+ public static Color Yellow
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// YellowGreen color (R:154,G:205,B:50,A:255).
+ ///
+ public static Color YellowGreen
+ {
+ get;
+ private set;
+ }
+
+ #endregion
+
+ #region Internal Properties
+
+ internal string DebugDisplayString
+ {
+ get
+ {
+ return string.Concat(
+ R.ToString(), " ",
+ G.ToString(), " ",
+ B.ToString(), " ",
+ A.ToString()
+ );
+ }
+ }
+
+ #endregion
+
+ #region Private Variables
+
+ // ARGB
+ private uint _packedValue;
+
+ #endregion
+
+ #region Private Static Constructors
+
+ static Color()
+ {
+ Transparent = new Color(0);
+ AliceBlue = new Color(0xfffff8f0);
+ AntiqueWhite = new Color(0xffd7ebfa);
+ Aqua = new Color(0xffffff00);
+ Aquamarine = new Color(0xffd4ff7f);
+ Azure = new Color(0xfffffff0);
+ Beige = new Color(0xffdcf5f5);
+ Bisque = new Color(0xffc4e4ff);
+ Black = new Color(0xff000000);
+ BlanchedAlmond = new Color(0xffcdebff);
+ Blue = new Color(0xffff0000);
+ BlueViolet = new Color(0xffe22b8a);
+ Brown = new Color(0xff2a2aa5);
+ BurlyWood = new Color(0xff87b8de);
+ CadetBlue = new Color(0xffa09e5f);
+ Chartreuse = new Color(0xff00ff7f);
+ Chocolate = new Color(0xff1e69d2);
+ Coral = new Color(0xff507fff);
+ CornflowerBlue = new Color(0xffed9564);
+ Cornsilk = new Color(0xffdcf8ff);
+ Crimson = new Color(0xff3c14dc);
+ Cyan = new Color(0xffffff00);
+ DarkBlue = new Color(0xff8b0000);
+ DarkCyan = new Color(0xff8b8b00);
+ DarkGoldenrod = new Color(0xff0b86b8);
+ DarkGray = new Color(0xffa9a9a9);
+ DarkGreen = new Color(0xff006400);
+ DarkKhaki = new Color(0xff6bb7bd);
+ DarkMagenta = new Color(0xff8b008b);
+ DarkOliveGreen = new Color(0xff2f6b55);
+ DarkOrange = new Color(0xff008cff);
+ DarkOrchid = new Color(0xffcc3299);
+ DarkRed = new Color(0xff00008b);
+ DarkSalmon = new Color(0xff7a96e9);
+ DarkSeaGreen = new Color(0xff8bbc8f);
+ DarkSlateBlue = new Color(0xff8b3d48);
+ DarkSlateGray = new Color(0xff4f4f2f);
+ DarkTurquoise = new Color(0xffd1ce00);
+ DarkViolet = new Color(0xffd30094);
+ DeepPink = new Color(0xff9314ff);
+ DeepSkyBlue = new Color(0xffffbf00);
+ DimGray = new Color(0xff696969);
+ DodgerBlue = new Color(0xffff901e);
+ Firebrick = new Color(0xff2222b2);
+ FloralWhite = new Color(0xfff0faff);
+ ForestGreen = new Color(0xff228b22);
+ Fuchsia = new Color(0xffff00ff);
+ Gainsboro = new Color(0xffdcdcdc);
+ GhostWhite = new Color(0xfffff8f8);
+ Gold = new Color(0xff00d7ff);
+ Goldenrod = new Color(0xff20a5da);
+ Gray = new Color(0xff808080);
+ Green = new Color(0xff008000);
+ GreenYellow = new Color(0xff2fffad);
+ Honeydew = new Color(0xfff0fff0);
+ HotPink = new Color(0xffb469ff);
+ IndianRed = new Color(0xff5c5ccd);
+ Indigo = new Color(0xff82004b);
+ Ivory = new Color(0xfff0ffff);
+ Khaki = new Color(0xff8ce6f0);
+ Lavender = new Color(0xfffae6e6);
+ LavenderBlush = new Color(0xfff5f0ff);
+ LawnGreen = new Color(0xff00fc7c);
+ LemonChiffon = new Color(0xffcdfaff);
+ LightBlue = new Color(0xffe6d8ad);
+ LightCoral = new Color(0xff8080f0);
+ LightCyan = new Color(0xffffffe0);
+ LightGoldenrodYellow = new Color(0xffd2fafa);
+ LightGray = new Color(0xffd3d3d3);
+ LightGreen = new Color(0xff90ee90);
+ LightPink = new Color(0xffc1b6ff);
+ LightSalmon = new Color(0xff7aa0ff);
+ LightSeaGreen = new Color(0xffaab220);
+ LightSkyBlue = new Color(0xffface87);
+ LightSlateGray = new Color(0xff998877);
+ LightSteelBlue = new Color(0xffdec4b0);
+ LightYellow = new Color(0xffe0ffff);
+ Lime = new Color(0xff00ff00);
+ LimeGreen = new Color(0xff32cd32);
+ Linen = new Color(0xffe6f0fa);
+ Magenta = new Color(0xffff00ff);
+ Maroon = new Color(0xff000080);
+ MediumAquamarine = new Color(0xffaacd66);
+ MediumBlue = new Color(0xffcd0000);
+ MediumOrchid = new Color(0xffd355ba);
+ MediumPurple = new Color(0xffdb7093);
+ MediumSeaGreen = new Color(0xff71b33c);
+ MediumSlateBlue = new Color(0xffee687b);
+ MediumSpringGreen = new Color(0xff9afa00);
+ MediumTurquoise = new Color(0xffccd148);
+ MediumVioletRed = new Color(0xff8515c7);
+ MidnightBlue = new Color(0xff701919);
+ MintCream = new Color(0xfffafff5);
+ MistyRose = new Color(0xffe1e4ff);
+ Moccasin = new Color(0xffb5e4ff);
+ NavajoWhite = new Color(0xffaddeff);
+ Navy = new Color(0xff800000);
+ OldLace = new Color(0xffe6f5fd);
+ Olive = new Color(0xff008080);
+ OliveDrab = new Color(0xff238e6b);
+ Orange = new Color(0xff00a5ff);
+ OrangeRed = new Color(0xff0045ff);
+ Orchid = new Color(0xffd670da);
+ PaleGoldenrod = new Color(0xffaae8ee);
+ PaleGreen = new Color(0xff98fb98);
+ PaleTurquoise = new Color(0xffeeeeaf);
+ PaleVioletRed = new Color(0xff9370db);
+ PapayaWhip = new Color(0xffd5efff);
+ PeachPuff = new Color(0xffb9daff);
+ Peru = new Color(0xff3f85cd);
+ Pink = new Color(0xffcbc0ff);
+ Plum = new Color(0xffdda0dd);
+ PowderBlue = new Color(0xffe6e0b0);
+ Purple = new Color(0xff800080);
+ Red = new Color(0xff0000ff);
+ RosyBrown = new Color(0xff8f8fbc);
+ RoyalBlue = new Color(0xffe16941);
+ SaddleBrown = new Color(0xff13458b);
+ Salmon= new Color(0xff7280fa);
+ SandyBrown = new Color(0xff60a4f4);
+ SeaGreen = new Color(0xff578b2e);
+ SeaShell = new Color(0xffeef5ff);
+ Sienna = new Color(0xff2d52a0);
+ Silver = new Color(0xffc0c0c0);
+ SkyBlue = new Color(0xffebce87);
+ SlateBlue= new Color(0xffcd5a6a);
+ SlateGray= new Color(0xff908070);
+ Snow= new Color(0xfffafaff);
+ SpringGreen= new Color(0xff7fff00);
+ SteelBlue= new Color(0xffb48246);
+ Tan= new Color(0xff8cb4d2);
+ Teal= new Color(0xff808000);
+ Thistle= new Color(0xffd8bfd8);
+ Tomato= new Color(0xff4763ff);
+ Turquoise= new Color(0xffd0e040);
+ Violet= new Color(0xffee82ee);
+ Wheat= new Color(0xffb3def5);
+ White= new Color(uint.MaxValue);
+ WhiteSmoke= new Color(0xfff5f5f5);
+ Yellow = new Color(0xff00ffff);
+ YellowGreen = new Color(0xff32cd9a);
+ }
+
+ #endregion
+
+ #region Public Constructors
+
+ ///
+ /// Creates a new instance of struct.
+ ///
+ /// A representing a color.
+ public Color(Vector4 color)
+ {
+ _packedValue = 0;
+
+ R = (byte) MathHelper.Clamp(color.X * 255, Byte.MinValue, Byte.MaxValue);
+ G = (byte) MathHelper.Clamp(color.Y * 255, Byte.MinValue, Byte.MaxValue);
+ B = (byte) MathHelper.Clamp(color.Z * 255, Byte.MinValue, Byte.MaxValue);
+ A = (byte) MathHelper.Clamp(color.W * 255, Byte.MinValue, Byte.MaxValue);
+ }
+
+ ///
+ /// Constructs an RGBA color from the XYZW unit length components of a vector.
+ ///
+ /// A representing a color.
+ public Color(Vector3 color)
+ {
+ _packedValue = 0;
+
+ R = (byte) MathHelper.Clamp(color.X * 255, Byte.MinValue, Byte.MaxValue);
+ G = (byte) MathHelper.Clamp(color.Y * 255, Byte.MinValue, Byte.MaxValue);
+ B = (byte) MathHelper.Clamp(color.Z * 255, Byte.MinValue, Byte.MaxValue);
+ A = 255;
+ }
+
+ ///
+ /// Constructs an RGBA color from a and an alpha value.
+ ///
+ ///
+ /// A for RGB values of new instance.
+ ///
+ /// The alpha component value from 0 to 255.
+ public Color(Color color, int alpha)
+ {
+ _packedValue = 0;
+
+ R = color.R;
+ G = color.G;
+ B = color.B;
+ A = (byte) MathHelper.Clamp(alpha, Byte.MinValue, Byte.MaxValue);
+ }
+
+ ///
+ /// Constructs an RGBA color from color and alpha value.
+ ///
+ ///
+ /// A for RGB values of new instance.
+ ///
+ /// Alpha component value from 0.0f to 1.0f.
+ public Color(Color color, float alpha)
+ {
+ _packedValue = 0;
+
+ R = color.R;
+ G = color.G;
+ B = color.B;
+ A = (byte) MathHelper.Clamp(alpha * 255, Byte.MinValue, Byte.MaxValue);
+ }
+
+ ///
+ /// Constructs an RGBA color from scalars which representing red, green and blue values. Alpha value will be opaque.
+ ///
+ /// Red component value from 0.0f to 1.0f.
+ /// Green component value from 0.0f to 1.0f.
+ /// Blue component value from 0.0f to 1.0f.
+ public Color(float r, float g, float b)
+ {
+ _packedValue = 0;
+
+ R = (byte) MathHelper.Clamp(r * 255, Byte.MinValue, Byte.MaxValue);
+ G = (byte) MathHelper.Clamp(g * 255, Byte.MinValue, Byte.MaxValue);
+ B = (byte) MathHelper.Clamp(b * 255, Byte.MinValue, Byte.MaxValue);
+ A = 255;
+ }
+
+ ///
+ /// Constructs an RGBA color from scalars which representing red, green and blue values. Alpha value will be opaque.
+ ///
+ /// Red component value from 0 to 255.
+ /// Green component value from 0 to 255.
+ /// Blue component value from 0 to 255.
+ public Color(int r, int g, int b)
+ {
+ _packedValue = 0;
+ R = (byte) MathHelper.Clamp(r, Byte.MinValue, Byte.MaxValue);
+ G = (byte) MathHelper.Clamp(g, Byte.MinValue, Byte.MaxValue);
+ B = (byte) MathHelper.Clamp(b, Byte.MinValue, Byte.MaxValue);
+ A = (byte)255;
+ }
+
+ ///
+ /// Constructs an RGBA color from scalars which representing red, green, blue and alpha values.
+ ///
+ /// Red component value from 0 to 255.
+ /// Green component value from 0 to 255.
+ /// Blue component value from 0 to 255.
+ /// Alpha component value from 0 to 255.
+ public Color(int r, int g, int b, int alpha)
+ {
+ _packedValue = 0;
+ R = (byte) MathHelper.Clamp(r, Byte.MinValue, Byte.MaxValue);
+ G = (byte) MathHelper.Clamp(g, Byte.MinValue, Byte.MaxValue);
+ B = (byte) MathHelper.Clamp(b, Byte.MinValue, Byte.MaxValue);
+ A = (byte) MathHelper.Clamp(alpha, Byte.MinValue, Byte.MaxValue);
+ }
+
+ ///
+ /// Constructs an RGBA color from scalars which representing red, green, blue and alpha values.
+ ///
+ /// Red component value from 0.0f to 1.0f.
+ /// Green component value from 0.0f to 1.0f.
+ /// Blue component value from 0.0f to 1.0f.
+ /// Alpha component value from 0.0f to 1.0f.
+ public Color(float r, float g, float b, float alpha)
+ {
+ _packedValue = 0;
+
+ R = (byte) MathHelper.Clamp(r * 255, Byte.MinValue, Byte.MaxValue);
+ G = (byte) MathHelper.Clamp(g * 255, Byte.MinValue, Byte.MaxValue);
+ B = (byte) MathHelper.Clamp(b * 255, Byte.MinValue, Byte.MaxValue);
+ A = (byte) MathHelper.Clamp(alpha * 255, Byte.MinValue, Byte.MaxValue);
+ }
+
+ #endregion
+
+ #region Private Constructors
+
+ private Color(uint packedValue)
+ {
+ _packedValue = packedValue;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ ///
+ /// Compares whether current instance is equal to specified .
+ ///
+ /// The to compare.
+ /// true if the instances are equal; false otherwise.
+ public bool Equals(Color other)
+ {
+ return this.PackedValue == other.PackedValue;
+ }
+
+ ///
+ /// Gets a representation for this object.
+ ///
+ /// A representation for this object.
+ public Vector3 ToVector3()
+ {
+ return new Vector3(R / 255.0f, G / 255.0f, B / 255.0f);
+ }
+
+ ///
+ /// Gets a representation for this object.
+ ///
+ /// A representation for this object.
+ public Vector4 ToVector4()
+ {
+ return new Vector4(R / 255.0f, G / 255.0f, B / 255.0f, A / 255.0f);
+ }
+
+ #endregion
+
+ #region Public Static Methods
+
+ ///
+ /// Performs linear interpolation of .
+ ///
+ /// Source .
+ /// Destination .
+ /// Interpolation factor.
+ /// Interpolated .
+ public static Color Lerp(Color value1, Color value2, float amount)
+ {
+ amount = MathHelper.Clamp(amount, 0.0f, 1.0f);
+ return new Color(
+ (int) MathHelper.Lerp(value1.R, value2.R, amount),
+ (int) MathHelper.Lerp(value1.G, value2.G, amount),
+ (int) MathHelper.Lerp(value1.B, value2.B, amount),
+ (int) MathHelper.Lerp(value1.A, value2.A, amount)
+ );
+ }
+
+ ///
+ /// Translate a non-premultipled alpha to a
+ /// that contains premultiplied alpha.
+ ///
+ /// A representing color.
+ /// A which contains premultiplied alpha data.
+ public static Color FromNonPremultiplied(Vector4 vector)
+ {
+ return new Color(
+ vector.X * vector.W,
+ vector.Y * vector.W,
+ vector.Z * vector.W,
+ vector.W
+ );
+ }
+
+ ///
+ /// Translate a non-premultipled alpha to a
+ /// that contains premultiplied alpha.
+ ///
+ /// Red component value.
+ /// Green component value.
+ /// Blue component value.
+ /// Alpha component value.
+ /// A which contains premultiplied alpha data.
+ public static Color FromNonPremultiplied(int r, int g, int b, int a)
+ {
+ return new Color(
+ (byte) (r * a / 255),
+ (byte) (g * a / 255),
+ (byte) (b * a / 255),
+ a
+ );
+ }
+
+ #endregion
+
+ #region Public Static Operators and Override Methods
+
+ ///
+ /// Compares whether two instances are equal.
+ ///
+ /// instance on the left of the equal sign.
+ /// instance on the right of the equal sign.
+ /// True if the instances are equal; false otherwise.
+ public static bool operator ==(Color a, Color b)
+ {
+ return ( a.A == b.A &&
+ a.R == b.R &&
+ a.G == b.G &&
+ a.B == b.B );
+ }
+
+ ///
+ /// Compares whether two instances are not equal.
+ ///
+ ///
+ /// instance on the left of the not equal sign.
+ ///
+ ///
+ /// instance on the right of the not equal sign.
+ ///
+ ///
+ /// True if the instances are not equal; false otherwise.
+ ///
+ public static bool operator !=(Color a, Color b)
+ {
+ return !(a == b);
+ }
+
+ ///
+ /// Gets the hash code of this .
+ ///
+ /// Hash code of this .
+ public override int GetHashCode()
+ {
+ return this._packedValue.GetHashCode();
+ }
+
+ ///
+ /// Compares whether current instance is equal to specified object.
+ ///
+ /// The to compare.
+ /// True if the instances are equal; false otherwise.
+ public override bool Equals(object obj)
+ {
+ return ((obj is Color) && this.Equals((Color) obj));
+ }
+
+ ///
+ /// Multiply by value.
+ ///
+ /// Source .
+ /// Multiplicator.
+ /// Multiplication result.
+ public static Color Multiply(Color value, float scale)
+ {
+ return new Color(
+ (int) (value.R * scale),
+ (int) (value.G * scale),
+ (int) (value.B * scale),
+ (int) (value.A * scale)
+ );
+ }
+
+ ///
+ /// Multiply by value.
+ ///
+ /// Source .
+ /// Multiplicator.
+ /// Multiplication result.
+ public static Color operator *(Color value, float scale)
+ {
+ return new Color(
+ (int) (value.R * scale),
+ (int) (value.G * scale),
+ (int) (value.B * scale),
+ (int) (value.A * scale)
+ );
+ }
+
+ ///
+ /// Returns a representation of this in the format:
+ /// {R:[red] G:[green] B:[blue] A:[alpha]}
+ ///
+ /// representation of this .
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder(25);
+ sb.Append("{R:");
+ sb.Append(R);
+ sb.Append(" G:");
+ sb.Append(G);
+ sb.Append(" B:");
+ sb.Append(B);
+ sb.Append(" A:");
+ sb.Append(A);
+ sb.Append("}");
+ return sb.ToString();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/ContainmentType.cs b/src/ContainmentType.cs
new file mode 100644
index 0000000..b8b62fe
--- /dev/null
+++ b/src/ContainmentType.cs
@@ -0,0 +1,34 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+
+/* Derived from code by the Mono.Xna Team (Copyright 2006).
+ * Released under the MIT License. See monoxna.LICENSE for details.
+ */
+#endregion
+
+namespace Microsoft.Xna.Framework
+{
+ ///
+ /// Defines how the bounding volumes intersects or contain one another.
+ ///
+ public enum ContainmentType
+ {
+ ///
+ /// Indicates that there is no overlap between two bounding volumes.
+ ///
+ Disjoint,
+ ///
+ /// Indicates that one bounding volume completely contains another volume.
+ ///
+ Contains,
+ ///
+ /// Indicates that bounding volumes partially overlap one another.
+ ///
+ Intersects
+ }
+}
diff --git a/src/Content/ContentExtensions.cs b/src/Content/ContentExtensions.cs
new file mode 100644
index 0000000..3a9060a
--- /dev/null
+++ b/src/Content/ContentExtensions.cs
@@ -0,0 +1,72 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+#endregion
+
+namespace Microsoft.Xna.Framework.Content
+{
+ internal static class ContentExtensions
+ {
+ #region Public Static Constructor Extractor Method
+
+ public static ConstructorInfo GetDefaultConstructor(this Type type)
+ {
+ BindingFlags attrs = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
+ return type.GetConstructor(attrs, null, new Type[0], null);
+ }
+
+ #endregion
+
+ #region Public Static Property Extractor Method
+
+ public static PropertyInfo[] GetAllProperties(this Type type)
+ {
+
+ /* Sometimes, overridden properties of abstract classes can show up even with
+ * BindingFlags.DeclaredOnly is passed to GetProperties. Make sure that
+ * all properties in this list are defined in this class by comparing
+ * its get method with that of its base class. If they're the same
+ * Then it's an overridden property.
+ */
+ const BindingFlags attrs = (
+ BindingFlags.NonPublic |
+ BindingFlags.Public |
+ BindingFlags.Instance |
+ BindingFlags.DeclaredOnly
+ );
+ List allProps = type.GetProperties(attrs).ToList();
+ PropertyInfo[] props = allProps.FindAll(
+ p => p.GetGetMethod(true) != null && p.GetGetMethod(true) == p.GetGetMethod(true).GetBaseDefinition()
+ ).ToArray();
+ return props;
+ }
+
+ #endregion
+
+ #region Public Static Field Extractor Method
+
+ public static FieldInfo[] GetAllFields(this Type type)
+ {
+ BindingFlags attrs = (
+ BindingFlags.NonPublic |
+ BindingFlags.Public |
+ BindingFlags.Instance |
+ BindingFlags.DeclaredOnly
+ );
+ return type.GetFields(attrs);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Content/ContentLoadException.cs b/src/Content/ContentLoadException.cs
new file mode 100644
index 0000000..b108d85
--- /dev/null
+++ b/src/Content/ContentLoadException.cs
@@ -0,0 +1,35 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+#endregion
+
+namespace Microsoft.Xna.Framework.Content
+{
+ public class ContentLoadException : Exception
+ {
+ #region Public Constructors
+
+ public ContentLoadException() : base()
+ {
+ }
+
+ public ContentLoadException(string message) : base(message)
+ {
+ }
+
+ public ContentLoadException(string message, Exception innerException) : base(message,innerException)
+ {
+ }
+
+ #endregion
+ }
+}
+
diff --git a/src/Content/ContentManager.cs b/src/Content/ContentManager.cs
new file mode 100644
index 0000000..4735261
--- /dev/null
+++ b/src/Content/ContentManager.cs
@@ -0,0 +1,596 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Media;
+using Microsoft.Xna.Framework.Utilities;
+#endregion
+
+namespace Microsoft.Xna.Framework.Content
+{
+ public partial class ContentManager : IDisposable
+ {
+ #region Public ServiceProvider Property
+
+ public IServiceProvider ServiceProvider
+ {
+ get;
+ private set;
+ }
+
+ #endregion
+
+ #region Public RootDirectory Property
+
+ public string RootDirectory
+ {
+ get;
+ set;
+ }
+
+ #endregion
+
+ #region Internal Root Directory Path Property
+
+ internal string RootDirectoryFullPath
+ {
+ get
+ {
+ if (Path.IsPathRooted(RootDirectory))
+ {
+ return RootDirectory;
+ }
+ return Path.Combine(TitleContainer.Location, RootDirectory);
+ }
+ }
+
+ #endregion
+
+ #region Private Variables
+
+ private IGraphicsDeviceService graphicsDeviceService;
+ private Dictionary loadedAssets = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ private List disposableAssets = new List();
+ private bool disposed;
+
+ #endregion
+
+ #region Private Static Variables
+
+ private static object ContentManagerLock = new object();
+ private static List ContentManagers = new List();
+
+ private static readonly byte[] xnbHeader = new byte[4];
+ private static List targetPlatformIdentifiers = new List()
+ {
+ 'w', // Windows (DirectX)
+ 'x', // Xbox360
+ 'm', // WindowsPhone
+ 'i', // iOS
+ 'a', // Android
+ 'd', // DesktopGL
+ 'X', // MacOSX
+ 'W', // WindowsStoreApp
+ 'n', // NativeClient
+ 'u', // Ouya
+ 'p', // PlayStationMobile
+ 'M', // WindowsPhone8
+ 'r', // RaspberryPi
+ 'P', // Playstation 4
+ 'g', // WindowsGL (deprecated for DesktopGL)
+ 'l', // Linux (deprecated for DesktopGL)
+ };
+
+ #endregion
+
+ #region Public Constructors
+
+ public ContentManager(IServiceProvider serviceProvider)
+ {
+ if (serviceProvider == null)
+ {
+ throw new ArgumentNullException("serviceProvider");
+ }
+ ServiceProvider = serviceProvider;
+ RootDirectory = string.Empty;
+ AddContentManager(this);
+ }
+
+ public ContentManager(IServiceProvider serviceProvider, string rootDirectory)
+ {
+ if (serviceProvider == null)
+ {
+ throw new ArgumentNullException("serviceProvider");
+ }
+ if (rootDirectory == null)
+ {
+ throw new ArgumentNullException("rootDirectory");
+ }
+ ServiceProvider = serviceProvider;
+ RootDirectory = rootDirectory;
+ AddContentManager(this);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ /* Use C# destructor syntax for finalization code.
+ * This destructor will run only if the Dispose method
+ * does not get called.
+ * It gives your base class the opportunity to finalize.
+ * Do not provide destructors in types derived from this class.
+ */
+ ~ContentManager()
+ {
+ /* Do not re-create Dispose clean-up code here.
+ * Calling Dispose(false) is optimal in terms of
+ * readability and maintainability.
+ */
+ Dispose(false);
+ }
+
+ #endregion
+
+ #region Dispose Methods
+
+ public void Dispose()
+ {
+ Dispose(true);
+ /* Tell the garbage collector not to call the finalizer
+ * since all the cleanup will already be done.
+ */
+ GC.SuppressFinalize(this);
+ // Once disposed, content manager wont be used again
+ RemoveContentManager(this);
+ }
+
+ /* If disposing is true, it was called explicitly and we should dispose managed
+ * objects. If disposing is false, it was called by the finalizer and managed
+ * objects should not be disposed.
+ */
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ if (disposing)
+ {
+ Unload();
+ }
+ disposed = true;
+ }
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public virtual T Load(string assetName)
+ {
+ if (string.IsNullOrEmpty(assetName))
+ {
+ throw new ArgumentNullException("assetName");
+ }
+ if (disposed)
+ {
+ throw new ObjectDisposedException("ContentManager");
+ }
+ T result = default(T);
+
+ /* On some platforms, name and slash direction matter.
+ * We store the asset by a /-separating key rather than
+ * how the path to the file was passed to us to avoid
+ * loading "content/asset1.xnb" and "content\\ASSET1.xnb"
+ * as if they were two different files. this matches
+ * stock XNA behavior. The Dictionary will ignore case
+ * differences.
+ */
+ string key = assetName.Replace('\\', '/');
+
+ // Check for a previously loaded asset first
+ object asset = null;
+ if (loadedAssets.TryGetValue(key, out asset))
+ {
+ if (asset is T)
+ {
+ return (T) asset;
+ }
+ }
+ // Load the asset.
+ result = ReadAsset(assetName, null);
+ loadedAssets[key] = result;
+ return result;
+ }
+
+ public virtual void Unload()
+ {
+ // Look for disposable assets.
+ foreach (IDisposable disposable in disposableAssets)
+ {
+ if (disposable != null)
+ {
+ disposable.Dispose();
+ }
+ }
+ disposableAssets.Clear();
+ loadedAssets.Clear();
+ }
+
+ #endregion
+
+ #region Protected Methods
+
+ protected virtual Stream OpenStream(string assetName)
+ {
+ Stream stream;
+ try
+ {
+ stream = TitleContainer.OpenStream(
+ Path.Combine(RootDirectory, assetName) + ".xnb"
+ );
+ }
+ catch (FileNotFoundException fileNotFound)
+ {
+ throw new ContentLoadException("The content file was not found.", fileNotFound);
+ }
+ catch (DirectoryNotFoundException directoryNotFound)
+ {
+ throw new ContentLoadException("The directory was not found.", directoryNotFound);
+ }
+ catch (Exception exception)
+ {
+ throw new ContentLoadException("Opening stream error.", exception);
+ }
+ return stream;
+ }
+
+ protected T ReadAsset(string assetName, Action recordDisposableObject)
+ {
+ if (string.IsNullOrEmpty(assetName))
+ {
+ throw new ArgumentNullException("assetName");
+ }
+ if (disposed)
+ {
+ throw new ObjectDisposedException("ContentManager");
+ }
+
+ object result = null;
+
+ // FIXME: Should this block be here? -flibit
+ if (graphicsDeviceService == null)
+ {
+ graphicsDeviceService = ServiceProvider.GetService(typeof(IGraphicsDeviceService)) as IGraphicsDeviceService;
+ if (graphicsDeviceService == null)
+ {
+ throw new InvalidOperationException("No Graphics Device Service");
+ }
+ }
+
+ Stream stream = null;
+ string modifiedAssetName = String.Empty; // Will be used if we have to guess a filename
+ try
+ {
+ stream = OpenStream(assetName);
+ }
+ catch (Exception e)
+ {
+ // Okay, so we couldn't open it. Maybe it needs a different extension?
+ // FIXME: This only works for files on the disk, what about custom streams? -flibit
+ modifiedAssetName = FileHelpers.NormalizeFilePathSeparators(
+ Path.Combine(RootDirectoryFullPath, assetName)
+ );
+ if (typeof(T) == typeof(Texture2D) || typeof(T) == typeof(Texture))
+ {
+ modifiedAssetName = Texture2DReader.Normalize(modifiedAssetName);
+ }
+ else if ((typeof(T) == typeof(SoundEffect)))
+ {
+ modifiedAssetName = SoundEffectReader.Normalize(modifiedAssetName);
+ }
+ else if ((typeof(T) == typeof(Effect)))
+ {
+ modifiedAssetName = EffectReader.Normalize(modifiedAssetName);
+ }
+ else if ((typeof(T) == typeof(Song)))
+ {
+ modifiedAssetName = SongReader.Normalize(modifiedAssetName);
+ }
+ else if ((typeof(T) == typeof(Video)))
+ {
+ modifiedAssetName = VideoReader.Normalize(modifiedAssetName);
+ }
+
+ // Did we get anything...?
+ if (String.IsNullOrEmpty(modifiedAssetName))
+ {
+ // Nope, nothing we're aware of!
+ throw new ContentLoadException(
+ "Could not load asset " + assetName + "! Error: " + e.Message,
+ e
+ );
+ }
+
+ stream = TitleContainer.OpenStream(modifiedAssetName);
+ }
+
+ // Check for XNB header
+ stream.Read(xnbHeader, 0, xnbHeader.Length);
+ if ( xnbHeader[0] == 'X' &&
+ xnbHeader[1] == 'N' &&
+ xnbHeader[2] == 'B' &&
+ targetPlatformIdentifiers.Contains((char) xnbHeader[3]) )
+ {
+ using (BinaryReader xnbReader = new BinaryReader(stream))
+ using (ContentReader reader = GetContentReaderFromXnb(assetName, ref stream, xnbReader, recordDisposableObject))
+ {
+ result = reader.ReadAsset();
+ GraphicsResource resource = result as GraphicsResource;
+ if (resource != null)
+ {
+ resource.Name = assetName;
+ }
+ }
+ }
+ else
+ {
+ // It's not an XNB file. Try to load as a raw asset instead.
+
+ // FIXME: Assuming seekable streams! -flibit
+ stream.Seek(0, SeekOrigin.Begin);
+
+ if (typeof(T) == typeof(Texture2D) || typeof(T) == typeof(Texture))
+ {
+ Texture2D texture = Texture2D.FromStream(
+ graphicsDeviceService.GraphicsDevice,
+ stream
+ );
+ texture.Name = assetName;
+ result = texture;
+ }
+ else if ((typeof(T) == typeof(SoundEffect)))
+ {
+ result = SoundEffect.FromStream(stream);
+ }
+ else if ((typeof(T) == typeof(Effect)))
+ {
+ byte[] data = new byte[stream.Length];
+ stream.Read(data, 0, (int) stream.Length);
+ result = new Effect(graphicsDeviceService.GraphicsDevice, data);
+ }
+ else if ((typeof(T) == typeof(Song)))
+ {
+ // FIXME: Not using the stream! -flibit
+ result = new Song(modifiedAssetName);
+ }
+ else if ((typeof(T) == typeof(Video)))
+ {
+ // FIXME: Not using the stream! -flibit
+ result = new Video(modifiedAssetName);
+ }
+ else
+ {
+ stream.Close();
+ throw new ContentLoadException("Could not load " + assetName + " asset!");
+ }
+
+ /* Because Raw Assets skip the ContentReader step, they need to have their
+ * disposables recorded here. Doing it outside of this catch will
+ * result in disposables being logged twice.
+ */
+ IDisposable disposableResult = result as IDisposable;
+ if (disposableResult != null)
+ {
+ if (recordDisposableObject != null)
+ {
+ recordDisposableObject(disposableResult);
+ }
+ else
+ {
+ disposableAssets.Add(disposableResult);
+ }
+ }
+
+ /* Because we're not using a BinaryReader for raw assets, we
+ * need to close the stream ourselves.
+ * -flibit
+ */
+ stream.Close();
+ }
+
+ return (T) result;
+ }
+
+ #endregion
+
+ #region Internal Methods
+
+ internal void RecordDisposable(IDisposable disposable)
+ {
+ Debug.Assert(disposable != null, "The disposable is null!");
+
+ /* Avoid recording disposable objects twice. ReloadAsset will try to record
+ * the disposables again. We don't know which asset recorded which
+ * disposable so just guard against storing multiple of the same instance.
+ */
+ if (!disposableAssets.Contains(disposable))
+ {
+ disposableAssets.Add(disposable);
+ }
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private ContentReader GetContentReaderFromXnb(string originalAssetName, ref Stream stream, BinaryReader xnbReader, Action recordDisposableObject)
+ {
+ byte version = xnbReader.ReadByte();
+ byte flags = xnbReader.ReadByte();
+ bool compressed = (flags & 0x80) != 0;
+ if (version != 5 && version != 4)
+ {
+ throw new ContentLoadException("Invalid XNB version");
+ }
+ // The next int32 is the length of the XNB file
+ int xnbLength = xnbReader.ReadInt32();
+ ContentReader reader;
+ if (compressed)
+ {
+ /* Decompress the XNB
+ * Thanks to ShinAli (https://bitbucket.org/alisci01/xnbdecompressor)
+ */
+ int compressedSize = xnbLength - 14;
+ int decompressedSize = xnbReader.ReadInt32();
+ MemoryStream decompressedStream = new MemoryStream(
+ new byte[decompressedSize],
+ 0,
+ decompressedSize,
+ true,
+ true // This MUST be true! We may need GetBuffer()!
+ );
+ // Default window size for XNB encoded files is 64Kb (need 16 bits to represent it)
+ LzxDecoder dec = new LzxDecoder(16);
+ int decodedBytes = 0;
+ long startPos = stream.Position;
+ long pos = startPos;
+
+ while (pos - startPos < compressedSize)
+ {
+ /* The compressed stream is separated into blocks that will
+ * decompress into 32kB or some other size if specified.
+ * Normal, 32kB output blocks will have a short indicating
+ * the size of the block before the block starts. Blocks
+ * that have a defined output will be preceded by a byte of
+ * value 0xFF (255), then a short indicating the output size
+ * and another for the block size. All shorts for these
+ * cases are encoded in big endian order.
+ */
+ int hi = stream.ReadByte();
+ int lo = stream.ReadByte();
+ int block_size = (hi << 8) | lo;
+ int frame_size = 0x8000; // Frame size is 32kB by default
+ // Does this block define a frame size?
+ if (hi == 0xFF)
+ {
+ hi = lo;
+ lo = (byte) stream.ReadByte();
+ frame_size = (hi << 8) | lo;
+ hi = (byte) stream.ReadByte();
+ lo = (byte) stream.ReadByte();
+ block_size = (hi << 8) | lo;
+ pos += 5;
+ }
+ else
+ {
+ pos += 2;
+ }
+ // Either says there is nothing to decode
+ if (block_size == 0 || frame_size == 0)
+ {
+ break;
+ }
+ dec.Decompress(stream, block_size, decompressedStream, frame_size);
+ pos += block_size;
+ decodedBytes += frame_size;
+ /* Reset the position of the input just in case the bit
+ * buffer read in some unused bytes.
+ */
+ stream.Seek(pos, SeekOrigin.Begin);
+ }
+ if (decompressedStream.Position != decompressedSize)
+ {
+ throw new ContentLoadException(
+ "Decompression of " + originalAssetName + " failed. "
+ );
+ }
+ decompressedStream.Seek(0, SeekOrigin.Begin);
+ reader = new ContentReader(
+ this,
+ decompressedStream,
+ graphicsDeviceService.GraphicsDevice,
+ originalAssetName,
+ version,
+ recordDisposableObject
+ );
+ }
+ else
+ {
+ reader = new ContentReader(
+ this,
+ stream,
+ graphicsDeviceService.GraphicsDevice,
+ originalAssetName,
+ version,
+ recordDisposableObject
+ );
+ }
+ return reader;
+ }
+
+ #endregion
+
+ #region Private Static Methods
+
+ private static void AddContentManager(ContentManager contentManager)
+ {
+ lock (ContentManagerLock)
+ {
+ /* Check if the list contains this content manager already. Also take
+ * the opportunity to prune the list of any finalized content managers.
+ */
+ bool contains = false;
+ for (int i = ContentManagers.Count - 1; i >= 0; i -= 1)
+ {
+ WeakReference contentRef = ContentManagers[i];
+ if (ReferenceEquals(contentRef.Target, contentManager))
+ {
+ contains = true;
+ }
+ if (!contentRef.IsAlive)
+ {
+ ContentManagers.RemoveAt(i);
+ }
+ }
+ if (!contains)
+ {
+ ContentManagers.Add(new WeakReference(contentManager));
+ }
+ }
+ }
+
+ private static void RemoveContentManager(ContentManager contentManager)
+ {
+ lock (ContentManagerLock)
+ {
+ /* Check if the list contains this content manager and remove it. Also
+ * take the opportunity to prune the list of any finalized content managers.
+ */
+ for (int i = ContentManagers.Count - 1; i >= 0; i -= 1)
+ {
+ WeakReference contentRef = ContentManagers[i];
+ if (!contentRef.IsAlive || ReferenceEquals(contentRef.Target, contentManager))
+ {
+ ContentManagers.RemoveAt(i);
+ }
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Content/ContentReader.cs b/src/Content/ContentReader.cs
new file mode 100644
index 0000000..fe7ad53
--- /dev/null
+++ b/src/Content/ContentReader.cs
@@ -0,0 +1,363 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2015 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+
+/* Derived from code by the Mono.Xna Team (Copyright 2006).
+ * Released under the MIT License. See monoxna.LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Utilities;
+#endregion
+
+namespace Microsoft.Xna.Framework.Content
+{
+ public sealed class ContentReader : BinaryReader
+ {
+ #region Public Properties
+
+ public ContentManager ContentManager
+ {
+ get
+ {
+ return contentManager;
+ }
+ }
+
+ public string AssetName
+ {
+ get
+ {
+ return assetName;
+ }
+ }
+
+ #endregion
+
+ #region Internal Properties
+
+ internal ContentTypeReader[] TypeReaders
+ {
+ get
+ {
+ return typeReaders;
+ }
+ }
+
+ internal GraphicsDevice GraphicsDevice
+ {
+ get
+ {
+ return this.graphicsDevice;
+ }
+ }
+
+ #endregion
+
+ #region Internal Variables
+
+ internal int version;
+ internal int sharedResourceCount;
+
+ #endregion
+
+ #region Private Variables
+
+ private ContentManager contentManager;
+ private Action recordDisposableObject;
+ private ContentTypeReaderManager typeReaderManager;
+ private GraphicsDevice graphicsDevice;
+ private string assetName;
+ private List>> sharedResourceFixups;
+ private ContentTypeReader[] typeReaders;
+
+ #endregion
+
+ #region Internal Constructor
+
+ internal ContentReader(
+ ContentManager manager,
+ Stream stream,
+ GraphicsDevice graphicsDevice,
+ string assetName,
+ int version,
+ Action recordDisposableObject
+ ) : base(stream) {
+ this.graphicsDevice = graphicsDevice;
+ this.recordDisposableObject = recordDisposableObject;
+ this.contentManager = manager;
+ this.assetName = assetName;
+ this.version = version;
+ }
+
+ #endregion
+
+ #region Public Read Methods
+
+ public T ReadExternalReference()
+ {
+ string externalReference = ReadString();
+ if (!String.IsNullOrEmpty(externalReference))
+ {
+ return contentManager.Load(FileHelpers.ResolveRelativePath(assetName, externalReference));
+ }
+ return default(T);
+ }
+
+ public Matrix ReadMatrix()
+ {
+ Matrix result = new Matrix();
+ result.M11 = ReadSingle();
+ result.M12 = ReadSingle();
+ result.M13 = ReadSingle();
+ result.M14 = ReadSingle();
+ result.M21 = ReadSingle();
+ result.M22 = ReadSingle();
+ result.M23 = ReadSingle();
+ result.M24 = ReadSingle();
+ result.M31 = ReadSingle();
+ result.M32 = ReadSingle();
+ result.M33 = ReadSingle();
+ result.M34 = ReadSingle();
+ result.M41 = ReadSingle();
+ result.M42 = ReadSingle();
+ result.M43 = ReadSingle();
+ result.M44 = ReadSingle();
+ return result;
+ }
+
+ public T ReadObject()
+ {
+ return ReadObject(default(T));
+ }
+
+ public T ReadObject(ContentTypeReader typeReader)
+ {
+ T result = (T) typeReader.Read(this, default(T));
+ RecordDisposable(result);
+ return result;
+ }
+
+ public T ReadObject(T existingInstance)
+ {
+ return InnerReadObject(existingInstance);
+ }
+
+ public T ReadObject(ContentTypeReader typeReader, T existingInstance)
+ {
+ if (!typeReader.TargetType.IsValueType)
+ {
+ return ReadObject(existingInstance);
+ }
+ T result = (T) typeReader.Read(this, existingInstance);
+ RecordDisposable(result);
+ return result;
+ }
+
+ public Quaternion ReadQuaternion()
+ {
+ Quaternion result = new Quaternion();
+ result.X = ReadSingle();
+ result.Y = ReadSingle();
+ result.Z = ReadSingle();
+ result.W = ReadSingle();
+ return result;
+ }
+
+ public T ReadRawObject()
+ {
+ return (T) ReadRawObject(default(T));
+ }
+
+ public T ReadRawObject(ContentTypeReader typeReader)
+ {
+ return (T) ReadRawObject(typeReader, default(T));
+ }
+
+ public T ReadRawObject(T existingInstance)
+ {
+ Type objectType = typeof(T);
+ foreach (ContentTypeReader typeReader in typeReaders)
+ {
+ if (typeReader.TargetType == objectType)
+ {
+ return (T) ReadRawObject(typeReader,existingInstance);
+ }
+ }
+ throw new NotSupportedException();
+ }
+
+ public T ReadRawObject(ContentTypeReader typeReader, T existingInstance)
+ {
+ return (T) typeReader.Read(this, existingInstance);
+ }
+
+ public void ReadSharedResource(Action fixup)
+ {
+ int index = Read7BitEncodedInt();
+ if (index > 0)
+ {
+ sharedResourceFixups.Add(
+ new KeyValuePair> (
+ index - 1,
+ delegate(object v)
+ {
+ if (!(v is T))
+ {
+ throw new ContentLoadException(
+ String.Format(
+ "Error loading shared resource. Expected type {0}, received type {1}",
+ typeof(T).Name, v.GetType().Name
+ )
+ );
+ }
+ fixup((T) v);
+ }
+ )
+ );
+ }
+ }
+
+ public Vector2 ReadVector2()
+ {
+ Vector2 result = new Vector2();
+ result.X = ReadSingle();
+ result.Y = ReadSingle();
+ return result;
+ }
+
+ public Vector3 ReadVector3()
+ {
+ Vector3 result = new Vector3();
+ result.X = ReadSingle();
+ result.Y = ReadSingle();
+ result.Z = ReadSingle();
+ return result;
+ }
+
+ public Vector4 ReadVector4()
+ {
+ Vector4 result = new Vector4();
+ result.X = ReadSingle();
+ result.Y = ReadSingle();
+ result.Z = ReadSingle();
+ result.W = ReadSingle();
+ return result;
+ }
+
+ public Color ReadColor()
+ {
+ Color result = new Color();
+ result.R = ReadByte();
+ result.G = ReadByte();
+ result.B = ReadByte();
+ result.A = ReadByte();
+ return result;
+ }
+
+ #endregion
+
+ #region Internal Methods
+
+ internal object ReadAsset()
+ {
+ InitializeTypeReaders();
+ // Read primary object
+ object result = ReadObject();
+ // Read shared resources
+ ReadSharedResources();
+ return result;
+ }
+
+ internal void InitializeTypeReaders()
+ {
+ typeReaderManager = new ContentTypeReaderManager();
+ typeReaders = typeReaderManager.LoadAssetReaders(this);
+ sharedResourceCount = Read7BitEncodedInt();
+ sharedResourceFixups = new List>>();
+ }
+
+ internal void ReadSharedResources()
+ {
+ if (sharedResourceCount <= 0)
+ {
+ return;
+ }
+
+ object[] sharedResources = new object[sharedResourceCount];
+ for (int i = 0; i < sharedResourceCount; i += 1)
+ {
+ sharedResources[i] = InnerReadObject